updated model editors to composable and base template

This commit is contained in:
vabene1111
2024-09-28 13:07:46 +02:00
parent 67fff17f06
commit 143eafa24a
43 changed files with 531 additions and 522 deletions

View File

@@ -475,7 +475,7 @@ class UserSpaceViewSet(viewsets.ModelViewSet):
queryset = UserSpace.objects
serializer_class = UserSpaceSerializer
permission_classes = [(CustomIsSpaceOwner | CustomIsOwnerReadOnly) & CustomTokenHasReadWriteScope]
http_method_names = ['get', 'patch', 'delete']
http_method_names = ['get', 'put', 'patch', 'delete']
pagination_class = DefaultPagination
def destroy(self, request, *args, **kwargs):

View File

@@ -4,7 +4,8 @@
<v-card>
<v-card-title>{{ $t('Delete') }}</v-card-title>
<v-card-text>
{{ $t('DeleteConfirmQuestion')}}
{{ $t('DeleteConfirmQuestion')}} <br/>
<b>{{ modelName }}</b><br/>
<b>{{ objectName }}</b>
</v-card-text>
<v-card-actions>
@@ -25,7 +26,8 @@ import {ref} from "vue";
const emit = defineEmits(['delete'])
const props = defineProps({
objectName: {type: String, default: ''}
objectName: {type: String, default: ''},
modelName: {type: String, default: ''},
})
const dialog = ref(false)

View File

