lots of improvements to recipe editor

This commit is contained in:
vabene1111
2024-12-04 16:55:50 +01:00
parent 931064a695
commit 15122387f4
39 changed files with 255 additions and 188 deletions

View File

@@ -12,8 +12,8 @@
<v-tooltip v-model="showTooltip" activator="parent" location="start">{{ props.ingredient.note }}</v-tooltip>
</v-icon>
</td>
<td v-if="props.draggable">
<i class="fas fa-grip-lines drag-handle cursor-move"></i>
<td v-if="props.draggable" >
<v-icon icon="$dragHandle" class="drag-handle cursor-move"></v-icon>
</td>
</template>

View File

@@ -9,15 +9,15 @@
:ref="`ref_${props.id}`"
class="material-multiselect"
:resolve-on-load="searchOnLoad"
:resolve-on-load="props.searchOnLoad"
v-model="model"
:options="search"
:on-create="createObject"
:createOption="props.allowCreate"
:delay="300"
:object="true"
:valueProp="props.itemValue"
:label="props.itemLabel"
:valueProp="itemValue"
:label="itemLabel"
:searchable="true"
:strict="false"
:disabled="props.disabled"
@@ -30,9 +30,10 @@
:noResultsText="$t('No_Results')"
:loading="loading"
@open="multiselect.refreshOptions()"
:append-to-body="appendToBody"
:append-to-body="props.appendToBody"
:classes="{
dropdown: 'multiselect-dropdown z-3000',
containerActive: '',
}"
/>
@@ -40,7 +41,7 @@
</template>
<script lang="ts" setup>
import {onBeforeMount, onMounted, PropType, ref, useTemplateRef} from "vue"
import {computed, onBeforeMount, onMounted, PropType, ref, useTemplateRef} from "vue"
import {EditorSupportedModels, GenericModel, getGenericModelFromString} from "@/types/Models"
import Multiselect from '@vueform/multiselect'
import {ErrorMessageType, MessageType, useMessageStore} from "@/stores/MessageStore";
@@ -55,8 +56,6 @@ const props = defineProps({
id: {type: String, required: false, default: Math.floor(Math.random()*10000).toString()},
itemLabel: {type: String, default: "name"},
itemValue: {type: String, default: "id"},
limit: {type: Number, default: 25},
disabled: {type: Boolean, default: false},
@@ -77,6 +76,26 @@ const props = defineProps({
searchOnLoad: {type: Boolean, default: false},
})
/**
* check if model has a non-standard value attribute defined, if not use "id" as the value attribute
*/
const itemValue = computed(() => {
if(modelClass.value.model.itemValue){
return modelClass.value.model.itemValue
}
return 'id'
})
/**
* check if model has a non-standard label attribute defined, if not use "name" as the value attribute
*/
const itemLabel = computed(() => {
if(modelClass.value.model.itemLabel){
return modelClass.value.model.itemLabel
}
return 'name'
})
const model = defineModel()
const modelClass = ref({} as GenericModel)
const loading = ref(false)
@@ -117,7 +136,7 @@ function search(query: string) {
* @param select$ reference to multiselect instance
*/
async function createObject(object: any, select$: Multiselect) {
return await modelClass.value.create({name: object[props.itemLabel]}).then((createdObj : any) => {
return await modelClass.value.create({name: object[itemLabel.value]}).then((createdObj : any) => {
useMessageStore().addMessage(MessageType.SUCCESS, 'Created', 5000, createdObj)
emit('create', object)
return createdObj
@@ -132,11 +151,11 @@ async function createObject(object: any, select$: Multiselect) {
<style src="@vueform/multiselect/themes/default.css"></style>
<style>
.material-multiselect {
--ms-line-height: 2.5;
--ms-bg: rgba(235, 235, 235, 0.75);
--ms-line-height: 2.3;
--ms-bg: rgba(235, 235, 235, 0.3);
--ms-border-color: 0;
--ms-border-color-active: 0;
border-bottom: 4px #0f0f0f;
border-bottom: inset 1px #323232;
border-bottom-left-radius: 0;
border-bottom-right-radius: 0;
}

View File

@@ -1,13 +1,28 @@
<template>
<!--TODO name, time, recipe, file(s), ingredients, quick add ingredients -->
<v-card>
<v-card variant="outlined">
<template #title>
<v-card-title v-if="step.name">{{ step.name }}</v-card-title>
<v-card-title v-else-if="stepIndex !== undefined">Step {{ stepIndex + 1 }}</v-card-title>
<v-card-title>
<v-chip color="primary">{{ props.stepIndex + 1 }}</v-chip>
{{ step.name }}
</v-card-title>
</template>
<template v-slot:append>
<v-btn size="small" variant="plain" icon="fas fa-sliders-h"></v-btn> <!--TODO implement -->
<v-btn size="small" variant="plain" icon>
<v-icon icon="fas fa-sliders-h"></v-icon>
<v-menu activator="parent">
<v-list>
<v-list-item prepend-icon="fas fa-plus-circle" @click="showTime = true" v-if="!showTime && step.time == 0">{{ $t('Time') }}</v-list-item>
<v-list-item prepend-icon="fas fa-plus-circle" @click="showFile = true" v-if="!showFile && step.file == null">{{ $t('File') }}</v-list-item>
<v-list-item prepend-icon="fas fa-plus-circle" @click="showRecipe = true" v-if="!showRecipe && step.stepRecipe == null">{{ $t('Recipe') }}</v-list-item>
<v-list-item prepend-icon="$delete">{{ $t('Delete') }}</v-list-item>
</v-list>
</v-menu>
</v-btn>
<v-icon icon="$dragHandle" class="drag-handle cursor-move"></v-icon>
</template>
<v-card-text>
@@ -15,126 +30,123 @@
v-model="step.name"
label="Step Name"
></v-text-field>
<v-chip-group>
<v-chip v-if="step.time == 0"><i class="fas fa-plus-circle fa-fw mr-1"></i> Time</v-chip>
<v-chip v-if="step.instruction == ''"><i class="fas fa-plus-circle fa-fw mr-1"></i> Instructions</v-chip>
<v-chip v-if="step.file == null"><i class="fas fa-plus-circle fa-fw mr-1"></i> File</v-chip>
<v-chip v-if="step.stepRecipe == null"><i class="fas fa-plus-circle fa-fw mr-1"></i> Recipe</v-chip>
</v-chip-group>
<v-table density="compact">
<v-row>
<v-col cols="12" md="6" v-if="showTime || step.time != 0">
<v-number-input :label="$t('Time')" v-model="step.time" :min="0" :step="5" control-variant="split"></v-number-input>
</v-col>
<v-col cols="12" md="6" v-if="showRecipe || step.stepRecipe != null">
<model-select model="Recipe" v-model="step.stepRecipe" append-to-body></model-select>
</v-col>
<v-col cols="12" md="6" v-if="showFile || step.file != null">
<model-select model="UserFile" v-model="step.file" append-to-body></model-select>
</v-col>
</v-row>
<draggable tag="tbody" v-model="step.ingredients" handle=".drag-handle" item-key="id" @sort="sortIngredients">
<template #item="{element}">
<v-dialog>
<template v-slot:activator="{ props: activatorProps }">
<IngredientsTableRow v-bind="activatorProps" :ingredient="element" :key="element.id" :show-notes="false" :draggable="true"></IngredientsTableRow>
</template>
<template v-slot:default="{ isActive }">
<v-card >
<v-card-title>Ingredient</v-card-title>
<v-card-text>
<v-form>
<v-text-field
label="Amount"
v-model.number="element.amount"
></v-text-field>
<model-select model="Unit" v-model="element.unit" :multiple="false"></model-select>
<model-select model="Food" v-model="element.food" :multiple="false"></model-select>
<v-text-field
label="Note"
v-model="element.note"
></v-text-field>
</v-form>
<v-row dense>
<v-col cols="12">
<v-label>{{ $t('Ingredients') }}</v-label>
</v-card-text>
</v-card>
</template>
</v-dialog>
<vue-draggable v-model="step.ingredients" handle=".drag-handle" :on-sort="sortIngredients">
<v-row v-for="(ingredient, index) in step.ingredients" dense>
<v-col cols="2">
<v-number-input :label="$t('Amount')" v-model="ingredient.amount" inset control-variant="stacked" :min="0"></v-number-input>
</v-col>
<v-col cols="3">
<model-select model="Unit" v-model="ingredient.unit"></model-select>
</v-col>
<v-col cols="3">
<model-select model="Food" v-model="ingredient.food"></model-select>
</v-col>
<v-col cols="3" @keydown.tab="insertAndFocusIngredient">
<v-text-field :label="$t('Note')" v-model="ingredient.note"></v-text-field>
</v-col>
<v-col cols="1">
<v-btn variant="plain" icon>
<v-icon icon="$settings" ></v-icon>
<v-menu activator="parent">
<v-list>
<v-list-item @click="step.ingredients.splice(index, 1)" prepend-icon="$delete">{{$t('Delete')}}</v-list-item>
</v-list>
</v-menu>
</v-btn>
<v-icon icon="$dragHandle" class="drag-handle"></v-icon>
</v-col>
</v-row>
</vue-draggable>
</v-col>
<v-col cols="12">
<v-label>{{ $t('Instructions') }}</v-label>
<v-alert @click="dialogMarkdownEdit = true" class="mt-2 cursor-text" min-height="52px">
{{ step.instruction }}
</v-alert>
</v-col>
</v-row>
</template>
</draggable>
</v-table>
<v-alert @click="dialog_markdown_edit = true" class="mt-2">
{{ step.instruction }}
</v-alert>
</v-card-text>
</v-card>
<v-dialog
v-model="dialog_markdown_edit"
transition="dialog-bottom-transition">
<v-card>
<v-card-title>Ingredient</v-card-title>
<v-form>
<v-text-field></v-text-field>
</v-form>
</v-card>
</v-dialog>
<v-dialog
v-model="dialog_markdown_edit"
transition="dialog-bottom-transition"
fullscreen>
v-model="dialogMarkdownEdit"
:max-width="(mobile) ? '100vw': '75vw'"
:fullscreen="mobile">
<v-card>
<v-toolbar>
<v-toolbar-title>Edit Instructions</v-toolbar-title>
<v-btn icon="fas fa-close" @click="dialog_markdown_edit = false"></v-btn>
<v-btn icon="fas fa-close" @click="dialogMarkdownEdit = false"></v-btn>
</v-toolbar>
<step-markdown-editor class="h-100" :step="step" @change="step = $event.step;"></step-markdown-editor>
<step-markdown-editor class="h-100" v-model="step"></step-markdown-editor>
</v-card>
</v-dialog>
</template>
<script lang="ts">
import {defineComponent, PropType} from 'vue'
import {Step} from "@/openapi";
<script setup lang="ts">
import {ref} from 'vue'
import {Ingredient, Step} from "@/openapi";
import StepMarkdownEditor from "@/components/inputs/StepMarkdownEditor.vue";
import IngredientsTable from "@/components/display/IngredientsTable.vue";
import {VNumberInput} from 'vuetify/labs/VNumberInput' //TODO remove once component is out of labs
import IngredientsTableRow from "@/components/display/IngredientsTableRow.vue";
import draggable from "vuedraggable";
import ModelSelect from "@/components/inputs/ModelSelect.vue";
import {useDisplay} from "vuetify";
import {VueDraggable} from "vue-draggable-plus";
export default defineComponent({
name: "StepEditor",
components: {ModelSelect, draggable, IngredientsTableRow, IngredientsTable, StepMarkdownEditor},
emits: ['update:modelValue'],
props: {
modelValue: {
type: Object as PropType<Step>,
required: true,
},
stepIndex: {
type: Number,
required: false,
},
},
computed: {
step: {
get() {
return this.modelValue
},
set(value: Step) {
this.$emit('update:modelValue', value)
}
}
},
data() {
return {
dialog_markdown_edit: false,
}
},
methods: {
sortIngredients() {
this.step.ingredients.forEach((value, index) => {
value.order = index
})
}
}
const step = defineModel<Step>({required: true})
const props = defineProps({
stepIndex: {type: Number, required: true},
})
const {mobile} = useDisplay()
const showTime = ref(false)
const showRecipe = ref(false)
const showFile = ref(false)
const dialogMarkdownEdit = ref(false)
/**
* sort function called by draggable when ingredient table is sorted
*/
function sortIngredients() {
step.value.ingredients.forEach((value, index) => {
value.order = index
})
}
function insertAndFocusIngredient(event: KeyboardEvent){
console.log('TRIGGER TAB')
event.preventDefault()
step.value.ingredients.push(
{
amount: 0,
food: null,
unit: null
} as Ingredient
)
}
</script>

View File

@@ -1,81 +1,58 @@
<template>
<mavon-editor v-model="mutable_step.instruction" :autofocus="false"
style="z-index: auto" :id="'id_instruction_' + mutable_step.id"
<mavon-editor v-model="steep.instruction" :autofocus="false"
style="z-index: auto" :id="'id_instruction_' + steep.id"
:language="'en'"
:toolbars="md_editor_toolbars" :defaultOpen="'edit'">
<template #left-toolbar-after>
<span class="op-icon-divider"></span>
<button
type="button"
@click="mutable_step.instruction+= ' {{ scale(100) }}'"
@click="steep.instruction+= ' {{ scale(100) }}'"
class="op-icon fas fa-calculator"
aria-hidden="true"
title="Scalable Number"
:title="$t('ScalableNumber')"
></button>
</template>
</mavon-editor>
</template>
<script lang="ts">
<script setup lang="ts">
import {defineComponent, PropType} from 'vue'
import {Step} from "@/openapi";
import 'mavon-editor/dist/css/index.css'
export default defineComponent({
name: "StepMarkdownEditor",
emits: {
change(payload: { step: Step }) {
return payload
}
},
watch: {
mutable_step: function (){
this.$emit('change', {step: this.mutable_step})
}
},
props: {
step: {type: Object as PropType<Step>, required: true}
},
data() {
return {
mutable_step: {} as Step,
const steep = defineModel<Step>({required: true})
const md_editor_toolbars = {
bold: true,
italic: true,
header: true,
underline: true,
strikethrough: true,
mark: false,
superscript: false,
subscript: false,
quote: true,
ol: true,
ul: true,
link: true,
imagelink: false,
code: false,
table: false,
fullscreen: false,
readmodel: false,
htmlcode: false,
help: false,
undo: true,
redo: true,
navigation: false,
alignleft: false,
aligncenter: false,
alignright: false,
subfield: true,
preview: true,
}
md_editor_toolbars: {
bold: true,
italic: true,
header: true,
underline: true,
strikethrough: true,
mark: false,
superscript: false,
subscript: false,
quote: true,
ol: true,
ul: true,
link: true,
imagelink: false,
code: false,
table: false,
fullscreen: false,
readmodel: false,
htmlcode: false,
help: false,
undo: true,
redo: true,
navigation: false,
alignleft: false,
aligncenter: false,
alignright: false,
subfield: true,
preview: true,
}
}
},
mounted() {
this.mutable_step = this.step
},
})
</script>

View File

@@ -15,13 +15,21 @@
<v-tab value="settings">{{ $t('Settings') }}</v-tab>
</v-tabs>
<v-card-text>
<v-tabs-window v-model="tab">
<v-tabs-window-item value="recipe">
<v-form :disabled="loading">
<v-text-field :label="$t('Name')" v-model="editingObj.name"></v-text-field>
<v-textarea :label="$t('Description')" v-model="editingObj.description" clearable counter="512"></v-textarea>
<v-row>
<v-col cols="12" md="6">
<v-textarea :label="$t('Description')" v-model="editingObj.description" clearable counter="512"></v-textarea>
</v-col>
<v-col cols="12" md="6">
<v-img style="max-height: 150px" :src="editingObj.image"></v-img>
</v-col>
</v-row>
<v-label>{{ $t('Keywords') }}</v-label>
<ModelSelect mode="tags" v-model="editingObj.keywords" model="Keyword"></ModelSelect>
@@ -41,27 +49,27 @@
</v-row>
</v-form>
</v-tabs-window-item>
<v-tabs-window-item value="steps">
<v-form :disabled="loading">
<v-timeline side="end" line-inset="10">
<v-row v-for="(s,i ) in editingObj.steps" :key="s.id">
<v-col>
<step-editor v-model="editingObj.steps[i]" :step-index="i"></step-editor>
</v-col>
</v-row>
<v-timeline-item v-for="(s,i) in editingObj.steps" dot-color="primary" size="small">
<template #icon>
{{ i+1 }}
</template>
<v-card>
<v-card-text >
<v-text-field style="min-width: 60vw" v-model="s.name"></v-text-field>
</v-card-text>
</v-card>
</v-timeline-item>
</v-timeline>
</v-form>
</v-tabs-window-item>
<v-tabs-window-item value="settings">
<v-form :disabled="loading">
<v-checkbox :label="$t('Ingredient Overview')" :hint="$t('show_ingredient_overview')" persistent-hint
v-model="editingObj.showIngredientOverview"></v-checkbox>
<v-text-field :label="$t('Imported_From')" v-model="editingObj.sourceUrl"></v-text-field>
<v-checkbox :label="$t('Private_Recipe')" :hint="$t('Private_Recipe_Help')" persistent-hint v-model="editingObj._private"></v-checkbox>
<ModelSelect mode="tags" model="User" :label="$t('Private_Recipe')" :hint="$t('Private_Recipe_Help')" persistent-hint v-model="editingObj.shared"
append-to-body></ModelSelect>
</v-form>
</v-tabs-window-item>
@@ -79,6 +87,7 @@ import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
import {useI18n} from "vue-i18n";
import ModelSelect from "@/components/inputs/ModelSelect.vue";
import StepEditor from "@/components/inputs/StepEditor.vue";
const {t} = useI18n()

View File

@@ -251,6 +251,7 @@
"Saturday": "",
"Save": "",
"Save_and_View": "",
"ScalableNumber": "",
"Search": "",
"Search Settings": "",
"Select": "",

View File

@@ -244,6 +244,7 @@
"Saturday": "",
"Save": "Запази",
"Save_and_View": "Запазете и прегледайте",
"ScalableNumber": "",
"Search": "Търсене",
"Search Settings": "Настройки търсене",
"Select": "Изберете",

View File

@@ -321,6 +321,7 @@
"Saturday": "",
"Save": "",
"Save_and_View": "Graveu-ho i mostreu-ho",
"ScalableNumber": "",
"Search": "",
"Search Settings": "",
"Second": "",

View File

@@ -319,6 +319,7 @@
"Saturday": "",
"Save": "Uložit",
"Save_and_View": "Uložit a zobrazit",
"ScalableNumber": "",
"Search": "Hledat",
"Search Settings": "Nastavení vyhledávání",
"Second": "Vteřina",

View File

@@ -301,6 +301,7 @@
"Saturday": "",
"Save": "Gem",
"Save_and_View": "Gem & Vis",
"ScalableNumber": "",
"Search": "Søg",
"Search Settings": "Søgningsindstillinger",
"Second": "Sekund",

View File

@@ -324,6 +324,7 @@
"Saturday": "Samstag",
"Save": "Speichern",
"Save_and_View": "Speichern & Ansehen",
"ScalableNumber": "Skalierbare Zahl",
"Search": "Suchen",
"Search Settings": "Sucheinstellungen",
"Second": "Sekunde",

View File

@@ -293,6 +293,7 @@
"Saturday": "",
"Save": "Αποθήκευση",
"Save_and_View": "Αποθήκευση και προβολή",
"ScalableNumber": "",
"Search": "Αναζήτηση",
"Search Settings": "Επιλογές αναζήτησης",
"Second": "Δευτερόλεπτο",

View File

@@ -323,6 +323,7 @@
"Saturday": "Saturday",
"Save": "Save",
"Save_and_View": "Save & View",
"ScalableNumber": "Scalable Number",
"Search": "Search",
"Search Settings": "Search Settings",
"Second": "Second",

View File

@@ -320,6 +320,7 @@
"Saturday": "",
"Save": "Guardar",
"Save_and_View": "Grabar y mostrar",
"ScalableNumber": "",
"Search": "Buscar",
"Search Settings": "Buscar ajustes",
"Second": "Segundo",

View File

@@ -178,6 +178,7 @@
"Saturday": "",
"Save": "Tallenna",
"Save_and_View": "Tallenna & Katso",
"ScalableNumber": "",
"Search": "Haku",
"Search Settings": "Hakuasetukset",
"Select_Book": "Valitse Kirja",

View File

@@ -321,6 +321,7 @@
"Saturday": "",
"Save": "Sauvegarder",
"Save_and_View": "Sauvegarder et visualiser",
"ScalableNumber": "",
"Search": "Rechercher",
"Search Settings": "Paramètres de recherche",
"Second": "Seconde",

View File

@@ -322,6 +322,7 @@
"Saturday": "",
"Save": "שמור",
"Save_and_View": "שמור וצפה",
"ScalableNumber": "",
"Search": "חיפוש",
"Search Settings": "חיפוש הגדרות",
"Second": "שניה",

View File

@@ -295,6 +295,7 @@
"Saturday": "",
"Save": "Mentés",
"Save_and_View": "Mentés & megtekintés",
"ScalableNumber": "",
"Search": "Keresés",
"Search Settings": "Keresési beállítások",
"Second": "Másodperc",

View File

@@ -123,6 +123,7 @@
"Saturday": "",
"Save": "",
"Save_and_View": "Պահպանել և Դիտել",
"ScalableNumber": "",
"Search": "",
"Select_Book": "Ընտրել գիրք",
"Select_File": "Ընտրել Ֆայլ",

View File

@@ -271,6 +271,7 @@
"Saturday": "",
"Save": "Menyimpan",
"Save_and_View": "Simpan & Lihat",
"ScalableNumber": "",
"Search": "Mencari",
"Search Settings": "Pengaturan Pencarian",
"Second": "",

View File

@@ -321,6 +321,7 @@
"Saturday": "",
"Save": "",
"Save_and_View": "",
"ScalableNumber": "",
"Search": "",
"Search Settings": "",
"Second": "",

View File

@@ -279,6 +279,7 @@
"Saturday": "",
"Save": "Salva",
"Save_and_View": "Salva & Mostra",
"ScalableNumber": "",
"Search": "Cerca",
"Search Settings": "Impostazioni di ricerca",
"Second": "Secondo",

View File

@@ -299,6 +299,7 @@
"Saturday": "",
"Save": "",
"Save_and_View": "Išsaugoti ir peržiūrėti",
"ScalableNumber": "",
"Search": "",
"Search Settings": "",
"Second": "",

View File

@@ -291,6 +291,7 @@
"Saturday": "",
"Save": "Lagre",
"Save_and_View": "Lagre og vis",
"ScalableNumber": "",
"Search": "Søk",
"Search Settings": "Søk Instillinger",
"Second": "Sekund",

View File

@@ -295,6 +295,7 @@
"Saturday": "",
"Save": "Opslaan",
"Save_and_View": "Sla op & Bekijk",
"ScalableNumber": "",
"Search": "Zoeken",
"Search Settings": "Zoekinstellingen",
"Second": "Seconde",

View File

@@ -323,6 +323,7 @@
"Saturday": "",
"Save": "Zapisz",
"Save_and_View": "Zapisz i wyświetl",
"ScalableNumber": "",
"Search": "Szukaj",
"Search Settings": "Ustawienia wyszukiwania",
"Second": "Sekunda",

View File

@@ -240,6 +240,7 @@
"Saturday": "",
"Save": "Guardar",
"Save_and_View": "Gravar & Ver",
"ScalableNumber": "",
"Search": "Pesquisar",
"Search Settings": "Definições de Pesquisa",
"Select": "Selecionar",

View File

@@ -310,6 +310,7 @@
"Saturday": "",
"Save": "Salvar",
"Save_and_View": "Salvar e Visualizar",
"ScalableNumber": "",
"Search": "Buscar",
"Search Settings": "Buscar Configuração",
"Second": "Segundo",

View File

@@ -283,6 +283,7 @@
"Saturday": "",
"Save": "Salvare",
"Save_and_View": "Salvare și vizionare",
"ScalableNumber": "",
"Search": "Căutare",
"Search Settings": "Setări de căutare",
"Second": "Secundă",

View File

@@ -225,6 +225,7 @@
"Saturday": "",
"Save": "Сохранить",
"Save_and_View": "Сохранить и показать",
"ScalableNumber": "",
"Search": "Поиск",
"Search Settings": "Искать настройки",
"Select": "Выбрать",

View File

@@ -216,6 +216,7 @@
"Saturday": "",
"Save": "Shrani",
"Save_and_View": "Shrani in poglej",
"ScalableNumber": "",
"Search": "Iskanje",
"Search Settings": "Išči nastavitev",
"Select_Book": "Izberi knjigo",

View File

@@ -323,6 +323,7 @@
"Saturday": "",
"Save": "Spara",
"Save_and_View": "Spara & visa",
"ScalableNumber": "",
"Search": "Sök",
"Search Settings": "Sökinställningar",
"Second": "Sekund",

View File

@@ -322,6 +322,7 @@
"Saturday": "",
"Save": "Kaydet",
"Save_and_View": "Kaydet & Görüntüle",
"ScalableNumber": "",
"Search": "Ara",
"Search Settings": "Arama Ayarları",
"Second": "Saniye",

View File

@@ -259,6 +259,7 @@
"Saturday": "",
"Save": "Зберегти",
"Save_and_View": "Зберегти і Подивитися",
"ScalableNumber": "",
"Search": "Пошук",
"Search Settings": "Налаштування Пошуку",
"Select": "",

View File

@@ -317,6 +317,7 @@
"Saturday": "",
"Save": "保存",
"Save_and_View": "保存并查看",
"ScalableNumber": "",
"Search": "搜索",
"Search Settings": "搜索设置",
"Second": "秒",

View File

@@ -95,6 +95,7 @@
"Saturday": "",
"Save": "",
"Save_and_View": "儲存並查看",
"ScalableNumber": "",
"Search": "",
"Select_Book": "選擇書籍",
"Select_File": "選擇檔案",

View File

@@ -58,6 +58,9 @@ export type Model = {
icon: string,
toStringKeys: Array<string>,
itemValue: string|undefined,
itemLabel: string|undefined,
disableList?: boolean | undefined,
disableRetrieve?: boolean | undefined,
disableCreate?: boolean | undefined,
@@ -82,6 +85,7 @@ export type EditorSupportedModels =
| 'Step'
| 'Ingredient'
| 'Food'
| 'Unit'
| 'Supermarket'
| 'SupermarketCategory'
| 'PropertyType'
@@ -89,6 +93,7 @@ export type EditorSupportedModels =
| 'Keyword'
| 'UserFile'
| 'ShoppingListEntry'
| 'User'
export const TFood = {
name: 'Food',
@@ -225,6 +230,7 @@ export const TUser = {
isPaginated: false,
toStringKeys: ['displayName'],
itemLabel: 'displayName',
tableHeaders: [
{title: 'Name', key: 'displayName'},