master
Ondřej Hruška 3 years ago
parent 4a51f7d3c2
commit ee24917bee
Signed by: MightyPork
GPG Key ID: 2C5FD5035250423D
  1. 5
      yopa-web/Makefile
  2. 21
      yopa-web/resources/src/components/EditObjectForm.vue
  3. 31
      yopa-web/resources/src/components/EditPropertyField.vue
  4. 24
      yopa-web/resources/src/components/EditRelationForm.vue
  5. 19
      yopa-web/resources/src/components/NewObjectForm.vue
  6. 49
      yopa-web/resources/src/components/NewRelationForm.vue
  7. 55
      yopa-web/resources/src/components/PropertyField.vue
  8. 222
      yopa-web/resources/src/style/_common.scss
  9. 4
      yopa-web/resources/src/style/_spectre-patches.scss
  10. 21
      yopa-web/resources/src/style/app.scss
  11. 3
      yopa-web/resources/src/style/spectre/src/_tables.scss
  12. 10412
      yopa-web/resources/static/bundle.js
  13. 2
      yopa-web/resources/static/bundle.js.map
  14. 30
      yopa-web/resources/static/style.css
  15. 39
      yopa-web/resources/templates/_form_macros.html.tera
  16. 20
      yopa-web/resources/templates/_layout.html.tera
  17. 1
      yopa-web/resources/templates/models/_schema_macros.html.tera
  18. 2
      yopa-web/resources/templates/models/index.html.tera
  19. 17
      yopa-web/resources/templates/models/model_create.html.tera
  20. 34
      yopa-web/resources/templates/models/model_update.html.tera
  21. 54
      yopa-web/resources/templates/models/property_create.html.tera
  22. 70
      yopa-web/resources/templates/models/property_update.html.tera
  23. 57
      yopa-web/resources/templates/models/relation_create.html.tera
  24. 39
      yopa-web/resources/templates/models/relation_update.html.tera
  25. 18
      yopa-web/resources/templates/objects/index.html.tera
  26. 3
      yopa-web/resources/templates/objects/object_create.html.tera
  27. 20
      yopa-web/resources/templates/objects/object_detail.html.tera
  28. 2
      yopa-web/resources/templates/objects/object_update.html.tera
  29. 13
      yopa-web/resources/test/edit_object.html
  30. 51
      yopa-web/resources/test/edit_object_model.html
  31. 83
      yopa-web/resources/test/edit_prop_model.htm
  32. 52
      yopa-web/resources/test/edit_rel_model.html
  33. 66
      yopa-web/resources/test/model_list.html
  34. 29
      yopa-web/resources/test/new_object.html
  35. 74
      yopa-web/resources/test/new_rel_model.html
  36. 73
      yopa-web/resources/test/object_detail.html
  37. 1
      yopa-web/src/routes/models/property.rs

@ -1,2 +1,7 @@
.PHONY: assets watch
assets:
cd resources && npm run build
watch:
cd resources && npm run watch