@@ -1,9 +1,13 @@
<template>
<v-card :loading="loading">
<v-card-title>
{{ $t(modelClass.model.localizationKey) }}
<v-btn class="float-right" icon="$close" variant="plain" @click="emit('close')" v-if="dialog"></v-btn>
</v-card-title>
<model-editor-base
:loading="loading"
:dialog="dialog"
@save="saveObject"
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:model-name="$t(modelClass.model.localizationKey)"
:object-name="editingObjName()">
<v-card-text>
<v-form :disabled="loading">
<v-row>
@@ -19,65 +23,33 @@
<v-date-input :label="$t('Valid Until')" v-model="editingObj.expires"></v-date-input>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn color="delete" prepend-icon="$delete" v-if="isUpdate">{{ $t('Delete') }}
<delete-confirm-dialog :object-name="objectName" @delete="deleteObject"></delete-confirm-dialog>
</v-btn>
<v-btn color="save" prepend-icon="$save" @click="saveObject(modelClass, editingObj)">{{ isUpdate ? $t('Save') : $t('Create') }}</v-btn>
</v-card-actions>
</v-card>
</model-editor-base>
</template>
<script setup lang="ts">
import {VDateInput} from 'vuetify/labs/VDateInput' //TODO remove once component is out of labs
import {computed, onBeforeMount, onMounted, PropType, ref} from "vue";
import {onMounted, PropType} from "vue";
import {AccessToken} from "@/openapi";
import DeleteConfirmDialog from "@/components/dialogs/DeleteConfirmDialog.vue";
import {useI18n} from "vue-i18n";
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
import {DateTime} from "luxon";
import BtnCopy from "@/components/buttons/BtnCopy.vue";
import {GenericModel, getGenericModelFromString} from "@/types/Models";
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
const {t} = useI18n()
const emit = defineEmits(['create', 'save', 'delete', 'close'])
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
const props = defineProps({
item: {type: {} as PropType<AccessToken>, required: false},
item: {type: {} as PropType<AccessToken>, required: false, default: null},
itemId: {type: Number, required: false, default: undefined},
dialog: {type: Boolean, default: false}
})
//const editingObj = ref({} as AccessToken)
const modelClass = ref({} as GenericModel)
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<AccessToken>('AccessToken', emit)
const {deleteObject, saveObject, loading, editingObj} = useModelEditorFunctions<AccessToken>(emit)
/**
* checks if given object has ID property to determine if it needs to be updated or created
*/
const isUpdate = computed(() => {
return editingObj.value.id !== undefined
})
/**
* display name for object in headers/delete dialog/...
*/
const objectName = computed(() => {
return isUpdate ? `${t(modelClass.value.model.localizationKey)} ${editingObj.value.token}` : `${t(modelClass.value.model.localizationKey)} (${t('New')})`
})
onBeforeMount(() => {
modelClass.value = getGenericModelFromString('AccessToken', t)
})
onMounted(() => {
if (props.item != null) {
editingObj.value = props.item
} else {
if (!setupState(props.item, props.itemId)) {
// functions to populate defaults
editingObj.value.expires = DateTime.now().plus({year: 1}).toJSDate()
editingObj.value.scope = 'read write'

View File

@@ -1,129 +1,65 @@
<template>
<v-card>
<v-card-title>
{{ $t(OBJ_LOCALIZATION_KEY) }}
<v-btn class="float-right" icon="$close" variant="plain" @click="emit('close')" v-if="dialog"></v-btn>
</v-card-title>
<model-editor-base
:loading="loading"
:dialog="dialog"
@save="saveObject"
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:model-name="$t(modelClass.model.localizationKey)"
:object-name="editingObjName()">
<v-card-text>
<v-form>
<v-form :disabled="loading">
<v-text-field :label="$t('Email')" v-model="editingObj.email"></v-text-field>
<v-select :label="$t('Role')" :items="groups" item-value="id" item-title="name" return-object v-model="editingObj.group"></v-select>
<v-date-input :label="$t('Valid Until')" v-model="editingObj.validUntil"></v-date-input>
<v-textarea :label="$t('Note')" v-model="editingObj.internalNote"></v-textarea>
<v-checkbox :label="$t('Reusable')" v-model="editingObj.reusable"></v-checkbox>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn color="delete" prepend-icon="$delete" v-if="isUpdate">{{ $t('Delete') }}
<delete-confirm-dialog :object-name="objectName" @delete="deleteObject"></delete-confirm-dialog>
</v-btn>
<v-btn color="save" prepend-icon="$save" @click="saveObject">{{ isUpdate ? $t('Save') : $t('Create') }}</v-btn>
</v-card-actions>
</v-card>
</model-editor-base>
</template>
<script setup lang="ts">
import {VDateInput} from 'vuetify/labs/VDateInput' //TODO remove once component is out of labs
import {computed, onMounted, ref} from "vue";
import {AccessToken, ApiApi, Group, InviteLink} from "@/openapi";
import DeleteConfirmDialog from "@/components/dialogs/DeleteConfirmDialog.vue";
import {useI18n} from "vue-i18n";
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
import { onMounted, PropType, ref} from "vue";
import {ApiApi, Group, InviteLink} from "@/openapi";
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
import {DateTime} from "luxon";
import {useClipboard} from "@vueuse/core";
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
const {t} = useI18n()
const {copy} = useClipboard()
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const props = defineProps({
item: {type: {} as InviteLink, required: false},
item: {type: {} as PropType<InviteLink>, required: false, default: null},
itemId: {type: Number, required: false, default: undefined},
dialog: {type: Boolean, default: false}
})
const OBJ_LOCALIZATION_KEY = 'Invite_Link'
const editingObj = ref({} as InviteLink)
const loading = ref(false)
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<InviteLink>('InviteLink', emit)
// object specific data (for selects/display)
const groups = ref([] as Group[])
/**
* checks if given object has ID property to determine if it needs to be updated or created
*/
const isUpdate = computed(() => {
return editingObj.value.id !== undefined
})
/**
* display name for object in headers/delete dialog/...
*/
const objectName = computed(() => {
return isUpdate ? `${t(OBJ_LOCALIZATION_KEY)} ${editingObj.value.token}` : `${t(OBJ_LOCALIZATION_KEY)} (${t('New')})`
})
onMounted(() => {
const api = new ApiApi()
api.apiGroupList().then(r => {
groups.value = r
if (props.item != null) {
editingObj.value = props.item
} else {
if (!setupState(props.item, props.itemId)) {
// functions to populate defaults
editingObj.value.validUntil = DateTime.now().plus({month: 1}).toJSDate()
editingObj.value.group = groups.value[0]
}
}).catch(err => {
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
})
})
/**
* saves the edited object in the database
*/
async function saveObject() {
let api = new ApiApi()
if (isUpdate.value) {
api.apiInviteLinkUpdate({id: editingObj.value.id, inviteLink: editingObj.value}).then(r => {
editingObj.value = r
emit('save', r)
useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
})
} else {
api.apiInviteLinkCreate({inviteLink: editingObj.value}).then(r => {
editingObj.value = r
emit('create', r)
useMessageStore().addPreparedMessage(PreparedMessage.CREATE_SUCCESS)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err)
})
}
}
/**
* deletes the editing object from the database
*/
async function deleteObject() {
let api = new ApiApi()
api.apiInviteLinkDestroy({id: editingObj.value.id}).then(r => {
editingObj.value = {} as InviteLink
emit('delete')
}).catch(err => {
useMessageStore().addError(ErrorMessageType.DELETE_ERROR, err)
})
}
</script>
<style scoped>

View File

@@ -1,11 +1,15 @@
<template>
<v-card>
<v-card-title>
{{ $t(OBJ_LOCALIZATION_KEY) }}
<v-btn class="float-right" icon="$close" variant="plain" @click="emit('close')" v-if="dialog"></v-btn>
</v-card-title>
<model-editor-base
:loading="loading"
:dialog="dialog"
@save="saveObject"
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:model-name="$t(modelClass.model.localizationKey)"
:object-name="editingObjName()">
<v-card-text>
<v-form>
<v-form :disabled="loading">
<v-text-field v-model="editingObj.name" :label="$t('Name')"></v-text-field>
<v-text-field
@@ -17,117 +21,49 @@
prepend-icon="fa-solid fa-clock"
readonly>
<v-menu
v-model="timePickerMenu"
:close-on-content-click="false"
activator="parent"
transition="scale-transition">
<v-time-picker v-if="timePickerMenu" format="24hr" v-model="editingObj.time"></v-time-picker>
</v-menu>
v-model="timePickerMenu"
:close-on-content-click="false"
activator="parent"
transition="scale-transition">
<v-time-picker v-if="timePickerMenu" format="24hr" v-model="editingObj.time"></v-time-picker>
</v-menu>
</v-text-field>
<v-color-picker v-model="editingObj.color" mode="hex" :modes="['hex']" show-swatches
:swatches="[['#ddbf86'],['#b98766'],['#b55e4f'],['#82aa8b'],['#385f84']]"></v-color-picker>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn color="delete" prepend-icon="$delete" v-if="isUpdate">{{ $t('Delete') }}
<delete-confirm-dialog :object-name="objectName" @delete="deleteObject"></delete-confirm-dialog>
</v-btn>
<v-btn color="save" prepend-icon="$save" @click="saveObject">{{ isUpdate ? $t('Save') : $t('Create') }}</v-btn>
</v-card-actions>
</v-card>
</model-editor-base>
</template>
<script setup lang="ts">
import {computed, onMounted, ref} from "vue";
import {ApiApi, MealType} from "@/openapi";
import DeleteConfirmDialog from "@/components/dialogs/DeleteConfirmDialog.vue";
import {useI18n} from "vue-i18n";
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
import {useClipboard} from "@vueuse/core";
import {VTimePicker} from 'vuetify/labs/VTimePicker'
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore"; // TODO remove once out of labs
import {onMounted, PropType, ref} from "vue";
import {MealType} from "@/openapi";
import {VTimePicker} from 'vuetify/labs/VTimePicker'; // TODO remove once out of labs
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
const {t} = useI18n()
const {copy} = useClipboard()
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const props = defineProps({
item: {type: {} as MealType, required: true},
item: {type: {} as PropType<MealType>, required: false, default: null},
itemId: {type: Number, required: false, default: undefined},
dialog: {type: Boolean, default: false}
})
const OBJ_LOCALIZATION_KEY = 'Meal_Type'
const editingObj = ref({} as MealType)
const loading = ref(false)
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<MealType>('MealType', emit)
// object specific data (for selects/display)
const timePickerMenu = ref(false)
/**
* checks if given object has ID property to determine if it needs to be updated or created
*/
const isUpdate = computed(() => {
return editingObj.value.id !== undefined
})
/**
* display name for object in headers/delete dialog/...
*/
const objectName = computed(() => {
return isUpdate ? `${t(OBJ_LOCALIZATION_KEY)} ${editingObj.value.token}` : `${t(OBJ_LOCALIZATION_KEY)} (${t('New')})`
})
onMounted(() => {
if (props.item != null) {
editingObj.value = props.item
} else {
if (!setupState(props.item, props.itemId)) {
// functions to populate defaults
}
})
/**
* saves the edited object in the database
*/
async function saveObject() {
let api = new ApiApi()
if (isUpdate.value) {
api.apiMealTypeUpdate({id: editingObj.value.id, mealType: editingObj.value}).then(r => {
editingObj.value = r
emit('save', r)
useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
})
} else {
api.apiMealTypeCreate({mealType: editingObj.value}).then(r => {
editingObj.value = r
emit('create', r)
useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
})
}
}
/**
* deletes the editing object from the database
*/
async function deleteObject() {
let api = new ApiApi()
api.apiMealTypeDestroy({id: editingObj.value.id}).then(r => {
editingObj.value = {} as MealType
emit('delete', editingObj.value)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.DELETE_ERROR, err)
})
}
</script>
<style scoped>

View File

@@ -0,0 +1,41 @@
<template>
<v-card :loading="loading">
<v-card-title>
{{ modelName }}
<v-btn class="float-right" icon="$close" variant="plain" @click="emit('close')" v-if="dialog"></v-btn>
<v-card-subtitle class="pa-0">{{ objectName }}</v-card-subtitle>
</v-card-title>
<v-divider></v-divider>
<slot name="default">
</slot>
<v-divider></v-divider>
<v-card-actions>
<v-btn color="delete" prepend-icon="$delete" v-if="isUpdate">{{ $t('Delete') }}
<delete-confirm-dialog :object-name="objectName" :model-name="modelName" @delete="emit('delete')"></delete-confirm-dialog>
</v-btn>
<v-btn color="save" prepend-icon="$save" @click="emit('save')">{{ isUpdate ? $t('Save') : $t('Create') }}</v-btn>
</v-card-actions>
</v-card>
</template>
<script setup lang="ts">
import DeleteConfirmDialog from "@/components/dialogs/DeleteConfirmDialog.vue";
const emit = defineEmits(['save', 'delete', 'close'])
const props = defineProps({
loading: {type: Boolean, default: false},
dialog: {type: Boolean, default: false},
objectName: {type: String, default: ''},
modelName: {type: String, default: ''},
isUpdate: {type: Boolean, default: false}
})
</script>
<style scoped>
</style>

View File

@@ -1,10 +1,13 @@
<template>
<v-card>
<v-card-title>
{{ $t(OBJ_LOCALIZATION_KEY) }}
<v-btn class="float-right" icon="$close" variant="plain" @click="emit('close')" v-if="dialog"></v-btn>
</v-card-title>
<model-editor-base
:loading="loading"
:dialog="dialog"
@save="saveObject"
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:model-name="$t(modelClass.model.localizationKey)"
:object-name="editingObjName()">
<v-card-text>
<v-form>
<v-number-input :step="10" v-model="editingObj.propertyAmount" control-variant="stacked">
@@ -15,116 +18,38 @@
<model-select :label="$t('Property')" v-model="editingObj.propertyType" model="PropertyType"></model-select>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn color="delete" prepend-icon="$delete" v-if="isUpdate">{{ $t('Delete') }}
<delete-confirm-dialog :object-name="objectName" @delete="deleteObject"></delete-confirm-dialog>
</v-btn>
<v-btn color="save" prepend-icon="$save" @click="saveObject">{{ isUpdate ? $t('Save') : $t('Create') }}</v-btn>
</v-card-actions>
</v-card>
</model-editor-base>
</template>
<script setup lang="ts">
import {computed, onMounted, ref} from "vue";
import {ApiApi, Property} from "@/openapi";
import DeleteConfirmDialog from "@/components/dialogs/DeleteConfirmDialog.vue";
import {useI18n} from "vue-i18n";
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
import {onMounted, PropType} from "vue";
import {Property} from "@/openapi";
import ModelSelect from "@/components/inputs/ModelSelect.vue";
import {VNumberInput} from 'vuetify/labs/VNumberInput' //TODO remove once component is out of labs
const {t} = useI18n()
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const props = defineProps({
item: {type: {} as Property, required: false},
itemId: {type: String, required: false},
item: {type: {} as PropType<Property>, required: false, default: null},
itemId: {type: Number, required: false, default: undefined},
dialog: {type: Boolean, default: false}
})
const OBJ_LOCALIZATION_KEY = 'Food'
const editingObj = ref({} as Property)
const loading = ref(false)
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<Property>('Property', emit)
// object specific data (for selects/display)
/**
* checks if given object has ID property to determine if it needs to be updated or created
*/
const isUpdate = computed(() => {
return Object.keys(editingObj.value).length > 0
})
/**
* display name for object in headers/delete dialog/...
*/
const objectName = computed(() => {
return isUpdate ? `${t(OBJ_LOCALIZATION_KEY)} ${editingObj.value.token}` : `${t(OBJ_LOCALIZATION_KEY)} (${t('New')})`
})
onMounted(() => {
if (props.item != null) {
editingObj.value = props.item
} else if (props.itemId != null) {
const api = new ApiApi()
api.apiPropertyRetrieve({id: props.itemId}).then(r => {
editingObj.value = r
}).catch(err => {
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
})
} else {
// functions to populate defaults for new item
if (!setupState(props.item, props.itemId)) {
// functions to populate defaults
}
})
/**
* saves the edited object in the database
*/
async function saveObject() {
let api = new ApiApi()
if (isUpdate.value) {
api.apiPropertyUpdate({id: editingObj.value.id, property: editingObj.value}).then(r => {
editingObj.value = r
emit('save', r)
useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
})
} else {
api.apiPropertyCreate({property: editingObj.value}).then(r => {
editingObj.value = r
emit('create', r)
useMessageStore().addPreparedMessage(PreparedMessage.CREATE_SUCCESS)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err)
})
}
}
/**
* deletes the editing object from the database
*/
async function deleteObject() {
if (editingObj.value.id !== undefined) {
let api = new ApiApi()
api.apiPropertyDestroy({id: editingObj.value.id}).then(r => {
editingObj.value = {} as Property
emit('delete', editingObj.value)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.DELETE_ERROR, err)
})
} else {
editingObj.value = {} as Property
emit('delete', editingObj.value)
}
}
// ------------------------------------------------------
// object specific functions
// ------------------------------------------------------
</script>

View File

@@ -1,15 +1,18 @@
<template>
<v-card>
<v-card-title>
{{ $t(OBJ_LOCALIZATION_KEY) }}
<v-btn class="float-right" icon="$close" variant="plain" @click="emit('close')" v-if="dialog"></v-btn>
</v-card-title>
<model-editor-base
:loading="loading"
:dialog="dialog"
@save="saveObject"
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:model-name="$t(modelClass.model.localizationKey)"
:object-name="editingObjName()">
<v-card-text>
<v-form>
<v-row>
<v-col>
<model-select model="Food" v-model="editingObj.food" :label="$t('Food')" :disabled="disabledFields.includes('food')"></model-select>
<model-select model="Food" v-model="editingObj.food" :label="$t('Food')"></model-select>
</v-col>
</v-row>
<v-row>
@@ -37,119 +40,36 @@
</v-row>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn color="delete" prepend-icon="$delete" v-if="isUpdate">{{ $t('Delete') }}
<delete-confirm-dialog :object-name="objectName" @delete="deleteObject"></delete-confirm-dialog>
</v-btn>
<v-btn color="save" prepend-icon="$save" @click="saveObject">{{ isUpdate ? $t('Save') : $t('Create') }}</v-btn>
</v-card-actions>
</v-card>
</model-editor-base>
</template>
<script setup lang="ts">
import {computed, onMounted, ref} from "vue";
import {ApiApi, Property, UnitConversion} from "@/openapi";
import DeleteConfirmDialog from "@/components/dialogs/DeleteConfirmDialog.vue";
import {useI18n} from "vue-i18n";
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
import {onMounted, PropType} from "vue";
import {UnitConversion} from "@/openapi";
import ModelSelect from "@/components/inputs/ModelSelect.vue";
import {VNumberInput} from 'vuetify/labs/VNumberInput' //TODO remove once component is out of labs
const {t} = useI18n()
const emit = defineEmits(['create', 'save', 'delete', 'close'])
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
const props = defineProps({
item: {type: {} as UnitConversion, required: false},
itemId: {type: String, required: false},
dialog: {type: Boolean, default: false},
disabledFields: {default: []},
item: {type: {} as PropType<UnitConversion>, required: false, default: null},
itemId: {type: Number, required: false, default: undefined},
dialog: {type: Boolean, default: false}
})
const OBJ_LOCALIZATION_KEY = 'Conversion'
const editingObj = ref({} as UnitConversion)
const loading = ref(false)
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<UnitConversion>('UnitConversion', emit)
// object specific data (for selects/display)
/**
* checks if given object has ID property to determine if it needs to be updated or created
*/
const isUpdate = computed(() => {
return Object.keys(editingObj.value).length > 0
})
/**
* display name for object in headers/delete dialog/...
*/
const objectName = computed(() => {
return isUpdate ? `${t(OBJ_LOCALIZATION_KEY)} ${editingObj.value.token}` : `${t(OBJ_LOCALIZATION_KEY)} (${t('New')})`
})
onMounted(() => {
if (props.item != null) {
editingObj.value = props.item
} else if (props.itemId != null) {
const api = new ApiApi()
api.apiUnitConversionRetrieve({id: props.itemId}).then(r => {
editingObj.value = r
}).catch(err => {
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
})
} else {
// functions to populate defaults for new item
if (!setupState(props.item, props.itemId)) {
// functions to populate defaults
}
})
/**
* saves the edited object in the database
*/
async function saveObject() {
let api = new ApiApi()
if (editingObj.value.id) {
api.apiUnitConversionUpdate({id: editingObj.value.id, unitConversion: editingObj.value}).then(r => {
editingObj.value = r
emit('save', r)
useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
})
} else {
api.apiUnitConversionCreate({unitConversion: editingObj.value}).then(r => {
editingObj.value = r
emit('create', r)
useMessageStore().addPreparedMessage(PreparedMessage.CREATE_SUCCESS)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err)
})
}
}
/**
* deletes the editing object from the database
*/
async function deleteObject() {
if (editingObj.value.id !== undefined) {
let api = new ApiApi()
api.apiUnitConversionDestroy({id: editingObj.value.id}).then(r => {
editingObj.value = {} as UnitConversion
emit('delete', editingObj.value)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.DELETE_ERROR, err)
})
} else {
editingObj.value = {} as UnitConversion
emit('delete', editingObj.value)
}
}
// ------------------------------------------------------
// object specific functions
// ------------------------------------------------------
</script>
<style scoped>

View File

@@ -1,66 +1,45 @@
<template>
<v-card>
<v-card-title>
{{ $t(OBJ_LOCALIZATION_KEY) }}
<v-btn class="float-right" icon="$close" variant="plain" @click="emit('close')" v-if="dialog"></v-btn>
</v-card-title>
<model-editor-base
:loading="loading"
:dialog="dialog"
@save="saveObject"
@delete="deleteObject"
@close="emit('close')"
:is-update="isUpdate()"
:model-name="$t(modelClass.model.localizationKey)"
:object-name="editingObjName()">
<v-card-text>
<v-form>
<v-select :label="$t('Role')" :items="groups" item-value="id" item-title="name" return-object multiple v-model="editingObj.groups"></v-select>
</v-form>
</v-card-text>
<v-card-actions>
<v-btn color="delete" prepend-icon="$delete" v-if="isUpdate">{{ $t('Delete') }}
<delete-confirm-dialog :object-name="objectName" @delete="deleteObject"></delete-confirm-dialog>
</v-btn>
<v-btn color="save" prepend-icon="$save" @click="saveObject">{{ isUpdate ? $t('Save') : $t('Create') }}</v-btn>
</v-card-actions>
</v-card>
</model-editor-base>
</template>
<script setup lang="ts">
import {computed, onMounted, ref} from "vue";
import {AccessToken, ApiApi, Group, InviteLink, UserSpace} from "@/openapi";
import DeleteConfirmDialog from "@/components/dialogs/DeleteConfirmDialog.vue";
import {useI18n} from "vue-i18n";
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
import {DateTime} from "luxon";
import {useClipboard} from "@vueuse/core";
import {tr} from "vuetify/locale";
import {onMounted, PropType, ref} from "vue";
import {ApiApi, Group, UserSpace} from "@/openapi";
const {t} = useI18n()
const {copy} = useClipboard()
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
const emit = defineEmits(['create', 'save', 'delete', 'close'])
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
const props = defineProps({
item: {type: {} as UserSpace, required: true},
item: {type: {} as PropType<UserSpace>, required: false, default: null},
itemId: {type: Number, required: false, default: undefined},
dialog: {type: Boolean, default: false}
})
const OBJ_LOCALIZATION_KEY = 'Invite_Link'
const editingObj = ref({} as UserSpace)
const loading = ref(false)
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, modelClass} = useModelEditorFunctions<UserSpace>('UserSpace', emit)
// object specific data (for selects/display)
const groups = ref([] as Group[])
/**
* checks if given object has ID property to determine if it needs to be updated or created
*/
const isUpdate = computed(() => {
return editingObj.value.id !== undefined
})
/**
* display name for object in headers/delete dialog/...
*/
const objectName = computed(() => {
return isUpdate ? `${t(OBJ_LOCALIZATION_KEY)} ${editingObj.value.token}` : `${t(OBJ_LOCALIZATION_KEY)} (${t('New')})`
})
onMounted(() => {
const api = new ApiApi()
api.apiGroupList().then(r => {
@@ -69,41 +48,11 @@ onMounted(() => {
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
})
if (props.item != null) {
editingObj.value = props.item
} else {
console.error('UserSpaceEditor cannot create items')
if (!setupState(props.item, props.itemId)) {
// functions to populate defaults
}
})
/**
* saves the edited object in the database
*/
async function saveObject() {
let api = new ApiApi()
if (isUpdate.value) {
api.apiUserSpacePartialUpdate({id: editingObj.value.id, patchedUserSpace: editingObj.value}).then(r => {
editingObj.value = r
emit('save', r)
useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
})
}
}
/**
* deletes the editing object from the database
*/
async function deleteObject() {
let api = new ApiApi()
api.apiUserSpaceDestroy({id: editingObj.value.id}).then(r => {
editingObj.value = {} as UserSpace
emit('delete', editingObj.value)
}).catch(err => {
useMessageStore().addError(ErrorMessageType.DELETE_ERROR, err)
})
}
</script>

View File

@@ -1,27 +1,94 @@
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
import {computed, onBeforeMount, ref} from "vue";
import {GenericModel} from "@/types/Models";
import {onBeforeMount, PropType, ref} from "vue";
import {GenericModel, getGenericModelFromString} from "@/types/Models";
import {useI18n} from "vue-i18n";
// TODO type emit parameter (https://mokkapps.de/vue-tips/emit-event-from-composable)
// TODO alternatively there seems to be a getContext method to get the calling context
// TODO alternatively there seems to be a getContext method to get the calling context (good practice?)
export function useModelEditorFunctions<T>(emit: any) {
export function useModelEditorFunctions<T>(modelName: string, emit: any) {
const loading = ref(false)
const editingObj = ref({} as T)
const modelClass = ref({} as GenericModel)
const {t} = useI18n()
/**
* before mounting the component UI set the model class based on the given model name
*/
onBeforeMount(() => {
console.log('COMPOSABLE OF TYPE ', typeof editingObj)
modelClass.value = getGenericModelFromString(modelName, t)
})
/**
* if given an object or id, sets up the editingObj with that item or loads the data from the API using the ID
* if both item and itemId are undefined return false to indicate that no editingObj has been initialized
* @param item item object to set as editingObj
* @param itemId id of object to be retrieved and set as editingObj
*/
function setupState(item: T | null, itemId: number | undefined) {
if (item === null && itemId === undefined) {
if (modelClass.value.model.disableCreate) {
throw Error('Trying to use a ModelEditor without an item and a model that does not allow object creation!')
}
return false
} else if (item !== null) {
editingObj.value = item
} else if (itemId !== undefined) {
loading.value = true
modelClass.value.retrieve(itemId).then((r: T) => {
editingObj.value = r
}).catch((err: any) => {
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
}).finally(() => {
loading.value = false
})
}
return true
}
/**
* checks if the object has the ID property, if yes its an update if not its a new object
*/
function isUpdate() {
return !!editingObj.value.id;
}
/**
* return the display name for the editingObj instance by concatenating the attributes
* given in the model type together
*/
function editingObjName(): string {
if (!isUpdate()) {
return t('New') + ' - ' + t(modelClass.value.model.localizationKey)
}
let name = ''
if (editingObj.value.id) {
modelClass.value.model.toStringKeys.forEach(key => {
name += ' ' + editingObj.value[key]
})
}
if (name == '') {
console.warn('No string keys given model type ', modelName)
return t(modelClass.value.model.localizationKey)
}
return name
}
/**
* saves the edited object in the database
*/
function saveObject(modelClass: GenericModel, obj: any) {
function saveObject() {
loading.value = true
if (obj.id) {
modelClass.update(obj.id, obj).then((r: any) => {
if (isUpdate()) {
modelClass.value.update(editingObj.value.id, editingObj.value).then((r: T) => {
emit('save', r)
editingObj.value = r
useMessageStore().addPreparedMessage(PreparedMessage.UPDATE_SUCCESS)
}).catch((err: any) => {
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
@@ -29,8 +96,9 @@ export function useModelEditorFunctions<T>(emit: any) {
loading.value = false
})
} else {
modelClass.create(obj).then((r: any) => {
modelClass.value.create(editingObj.value).then((r: T) => {
emit('create', r)
editingObj.value = r
useMessageStore().addPreparedMessage(PreparedMessage.CREATE_SUCCESS)
}).catch((err: any) => {
useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err)
@@ -43,13 +111,14 @@ export function useModelEditorFunctions<T>(emit: any) {
/**
* deletes the editing object from the database
*/
function deleteObject(modelClass: GenericModel, obj: any) {
modelClass.destroy(obj.id).then((r: any) => {
emit('delete', obj)
function deleteObject() {
modelClass.value.destroy(editingObj.value.id).then((r: any) => {
emit('delete', editingObj)
editingObj.value = {} as T
}).catch((err: any) => {
useMessageStore().addError(ErrorMessageType.DELETE_ERROR, err)
})
}
return {emit, saveObject, deleteObject, loading, editingObj}
return {setupState, saveObject, deleteObject, isUpdate, editingObjName, loading, editingObj, modelClass}
}

View File

@@ -77,6 +77,7 @@
"Edit_Keyword": "",
"Edit_Meal_Plan_Entry": "",
"Edit_Recipe": "",
"Email": "",
"Empty": "",
"Enable_Amount": "",
"Energy": "",
@@ -131,6 +132,7 @@
"InheritWarning": "",
"Instructions": "",
"Internal": "",
"Invite_Link": "",
"Invites": "",
"Key_Ctrl": "",
"Key_Shift": "",
@@ -231,6 +233,8 @@
"Remove_nutrition_recipe": "",
"Reset": "",
"Reset_Search": "",
"Reusable": "",
"Role": "",
"Root": "",
"Saturday": "",
"Save": "",

View File

@@ -74,6 +74,7 @@
"Edit_Keyword": "Редактиране на ключова дума",
"Edit_Meal_Plan_Entry": "Редактиране на записа в плана за хранене",
"Edit_Recipe": "Редактиране на рецепта",
"Email": "",
"Empty": "Празно",
"Enable_Amount": "Активиране на сумата",
"Energy": "Енергия",
@@ -127,6 +128,7 @@
"InheritWarning": "{food} е настроен да наследява, промените може да не продължат.",
"Instructions": "Инструкции",
"Internal": "Вътрешен",
"Invite_Link": "",
"Key_Ctrl": "Контрол",
"Key_Shift": "Превключване",
"Keyword": "Ключова дума",
@@ -224,6 +226,8 @@
"Remove_nutrition_recipe": "Изтрийте хранителните стойности от рецептата",
"Reset": "Нулиране",
"Reset_Search": "Нулиране на търсенето",
"Reusable": "",
"Role": "",
"Root": "Корен",
"Saturday": "",
"Save": "Запази",

View File

@@ -109,6 +109,7 @@
"Edit_Keyword": "Editeu paraula clau",
"Edit_Meal_Plan_Entry": "",
"Edit_Recipe": "Editeu recepta",
"Email": "",
"Empty": "",
"Enable": "",
"Enable_Amount": "Habiliteu quantitat",
@@ -176,6 +177,7 @@
"Instruction_Replace": "Substituïu instrucció",
"Instructions": "",
"Internal": "",
"Invite_Link": "",
"Invites": "",
"Key_Ctrl": "",
"Key_Shift": "",
@@ -301,6 +303,8 @@
"Remove_nutrition_recipe": "Esborreu nutrició de la recepta",
"Reset": "",
"Reset_Search": "Reinicieu la cerca",
"Reusable": "",
"Role": "",
"Root": "",
"Saturday": "",
"Save": "",

View File

@@ -109,6 +109,7 @@
"Edit_Keyword": "Upravit štítek",
"Edit_Meal_Plan_Entry": "Upravit položku v jídelníčku",
"Edit_Recipe": "Upravit recept",
"Email": "",
"Empty": "Prázdné",
"Enable": "Aktivovat",
"Enable_Amount": "Zobrazit množství",
@@ -175,6 +176,7 @@
"Instruction_Replace": "Nahraď instrukce",
"Instructions": "Instrukce",
"Internal": "Interní",
"Invite_Link": "",
"Invites": "Pozvánky",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -299,6 +301,8 @@
"Remove_nutrition_recipe": "Smazat nutriční hodnoty",
"Reset": "Resetovat",
"Reset_Search": "Zrušit filtry vyhledávání",
"Reusable": "",
"Role": "",
"Root": "Kořen",
"Saturday": "",
"Save": "Uložit",

View File

@@ -100,6 +100,7 @@
"Edit_Keyword": "Rediger nøgleord",
"Edit_Meal_Plan_Entry": "Rediger punkt i madplan",
"Edit_Recipe": "Rediger opskrift",
"Email": "",
"Empty": "Tom",
"Enable_Amount": "Aktiver antal",
"EndDate": "Slutdato",
@@ -163,6 +164,7 @@
"Instruction_Replace": "Erstat instruktion",
"Instructions": "Instruktioner",
"Internal": "Interne",
"Invite_Link": "",
"Invites": "Invitationer",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -281,6 +283,8 @@
"Remove_nutrition_recipe": "Fjern næringsindhold fra opskrift",
"Reset": "Nulstil",
"Reset_Search": "Nulstil søgning",
"Reusable": "",
"Role": "",
"Root": "Rod",
"Saturday": "",
"Save": "Gem",

View File

@@ -111,6 +111,7 @@
"Edit_Keyword": "Schlagwort bearbeiten",
"Edit_Meal_Plan_Entry": "Eintrag bearbeiten",
"Edit_Recipe": "Rezept bearbeiten",
"Email": "Email",
"Empty": "Leer",
"Enable": "Aktivieren",
"Enable_Amount": "Menge aktivieren",
@@ -178,6 +179,7 @@
"Instruction_Replace": "Anleitung ersetzen",
"Instructions": "Anleitung",
"Internal": "Intern",
"Invite_Link": "Einladungs Link",
"Invites": "Einladungen",
"Key_Ctrl": "Strg",
"Key_Shift": "Umschalttaste",
@@ -303,6 +305,8 @@
"Remove_nutrition_recipe": "Nährwerte aus Rezept löschen",
"Reset": "Zurücksetzen",
"Reset_Search": "Suche zurücksetzen",
"Reusable": "Wiederverwendbar",
"Role": "Rolle",
"Root": "Wurzel",
"Saturday": "Samstag",
"Save": "Speichern",

View File

@@ -99,6 +99,7 @@
"Edit_Keyword": "Τροποποίηση λέξης-κλειδί",
"Edit_Meal_Plan_Entry": "Τροποποίηση εγγραφής στο πρόγραμμα γευμάτων",
"Edit_Recipe": "Τροποποίηση συνταγής",
"Email": "",
"Empty": "Κενό",
"Enable_Amount": "Ενεργοποίηση ποσότητας",
"Energy": "Ενέργεια",
@@ -158,6 +159,7 @@
"Instruction_Replace": "Αλλαγή οδηγίας",
"Instructions": "Οδηγίες",
"Internal": "Εσωτερική",
"Invite_Link": "",
"Invites": "Προσκλήσεις",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -273,6 +275,8 @@
"Remove_nutrition_recipe": "Αφαίρεση διατροφικής αξίας από τη συνταγή",
"Reset": "Επαναφορά",
"Reset_Search": "Επαναφορά αναζήτησης",
"Reusable": "",
"Role": "",
"Root": "Ρίζα",
"Saturday": "",
"Save": "Αποθήκευση",

View File

@@ -110,6 +110,7 @@
"Edit_Keyword": "Edit Keyword",
"Edit_Meal_Plan_Entry": "Edit meal plan entry",
"Edit_Recipe": "Edit Recipe",
"Email": "Email",
"Empty": "Empty",
"Enable": "Enable",
"Enable_Amount": "Enable Amount",
@@ -304,6 +305,7 @@
"Remove_nutrition_recipe": "Delete nutrition from recipe",
"Reset": "Reset",
"Reset_Search": "Reset Search",
"Reusable": "Reusable",
"Role": "Role",
"Root": "Root",
"Saturday": "Saturday",

View File

@@ -110,6 +110,7 @@
"Edit_Keyword": "Editar palabra clave",
"Edit_Meal_Plan_Entry": "Eliminar entrada del régimen de comidas",
"Edit_Recipe": "Editar receta",
"Email": "",
"Empty": "Vacio",
"Enable": "Activado",
"Enable_Amount": "Habilitar cantidad",
@@ -177,6 +178,7 @@
"Instruction_Replace": "Reemplazar Instrucción",
"Instructions": "Instrucciones",
"Internal": "Interno",
"Invite_Link": "",
"Invites": "Invitaciones",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -300,6 +302,8 @@
"Remove_nutrition_recipe": "Borrar nutrición de la canasta",
"Reset": "Restablecer",
"Reset_Search": "Resetear busqueda",
"Reusable": "",
"Role": "",
"Root": "Raíz",
"Saturday": "",
"Save": "Guardar",

View File

@@ -53,6 +53,7 @@
"Edit_Keyword": "Muokkaa avainsanaa",
"Edit_Meal_Plan_Entry": "Muokkaa ateriasuunnitelma merkintää",
"Edit_Recipe": "Muokkaa Reseptiä",
"Email": "",
"Empty": "Tyhjä",
"Enable_Amount": "Ota Määrä käyttöön",
"Energy": "Energia",
@@ -83,6 +84,7 @@
"Information": "Tiedot",
"Ingredients": "Ainesosat",
"Instructions": "Ohjeet",
"Invite_Link": "",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
"Keyword_Alias": "Avainsana-alias",
@@ -157,6 +159,8 @@
"Remove": "",
"Remove_nutrition_recipe": "Poista ravintoaine reseptistä",
"Reset_Search": "Nollaa haku",
"Reusable": "",
"Role": "",
"Root": "Root",
"Saturday": "",
"Save": "Tallenna",

View File

@@ -109,6 +109,7 @@
"Edit_Keyword": "Modifier le mot-clé",
"Edit_Meal_Plan_Entry": "Modifier une entrée de menu",
"Edit_Recipe": "Modifier la recette",
"Email": "",
"Empty": "Vider",
"Enable": "Activer",
"Enable_Amount": "Activer la quantité",
@@ -176,6 +177,7 @@
"Instruction_Replace": "Instruction Remplacer",
"Instructions": "Instructions",
"Internal": "Interne",
"Invite_Link": "",
"Invites": "Invitations",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Maj",
@@ -301,6 +303,8 @@
"Remove_nutrition_recipe": "Supprimer les valeurs nutritionelles de la recette",
"Reset": "Réinitialiser",
"Reset_Search": "Réinitialiser la recherche",
"Reusable": "",
"Role": "",
"Root": "Racine",
"Saturday": "",
"Save": "Sauvegarder",

View File

@@ -110,6 +110,7 @@
"Edit_Keyword": "עדכן מילת מפתח",
"Edit_Meal_Plan_Entry": "ערוך רשימת תכנון אוכל",
"Edit_Recipe": "עדכן מתכון",
"Email": "",
"Empty": "ריק",
"Enable": "הפעל",
"Enable_Amount": "אפשר כמות",
@@ -177,6 +178,7 @@
"Instruction_Replace": "החלפת הוראות",
"Instructions": "הוראות",
"Internal": "פנימי",
"Invite_Link": "",
"Invites": "הזמנות",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -302,6 +304,8 @@
"Remove_nutrition_recipe": "מחר ערכים תזונתיים מהמתכון",
"Reset": "אפס",
"Reset_Search": "אפס חיפוש",
"Reusable": "",
"Role": "",
"Root": "ראשי",
"Saturday": "",
"Save": "שמור",

View File

@@ -98,6 +98,7 @@
"Edit_Keyword": "Kulcsszó szerkesztése",
"Edit_Meal_Plan_Entry": "Menüterv bejegyzés szerkesztése",
"Edit_Recipe": "Recept szerkesztése",
"Email": "",
"Empty": "Üres",
"Enable_Amount": "Összeg bekapcsolása",
"EndDate": "Befejezés dátuma",
@@ -159,6 +160,7 @@
"Instruction_Replace": "Elkészítési leírás cseréje",
"Instructions": "Elkészítés",
"Internal": "Belső",
"Invite_Link": "",
"Invites": "Meghívók",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -275,6 +277,8 @@
"Remove_nutrition_recipe": "Tápértékadatok törlése a receptből",
"Reset": "Visszaállítás",
"Reset_Search": "Keresés alaphelyzetbe állítása",
"Reusable": "",
"Role": "",
"Root": "Gyökér",
"Saturday": "",
"Save": "Mentés",

View File

@@ -37,6 +37,7 @@
"Edit_Food": "Խմբագրել սննդամթերքը",
"Edit_Keyword": "Խմբագրել բանալի բառը",
"Edit_Recipe": "Խմբագրել բաղադրատոմսը",
"Email": "",
"Empty": "Դատարկ",
"Energy": "",
"Export": "",
@@ -57,6 +58,7 @@
"Import_finished": "Ներմուծումն ավարտված է",
"Information": "Տեղեկություն",
"Ingredients": "",
"Invite_Link": "",
"Keywords": "",
"Link": "",
"Load_More": "",
@@ -103,6 +105,8 @@
"Remove": "",
"Remove_nutrition_recipe": "Հեռացնել բաղադրատոմսի սննդայնությունը",
"Reset_Search": "Զրոյացնել որոնումը",
"Reusable": "",
"Role": "",
"Saturday": "",
"Save": "",
"Save_and_View": "Պահպանել և Դիտել",

View File

@@ -88,6 +88,7 @@
"Edit_Keyword": "Rubah Kata Kunci",
"Edit_Meal_Plan_Entry": "",
"Edit_Recipe": "Rubah Resep",
"Email": "",
"Empty": "",
"Enable_Amount": "Aktifkan Jumlah",
"Energy": "Energi",
@@ -145,6 +146,7 @@
"InheritWarning": "",
"Instructions": "",
"Internal": "",
"Invite_Link": "",
"Invites": "",
"Key_Ctrl": "",
"Key_Shift": "",
@@ -251,6 +253,8 @@
"Remove_nutrition_recipe": "Hapus nutrisi dari resep",
"Reset": "",
"Reset_Search": "Setel Ulang Pencarian",
"Reusable": "",
"Role": "",
"Root": "Akar",
"Saturday": "",
"Save": "Menyimpan",

View File

@@ -109,6 +109,7 @@
"Edit_Keyword": "",
"Edit_Meal_Plan_Entry": "",
"Edit_Recipe": "",
"Email": "",
"Empty": "",
"Enable": "",
"Enable_Amount": "",
@@ -176,6 +177,7 @@
"Instruction_Replace": "",
"Instructions": "",
"Internal": "",
"Invite_Link": "",
"Invites": "",
"Key_Ctrl": "",
"Key_Shift": "",
@@ -301,6 +303,8 @@
"Remove_nutrition_recipe": "",
"Reset": "",
"Reset_Search": "",
"Reusable": "",
"Role": "",
"Root": "",
"Saturday": "",
"Save": "",

View File

@@ -93,6 +93,7 @@
"Edit_Keyword": "Modifica parola chiave",
"Edit_Meal_Plan_Entry": "Modifica voce del piano alimentare",
"Edit_Recipe": "Modifica Ricetta",
"Email": "",
"Empty": "Vuoto",
"Enable_Amount": "Abilita Quantità",
"Energy": "Energia",
@@ -150,6 +151,7 @@
"Instruction_Replace": "Sostituisci istruzioni",
"Instructions": "Istruzioni",
"Internal": "Interno",
"Invite_Link": "",
"Invites": "Inviti",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Maiusc",
@@ -259,6 +261,8 @@
"Remove_nutrition_recipe": "Elimina nutrienti dalla ricetta",
"Reset": "Azzera",
"Reset_Search": "Ripristina Ricerca",
"Reusable": "",
"Role": "",
"Root": "Radice",
"Saturday": "",
"Save": "Salva",

View File

@@ -100,6 +100,7 @@
"Edit_Keyword": "Redaguoti raktažodį",
"Edit_Meal_Plan_Entry": "",
"Edit_Recipe": "Redaguoti receptą",
"Email": "",
"Empty": "",
"Enable_Amount": "Įjungti sumą",
"EndDate": "",
@@ -161,6 +162,7 @@
"Instruction_Replace": "",
"Instructions": "",
"Internal": "",
"Invite_Link": "",
"Invites": "",
"Key_Ctrl": "",
"Key_Shift": "",
@@ -279,6 +281,8 @@
"Remove_nutrition_recipe": "Ištrinti mitybos informaciją iš recepto",
"Reset": "",
"Reset_Search": "Iš naujo nustatyti paiešką",
"Reusable": "",
"Role": "",
"Root": "",
"Saturday": "",
"Save": "",

View File

@@ -97,6 +97,7 @@
"Edit_Keyword": "Rediger nøkkelord",
"Edit_Meal_Plan_Entry": "Rediger måltidsplanoppføring",
"Edit_Recipe": "Rediger oppskrift",
"Email": "",
"Empty": "Tom",
"Enable_Amount": "Aktiver mengde",
"Energy": "Energi",
@@ -156,6 +157,7 @@
"Instruction_Replace": "Erstatt instruksjoner",
"Instructions": "Instruksjoner",
"Internal": "",
"Invite_Link": "",
"Invites": "Invitasjoner",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -271,6 +273,8 @@
"Remove_nutrition_recipe": "Fjern næringsinnhold fra oppskrift",
"Reset": "",
"Reset_Search": "Nullstill søk",
"Reusable": "",
"Role": "",
"Root": "Rot",
"Saturday": "",
"Save": "Lagre",

View File

@@ -101,6 +101,7 @@
"Edit_Keyword": "Bewerk Etiket",
"Edit_Meal_Plan_Entry": "Bewerk maaltijdplan",
"Edit_Recipe": "Bewerk Recept",
"Email": "",
"Empty": "Leeg",
"Enable_Amount": "Schakel hoeveelheid in",
"Energy": "Energie",
@@ -160,6 +161,7 @@
"Instruction_Replace": "Vervang instructie",
"Instructions": "Instructies",
"Internal": "Interne",
"Invite_Link": "",
"Invites": "Uitnodigingen",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -275,6 +277,8 @@
"Remove_nutrition_recipe": "Verwijder voedingswaarde van recept",
"Reset": "Herstel",
"Reset_Search": "Zoeken resetten",
"Reusable": "",
"Role": "",
"Root": "Bron",
"Saturday": "",
"Save": "Opslaan",

View File

@@ -111,6 +111,7 @@
"Edit_Keyword": "Edytuj słowo kluczowe",
"Edit_Meal_Plan_Entry": "Edytuj wpis planu posiłków",
"Edit_Recipe": "Edytuj przepis",
"Email": "",
"Empty": "Pusty",
"Enable": "Włączyć",
"Enable_Amount": "Włącz ilość",
@@ -178,6 +179,7 @@
"Instruction_Replace": "Zmień instrukcję",
"Instructions": "Instrukcje",
"Internal": "Wewnętrzne",
"Invite_Link": "",
"Invites": "Zaprasza",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -303,6 +305,8 @@
"Remove_nutrition_recipe": "Usuń wartości odżywcze z przepisu",
"Reset": "Resetowanie",
"Reset_Search": "Resetuj wyszukiwanie",
"Reusable": "",
"Role": "",
"Root": "Główny",
"Saturday": "",
"Save": "Zapisz",

View File

@@ -78,6 +78,7 @@
"Edit_Keyword": "Editar Palavra Chave",
"Edit_Meal_Plan_Entry": "Editar entrada de plano de refeições",
"Edit_Recipe": "Editar receita",
"Email": "",
"Empty": "Esvaziar",
"Enable_Amount": "Ativar quantidade",
"Energy": "Energia",
@@ -123,6 +124,7 @@
"Instruction_Replace": "Substituir Instrução",
"Instructions": "Instruções",
"Internal": "Interno",
"Invite_Link": "",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
"Keyword": "Palavra Chave",
@@ -220,6 +222,8 @@
"Remove_nutrition_recipe": "Remover valor nutricional da receita",
"Reset": "Reiniciar",
"Reset_Search": "Repor Pesquisa",
"Reusable": "",
"Role": "",
"Root": "Raiz",
"Saturday": "",
"Save": "Guardar",

View File

@@ -107,6 +107,7 @@
"Edit_Keyword": "Editar palavra-chave",
"Edit_Meal_Plan_Entry": "Editar plano de refeição",
"Edit_Recipe": "Editar Receita",
"Email": "",
"Empty": "Vazio",
"Enable_Amount": "Habilitar Quantidade",
"EndDate": "Data Fim",
@@ -171,6 +172,7 @@
"Instruction_Replace": "Substituir Instrução",
"Instructions": "Instruções",
"Internal": "Interno",
"Invite_Link": "",
"Invites": "Convites",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -290,6 +292,8 @@
"Remove_nutrition_recipe": "Deletar dados nutricionais da receita",
"Reset": "Reiniciar",
"Reset_Search": "Resetar Busca",
"Reusable": "",
"Role": "",
"Root": "Raiz",
"Saturday": "",
"Save": "Salvar",

View File

@@ -95,6 +95,7 @@
"Edit_Keyword": "Editează cuvânt cheie",
"Edit_Meal_Plan_Entry": "Editarea înregistrării în planul de alimentare",
"Edit_Recipe": "Editează rețeta",
"Email": "",
"Empty": "Gol",
"Enable_Amount": "Activare cantitate",
"Energy": "Energie",
@@ -154,6 +155,7 @@
"Instruction_Replace": "Înlocuire instrucții",
"Instructions": "Instrucțiuni",
"Internal": "Intern",
"Invite_Link": "",
"Invites": "Invită",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -263,6 +265,8 @@
"Remove_nutrition_recipe": "Ștergere a nutriției din rețetă",
"Reset": "Resetare",
"Reset_Search": "Resetarea căutării",
"Reusable": "",
"Role": "",
"Root": "Rădăcină",
"Saturday": "",
"Save": "Salvare",

View File

@@ -68,6 +68,7 @@
"Edit_Keyword": "Редактировать ключевое слово",
"Edit_Meal_Plan_Entry": "Редактировать план питания",
"Edit_Recipe": "Редактировать рецепт",
"Email": "",
"Empty": "Пустой",
"Enable_Amount": "Активировать Количество",
"Energy": "Энергетическая ценность",
@@ -113,6 +114,7 @@
"InheritWarning": "{food} примет предыдущие настройки, изменения не будут приняты.",
"Instructions": "Инструкции",
"Internal": "Внутренний",
"Invite_Link": "",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
"Keyword": "Ключевое слово",
@@ -205,6 +207,8 @@
"Remove_nutrition_recipe": "Уберите питательные вещества из рецепта",
"Reset": "Сбросить",
"Reset_Search": "Очистить строку поиска",
"Reusable": "",
"Role": "",
"Root": "Корневой элемент",
"Saturday": "",
"Save": "Сохранить",

View File

@@ -68,6 +68,7 @@
"Edit_Keyword": "Uredi ključno besedo",
"Edit_Meal_Plan_Entry": "Spremeni vnos za načrtovan obrok",
"Edit_Recipe": "Uredi Recept",
"Email": "",
"Empty": "Prazno",
"Enable_Amount": "Omogoči količino",
"Energy": "Energija",
@@ -109,6 +110,7 @@
"InheritWarning": "{food} je nastavljena na dedovanje, spremembe morda ne bodo trajale.",
"Instruction_Replace": "Zamenjaj Navodila",
"Instructions": "Navodila",
"Invite_Link": "",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
"Keyword_Alias": "Vzdevek ključne besede",
@@ -196,6 +198,8 @@
"RemoveFoodFromShopping": "Odstrani {food} iz nakupovalnega listka",
"Remove_nutrition_recipe": "Receptu izbriši hranilno vrednost",
"Reset_Search": "Ponastavi iskalnik",
"Reusable": "",
"Role": "",
"Root": "",
"Saturday": "",
"Save": "Shrani",

View File

@@ -111,6 +111,7 @@
"Edit_Keyword": "Redigera nyckelord",
"Edit_Meal_Plan_Entry": "Redigera matplansinlägg",
"Edit_Recipe": "Redigera recept",
"Email": "",
"Empty": "Tom",
"Enable": "Aktivera",
"Enable_Amount": "Aktivera belopp",
@@ -178,6 +179,7 @@
"Instruction_Replace": "Ersätt instruktion",
"Instructions": "Instruktioner",
"Internal": "Intern",
"Invite_Link": "",
"Invites": "Inbjudningar",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -303,6 +305,8 @@
"Remove_nutrition_recipe": "Ta bort näring från receptet",
"Reset": "Återställ",
"Reset_Search": "Rensa sök",
"Reusable": "",
"Role": "",
"Root": "Rot",
"Saturday": "",
"Save": "Spara",

View File

@@ -110,6 +110,7 @@
"Edit_Keyword": "Anahtar Kelimeyi Düzenle",
"Edit_Meal_Plan_Entry": "Yemek planı girişini düzenle",
"Edit_Recipe": "Tarifi Düzenle",
"Email": "",
"Empty": "Boş",
"Enable": "Etkinleştir",
"Enable_Amount": "Tutarı Etkinleştir",
@@ -177,6 +178,7 @@
"Instruction_Replace": "Talimat Değiştir",
"Instructions": "Talimatlar",
"Internal": "Dahili",
"Invite_Link": "",
"Invites": "Davetler",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -302,6 +304,8 @@
"Remove_nutrition_recipe": "Tariften besin değeri sil",
"Reset": "Sıfırla",
"Reset_Search": "Aramayı Sıfırla",
"Reusable": "",
"Role": "",
"Root": "Kök",
"Saturday": "",
"Save": "Kaydet",

View File

@@ -83,6 +83,7 @@
"Edit_Keyword": "Редагувати Ключове слово",
"Edit_Meal_Plan_Entry": "Редагувати запис в плані харчування",
"Edit_Recipe": "Редагувати Рецепт",
"Email": "",
"Empty": "Пусто",
"Enable_Amount": "Включити Кількість",
"Energy": "Енергія",
@@ -137,6 +138,7 @@
"Instruction_Replace": "Замінити Інструкцію",
"Instructions": "Інструкції",
"Internal": "",
"Invite_Link": "",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
"Keyword": "",
@@ -239,6 +241,8 @@
"Remove_nutrition_recipe": "Видалити харчову цінність з рецепта",
"Reset": "",
"Reset_Search": "Скинути Пошук",
"Reusable": "",
"Role": "",
"Root": "Корінь",
"Saturday": "",
"Save": "Зберегти",

View File

@@ -107,6 +107,7 @@
"Edit_Keyword": "编辑关键词",
"Edit_Meal_Plan_Entry": "编辑用餐计划条目",
"Edit_Recipe": "编辑食谱",
"Email": "",
"Empty": "空的",
"Enable": "启用",
"Enable_Amount": "启用金额",
@@ -173,6 +174,7 @@
"Instruction_Replace": "替换指令",
"Instructions": "说明",
"Internal": "内部",
"Invite_Link": "",
"Invites": "邀请",
"Key_Ctrl": "Ctrl",
"Key_Shift": "Shift",
@@ -297,6 +299,8 @@
"Remove_nutrition_recipe": "从食谱中删除营养信息",
"Reset": "重置",
"Reset_Search": "重置搜索",
"Reusable": "",
"Role": "",
"Root": "根",
"Saturday": "",
"Save": "保存",

View File

@@ -26,6 +26,7 @@
"DeviceSettingsHelp": "",
"Download": "",
"Edit": "",
"Email": "",
"Energy": "",
"Export": "",
"External": "",
@@ -42,6 +43,7 @@
"Import_finished": "匯入完成",
"Information": "",
"Ingredients": "",
"Invite_Link": "",
"Keywords": "",
"Link": "",
"Load_More": "",
@@ -75,6 +77,8 @@
"Remove": "",
"Remove_nutrition_recipe": "從食譜中刪除營養資訊",
"Reset_Search": "",
"Reusable": "",
"Role": "",
"Saturday": "",
"Save": "",
"Save_and_View": "儲存並查看",

View File

@@ -1649,6 +1649,11 @@ export interface ApiUserSpaceRetrieveRequest {
id: number;
}
export interface ApiUserSpaceUpdateRequest {
id: number;
userSpace: Omit<UserSpace, 'user'|'space'|'invite_link'|'created_at'|'updated_at'>;
}
export interface ApiViewLogCreateRequest {
viewLog: Omit<ViewLog, 'created_by'|'created_at'>;
}
@@ -12380,6 +12385,51 @@ export class ApiApi extends runtime.BaseAPI {
return await response.value();
}
/**
*/
async apiUserSpaceUpdateRaw(requestParameters: ApiUserSpaceUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<UserSpace>> {
if (requestParameters['id'] == null) {
throw new runtime.RequiredError(
'id',
'Required parameter "id" was null or undefined when calling apiUserSpaceUpdate().'
);
}
if (requestParameters['userSpace'] == null) {
throw new runtime.RequiredError(
'userSpace',
'Required parameter "userSpace" was null or undefined when calling apiUserSpaceUpdate().'
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
headerParameters['Content-Type'] = 'application/json';
if (this.configuration && this.configuration.apiKey) {
headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiKeyAuth authentication
}
const response = await this.request({
path: `/api/user-space/{id}/`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters['id']))),
method: 'PUT',
headers: headerParameters,
query: queryParameters,
body: UserSpaceToJSON(requestParameters['userSpace']),
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => UserSpaceFromJSON(jsonValue));
}
/**
*/
async apiUserSpaceUpdate(requestParameters: ApiUserSpaceUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<UserSpace> {
const response = await this.apiUserSpaceUpdateRaw(requestParameters, initOverrides);
return await response.value();
}
/**
*/
async apiViewLogCreateRaw(requestParameters: ApiViewLogCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<ViewLog>> {

View File

@@ -50,7 +50,7 @@ type GenericListRequestParameter = {
type ModelTableHeaders = {
title: string,
key: string,
align: 'end'|'start',
align: 'end' | 'start',
hidden?: boolean,
}
@@ -61,10 +61,12 @@ type Model = {
name: string,
localizationKey: string,
icon: string,
toStringKeys: Array<string>,
disableList?: boolean | undefined,
disableRetrieve?: boolean | undefined,
disableCreate?: boolean | undefined,
disableUpdate?: boolean | undefined,
disableDelete?: boolean | undefined,
isPaginated: boolean | undefined,
@@ -79,6 +81,7 @@ export const TFood = {
icon: 'fa-solid fa-carrot',
isPaginated: true,
toStringKeys: ['name'],
tableHeaders: [
{title: 'Name', key: 'name'},
@@ -95,6 +98,7 @@ export const TUnit = {
icon: 'fa-solid fa-scale-balanced',
isPaginated: true,
toStringKeys: ['name'],
tableHeaders: [
{title: 'Name', key: 'name'},
@@ -110,6 +114,7 @@ export const TKeyword = {
icon: 'fa-solid fa-tags',
isPaginated: true,
toStringKeys: ['name'],
tableHeaders: [
{title: 'Name', key: 'name'},
@@ -124,6 +129,7 @@ export const TRecipe = {
icon: 'fa-solid fa-book',
isPaginated: true,
toStringKeys: ['name'],
tableHeaders: [
{title: 'Name', key: 'name'},
@@ -138,6 +144,7 @@ export const TMealType = {
icon: 'fa-solid fa-utensils',
isPaginated: true,
toStringKeys: ['name'],
tableHeaders: [
{title: 'Name', key: 'name'},
@@ -149,12 +156,14 @@ SUPPORTED_MODELS.set(TMealType.name, TMealType)
export const TUser = {
name: 'User',
localizationKey: 'User',
icon: 'fa-solid fa-users',
icon: 'fa-solid fa-user',
disableCreate: true,
disableDelete: true,
disableUpdate: true,
isPaginated: false,
toStringKeys: ['displayName'],
tableHeaders: [
{title: 'Name', key: 'displayName'},
@@ -169,6 +178,7 @@ export const TSupermarket = {
icon: 'fa-solid fa-store',
isPaginated: true,
toStringKeys: ['name'],
tableHeaders: [
{title: 'Name', key: 'name'},
@@ -183,6 +193,7 @@ export const TSupermarketCategory = {
icon: 'fa-solid fa-boxes-stacked',
isPaginated: true,
toStringKeys: ['name'],
tableHeaders: [
{title: 'Name', key: 'name'},
@@ -197,6 +208,7 @@ export const TPropertyType = {
icon: 'fa-solid fa-database',
isPaginated: true,
toStringKeys: ['name'],
tableHeaders: [
{title: 'Name', key: 'name'},
@@ -205,12 +217,29 @@ export const TPropertyType = {
} as Model
SUPPORTED_MODELS.set(TPropertyType.name, TPropertyType)
export const TProperty = {
name: 'Property',
localizationKey: 'Property',
icon: 'fa-solid fa-database',
isPaginated: true,
toStringKeys: ['propertyType'], // TODO improve
tableHeaders: [
{title: 'Amount', key: 'propertyAmount'},
{title: 'PropertyType', key: 'propertyType.name'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TProperty.name, TProperty)
export const TUnitConversion = {
name: 'UnitConversion',
localizationKey: 'UnitConversion',
icon: 'fa-solid fa-exchange-alt',
isPaginated: true,
toStringKeys: ['food'], // TODO improve
tableHeaders: [
{title: 'Food', key: 'food.name'},
@@ -229,6 +258,7 @@ export const TUserFile = {
icon: 'fa-solid fa-file',
isPaginated: true,
toStringKeys: ['name'],
tableHeaders: [
{title: 'Name', key: 'name'},
@@ -243,6 +273,7 @@ export const TAutomation = {
icon: 'fa-solid fa-robot',
isPaginated: true,
toStringKeys: ['name'],
tableHeaders: [
{title: 'Name', key: 'name'},
@@ -257,6 +288,7 @@ export const TCookLog = {
icon: 'fa-solid fa-table-list',
isPaginated: true,
toStringKeys: ['recipe'],
tableHeaders: [
{title: 'Recipe', key: 'recipe'},
@@ -272,6 +304,7 @@ export const TViewLog = {
icon: 'fa-solid fa-clock-rotate-left',
isPaginated: true,
toStringKeys: ['recipe'],
tableHeaders: [
{title: 'Recipe', key: 'recipe'},
@@ -287,6 +320,7 @@ export const TAccessToken = {
icon: 'fa-solid fa-key',
isPaginated: true,
toStringKeys: ['token'],
tableHeaders: [
{title: 'Access_Token', key: 'token'},
@@ -296,14 +330,51 @@ export const TAccessToken = {
} as Model
SUPPORTED_MODELS.set(TAccessToken.name, TAccessToken)
export const TUserSpace = {
name: 'UserSpace',
localizationKey: 'SpaceMembers',
icon: 'fa-solid fa-users',
isPaginated: true,
toStringKeys: ['user'], // TODO improve
disableCreate: true,
tableHeaders: [
{title: 'User', key: 'user'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TUserSpace.name, TUserSpace)
export const TInviteLink = {
name: 'InviteLink',
localizationKey: 'Invite_Link',
icon: 'fa-solid fa-link',
isPaginated: true,
toStringKeys: ['email', 'role'],
tableHeaders: [
{title: 'Email', key: 'email'},
{title: 'Role', key: 'group'},
{title: 'Valid Until', key: 'validUntil'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
SUPPORTED_MODELS.set(TInviteLink.name, TInviteLink)
export const TFoodInheritField = {
name: 'FoodInheritField',
localizationKey: 'FoodInherit',
icon: 'fa-solid fa-list',
toStringKeys: ['name'],
disableCreate: true,
disableDelete: true,
disableRetrieve: true,
disableUpdate: true,
isPaginated: false,
} as Model
@@ -332,10 +403,10 @@ export class GenericModel {
this.t = t
}
getTableHeaders(): VDataTableProps['headers'][]{
getTableHeaders(): VDataTableProps['headers'][] {
let tableHeaders: VDataTableProps['headers'][] = []
this.model.tableHeaders.forEach(header => {
if(!header.hidden){
if (!header.hidden) {
header.title = this.t(header.title)
tableHeaders.push(header as unknown as VDataTableProps['headers'])
}
@@ -380,7 +451,7 @@ export class GenericModel {
* @return promise of request
*/
update(id: number, obj: any) {
if (this.model.disableCreate) {
if (this.model.disableUpdate) {
throw new Error('Cannot update on this model!')
} else {
let updateRequestParams: any = {}
@@ -390,6 +461,22 @@ export class GenericModel {
}
}
/**
* retrieves the given model
* throws error if retrieving is not supported for given model
* @param id object id to retrieve
* @return promise of request
*/
retrieve(id: number) {
if (this.model.disableRetrieve) {
throw new Error('Cannot delete on this model!')
} else {
let retrieveRequestParams: any = {}
retrieveRequestParams['id'] = id
return this.api[`api${this.model.name}Retrieve`](retrieveRequestParams)
}
}
/**
* deletes the given model instance
* throws error if creation is not supported for given model