@ -134,19 +134,20 @@ export default {
</script>
<template>
<div class="cols">
<div class="col-9">
<h2>Edit {{ model.name }}</h2>
</div>
<div class="col-3 text-right">
<button @click="trySave" class="btn btn-primary">
<i class="icon icon-check"></i>
Save
</button>
<div class="container">
<div class="cols">
<div class="col col-9">
<h1>Edit {{ model.name }}</h1>
</div>
<div class="col col-3 text-right">
<button @click="trySave" class="btn btn-primary">
<i class="icon icon-check"></i>Save
</button>
</div>
</div>
</div>
<div class="form-horizontal">
<div class="form-horizontal container">
<edit-property v-for="(property, pi) in properties" :model="property" :values="values[property.id]" :key="pi"></edit-property>
</div>

@ -38,38 +38,37 @@ export default {
</script>
<template>
<div v-if="values.length===0" class="form-group">
<div class="col-3">
<label class="form-label" :for="widget_id">{{ model.name }}</label>
<div v-if="values.length===0" class="form-group cols">
<div class="col-3 pl-2">
<label class="form-label">{{ model.name }}</label>
</div>
<div class="col-9">
<div class="col-9 pr-2">
<a class="btn" @click="addValue">
<i class="icon icon-plus"></i>
Add
<i class="icon icon-plus"></i>Add
</a>
</div>
</div>
<div v-if="values.length>0" class="form-group" v-for="(instance, vi) in values" :key="vi">
<div class="col-3">
<div v-if="values.length>0" class="form-group cols" v-for="(instance, vi) in values" :key="vi">
<div class="col-3 pl-2">
<label class="form-label" :for="widget_id" v-if="vi===0">{{ model.name }}</label>
</div>
<div class="col-9">
<div class="col-9 pr-2">
<string-value :ref="setFieldRef" :value="instance.value" :id="vi === 0 ? widget_id : null" v-if="model.data_type==='String'"></string-value>
<integer-value :ref="setFieldRef" :value="instance.value" :id="vi === 0 ? widget_id : null" v-if="model.data_type==='Integer'"></integer-value>
<decimal-value :ref="setFieldRef" :value="instance.value" :id="vi === 0 ? widget_id : null" v-if="model.data_type==='Decimal'"></decimal-value>
<boolean-value :ref="setFieldRef" :value="instance.value" :id="vi === 0 ? widget_id : null" v-if="model.data_type==='Boolean'"></boolean-value>
<a class="btn btn-delete ml-1" @click="removeValue(vi)" v-if="values.length > 1 || model.optional">
<i class="icon icon-cross"></i>
Delete
<i class="icon icon-cross"></i>Remove
</a>
</div>
</div>
<div v-if="values.length>0 && model.multiple" class="form-group">
<div class="col-3"></div>
<div class="col-9">
<div v-if="values.length>0 && model.multiple" class="form-group cols">
<div class="col-3 pl-2"></div>
<div class="col-9 pr-2">
<a class="btn" @click="addValue">
<i class="icon icon-plus"></i>
Add
<i class="icon icon-plus"></i>Add
</a>
</div>
</div>

@ -95,31 +95,20 @@ export default {
}
</script>
<style scoped>
.new-relation {
border: 1px dashed gray;
margin: 10px 0;
padding: 10px;
}
</style>
<template>
<div class="form-horizontal panel mt-1 mb-1 p-2" v-for="(instance, ri) in instances" :key="ri">
<div class="form-group">
<div class="col-3">
<label class="form-label">{{ model.name }} -&gt; {{ related_model.name }}</label>
<div class="form-group cols">
<div class="col-3 pl-2">
<label class="form-label text-bold">{{ model.name }}</label>
</div>
<div class="col-7">
<select class="form-select input-inline" v-model="instance.related">
<option v-for="(name, id) in object_names" :value="id">{{name}}</option>
</select>
</div>
<div class="col-2 text-right">
<div class="col-2 text-right pr-2">
<a class="btn btn-delete" v-if="model.multiple || model.optional && instances.length > 0"
@click="removeInstance(ri)">
<i class="icon-cross icon"></i>
Delete
</a>
@click="removeInstance(ri)"><i class="icon-delete icon"></i>Delete</a>
</div>
</div>
@ -131,8 +120,7 @@ export default {
<div class="mt-2 mb-2">
<a class="btn" v-if="model.multiple || model.optional && instances.length==0"
@click="addInstance">
<i class="icon icon-plus"></i>
Add {{ model.name }} -&gt; {{ related_model.name }}
<i class="icon icon-plus"></i>Add {{ model.name }}
</a>
</div>
</template>

@ -116,13 +116,22 @@ export default {
</script>
<template>
<h2>New {{ model.name }}</h2>
<p><input type="button" value="Save" @click="trySave"></p>
<div class="container">
<div class="cols">
<div class="col col-9">
<h1>New {{ model.name }}</h1>
</div>
<div class="col col-3 text-right">
<button @click="trySave" class="btn btn-primary">
<i class="icon icon-check"></i>Save
</button>
</div>
</div>
</div>
<table>
<div class="form-horizontal container">
<property v-for="(property, pi) in properties" :model="property" :values="values[property.id]" :key="pi"></property>
</table>
</div>
<div v-if="haveRelations">
<h3>Relations</h3>

@ -114,31 +114,32 @@ export default {
}
</script>
<style scoped>
.new-relation {
border: 1px dashed gray;
margin: 10px 0;
padding: 10px;
}
</style>
<template>
<div class="new-relation" v-for="(instance, ri) in instances" :key="ri">
<b>{{ model.name }} -&gt; {{ related_model.name }}
<select v-model="instance.related">
<option v-for="(name, id) in object_names" :value="id">{{name}}</option>
</select>
</b>
<a href="#" v-if="model.multiple || model.optional && instances.length > 0"
style="margin-left: 5px"
@click="removeInstance(ri)">X</a>
<table v-if="properties">
<property v-for="(property, id) in properties" :model="property" :values="instance.values[id]" :key="id"></property>
</table>
<div class="form-horizontal panel mt-1 mb-1 p-2" v-for="(instance, ri) in instances" :key="ri">
<div class="form-group cols">
<div class="col-3 pl-2">
<label class="form-label text-bold">{{ model.name }}</label>
</div>
<div class="col-7">
<select class="form-select input-inline" v-model="instance.related">
<option v-for="(name, id) in object_names" :value="id">{{name}}</option>
</select>
</div>
<div class="col-2 text-right pr-2">
<a class="btn btn-delete" v-if="model.multiple || model.optional && instances.length > 0"
@click="removeInstance(ri)"><i class="icon-delete icon"></i>Delete</a>
</div>
</div>
<property v-for="(property, id) in properties"
:model="property"
:values="instance.values[id]" :key="id"></property>
</div>
<a href="#" v-if="model.multiple || model.optional && instances.length==0"
@click="addInstance">Add {{ model.name }} -&gt; {{ related_model.name }}</a><br>
<div class="mt-2 mb-2">
<a class="btn" v-if="model.multiple || model.optional && instances.length===0"
@click="addInstance">
<i class="icon icon-plus"></i>Add {{ model.name }}
</a>
</div>
</template>

@ -35,25 +35,38 @@ export default {
</script>
<template>
<tr v-if="values.length===0">
<th @click="addValue">{{model.name}}</th>
<td>
<a href="#" @click="addValue">Add</a>
</td>
</tr>
<tr v-else v-for="(value, vi) in values" :key="vi">
<th :rowspan="values.length + model.multiple" v-if="vi == 0"><label :for="widget_id">{{model.name}}</label></th>
<td>
<string-value :ref="setFieldRef" :value="value" :id="vi===0?widget_id:null" v-if="model.data_type==='String'"></string-value>
<integer-value :ref="setFieldRef" :value="value" :id="vi===0?widget_id:null" v-if="model.data_type==='Integer'"></integer-value>
<decimal-value :ref="setFieldRef" :value="value" :id="vi===0?widget_id:null" v-if="model.data_type==='Decimal'"></decimal-value>
<boolean-value :ref="setFieldRef" :value="value" :id="vi===0?widget_id:null" v-if="model.data_type==='Boolean'"></boolean-value>
<a class="button ml-2" @click="removeValue(vi)" v-if="vi > 0 || model.optional" style="margin-left:5px">Remove</a>
</td>
</tr>
<tr v-if="values.length > 0 && model.multiple">
<td>
<a class="button" @click="addValue">Add</a>
</td>
</tr>
<div v-if="values.length===0" class="form-group cols">
<div class="col-3 pl-2">
<label class="form-label">{{ model.name }}</label>
</div>
<div class="col-9 pr-2">
<a class="btn" @click="addValue">
<i class="icon icon-plus"></i>Add
</a>
</div>
</div>
<div v-if="values.length>0" class="form-group cols" v-for="(value, vi) in values" :key="vi">
<div class="col-3 pl-2">
<label class="form-label" :for="widget_id" v-if="vi===0">{{ model.name }}</label>
</div>
<div class="col-9 pr-2">
<string-value :ref="setFieldRef" :value="value" :id="vi === 0 ? widget_id : null" v-if="model.data_type==='String'"></string-value>
<integer-value :ref="setFieldRef" :value="value" :id="vi === 0 ? widget_id : null" v-if="model.data_type==='Integer'"></integer-value>
<decimal-value :ref="setFieldRef" :value="value" :id="vi === 0 ? widget_id : null" v-if="model.data_type==='Decimal'"></decimal-value>
<boolean-value :ref="setFieldRef" :value="value" :id="vi === 0 ? widget_id : null" v-if="model.data_type==='Boolean'"></boolean-value>
<a class="btn btn-delete ml-1" @click="removeValue(vi)" v-if="values.length > 1 || model.optional">
<i class="icon icon-cross"></i>Remove
</a>
</div>
</div>
<div v-if="values.length>0 && model.multiple" class="form-group cols">
<div class="col-3 pl-2"></div>
<div class="col-9 pr-2">
<a class="btn" @click="addValue">
<i class="icon icon-plus"></i>Add
</a>
</div>
</div>
</template>

@ -1,222 +0,0 @@
*, *::before, *::after {
box-sizing: border-box;
}
html, textarea, select {
font-family: "IBM Plex", "DejaVu Sans", "Helvetica", sans-serif;
}
.Form {
display: block;
width: 900px;
margin: 0 auto;
}
nav.top-nav {
margin-bottom: .5rem;
border-bottom: 1px solid silver;
}
nav.top-nav, .content {
margin: 0 auto;
width: 900px;
}
a {
color: gray;
text-decoration: none;
}
a:hover {
color: black;
text-decoration: underline;
}
nav.top-nav a {
display: inline-block;
padding: .75rem;
color: gray;
text-decoration: none;
}
nav.top-nav a:hover {
color: black;
text-decoration: underline;
}
.Form .Row {
display: flex;
padding: .25rem;
}
.Form .Row.indented {
padding-left: 10.25rem;
}
input[type="text"],
input[type="number"],
textarea,
.tag-input {
border: 1px solid silver;
padding: 0.5rem;
border-radius: 5px;
font-size: 1rem;
}
input[type="text"]:focus,
input[type="number"]:focus,
textarea:focus,
.tag-input.active {
box-shadow: inset 0 0 0 1px #3c97ff;
border-color: #3c97ff;
outline: 0 none !important;
}
.Form label {
flex-shrink: 0;
width: 10rem;
height: 2.1rem;
line-height: 2.1rem;
vertical-align: middle;
text-align: right;
display: inline-block;
padding-right: .5rem;
align-self: flex-start;
}
.Form input[type="text"],
.Form input[type="number"],
.Form select {
height: 2.1rem;
width: 15rem;
}
.Form textarea {
flex-shrink: 1;
width: 30rem;
height: 6rem;
}
.Form label.checkbox-wrap {
width: 15rem;
padding-right: 1rem;
text-align: left !important;
}
.tag-input {
position: relative;
width: 30rem;
padding-bottom: 0rem !important;
}
.tag-input input,
.tag-input input:focus {
border: 0 transparent;
padding: 0;
margin: 0;
box-shadow: none;
outline: 0 none !important;
}
/*
.cards-table {
border-collapse: collapse;
margin: 0 auto;
margin-top: 1rem;
}
.cards-table .actions {
font-size: 90%;
}
.cards-table td,
.cards-table th {
padding: .5rem;
}
.cards-table thead th {
border-bottom: 2px solid silver;
}
.cards-table tbody td {
border-bottom: 1px solid silver;
}
.cards-table tbody tr:last-child td {
border-bottom: 2px solid silver;
}
.cards-table td.tags {
padding: .25rem;
}
.cards-table .tag {
background: #E2E1DF;
font-size: 90%;
padding: 0.25rem .45rem;
border-radius: 3px;
display: inline-block;
}
.paginate {
margin: 1rem auto;
width: 300px;
text-align: center;
white-space: nowrap;
}
.paginate span,
.paginate a {
padding: .5rem 1rem;
border-radius: .5rem;
border: 1px solid silver;
text-decoration: none;
}
.paginate span.num {
border: 1px solid #ccc;
color: gray;
}
.paginate a {
cursor: pointer;
user-select: none;
}
.paginate a:hover {
background: #ccc;
text-decoration: none;
}
.paginate .disabled {
opacity: .5;
cursor: default;
}
.paginate .disabled:hover {
color: gray;
background: transparent;
}
*/
li {
padding-bottom: .5rem;
}
.toast {
border: 1px solid black;
border-radius: 5px;
padding: .5rem;
margin: .5rem 0;
}
.toast.error {
border-color: #dc143c;
}
.toast.success {
border-color: #32cd32;
}

@ -25,3 +25,7 @@ $error-color-dark: darken($error-color, 3%) !default;
border-color: darken($error-color-dark, 5%);
}
}
.btn .icon {
margin-right: $unit-2;
}

@ -1,23 +1,16 @@
//@import "common";
//@import "bulma/bulma";
@import "spectre/src/spectre";
@import "spectre/src/spectre-exp";
@import "spectre/src/spectre-icons";
@import "icons-extra";
@import "spectre-patches";
/*
.EditForm th {
text-align: left;
vertical-align: top;
body {
max-width: 976px;
margin: 0 auto;
}
label {
cursor: pointer;
table.object-display {
tbody th {
width: 225px;
}
}
*/
//.navbar-brand {
// font-size: 120%;
// font-weight: bold;
//}

@ -51,7 +51,8 @@
border-bottom: $border-width solid $border-color;
padding: $unit-3 $unit-2;
}
th {
// XXX added thead selector!
thead th {
border-bottom-width: $border-width-lg;
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

@ -597,7 +597,7 @@ html:lang(ko),
.table th {
border-bottom: 0.05rem solid #dadee4;
padding: 0.6rem 0.4rem; }
.table th {
.table thead th {
border-bottom-width: 0.1rem; }
.btn {
@ -4118,22 +4118,12 @@ a.text-error:visited {
background: #e85600;
border-color: #bf4700; }
/*
.EditForm th {
text-align: left;
vertical-align: top;
}
label {
cursor: pointer;
}
*/
.new-relation[data-v-0f98a4a0] {
border: 1px dashed gray;
margin: 10px 0;
padding: 10px; }
.new-relation[data-v-760e133a] {
border: 1px dashed gray;
margin: 10px 0;
padding: 10px; }
.btn .icon {
margin-right: 0.4rem; }
body {
max-width: 976px;
margin: 0 auto; }
table.object-display tbody th {
width: 225px; }

@ -0,0 +1,39 @@
{% macro header_with_save_button(heading) %}
<div class="container">
<div class="cols">
<div class="col col-9">
<h1>{{heading}}</h1>
</div>
<div class="col col-3 text-right">
<button type="submit" class="btn btn-primary">
<i class="icon icon-check"></i>Save
</button>
</div>
</div>
</div>
{% endmacro input %}
{% macro text(name, label, value) %}
<div class="form-group cols">
<div class="col-3 pl-2">
<label class="form-label" for="{{name}}">{{label}}</label>
</div>
<div class="col-9 pr-2">
<input type="text" class="form-input input-inline" id="{{name}}" name="{{name}}" value="{{value}}" autocomplete="off">
</div>
</div>
{% endmacro input %}
{% macro checkbox(name, label, checked) %}
<div class="form-group cols">
<div class="col-3 pl-2">
<label class="form-label" for="{{name}}">{{label}}</label>
</div>
<div class="col-9 pr-2">
<label class="form-switch input-inline">
<input type="checkbox" id="{{name}}" name="{{name}}" value="true" autocomplete="off" {{opt(checked=checked)}}>
<i class="form-icon"></i>
</label>
</div>
</div>
{% endmacro input %}

@ -7,19 +7,27 @@
<link rel="stylesheet" href="/static/style.css">
</head>
<body>
<nav class="top-nav">
{%- block nav -%}{%- endblock -%}
</nav>
<div class="content">
<header class="navbar mb-2 mt-2">
<section class="navbar-section">
<a href="/" class="navbar-brand text-bold mr-2">
Yopa
</a>
{%- block nav -%}{%- endblock -%}
</section>
<section class="navbar-section">
YOPA is the best
</section>
</header>
<div class="content">
{%- if flash_error -%}
<div class="toast error">
<div class="toast toast-error mb-2">
{{ flash_error }}
</div>
{%- endif -%}
{%- if flash_success -%}
<div class="toast success">
<div class="toast toast-success mb-2">
{{ flash_success }}
</div>
{%- endif -%}

@ -3,6 +3,7 @@
{%- if prop.default -%}
, default: "{{prop.default | print_typed_value}}"
{%- endif -%}
{%- if prop.unique %}, UNIQUE{% endif %}
{%- if prop.optional %}, OPTIONAL{% endif %}
{%- if prop.multiple %}, MULTIPLE{% endif %}
<a href="/model/property/update/{{prop.id}}">Edit property</a> &middot;

@ -6,7 +6,7 @@
{%- endblock %}
{% block nav -%}
<a href="/">Home</a>
<a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a>
{%- endblock %}
{% block content -%}

@ -1,27 +1,22 @@
{% extends "_layout" %}
{% import "_form_macros" as form %}
{% block title -%}
Define object
{%- endblock %}
{% block nav -%}
<a href="/">Home</a>
<a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a>
{%- endblock %}
{% block content -%}
<h1>Define new object model</h1>
<form action="/model/object/create" method="POST">
<table>
<tr>
<th><label for="name">Name:</label></th>
<td><input type="text" id="name" name="name" value="{{old.name}}" autocomplete="off">
</td>
</tr>
</table>
{{ form::header_with_save_button(heading="Define new object model") }}
<input type="submit" value="Save">
<div class="form-horizontal container">
{{ form::text(name="name", label="Name", value=old.name) }}
</div>
</form>
{%- endblock %}

@ -1,38 +1,36 @@
{% extends "_layout" %}
{% import "_form_macros" as form %}
{% block title -%}
Edit object model
{%- endblock %}
{% block nav -%}
<a href="/">Home</a>
<a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a>
{%- endblock %}
{% block content -%}
<h1>Edit object model {{ model.name }}</h1>
<form action="/model/object/update/{{ model.id }}" method="POST">
<table>
<tr>
<th><label for="name">Name:</label></th>
<td><input type="text" id="name" name="name" value="{{ model.name }}" autocomplete="off">
</td>
</tr>
<tr>
<th><label for="name_property">Name property:</label></th>
<td>
<select name="name_property" id="name_property" autocomplete="off">
{{ form::header_with_save_button(heading="Edit object model "~model.name) }}
<div class="form-horizontal container">
{{ form::text(name="name", label="Name", value=model.name) }}
<div class="form-group cols">
<div class="col-3 pl-2">
<label class="form-label" for="name_property">Name property</label>
</div>
<div class="col-9 pr-2">
<select name="name_property" class="form-select input-inline" id="name_property" autocomplete="off">
<option value=""></option>
{% for p in properties %}
<option value="{{ p.id }}" {{selected(val=old.name_property, opt=p.id)}}>{{ p.name }}</option>
{% endfor %}
</select>
</td>
</tr>
</table>
<input type="submit" value="Save">
</div>
</div>
</div>
</form>
{%- endblock %}

@ -1,56 +1,44 @@
{% extends "_layout" %}
{% import "_form_macros" as form %}
{% block title -%}
Define property
{%- endblock %}
{% block nav -%}
<a href="/">Home</a>
<a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a>
{%- endblock %}
{% block content -%}
{# The parent can be either object or relation model #}
<h1>Add new property to {{object.describe}}</h1>
<form action="/model/property/create" method="POST">
{{ form::header_with_save_button(heading="Add new property to "~object.describe) }}
<input type="hidden" name="object" value="{{object.id}}">
<table>
<tr>
<th><label for="name">Name:</label></th>
<td><input type="text" id="name" name="name" value="{{old.name}}" autocomplete="off"></td>
</tr>
<tr>
<th><label for="unique">Unique:</label></th>
<td><input type="checkbox" name="unique" id="unique" value="true" {{opt(checked=old.unique)}} autocomplete="off"></td>
</tr>
<tr>
<th><label for="optional">Optional:</label></th>
<td><input type="checkbox" name="optional" id="optional" value="true" {{opt(checked=old.optional)}} autocomplete="off"></td>
</tr>
<tr>
<th><label for="multiple">Multiple:</label></th>
<td><input type="checkbox" name="multiple" id="multiple" value="true" {{opt(checked=old.multiple)}} autocomplete="off"></td>
</tr>
<tr>
<th><label for="data_type">Type:</label></th>
<td>
<select name="data_type" id="data_type" autocomplete="off">
<div class="form-horizontal container">
{{ form::text(name="name", label="Name", value=old.name) }}
{{ form::checkbox(name="unique", label="Unique", checked=old.unique) }}
{{ form::checkbox(name="optional", label="Optional", checked=old.optional) }}
{{ form::checkbox(name="multiple", label="Multiple", checked=old.multiple) }}
<div class="form-group cols">
<div class="col-3 pl-2">
<label class="form-label" for="data_type">Data type</label>
</div>
<div class="col-9 pr-2">
<select name="data_type" class="form-select input-inline" id="data_type" autocomplete="off">
<option value="String" {{selected(opt="String",val=old.data_type)}}>String</option>
<option value="Integer" {{selected(opt="Integer",val=old.data_type)}}>Integer</option>
<option value="Decimal" {{selected(opt="Decimal",val=old.data_type)}}>Decimal</option>
<option value="Boolean" {{selected(opt="Boolean",val=old.data_type)}}>Boolean</option>
</select>
</td>
</tr>
<tr>
<th><label for="default">Default:</label></th>
<td><input type="text" id="default" name="default" value="{{old.default}}" autocomplete="off"></td>
</tr>
</table>
</div>
</div>
<input type="submit" value="Save">
{{ form::text(name="default", label="Default", value=old.default) }}
</div>
</form>
<script>

@ -1,62 +1,42 @@
{% extends "_layout" %}
{% import "_form_macros" as form %}
{% block title -%}
Edit property
{%- endblock %}
{% block nav -%}
<a href="/">Home</a>
<a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a>
{%- endblock %}
{% block content -%}
<h1>Edit property {{model.name}}</h1>
<form action="/model/property/update/{{model.id}}" method="POST">
<table>
<tr>
<th><label for="name">Name:</label></th>
<td><input type="text" id="name" name="name" value="{{model.name}}" autocomplete="off"></td>
</tr>
<tr>
<th><label for="unique">Unique:</label></th>
<td>
<input type="checkbox" name="unique" id="unique" value="true" {{opt(checked=model.unique)}} autocomplete="off">
</td>
</tr>
<tr>
<th><label for="optional">Optional:</label></th>
<td>
<input type="checkbox" name="optional" id="optional" value="true" {{opt(checked=model.optional)}} autocomplete="off">
</td>
</tr>
<tr>
<th><label for="multiple">Multiple:</label></th>
<td>
<input type="checkbox" name="multiple" id="multiple" value="true" {{opt(checked=model.multiple)}} autocomplete="off">
</td>
</tr>
<tr>
<th><label for="data_type">Type:</label></th>
<td>
<select name="data_type" id="data_type" autocomplete="off">
<option value="String" {{selected(val=model.data_type, opt="String")}}>String</option>
<option value="Integer" {{selected(val=model.data_type, opt="Integer")}}>Integer</option>
<option value="Decimal" {{selected(val=model.data_type, opt="Decimal")}}>Decimal</option>
<option value="Boolean" {{selected(val=model.data_type, opt="Boolean")}}>Boolean</option>
{{ form::header_with_save_button(heading="Edit property "~model.name) }}
<div class="form-horizontal container">
{{ form::text(name="name", label="Name", value=model.name) }}
{{ form::checkbox(name="unique", label="Unique", checked=model.unique) }}
{{ form::checkbox(name="optional", label="Optional", checked=model.optional) }}
{{ form::checkbox(name="multiple", label="Multiple", checked=model.multiple) }}
<div class="form-group cols">
<div class="col-3 pl-2">
<label class="form-label" for="data_type">Data type</label>
</div>
<div class="col-9 pr-2">
<select name="data_type" class="form-select input-inline" id="data_type" autocomplete="off">
<option value="String" {{selected(opt="String",val=model.data_type)}}>String</option>
<option value="Integer" {{selected(opt="Integer",val=model.data_type)}}>Integer</option>
<option value="Decimal" {{selected(opt="Decimal",val=model.data_type)}}>Decimal</option>
<option value="Boolean" {{selected(opt="Boolean",val=model.data_type)}}>Boolean</option>
</select>
</td>
</tr>
<tr>
<th><label for="default">Default:</label></th>
<td>
<input type="text" id="default" name="default" value="{{model.default | print_typed_value}}" autocomplete="off">
</td>
</tr>
</table>
</div>
</div>
<input type="submit" value="Save">
{{ form::text(name="default", label="Default", value=model.default|print_typed_value) }}
</div>
</form>
<script>

@ -1,59 +1,40 @@
{% extends "_layout" %}
{% import "_form_macros" as form %}
{% block title -%}
Define relation
{%- endblock %}
{% block nav -%}
<a href="/">Home</a>
<a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a>
{%- endblock %}
{% block content -%}
<h1>Define new relation from "{{object.name}}"</h1>
<form action="/model/relation/create" method="POST">
<input type="hidden" name="object" value="{{object.id}}">
<table>
<tr>
<th><label for="name">Name:</label></th>
<td>
<input type="text" id="name" name="name" value="{{old.name}}" autocomplete="off"><br>
</td>
</tr>
<tr>
<th><label for="reciprocal_name">Reciprocal name:</label></th>
<td>
<input type="text" id="reciprocal_name" name="reciprocal_name" value="{{old.reciprocal_name}}" autocomplete="off">
</td>
</tr>
<tr>
<th><label for="optional">Optional:</label></th>
<td>
<input type="checkbox" name="optional" id="optional" value="true" {{opt(checked=old.optional)}} autocomplete="off">
</td>
</tr>
<tr>
<th><label for="multiple">Multiple:</label></th>
<td>
<input type="checkbox" name="multiple" id="multiple" value="true" {{opt(checked=old.multiple)}} autocomplete="off">
</td>
</tr>
<tr>
<th><label for="related">Related object:</label></th>
<td>
<select name="related" id="related" autocomplete="off">
{{ form::header_with_save_button(heading='Define new relation from "'~object.name~'"') }}
<div class="form-horizontal container">
{{ form::text(name="name", label="Name", value=old.name) }}
{{ form::text(name="reciprocal_name", label="Reciprocal name", value=old.reciprocal_name) }}
{{ form::checkbox(name="optional", label="Optional", checked=old.optional) }}
{{ form::checkbox(name="multiple", label="Multiple", checked=old.multiple) }}
<div class="form-group cols">
<div class="col-3 pl-2">
<label class="form-label" for="related">Related object</label>
</div>
<div class="col-9 pr-2">
<select name="related" class="form-select input-inline" id="related" autocomplete="off">
{% for m in models %}
<option value="{{ m.id }}" {{selected(val=old.related, opt=m.id)}}>{{ m.name }}</option>
{% endfor %}
</select>
</td>
</tr>
</table>
<input type="submit" value="Save">
</div>
</div>
</div>
</form>
{%- endblock %}

@ -1,46 +1,27 @@
{% extends "_layout" %}
{% import "_form_macros" as form %}
{% block title -%}
Edit relation
{%- endblock %}
{% block nav -%}
<a href="/">Home</a>
<a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a>
{%- endblock %}
{% block content -%}
<h1>Edit relation model "{{model.name}}"</h1>
<form action="/model/relation/update/{{model.id}}" method="POST">
<table>
<tr>
<th><label for="name">Name:</label></th>
<td><input type="text" id="name" name="name" value="{{model.name}}" autocomplete="off">
</td>
</tr>
<tr>
<th><label for="reciprocal_name">Reciprocal name:</label></th>
<td><input type="text" id="reciprocal_name" name="reciprocal_name" value="{{model.reciprocal_name}}" autocomplete="off">
</td>
</tr>
<tr>
<th><label for="optional">Optional:</label>
</th>
<td><input type="checkbox" name="optional" id="optional" value="true" {{opt(checked=model.optional)}} autocomplete="off">
</td>
</tr>
<tr>
<th><label for="multiple">Multiple:</label></th>
<td><input type="checkbox" name="multiple" id="multiple" value="true" {{opt(checked=model.multiple)}} autocomplete="off">
</td>
</tr>
</table>
{{ form::header_with_save_button(heading='Edit relation model "'~model.name~'"') }}
<p>The related object cannot be changed. Create a new relation if needed.</p>
<div class="form-horizontal container">
{{ form::text(name="name", label="Name", value=model.name) }}
{{ form::text(name="reciprocal_name", label="Reciprocal name", value=model.reciprocal_name) }}
{{ form::checkbox(name="optional", label="Optional", checked=model.optional) }}
{{ form::checkbox(name="multiple", label="Multiple", checked=model.multiple) }}
</div>
<input type="submit" value="Save">
<p>The related object cannot be changed. Create a new relation if needed.</p>
</form>
{%- endblock %}

@ -5,8 +5,8 @@ Objects
{%- endblock %}
{% block nav -%}
<a href="/models">Edit models</a>
<a href="/takeout">JSON</a>
<a href="/models" class="btn btn-link"><i class="icon icon-edit"></i>Edit models</a>
<a href="/takeout" class="btn btn-link"><i class="icon icon-code"></i>JSON</a>
{%- endblock %}
{% block content -%}
@ -15,8 +15,18 @@ Objects
{% for table in models %}
<h2>{{ table.model.name }}</h2>
<a href="/object/create/{{table.model.id}}">Add {{ table.model.name }}</a>
<div class="container">
<div class="cols">
<div class="col-9">
<h2>{{ table.model.name }}</h2>
</div>
<div class="col-3 text-right">
<a href="/object/create/{{table.model.id}}" class="btn">
<i class="icon icon-plus"></i>Add {{ table.model.name }}
</a>
</div>
</div>
</div>
<ul>
{% for object in table.objects %}

@ -5,7 +5,8 @@ Create {{model.name}}
{%- endblock %}
{% block nav -%}
<a href="/">Home</a>
<a href="/" class="btn btn-link">
<i class="icon icon-home"></i>Home</a>
{%- endblock %}
{% block content -%}

@ -5,16 +5,22 @@
{%- endblock %}
{% block nav -%}
<a href="/">Home</a>
<a href="/object/update/{{object.id}}">Edit</a>
<a href="/object/delete/{{object.id}}" onclick="return confirm('Delete object?')">Delete</a>
<a href="/" class="btn btn-link">
<i class="icon icon-home"></i>Home</a>
<a href="/object/update/{{object.id}}" class="btn btn-link">
<i class="icon icon-edit"></i>Edit</a>
<a href="/object/delete/{{object.id}}" class="btn btn-link" onclick="return confirm('Delete object?')">
<i class="icon icon-delete"></i>Delete</a>
{%- endblock %}
{% block content -%}
<h1>{{kind}} "{{object.name}}"</h1>
<table>
<table class="table table-striped object-display">
<tbody>
{% for property in properties %}
{% for value in property.values %}
<tr>
@ -29,11 +35,11 @@
</tr>
{% endfor %}
{% endfor %}
</tbody>
</table>
{% for relation in relations %}
<h3>{{relation.model.name}}</h3>
<ul>
{% for instance in relation.instances %}
<li>
@ -60,14 +66,10 @@
</li>
{% endfor %}
</ul>
{% endfor %}
{% for relation in reciprocal_relations %}
<h3>{{relation.model.reciprocal_name}}</h3>
<ul>
{% for instance in relation.instances %}
<li>

@ -5,7 +5,7 @@ Edit {{object.name}}
{%- endblock %}
{% block nav -%}
<a href="/">Home</a>
<a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a>
{%- endblock %}
{% block content -%}

@ -6,26 +6,21 @@
<script src="../static/bundle.js"></script>
<link rel="stylesheet" href="../static/style.css">
</head>
<body class="container grid-lg">
<body>
<header class="navbar">
<header class="navbar mb-2 mt-2">
<section class="navbar-section">
<a href="/" class="navbar-brand text-bold mr-2">
Yopa
</a>
<a href="/" class="btn btn-link">
<i class="icon icon-home"></i>
Home
</a>
<a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a>
</section>
<section class="navbar-section">
YOPA is the best
</section>
</header>
<div class="content">
<div id="edit-object-form"></div>
</div>
<div id="edit-object-form"></div>
<script>
onLoad(() => {

@ -0,0 +1,51 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Edit object model &bull; YOPA</title>
<script src="../static/bundle.js"></script>
<link rel="stylesheet" href="../static/style.css">
</head>
<body>
<header class="navbar mb-2 mt-2">
<section class="navbar-section">
<a href="/" class="navbar-brand text-bold mr-2">
Yopa
</a><a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a></section>
<section class="navbar-section">
YOPA is the best
</section>
</header>
<div class="content"><h1>Edit object model Animal</h1>
<form action="/model/object/update/0" method="POST">
<table>
<tr>
<th><label for="name">Name:</label></th>
<td><input type="text" id="name" name="name" value="Animal" autocomplete="off">
</td>
</tr>
<tr>
<th><label for="name_property">Name property:</label></th>
<td>
<select name="name_property" id="name_property" autocomplete="off">
<option value=""></option>
<option value="11" >carnivore</option>
<option value="2" >Name</option>
<option value="12" >weight</option>
<option value="5" selected>czech name</option>
</select>
</td>
</tr>
</table>
<input type="submit" value="Save">
</form></div>
</body>
</html>

@ -0,0 +1,83 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Edit property &bull; YOPA</title>
<script src="../static/bundle.js"></script>
<link rel="stylesheet" href="../static/style.css">
</head>
<body>
<header class="navbar mb-2 mt-2">
<section class="navbar-section">
<a href="/" class="navbar-brand text-bold mr-2">
Yopa
</a><a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a></section>
<section class="navbar-section">
YOPA is the best
</section>
</header>
<div class="content"><h1>Edit property Name</h1>
<form action="/model/property/update/2" method="POST">
<table>
<tr>
<th><label for="name">Name:</label></th>
<td><input type="text" id="name" name="name" value="Name" autocomplete="off"></td>
</tr>
<tr>
<th><label for="unique">Unique:</label></th>
<td>
<input type="checkbox" name="unique" id="unique" value="true" checked autocomplete="off">
</td>
</tr>
<tr>
<th><label for="optional">Optional:</label></th>
<td>
<input type="checkbox" name="optional" id="optional" value="true" autocomplete="off">
</td>
</tr>
<tr>
<th><label for="multiple">Multiple:</label></th>
<td>
<input type="checkbox" name="multiple" id="multiple" value="true" autocomplete="off">
</td>
</tr>
<tr>
<th><label for="data_type">Type:</label></th>
<td>
<select name="data_type" id="data_type" autocomplete="off">
<option value="String" selected>String</option>
<option value="Integer" >Integer</option>
<option value="Decimal" >Decimal</option>
<option value="Boolean" >Boolean</option>
</select>
</td>
</tr>
<tr>
<th><label for="default">Default:</label></th>
<td>
<input type="text" id="default" name="default" value="" autocomplete="off">
</td>
</tr>
</table>
<input type="submit" value="Save">
</form>
<script>
(function () {
// multiple and unique are XORed. This is also enforced server-side
let multiple = document.getElementById('multiple');
let unique = document.getElementById('unique');
unique.addEventListener('input', function () {
multiple.checked &= !unique.checked;
})
multiple.addEventListener('input', function () {
unique.checked &= !multiple.checked;
})
})();
</script></div>
</body>
</html>

@ -0,0 +1,52 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Edit relation &bull; YOPA</title>
<script src="../static/bundle.js"></script>
<link rel="stylesheet" href="../static/style.css">
</head>
<body>
<header class="navbar mb-2 mt-2">
<section class="navbar-section">
<a href="/" class="navbar-brand text-bold mr-2">
Yopa
</a><a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a></section>
<section class="navbar-section">
YOPA is the best
</section>
</header>
<div class="content"><h1>Edit relation model "eats"</h1>
<form action="/model/relation/update/15" method="POST">
<table>
<tr>
<th><label for="name">Name:</label></th>
<td><input type="text" id="name" name="name" value="eats" autocomplete="off">
</td>
</tr>
<tr>
<th><label for="reciprocal_name">Reciprocal name:</label></th>
<td><input type="text" id="reciprocal_name" name="reciprocal_name" value="eaten by" autocomplete="off">
</td>
</tr>
<tr>
<th><label for="optional">Optional:</label>
</th>
<td><input type="checkbox" name="optional" id="optional" value="true" checked autocomplete="off">
</td>
</tr>
<tr>
<th><label for="multiple">Multiple:</label></th>
<td><input type="checkbox" name="multiple" id="multiple" value="true" autocomplete="off">
</td>
</tr>
</table>
<p>The related object cannot be changed. Create a new relation if needed.</p>
<input type="submit" value="Save">
</form></div>
</body>
</html>

@ -0,0 +1,66 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Index &bull; YOPA</title>
<script src="../static/bundle.js"></script>
<link rel="stylesheet" href="../static/style.css">
</head>
<body>
<header class="navbar mb-2 mt-2">
<section class="navbar-section">
<a href="/" class="navbar-brand text-bold mr-2">
Yopa
</a><a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a></section>
<section class="navbar-section">
YOPA is the best
</section>
</header>
<div class="content"><h1>Models</h1>
<a href="/model/object/create">New model</a>
<h2>Defined models:</h2>
<ul>
<li>
<b title="0">Animal</b><br>
<a href="/model/object/delete/0" onclick="return confirm('Delete model?')">Delete model</a> &middot;
<a href="/model/object/update/0">Edit model</a> &middot;
<a href="/model/relation/create/0">New relation</a> &middot;
<a href="/model/property/create/0">New property</a>
<br>
Properties:
<ul>
<li>
Name, String, default: ""
<a href="/model/property/update/2">Edit property</a> &middot;
<a href="/model/property/delete/2" onclick="return confirm('Delete property?')">Delete property</a>
</li>
<li>
carnivore, Boolean, default: "false"
<a href="/model/property/update/11">Edit property</a> &middot;
<a href="/model/property/delete/11" onclick="return confirm('Delete property?')">Delete property</a>
</li>
<li>
czech name, String, default: "", OPTIONAL
<a href="/model/property/update/5">Edit property</a> &middot;
<a href="/model/property/delete/5" onclick="return confirm('Delete property?')">Delete property</a>
</li>
<li>
weight, Decimal, default: "0"
<a href="/model/property/update/12">Edit property</a> &middot;
<a href="/model/property/delete/12" onclick="return confirm('Delete property?')">Delete property</a>
</li>
</ul>
</li>
<li>
<b title="1">Food</b><br>
<a href="/model/object/delete/1" onclick="return confirm('Delete model?')">Delete model</a> &middot;
<a href="/model/object/update/1">Edit model</a> &middot;
<a href="/model/relation/create/1">New relation</a> &middot;
<a href="/model/property/create/1">New property</a>
<br>
</li>
</ul>
</div>
</body>
</html>

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Create Animal &bull; YOPA</title>
<script src="../static/bundle.js"></script>
<link rel="stylesheet" href="../static/style.css">
</head>
<body>
<header class="navbar mb-2 mt-2">
<section class="navbar-section">
<a href="/" class="navbar-brand text-bold mr-2">
Yopa
</a><a href="/" class="btn btn-link">
<i class="icon icon-home"></i>Home</a></section>
<section class="navbar-section">
YOPA is the best
</section>
</header>
<div id="new-object-form"></div>
<script>
onLoad(() => {
window.app = Yopa.newObjectForm({"model_id":0,"objects":[],"schema":{"obj_models":[{"id":0,"name":"Animal","name_property":5},{"id":1,"name":"Food","name_property":null}],"prop_models":[{"data_type":"Boolean","default":{"Boolean":false},"id":11,"multiple":false,"name":"carnivore","object":0,"optional":false,"unique":false},{"data_type":"String","default":{"String":""},"id":2,"multiple":false,"name":"Name","object":0,"optional":false,"unique":true},{"data_type":"Decimal","default":{"Decimal":0.0},"id":12,"multiple":false,"name":"weight","object":0,"optional":false,"unique":false},{"data_type":"String","default":{"String":""},"id":5,"multiple":false,"name":"czech name","object":0,"optional":true,"unique":false}],"rel_models":[{"id":15,"multiple":false,"name":"eats","object":0,"optional":true,"reciprocal_name":"eaten by","related":1}]}})
});
</script>
</body>
</html>

@ -0,0 +1,74 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Define relation &bull; YOPA</title>
<script src="../static/bundle.js"></script>
<link rel="stylesheet" href="../static/style.css">
</head>
<body>
<header class="navbar mb-2 mt-2">
<section class="navbar-section">
<a href="/" class="navbar-brand text-bold mr-2">
Yopa
</a><a href="/" class="btn btn-link"><i class="icon icon-home"></i>Home</a></section>
<section class="navbar-section">
YOPA is the best
</section>
</header>
<div class="content">
<form action="/model/relation/create" method="POST">
<input type="hidden" name="object" value="0">
<div class="container">
<div class="cols">
<div class="col col-9">
<h1>Define new relation from "Animal"</h1>
</div>
<div class="col col-3 text-right">
<button type="submit" class="btn btn-primary">
<i class="icon icon-check"></i>Save
</button>
</div>
</div>
</div>
<div class="form-horizontal container">
<div class="form-group cols">
<div class="col-3 pl-2">
<label class="form-label" for="name">Name</label>
</div>
<div class="col-9 pr-2">
<input type="text" class="form-input input-inline" id="name" name="name" value="" autocomplete="off">
</div>
</div>
<div class="form-group cols">
<div class="col-3 pl-2">
<label class="form-label" for="optional">Optional</label>
</div>
<div class="col-9 pr-2">
<label class="form-switch input-inline">
<input type="checkbox" id="optional" value="true">
<i class="form-icon"></i>
</label>
</div>
</div>
<div class="form-group cols">
<div class="col-3 pl-2">
<label class="form-label" for="related">dsfsdf</label>
</div>
<div class="col-9 pr-2">
<select name="related" class="form-select input-inline" id="related" autocomplete="off">
<option value="0" selected>Animal</option>
<option value="1" >Food</option>
</select>
</div>
</div>
</div>
</form></div>
</body>
</html>

@ -0,0 +1,73 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>kočka &bull; YOPA</title>
<script src="../static/bundle.js"></script>
<link rel="stylesheet" href="..//static/style.css">
</head>
<body>
<header class="navbar mb-2 mt-2">
<section class="navbar-section">
<a href="/" class="navbar-brand text-bold mr-2">
Yopa
</a><a href="/" class="btn btn-link">
<i class="icon icon-home"></i>Home</a>
<a href="/object/update/7" class="btn btn-link">
<i class="icon icon-edit"></i>Edit</a>
<a href="/object/delete/7" class="btn btn-link" onclick="return confirm('Delete object?')">
<i class="icon icon-delete"></i>Delete</a></section>
<section class="navbar-section">
YOPA is the best
</section>
</header>
<div class="content"><h1>Animal "kočka"</h1>
<table class="table table-striped object-display">
<tbody>
<tr>
<th rowspan="1">
Name
</th>
<td title="9">
cat
</td>
</tr>
<tr>
<th rowspan="1">
carnivore
</th>
<td title="13">
true
</td>
</tr>
<tr>
<th rowspan="1">
czech name
</th>
<td title="8">
kočka
</td>
</tr>
<tr>
<th rowspan="1">
weight
</th>
<td title="14">
15.5
</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>

@ -226,6 +226,7 @@ pub(crate) async fn update_form(
model.default = TypedValue::String(form.default.into());
model.optional = form.optional;
model.multiple = form.multiple;
model.unique = form.unique;
context.insert("model", &model);
} else {
context.insert("model", model);

Loading…
Cancel
Save