added support for external recipes to new frontend

This commit is contained in:
vabene1111
2025-06-04 20:35:35 +02:00
parent cd707d20a1
commit 63069dd716
56 changed files with 1428 additions and 75 deletions

View File

@@ -1094,6 +1094,19 @@ class RecipeImport(models.Model, PermissionModelMixin):
def __str__(self):
return self.name
def convert_to_recipe(self, user):
recipe = Recipe(
name=self.name,
file_path=self.file_path,
storage=self.storage,
file_uid=self.file_uid,
created_by=user,
space=self.space
)
recipe.save()
self.delete()
return recipe
class RecipeBook(ExportModelOperationsMixin('book'), models.Model, PermissionModelMixin):
name = models.CharField(max_length=128)

View File

@@ -31,7 +31,7 @@ class Dropbox(Provider):
except ValueError:
log_entry = SyncLog(status='ERROR', msg=str(r), sync=monitor)
log_entry.save()
return r
return log_entry
import_count = 0
# TODO check if has_more is set and import that as well
@@ -59,7 +59,7 @@ class Dropbox(Provider):
monitor.last_checked = datetime.now()
monitor.save()
return True
return log_entry
@staticmethod
def create_share_link(recipe):

View File

@@ -42,7 +42,7 @@ class Local(Provider):
monitor.last_checked = datetime.now()
monitor.save()
return True
return log_entry
@staticmethod
def get_file(recipe):

View File

@@ -66,7 +66,7 @@ class Nextcloud(Provider):
monitor.last_checked = datetime.now()
monitor.save()
return True
return log_entry
@staticmethod
def create_share_link(recipe):

View File

@@ -447,27 +447,6 @@ class UserPreferenceSerializer(WritableNestedModelSerializer):
read_only_fields = ('user',)
class StorageSerializer(SpacedModelSerializer):
def create(self, validated_data):
validated_data['created_by'] = self.context['request'].user
return super().create(validated_data)
class Meta:
model = Storage
fields = (
'id', 'name', 'method', 'username', 'password',
'token', 'created_by'
)
read_only_fields = ('created_by',)
extra_kwargs = {
'password': {'write_only': True},
'token': {'write_only': True},
}
class ConnectorConfigConfigSerializer(SpacedModelSerializer):
def create(self, validated_data):
@@ -489,7 +468,38 @@ class ConnectorConfigConfigSerializer(SpacedModelSerializer):
}
class SyncSerializer(SpacedModelSerializer):
class StorageSerializer(WritableNestedModelSerializer, SpacedModelSerializer):
def create(self, validated_data):
validated_data['created_by'] = self.context['request'].user
return super().create(validated_data)
class Meta:
model = Storage
fields = (
'id', 'name', 'method', 'username', 'password',
'token', 'url', 'path', 'created_by'
)
read_only_fields = ( 'id', 'created_by',)
extra_kwargs = {
'password': {'write_only': True},
'token': {'write_only': True},
}
class RecipeImportSerializer(WritableNestedModelSerializer, SpacedModelSerializer):
storage = StorageSerializer()
class Meta:
model = RecipeImport
fields = ('id', 'storage', 'name', 'file_uid', 'file_path', 'created_at')
class SyncSerializer(WritableNestedModelSerializer, SpacedModelSerializer):
storage = StorageSerializer()
class Meta:
model = Sync
fields = (
@@ -499,6 +509,8 @@ class SyncSerializer(SpacedModelSerializer):
class SyncLogSerializer(SpacedModelSerializer):
sync = SyncSerializer(read_only=True)
class Meta:
model = SyncLog
fields = ('id', 'sync', 'status', 'msg', 'created_at')
@@ -1710,6 +1722,7 @@ class ExportRequestSerializer(serializers.Serializer):
recipes = RecipeFlatSerializer(many=True, default=[])
custom_filter = CustomFilterSerializer(many=False, default=None, allow_null=True)
class ImportOpenDataSerializer(serializers.Serializer):
selected_version = serializers.CharField()
selected_datatypes = serializers.ListField(child=serializers.CharField())

View File

@@ -56,6 +56,7 @@ router.register(r'supermarket-category', api.SupermarketCategoryViewSet)
router.register(r'supermarket-category-relation', api.SupermarketCategoryRelationViewSet)
router.register(r'sync', api.SyncViewSet)
router.register(r'sync-log', api.SyncLogViewSet)
router.register(r'recipe-import', api.RecipeImportViewSet)
router.register(r'unit', api.UnitViewSet)
router.register(r'user-file', api.UserFileViewSet)
router.register(r'user', api.UserViewSet)

View File

@@ -85,7 +85,7 @@ from cookbook.models import (Automation, BookmarkletImport, ConnectorConfig, Coo
RecipeBookEntry, ShareLink, ShoppingListEntry,
ShoppingListRecipe, Space, Step, Storage, Supermarket, SupermarketCategory,
SupermarketCategoryRelation, Sync, SyncLog, Unit, UnitConversion,
UserFile, UserPreference, UserSpace, ViewLog
UserFile, UserPreference, UserSpace, ViewLog, RecipeImport
)
from cookbook.provider.dropbox import Dropbox
from cookbook.provider.local import Local
@@ -109,7 +109,8 @@ from cookbook.serializer import (AccessTokenSerializer, AutomationSerializer, Au
UnitConversionSerializer, UnitSerializer, UserFileSerializer, UserPreferenceSerializer,
UserSerializer, UserSpaceSerializer, ViewLogSerializer,
LocalizationSerializer, ServerSettingsSerializer, RecipeFromSourceResponseSerializer, ShoppingListEntryBulkCreateSerializer, FdcQuerySerializer,
AiImportSerializer, ImportOpenDataSerializer, ImportOpenDataMetaDataSerializer, ImportOpenDataResponseSerializer, ExportRequestSerializer
AiImportSerializer, ImportOpenDataSerializer, ImportOpenDataMetaDataSerializer, ImportOpenDataResponseSerializer, ExportRequestSerializer,
RecipeImportSerializer
)
from cookbook.version_info import TANDOOR_VERSION
from cookbook.views.import_export import get_integration
@@ -585,17 +586,7 @@ class StorageViewSet(LoggingMixin, viewsets.ModelViewSet):
queryset = Storage.objects
serializer_class = StorageSerializer
permission_classes = [CustomIsAdmin & CustomTokenHasReadWriteScope]
pagination_disabled = True
def get_queryset(self):
return self.queryset.filter(space=self.request.space)
class ConnectorConfigConfigViewSet(LoggingMixin, viewsets.ModelViewSet):
queryset = ConnectorConfig.objects
serializer_class = ConnectorConfigConfigSerializer
permission_classes = [CustomIsAdmin & CustomTokenHasReadWriteScope]
pagination_disabled = True
pagination_class = DefaultPagination
def get_queryset(self):
return self.queryset.filter(space=self.request.space)
@@ -610,6 +601,21 @@ class SyncViewSet(LoggingMixin, viewsets.ModelViewSet):
def get_queryset(self):
return self.queryset.filter(space=self.request.space)
@extend_schema(responses=SyncLogSerializer(many=False))
@decorators.action(detail=True, pagination_class=None, methods=['POST'], )
def perform_update(self, request, pk):
sync = get_object_or_404(Sync, pk=pk)
sync_log = None
if sync.storage.method == Storage.DROPBOX:
sync_log = Dropbox.import_all(sync)
if sync.storage.method == Storage.NEXTCLOUD:
sync_log = Nextcloud.import_all(sync)
if sync.storage.method == Storage.LOCAL:
sync_log = Local.import_all(sync)
return Response(SyncLogSerializer(sync_log, many=False, context={'request': self.request}).data)
class SyncLogViewSet(LoggingMixin, viewsets.ReadOnlyModelViewSet):
queryset = SyncLog.objects
@@ -621,6 +627,42 @@ class SyncLogViewSet(LoggingMixin, viewsets.ReadOnlyModelViewSet):
return self.queryset.filter(sync__space=self.request.space)
class RecipeImportViewSet(LoggingMixin, viewsets.ModelViewSet):
queryset = RecipeImport.objects
serializer_class = RecipeImportSerializer
permission_classes = [CustomIsAdmin & CustomTokenHasReadWriteScope]
pagination_class = DefaultPagination
def get_queryset(self):
return self.queryset.filter(space=self.request.space)
@extend_schema(responses=RecipeSerializer(many=False))
@decorators.action(detail=True, pagination_class=None, methods=['POST'], )
def import_recipe(self, request, pk):
new_recipe = get_object_or_404(RecipeImport, pk=pk, space=request.space)
recipe = new_recipe.convert_to_recipe(request.user)
return Response(RecipeSerializer(recipe, many=False, context={'request': self.request}).data)
@decorators.action(detail=False, pagination_class=None, methods=['POST'], )
def import_all(self, request):
imports = RecipeImport.objects.filter(space=request.space).all()
for new_recipe in imports:
new_recipe.convert_to_recipe(request.user)
return Response({'msg': 'ok'}, status=status.HTTP_200_OK)
class ConnectorConfigConfigViewSet(LoggingMixin, viewsets.ModelViewSet):
queryset = ConnectorConfig.objects
serializer_class = ConnectorConfigConfigSerializer
permission_classes = [CustomIsAdmin & CustomTokenHasReadWriteScope]
pagination_disabled = True
def get_queryset(self):
return self.queryset.filter(space=self.request.space)
class SupermarketViewSet(LoggingMixin, StandardFilterModelViewSet):
queryset = Supermarket.objects
serializer_class = SupermarketSerializer
@@ -1984,6 +2026,7 @@ class AppExportView(APIView):
return Response({'error': True, 'msg': serializer.errors}, status=status.HTTP_400_BAD_REQUEST)
class FdcSearchView(APIView):
permission_classes = [CustomIsUser & CustomTokenHasReadWriteScope]

View File

@@ -0,0 +1,58 @@
<template>
<v-dialog max-width="600px" activator="parent" v-model="dialog">
<v-card>
<v-closable-card-title v-model="dialog" :title="$t('Import')"></v-closable-card-title>
<v-card-text>
<div v-if="loading" class="text-center">
<v-progress-circular :indeterminate="true" color="success" size="x-large"></v-progress-circular>
</div>
<template v-if="syncLog">
<v-chip label v-if="syncLog.status == 'SUCCESS'" color="success">{{ $t('Success') }}</v-chip>
<v-chip label v-if="syncLog.status != 'SUCCESS'" color="danger">{{ $t('Error') }}</v-chip>
<v-textarea auto-grow max-rows="10" v-model="syncLog.msg" :hint="DateTime.fromJSDate(syncLog.createdAt).toLocaleString(DateTime.DATETIME_SHORT)" persistent-hint readonly></v-textarea>
</template>
</v-card-text>
<v-card-actions>
<v-btn @click="performSync()" color="create" :loading="loading" v-if="!syncLog">{{ $t('Import') }}</v-btn>
<v-btn :to="{name: 'ModelListPage', params: {model: 'RecipeImport'}}" color="primary" :loading="loading" v-if="syncLog">{{ $t('View') }}</v-btn>
</v-card-actions>
</v-card>
</v-dialog>
</template>
<script setup lang="ts">
import {PropType, ref} from "vue";
import {ApiApi, Sync, SyncLog} from "@/openapi";
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore.ts";
import VClosableCardTitle from "@/components/dialogs/VClosableCardTitle.vue";
import {DateTime} from "luxon";
const props = defineProps({
sync: {type: {} as PropType<Sync>, required: true}
})
const dialog = ref(false)
const loading = ref(false)
const syncLog = ref<undefined | SyncLog>(undefined)
function performSync() {
let api = new ApiApi()
api.apiSyncPerformUpdateCreate({id: props.sync.id!, sync: props.sync}).then(r => {
syncLog.value = r
}).catch(err => {
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
})
}
</script>
<style scoped>
</style>

View File

@@ -0,0 +1,60 @@
<template>
<model-editor-base
:loading="loading"
:dialog="dialog"
@save="saveObject"
@delete="deleteObject"
@close="emit('close'); editingObjChanged = false"
:is-update="isUpdate()"
:is-changed="editingObjChanged"
:model-class="modelClass"
:object-name="editingObjName()">
<v-card-text>
<v-form :disabled="loading">
<v-text-field :label="$t('Name')" v-model="editingObj.name"></v-text-field>
<v-select :label="$t('Type')" v-model="editingObj.method" :items="['DB', 'NEXTCLOUD', 'LOCAL']"></v-select>
<v-text-field :label="$t('Username')" v-model="editingObj.username" v-if="editingObj.method == 'NEXTCLOUD' || editingObj.method == 'DB'"></v-text-field>
<v-text-field :label="$t('Password')" :hint="$t('StoragePasswordTokenHelp')" persistent-hint v-model="editingObj.password" v-if="editingObj.method == 'NEXTCLOUD'"></v-text-field>
<v-text-field :label="$t('Access_Token')" :hint="$t('StoragePasswordTokenHelp')" persistent-hint v-model="editingObj.token" v-if="editingObj.method == 'DB'"></v-text-field>
<v-text-field :label="$t('Path')" v-model="editingObj.path"></v-text-field>
</v-form>
</v-card-text>
</model-editor-base>
</template>
<script setup lang="ts">
import {onMounted, PropType} from "vue";
import { Storage } from "@/openapi";
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
const props = defineProps({
item: {type: {} as PropType<Storage>, required: false, default: null},
itemId: {type: [Number, String], required: false, default: undefined},
itemDefaults: {type: {} as PropType<Storage>, required: false, default: {} as Storage},
dialog: {type: Boolean, default: false}
})
const emit = defineEmits(['create', 'save', 'delete', 'close'])
const {setupState, deleteObject, saveObject, isUpdate, editingObjName, loading, editingObj, editingObjChanged, modelClass} = useModelEditorFunctions<Storage>('Storage', emit)
// object specific data (for selects/display)
onMounted(() => {
setupState(props.item, props.itemId, {itemDefaults: props.itemDefaults})
})
</script>
<style scoped>
</style>

View File

@@ -13,6 +13,7 @@
<v-form :disabled="loading">
<v-text-field :label="$t('Path')" v-model="editingObj.path"></v-text-field>
<model-select :label="$t('Storage')" model="Storage" v-model="editingObj.storage"></model-select>
<v-checkbox :label="$t('Enabled')" v-model="editingObj.active"></v-checkbox>
<p>{{$t('Updated')}}: {{editingObj.updatedAt}}</p>
@@ -29,6 +30,7 @@ import {onMounted, PropType} from "vue";
import { Sync} from "@/openapi";
import ModelEditorBase from "@/components/model_editors/ModelEditorBase.vue";
import {useModelEditorFunctions} from "@/composables/useModelEditorFunctions";
import ModelSelect from "@/components/inputs/ModelSelect.vue";
const props = defineProps({
item: {type: {} as PropType<Sync>, required: false, default: null},

View File

@@ -125,6 +125,8 @@
"Export_Supported": "",
"Export_To_ICal": "",
"External": "",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "",
"Failure": "",
@@ -160,6 +162,7 @@
"IgnoredFood": "",
"Image": "",
"Import": "",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "",
"Import_Not_Yet_Supported": "",
@@ -264,6 +267,8 @@
"Page": "",
"Parameter": "",
"Parent": "",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "",
"Periods": "",
@@ -379,6 +384,7 @@
"StepsOverview": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "",
"Substitutes": "",
"Success": "",

View File

@@ -122,6 +122,8 @@
"Export_Supported": "Поддържа се експорт",
"Export_To_ICal": "Експортиране на .ics",
"External": "Външен",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Външно изображение на рецептата",
"Failure": "Неуспешно",
@@ -157,6 +159,7 @@
"IgnoredFood": "{food} е настроен да игнорира пазаруването.",
"Image": "Изображение",
"Import": "Импортиране",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "Възникна грешка по време на импортирането ви. Моля, разгънете подробностите в долната част на страницата, за да ги видите.",
"Import_Not_Yet_Supported": "Импортирането все още не се поддържа",
@@ -257,6 +260,8 @@
"Page": "Страница",
"Parameter": "Параметър",
"Parent": "Родител",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Период",
"Periods": "Периоди",
@@ -372,6 +377,7 @@
"StepsOverview": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "Имате заместител под ръка.",
"Substitutes": "",
"Success": "Успешно",

View File

@@ -160,6 +160,8 @@
"Export_Supported": "",
"Export_To_ICal": "",
"External": "",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Imatge externa de la recepta",
"FDC_ID": "",
@@ -203,6 +205,7 @@
"Image": "",
"Import": "",
"Import Recipe": "",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "",
"Import_Not_Yet_Supported": "",
@@ -325,6 +328,8 @@
"Page": "",
"Parameter": "",
"Parent": "",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "",
"Periods": "",
@@ -458,6 +463,7 @@
"Sticky_Nav_Help": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "",
"Substitutes": "",
"Success": "",

View File

@@ -160,6 +160,8 @@
"Export_Supported": "Export podporován",
"Export_To_ICal": "Export ovat .ics",
"External": "Externí",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Externí obrázek receptu",
"FDC_ID": "FDC ID",
@@ -203,6 +205,7 @@
"Image": "Obrázek",
"Import": "Import",
"Import Recipe": "Importovat recept",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "Během importu došlo k chybě. Pro více informací rozbalte Detaily na konci stránky.",
"Import_Not_Yet_Supported": "Import není zatím podporován",
@@ -323,6 +326,8 @@
"Page": "Stránka",
"Parameter": "Parametr",
"Parent": "Nadřazená",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Období",
"Periods": "Období",
@@ -454,6 +459,7 @@
"Sticky_Nav_Help": "Vždy zobrazit navigační panel na vrchu stránky.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "Máte k dispozici náhradu.",
"Substitutes": "",
"Success": "Úspěch",

View File

@@ -149,6 +149,8 @@
"Export_Supported": "Eksport understøttet",
"Export_To_ICal": "Eksporter .ics",
"External": "Ekstern",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Eksternt billede af opskrift",
"FDC_ID": "FDC ID",
@@ -191,6 +193,7 @@
"Image": "Billede",
"Import": "Importer",
"Import Recipe": "Importer opskrift",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "Der opstod en fejl under din importering. Udvid detaljerne i bunden af siden for at se fejlen.",
"Import_Not_Yet_Supported": "Import endnu ikke understøttet",
@@ -308,6 +311,8 @@
"Page": "Side",
"Parameter": "Parameter",
"Parent": "Forælder",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Periode",
"Periods": "Perioder",
@@ -434,6 +439,7 @@
"Sticky_Nav_Help": "Vis altid navigationsmenuen øverst på skærmen.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "Du har erstatninger tilgængeligt.",
"Substitutes": "",
"Success": "Succes",

View File

@@ -163,6 +163,8 @@
"Export_Supported": "Exportieren wird unterstützt",
"Export_To_ICal": "Export als .ics",
"External": "Extern",
"ExternalRecipeImport": "Externer Rezeptimport",
"ExternalRecipeImportHelp": "Dateien die in überwachten Ordnern auf externen Speichern gefunden werden, werden nicht sofort als Rezept importiert, sondern zunächst als Rezeptimport zwischengespeichert. Hier können gefundene Rezepte schnell und einfach editiert werden, bevor Sie in die Sammlung aufgenommen werden",
"ExternalStorage": "Externer Speicher",
"External_Recipe_Image": "Externes Rezeptbild",
"FDC_ID": "FDC ID",
@@ -206,6 +208,7 @@
"Image": "Bild",
"Import": "Importieren",
"Import Recipe": "Rezept importieren",
"ImportAll": "Alle importieren",
"ImportIntoTandoor": "In Tandoor importieren",
"Import_Error": "Es ist ein Fehler beim Importieren aufgetreten. Bitte sieh dir die ausgeklappten Details unten auf der Seite an.",
"Import_Not_Yet_Supported": "Importieren wird noch nicht unterstützt",
@@ -328,6 +331,8 @@
"Page": "Seite",
"Parameter": "Parameter",
"Parent": "Eltern",
"Password": "Passwort",
"Path": "Pfad",
"PerPage": "Pro Seite",
"Period": "Zeitraum",
"Periods": "Zeiträume",
@@ -460,8 +465,9 @@
"StepsOverview": "Schrittübersicht",
"Sticky_Nav": "Navigationsleiste immer sichtbar (sticky navigation)",
"Sticky_Nav_Help": "Navigationsleiste immer im Seitenkopf anzeigen.",
"Storage": "Externer speicher",
"Storage": "Externer Speicher",
"StorageHelp": "Externe Speicherorte an denen Rezepte als Dateien (Foto/PDF) abgelegt und mit Tandor syncronisiert werden können.",
"StoragePasswordTokenHelp": "Das hinterlegte Passwort/Token kann nicht angezeigt werden. Es wird nur aktualisiert wenn etwas neues in das Feld eingegeben wird. ",
"SubstituteOnHand": "Du hast eine Alternative vorrätig.",
"Substitutes": "Alternativen",
"Success": "Erfolgreich",

View File

@@ -147,6 +147,8 @@
"Export_Supported": "Υποστηρίζεται εξαγωγή",
"Export_To_ICal": "Εξαγωγή .ics",
"External": "Εξωτερική",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Εξωτερική εικόνα συνταγής",
"Failure": "Αποτυχία",
@@ -186,6 +188,7 @@
"Image": "Εικόνα",
"Import": "Εισαγωγή",
"Import Recipe": "Εισαγωγή συνταγής",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "Συνέβη ένα σφάλμα κατά την εισαγωγή. Για να το δείτε, εμφανίστε τις λεπτομέρειες στο κάτω μέρος της σελίδας.",
"Import_Not_Yet_Supported": "Η εισαγωγή δεν υποστηρίζεται ακόμη",
@@ -300,6 +303,8 @@
"Page": "Σελίδα",
"Parameter": "Παράμετρος",
"Parent": "Γονέας",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Περίοδος",
"Periods": "Περίοδοι",
@@ -425,6 +430,7 @@
"Sticky_Nav_Help": "Μόνιμη εμφάνιση του μενού πλοήγησης στο πάνω μέρος της οθόνης.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "Έχετε διαθέσιμο ένα υποκατάστατο.",
"Substitutes": "",
"Success": "Επιτυχία",

View File

@@ -161,6 +161,8 @@
"Export_Supported": "Export supported",
"Export_To_ICal": "Export .ics",
"External": "External",
"ExternalRecipeImport": "External recipe import",
"ExternalRecipeImportHelp": "Files in synced folders on external storages are not imported directly but temporarily saved as external import recipes. Here you can quickly view and edit newly found files before they are moved to the main collection. ",
"ExternalStorage": "External storage",
"External_Recipe_Image": "External Recipe Image",
"FDC_ID": "FDC ID",
@@ -204,6 +206,7 @@
"Image": "Image",
"Import": "Import",
"Import Recipe": "Import Recipe",
"ImportAll": "Import all",
"ImportIntoTandoor": "Import into Tandoor",
"Import_Error": "An Error occurred during your import. Please expand the Details at the bottom of the page to view it.",
"Import_Not_Yet_Supported": "Import not yet supported",
@@ -326,6 +329,8 @@
"Page": "Page",
"Parameter": "Parameter",
"Parent": "Parent",
"Password": "Password",
"Path": "Path",
"PerPage": "Per Page",
"Period": "Period",
"Periods": "Periods",
@@ -460,6 +465,7 @@
"Sticky_Nav_Help": "Always show the navigation menu at the top of the screen.",
"Storage": "External Storage",
"StorageHelp": "External storage locations where recipe files (image/pdf) can be stored and synced with Tandoor.",
"StoragePasswordTokenHelp": "The stored password/token will never be displayed. It is only changed if something new is entered into the field. ",
"SubstituteOnHand": "You have a substitute on hand.",
"Substitutes": "Substitutes",
"Success": "Success",

View File

@@ -161,6 +161,8 @@
"Export_Supported": "Exportación soportada",
"Export_To_ICal": "Exportar .ics",
"External": "Externo",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Imagen externa de la receta",
"FDC_ID": "FDC ID",
@@ -204,6 +206,7 @@
"Image": "Imagen",
"Import": "Importar",
"Import Recipe": "Importar Receta",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "Ocurrió un Error ocurrió durante la importación. Por favor, expanda los Detalles al final de la página para verlo.",
"Import_Not_Yet_Supported": "Importación no soportada todavía",
@@ -326,6 +329,8 @@
"Page": "Página",
"Parameter": "Parametro",
"Parent": "Padre",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Periodo",
"Periods": "Periódos",
@@ -458,6 +463,7 @@
"Sticky_Nav_Help": "Mostrar siempre el menú de navegación el la parte superior de la pantalla.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "Tienen un sustituto disponible.",
"Substitutes": "",
"Success": "Exito",

View File

@@ -99,6 +99,8 @@
"Export_As_ICal": "Vie nykyinen jakso iCal muotoon",
"Export_To_ICal": "Vie .ics",
"External": "Ulkoinen",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Ulkoinen reseptin kuva",
"Failure": "Epäonnistui",
@@ -127,6 +129,7 @@
"Ignore_Shopping": "Ohita Ostokset",
"Image": "Kuva",
"Import": "Tuo",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_finished": "Tuonti valmistui",
"Information": "Tiedot",
@@ -202,6 +205,8 @@
"Owner": "",
"Parameter": "Parametri",
"Parent": "Yläluokka",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Jakso",
"Periods": "Jaksot",
@@ -301,6 +306,7 @@
"StepsOverview": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"Substitutes": "",
"Success": "Onnistui",
"Sunday": "",

View File

@@ -160,6 +160,8 @@
"Export_Supported": "Exportation prise en charge",
"Export_To_ICal": "Exporter .ics",
"External": "Externe",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Image de recette externe",
"FDC_ID": "ID FCD",
@@ -203,6 +205,7 @@
"Image": "Image",
"Import": "Importer",
"Import Recipe": "Importer une recette",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "Une erreur est survenue pendant votre importation. Veuillez développer les détails au bas de la page pour la consulter.",
"Import_Not_Yet_Supported": "Importation pas encore prise en charge",
@@ -325,6 +328,8 @@
"Page": "Page",
"Parameter": "Paramètre",
"Parent": "Parent",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Période",
"Periods": "Périodes",
@@ -458,6 +463,7 @@
"Sticky_Nav_Help": "Toujours afficher le menu de navigation en haut de lécran.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"Substitutes": "",
"Success": "Réussite",
"SuccessClipboard": "Liste de courses copiée dans le presse-papiers",

View File

@@ -161,6 +161,8 @@
"Export_Supported": "ייצוא נתמך",
"Export_To_ICal": "ייצא .ics",
"External": "חיצוני",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "תמונת מתכון חיצונית",
"FDC_ID": "מספר FDC",
@@ -204,6 +206,7 @@
"Image": "תמונה",
"Import": "ייבוא",
"Import Recipe": "ייבא מתכון",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "שגיאה בעת ייבוא. הרחב את הפירוט בסוף עמוד זה לראות מידע נוסף.",
"Import_Not_Yet_Supported": "ייבוא לא נתמך עדיין",
@@ -326,6 +329,8 @@
"Page": "עמוד",
"Parameter": "פרמטר",
"Parent": "הורה",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "תקופה",
"Periods": "תקופות",
@@ -459,6 +464,7 @@
"Sticky_Nav_Help": "תמיד הצג את תפריט הניווט בראש העמוד.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "יש לך תחלופה זמינה.",
"Substitutes": "",
"Success": "הצלחה",

View File

@@ -147,6 +147,8 @@
"Export_Supported": "",
"Export_To_ICal": "",
"External": "Külső",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Külső receptkép",
"Failure": "Hiba",
@@ -187,6 +189,7 @@
"Image": "Kép",
"Import": "Import",
"Import Recipe": "Recept importálása",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "Hiba történt az importálás során. Kérjük, a megtekintéshez bontsa ki az oldal alján található Részletek menüpontot.",
"Import_Not_Yet_Supported": "",
@@ -302,6 +305,8 @@
"Page": "Oldal",
"Parameter": "Paraméter",
"Parent": "Szülő",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Periódus",
"Periods": "Periódusok",
@@ -427,6 +432,7 @@
"Sticky_Nav_Help": "A navigációs menü mindig a képernyő tetején jelenjen meg.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "Van elérhető helyettesítője.",
"Substitutes": "",
"Success": "Sikeres",

View File

@@ -80,6 +80,8 @@
"ErrorUrlListImport": "",
"Export": "",
"External": "",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "",
"Fats": "",
@@ -102,6 +104,7 @@
"History": "",
"HostedFreeVersion": "",
"Import": "Ներմուծել",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_finished": "Ներմուծումն ավարտված է",
"Information": "Տեղեկություն",
@@ -156,6 +159,8 @@
"Order": "",
"Owner": "",
"Parent": "Ծնող",
"Password": "",
"Path": "",
"PerPage": "",
"Planning&Shopping": "",
"Plural": "",
@@ -239,6 +244,7 @@
"StepsOverview": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"Substitutes": "",
"Success": "",
"Sunday": "",

View File

@@ -136,6 +136,8 @@
"Export_Supported": "",
"Export_To_ICal": "",
"External": "Luar",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Gambar Resep Eksternal",
"Failure": "Kegagalan",
@@ -174,6 +176,7 @@
"IgnoredFood": "",
"Image": "Gambar",
"Import": "Impor",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "",
"Import_Not_Yet_Supported": "",
@@ -283,6 +286,8 @@
"Page": "",
"Parameter": "Parameter",
"Parent": "Induk",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "",
"Periods": "",
@@ -403,6 +408,7 @@
"Sticky_Nav_Help": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "",
"Substitutes": "",
"Success": "Sukses",

View File

@@ -160,6 +160,8 @@
"Export_Supported": "",
"Export_To_ICal": "",
"External": "",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "",
"FDC_ID": "",
@@ -203,6 +205,7 @@
"Image": "",
"Import": "",
"Import Recipe": "",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "",
"Import_Not_Yet_Supported": "",
@@ -325,6 +328,8 @@
"Page": "",
"Parameter": "",
"Parent": "",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "",
"Periods": "",
@@ -457,6 +462,7 @@
"Sticky_Nav_Help": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "",
"Substitutes": "",
"Success": "",

View File

@@ -141,6 +141,8 @@
"Export_Supported": "Esportazione supportata",
"Export_To_ICal": "Esporta .ics",
"External": "Esterna",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Immagine ricetta esterna",
"Failure": "Errore",
@@ -179,6 +181,7 @@
"IgnoredFood": "{food} è impostato per ignorare la spesa.",
"Image": "Immagine",
"Import": "Importa",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "Si è verificato un errore durante l'importazione. Per avere maggiori informazioni, espandi la sezione dettagli in fondo alla pagina.",
"Import_Not_Yet_Supported": "Importazione non ancora supportata",
@@ -289,6 +292,8 @@
"Page": "Pagina",
"Parameter": "Parametro",
"Parent": "Primario",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Periodo",
"Periods": "Periodi",
@@ -412,6 +417,7 @@
"Sticky_Nav_Help": "Mostra sempre il menu di navigazione in alto.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "Hai un sostituto disponibile.",
"Substitutes": "",
"Success": "Riuscito",

View File

@@ -149,6 +149,8 @@
"Export_Supported": "",
"Export_To_ICal": "",
"External": "",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Išorinis recepto vaizdas",
"Failure": "",
@@ -189,6 +191,7 @@
"Image": "",
"Import": "",
"Import Recipe": "",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "",
"Import_Not_Yet_Supported": "",
@@ -306,6 +309,8 @@
"Page": "",
"Parameter": "",
"Parent": "",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "",
"Periods": "",
@@ -432,6 +437,7 @@
"Sticky_Nav_Help": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "",
"Substitutes": "",
"Success": "",

View File

@@ -145,6 +145,8 @@
"Export_Supported": "",
"Export_To_ICal": "Eksporter .ics",
"External": "Ekstern",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Bilde av ekstern oppskrift",
"Failure": "Feil",
@@ -184,6 +186,7 @@
"Image": "Bilde",
"Import": "Importer",
"Import Recipe": "Importer oppskrift",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "",
"Import_Not_Yet_Supported": "",
@@ -298,6 +301,8 @@
"Page": "",
"Parameter": "Parameter",
"Parent": "Forelder",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Periode",
"Periods": "Perioder",
@@ -423,6 +428,7 @@
"Sticky_Nav_Help": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "",
"Substitutes": "",
"Success": "Vellykket",

View File

@@ -149,6 +149,8 @@
"Export_Supported": "Export ondersteund",
"Export_To_ICal": "Exporteer .ics",
"External": "Externe",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Externe Afbeelding Recept",
"Failure": "Storing",
@@ -188,6 +190,7 @@
"Image": "Afbeelding",
"Import": "Importeer",
"Import Recipe": "Recept Importeren",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "Er is een fout opgetreden tijdens je import. Breid de details aan de onderzijde van de pagina uit om ze te bekijken.",
"Import_Not_Yet_Supported": "Import nog niet ondersteund",
@@ -302,6 +305,8 @@
"Page": "Pagina",
"Parameter": "Parameter",
"Parent": "Ouder",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Periode",
"Periods": "Periodes",
@@ -427,6 +432,7 @@
"Sticky_Nav_Help": "Geef navigatiemenu altijd bovenin weer.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "Je hebt een vervanger op voorraad.",
"Substitutes": "",
"Success": "Succes",

View File

@@ -162,6 +162,8 @@
"Export_Supported": "Eksportowanie wspierane",
"Export_To_ICal": "Eksportuj .ics",
"External": "Zewnętrzny",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Zewnętrzny obraz dla przepisu",
"FDC_ID": "Identyfikator FDC",
@@ -205,6 +207,7 @@
"Image": "Obraz",
"Import": "Importuj",
"Import Recipe": "Importuj przepis",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "Podczas importowania wystąpił błąd. Rozwiń Szczegóły na dole strony, aby go wyświetlić.",
"Import_Not_Yet_Supported": "Importowanie jeszcze nie wspierane",
@@ -327,6 +330,8 @@
"Page": "Strona",
"Parameter": "Parametr",
"Parent": "Nadrzędny",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Okres",
"Periods": "Okresy",
@@ -460,6 +465,7 @@
"Sticky_Nav_Help": "Zawsze pokazuj menu nawigacyjne u góry ekranu.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "Masz pod ręką zamienniki.",
"Substitutes": "",
"Success": "Powodzenie",

View File

@@ -124,6 +124,8 @@
"Export_As_ICal": "Exportar período atual para o formato ICal",
"Export_To_ICal": "Exportar .ics",
"External": "Externo",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Imagem da receita externa",
"Failure": "Falha",
@@ -159,6 +161,7 @@
"IgnoredFood": "{food} está definida para ignorar compras.",
"Image": "Image",
"Import": "Importar",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_finished": "Importação terminada",
"Information": "Informação",
@@ -252,6 +255,8 @@
"Page": "Página",
"Parameter": "Parâmetro",
"Parent": "Parente",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Período",
"Periods": "Períodos",
@@ -366,6 +371,7 @@
"StepsOverview": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "",
"Substitutes": "",
"Success": "Sucesso",

View File

@@ -156,6 +156,8 @@
"Export_Supported": "Exportação suportada",
"Export_To_ICal": "Exportar .ics",
"External": "Externo",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Imagem externa da receita",
"FDC_ID": "FDC ID",
@@ -199,6 +201,7 @@
"Image": "Imagem",
"Import": "Importar",
"Import Recipe": "Importar Receita",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Not_Yet_Supported": "Importação ainda não suportada",
"Import_Result_Info": "{imported} de {total} receitas foram importadas",
@@ -315,6 +318,8 @@
"Page": "Página",
"Parameter": "Parâmetro",
"Parent": "Pai",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Período",
"Periods": "Períodos",
@@ -442,6 +447,7 @@
"Sticky_Nav_Help": "Permitir mostrar o menu de navegação no topo da tela.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "Você tem um substituto disponível.",
"Substitutes": "",
"Success": "Sucesso",

View File

@@ -143,6 +143,8 @@
"Export_Supported": "Export compatibil",
"Export_To_ICal": "Exportă .ics",
"External": "Extern",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Imagine rețetă externă",
"Failure": "Eșec",
@@ -182,6 +184,7 @@
"Image": "Imagine",
"Import": "Importă",
"Import Recipe": "Importă rețeta",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "A apărut o eroare în timpul importului. Vă rugăm să extindeți detaliile din partea de jos a paginii pentru a le vizualiza.",
"Import_Not_Yet_Supported": "Importul încă nu este compatibil",
@@ -293,6 +296,8 @@
"Page": "Pagină",
"Parameter": "Parametru",
"Parent": "Părinte",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Perioadă",
"Periods": "Perioade",
@@ -416,6 +421,7 @@
"Sticky_Nav_Help": "Afișați întotdeauna meniul de navigare din partea de sus a ecranului.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "Ai un înlocuitor la îndemână.",
"Substitutes": "",
"Success": "Succes",

View File

@@ -114,6 +114,8 @@
"Export_As_ICal": "Экспорт текущего периода в iCal формат",
"Export_To_ICal": "Экспортировать .ics",
"External": "Внешний",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Изображение рецепта из внешнего источника",
"Failure": "Ошибка",
@@ -148,6 +150,7 @@
"IgnoredFood": "{food} будет исключён из списка покупок.",
"Image": "Изображение",
"Import": "Импорт",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "Во время импорта произошла ошибка. Для просмотра разверните \"Подробности\" в нижней части страницы.",
"Import_finished": "Импорт завершен",
@@ -242,6 +245,8 @@
"Page": "Страница",
"Parameter": "Параметр",
"Parent": "Родитель",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Период",
"Periods": "Периоды",
@@ -351,6 +356,7 @@
"StepsOverview": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"Substitutes": "",
"Success": "Успешно",
"Sunday": "",

View File

@@ -114,6 +114,8 @@
"Export_As_ICal": "Izvozi trenutno obdobje v iCal format",
"Export_To_ICal": "Izvoz.ics",
"External": "Zunanje",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Zunanja slika recepta",
"Failure": "Napaka",
@@ -147,6 +149,7 @@
"Ignore_Shopping": "Prezri nakup",
"Image": "Slika",
"Import": "Uvozi",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_finished": "Uvoz je končan",
"Information": "Informacija",
@@ -234,6 +237,8 @@
"Owner": "",
"Parameter": "Parameter",
"Parent": "Starš",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Obdobje",
"Periods": "Obdobja",
@@ -340,6 +345,7 @@
"StepsOverview": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"Substitutes": "",
"Success": "Uspešno",
"SuccessClipboard": "Nakupovalni listek je kopiran v odložišče",

View File

@@ -162,6 +162,8 @@
"Export_Supported": "Export stöds",
"Export_To_ICal": "Exportera .ics",
"External": "Extern",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Extern receptbild",
"FDC_ID": "FDC ID",
@@ -205,6 +207,7 @@
"Image": "Bild",
"Import": "Importera",
"Import Recipe": "Importera recept",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "Ett fel uppstod under din import. Expandera informationen längst ner på sidan för att se den.",
"Import_Not_Yet_Supported": "Import stöds inte ännu",
@@ -327,6 +330,8 @@
"Page": "Sida",
"Parameter": "Parameter",
"Parent": "Förälder",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Period",
"Periods": "Perioder",
@@ -460,6 +465,7 @@
"Sticky_Nav_Help": "Visa alltid navigeringsmenyn högst upp på skärmen.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "Du har ett substitut till hands.",
"Substitutes": "",
"Success": "Lyckas",

View File

@@ -161,6 +161,8 @@
"Export_Supported": "Desteklenen Dışa Aktarma",
"Export_To_ICal": ".ics olarak dışa aktar",
"External": "Harici",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Harici Tarif Resim",
"FDC_ID": "FDC Kimlik",
@@ -204,6 +206,7 @@
"Image": "Resim",
"Import": "İçeriye Aktar",
"Import Recipe": "Tarif İçe Aktar",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "İçeri aktarma sırasında bir hata oluştu. Görüntülemek için lütfen sayfanın altındaki Ayrıntıları genişletin.",
"Import_Not_Yet_Supported": "İçe aktarma henüz desteklenmiyor",
@@ -326,6 +329,8 @@
"Page": "Sayfa",
"Parameter": "Parametre",
"Parent": "Üst Öğe",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Dönem",
"Periods": "Dönemler",
@@ -459,6 +464,7 @@
"Sticky_Nav_Help": "Gezinme menüsünü her zaman ekranın üst kısmında gösterin.",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "Elinizde bir yedek var.",
"Substitutes": "",
"Success": "Başarılı",

View File

@@ -131,6 +131,8 @@
"Export_Supported": "",
"Export_To_ICal": "Експортувати .ics",
"External": "Зовнішній",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "Зображення Зовнішнього Рецепту",
"Failure": "Невдало",
@@ -166,6 +168,7 @@
"IgnoredFood": "{food} ігнорується в покупках.",
"Image": "Зображення",
"Import": "Імпорт",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "",
"Import_Not_Yet_Supported": "",
@@ -270,6 +273,8 @@
"Page": "",
"Parameter": "Параметр",
"Parent": "Батько",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "Період",
"Periods": "Періоди",
@@ -387,6 +392,7 @@
"StepsOverview": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "",
"Substitutes": "",
"Success": "Успішно",

View File

@@ -157,6 +157,8 @@
"Export_Supported": "导出支持",
"Export_To_ICal": "导出 .ics",
"External": "外部",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "外部食谱图像",
"FDC_ID": "FDC ID",
@@ -200,6 +202,7 @@
"Image": "图片",
"Import": "导入",
"Import Recipe": "导入食谱",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_Error": "导入时发生错误。 请跳转至页面底部的详细信息进行查看。",
"Import_Not_Yet_Supported": "导入尚未支持",
@@ -321,6 +324,8 @@
"Page": "页",
"Parameter": "范围",
"Parent": "父级",
"Password": "",
"Path": "",
"PerPage": "",
"Period": "周期",
"Periods": "周期",
@@ -453,6 +458,7 @@
"Sticky_Nav_Help": "始终在屏幕顶部显示导航菜单。",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"SubstituteOnHand": "你手头有一个替代品。",
"Substitutes": "",
"Success": "成功",

View File

@@ -68,6 +68,8 @@
"ErrorUrlListImport": "",
"Export": "",
"External": "",
"ExternalRecipeImport": "",
"ExternalRecipeImportHelp": "",
"ExternalStorage": "",
"External_Recipe_Image": "外部食譜圖片",
"Failure": "",
@@ -87,6 +89,7 @@
"History": "",
"HostedFreeVersion": "",
"Import": "",
"ImportAll": "",
"ImportIntoTandoor": "",
"Import_finished": "匯入完成",
"Information": "",
@@ -131,6 +134,8 @@
"Open_Data_Import": "",
"Order": "",
"Owner": "",
"Password": "",
"Path": "",
"PerPage": "",
"Planning&Shopping": "",
"Plural": "",
@@ -209,6 +214,7 @@
"StepsOverview": "",
"Storage": "",
"StorageHelp": "",
"StoragePasswordTokenHelp": "",
"Substitutes": "",
"Success": "",
"Sunday": "",

View File

@@ -66,11 +66,13 @@ models/PaginatedPropertyList.ts
models/PaginatedPropertyTypeList.ts
models/PaginatedRecipeBookEntryList.ts
models/PaginatedRecipeBookList.ts
models/PaginatedRecipeImportList.ts
models/PaginatedRecipeOverviewList.ts
models/PaginatedShoppingListEntryList.ts
models/PaginatedShoppingListRecipeList.ts
models/PaginatedSpaceList.ts
models/PaginatedStepList.ts
models/PaginatedStorageList.ts
models/PaginatedSupermarketCategoryList.ts
models/PaginatedSupermarketCategoryRelationList.ts
models/PaginatedSupermarketList.ts
@@ -108,6 +110,7 @@ models/PatchedPropertyType.ts
models/PatchedRecipe.ts
models/PatchedRecipeBook.ts
models/PatchedRecipeBookEntry.ts
models/PatchedRecipeImport.ts
models/PatchedShoppingListEntry.ts
models/PatchedShoppingListRecipe.ts
models/PatchedSpace.ts
@@ -132,6 +135,7 @@ models/RecipeFlat.ts
models/RecipeFromSource.ts
models/RecipeFromSourceResponse.ts
models/RecipeImage.ts
models/RecipeImport.ts
models/RecipeOverview.ts
models/RecipeShoppingUpdate.ts
models/RecipeSimple.ts

View File

@@ -63,11 +63,13 @@ import type {
PaginatedPropertyTypeList,
PaginatedRecipeBookEntryList,
PaginatedRecipeBookList,
PaginatedRecipeImportList,
PaginatedRecipeOverviewList,
PaginatedShoppingListEntryList,
PaginatedShoppingListRecipeList,
PaginatedSpaceList,
PaginatedStepList,
PaginatedStorageList,
PaginatedSupermarketCategoryList,
PaginatedSupermarketCategoryRelationList,
PaginatedSupermarketList,
@@ -105,6 +107,7 @@ import type {
PatchedRecipe,
PatchedRecipeBook,
PatchedRecipeBookEntry,
PatchedRecipeImport,
PatchedShoppingListEntry,
PatchedShoppingListRecipe,
PatchedSpace,
@@ -129,6 +132,7 @@ import type {
RecipeFromSource,
RecipeFromSourceResponse,
RecipeImage,
RecipeImport,
RecipeShoppingUpdate,
RecipeSimple,
ServerSettings,
@@ -250,6 +254,8 @@ import {
PaginatedRecipeBookEntryListToJSON,
PaginatedRecipeBookListFromJSON,
PaginatedRecipeBookListToJSON,
PaginatedRecipeImportListFromJSON,
PaginatedRecipeImportListToJSON,
PaginatedRecipeOverviewListFromJSON,
PaginatedRecipeOverviewListToJSON,
PaginatedShoppingListEntryListFromJSON,
@@ -260,6 +266,8 @@ import {
PaginatedSpaceListToJSON,
PaginatedStepListFromJSON,
PaginatedStepListToJSON,
PaginatedStorageListFromJSON,
PaginatedStorageListToJSON,
PaginatedSupermarketCategoryListFromJSON,
PaginatedSupermarketCategoryListToJSON,
PaginatedSupermarketCategoryRelationListFromJSON,
@@ -334,6 +342,8 @@ import {
PatchedRecipeBookToJSON,
PatchedRecipeBookEntryFromJSON,
PatchedRecipeBookEntryToJSON,
PatchedRecipeImportFromJSON,
PatchedRecipeImportToJSON,
PatchedShoppingListEntryFromJSON,
PatchedShoppingListEntryToJSON,
PatchedShoppingListRecipeFromJSON,
@@ -382,6 +392,8 @@ import {
RecipeFromSourceResponseToJSON,
RecipeImageFromJSON,
RecipeImageToJSON,
RecipeImportFromJSON,
RecipeImportToJSON,
RecipeShoppingUpdateFromJSON,
RecipeShoppingUpdateToJSON,
RecipeSimpleFromJSON,
@@ -1211,6 +1223,42 @@ export interface ApiRecipeImageUpdateRequest {
imageUrl?: string;
}
export interface ApiRecipeImportCreateRequest {
recipeImport: Omit<RecipeImport, 'createdAt'>;
}
export interface ApiRecipeImportDestroyRequest {
id: number;
}
export interface ApiRecipeImportImportAllCreateRequest {
recipeImport: Omit<RecipeImport, 'createdAt'>;
}
export interface ApiRecipeImportImportRecipeCreateRequest {
id: number;
recipeImport: Omit<RecipeImport, 'createdAt'>;
}
export interface ApiRecipeImportListRequest {
page?: number;
pageSize?: number;
}
export interface ApiRecipeImportPartialUpdateRequest {
id: number;
patchedRecipeImport?: Omit<PatchedRecipeImport, 'createdAt'>;
}
export interface ApiRecipeImportRetrieveRequest {
id: number;
}
export interface ApiRecipeImportUpdateRequest {
id: number;
recipeImport: Omit<RecipeImport, 'createdAt'>;
}
export interface ApiRecipeListRequest {
books?: Array<number>;
booksAnd?: Array<number>;
@@ -1402,6 +1450,11 @@ export interface ApiStorageDestroyRequest {
id: number;
}
export interface ApiStorageListRequest {
page?: number;
pageSize?: number;
}
export interface ApiStoragePartialUpdateRequest {
id: number;
patchedStorage?: Omit<PatchedStorage, 'createdBy'>;
@@ -1546,6 +1599,11 @@ export interface ApiSyncPartialUpdateRequest {
patchedSync?: Omit<PatchedSync, 'createdAt'|'updatedAt'>;
}
export interface ApiSyncPerformUpdateCreateRequest {
id: number;
sync: Omit<Sync, 'createdAt'|'updatedAt'>;
}
export interface ApiSyncRetrieveRequest {
id: number;
}
@@ -8928,6 +8986,331 @@ export class ApiApi extends runtime.BaseAPI {
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportCreateRaw(requestParameters: ApiRecipeImportCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<RecipeImport>> {
if (requestParameters['recipeImport'] == null) {
throw new runtime.RequiredError(
'recipeImport',
'Required parameter "recipeImport" was null or undefined when calling apiRecipeImportCreate().'
);
}
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/recipe-import/`,
method: 'POST',
headers: headerParameters,
query: queryParameters,
body: RecipeImportToJSON(requestParameters['recipeImport']),
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => RecipeImportFromJSON(jsonValue));
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportCreate(requestParameters: ApiRecipeImportCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<RecipeImport> {
const response = await this.apiRecipeImportCreateRaw(requestParameters, initOverrides);
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportDestroyRaw(requestParameters: ApiRecipeImportDestroyRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<void>> {
if (requestParameters['id'] == null) {
throw new runtime.RequiredError(
'id',
'Required parameter "id" was null or undefined when calling apiRecipeImportDestroy().'
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
if (this.configuration && this.configuration.apiKey) {
headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiKeyAuth authentication
}
const response = await this.request({
path: `/api/recipe-import/{id}/`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters['id']))),
method: 'DELETE',
headers: headerParameters,
query: queryParameters,
}, initOverrides);
return new runtime.VoidApiResponse(response);
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportDestroy(requestParameters: ApiRecipeImportDestroyRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<void> {
await this.apiRecipeImportDestroyRaw(requestParameters, initOverrides);
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportImportAllCreateRaw(requestParameters: ApiRecipeImportImportAllCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<RecipeImport>> {
if (requestParameters['recipeImport'] == null) {
throw new runtime.RequiredError(
'recipeImport',
'Required parameter "recipeImport" was null or undefined when calling apiRecipeImportImportAllCreate().'
);
}
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/recipe-import/import_all/`,
method: 'POST',
headers: headerParameters,
query: queryParameters,
body: RecipeImportToJSON(requestParameters['recipeImport']),
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => RecipeImportFromJSON(jsonValue));
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportImportAllCreate(requestParameters: ApiRecipeImportImportAllCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<RecipeImport> {
const response = await this.apiRecipeImportImportAllCreateRaw(requestParameters, initOverrides);
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportImportRecipeCreateRaw(requestParameters: ApiRecipeImportImportRecipeCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Recipe>> {
if (requestParameters['id'] == null) {
throw new runtime.RequiredError(
'id',
'Required parameter "id" was null or undefined when calling apiRecipeImportImportRecipeCreate().'
);
}
if (requestParameters['recipeImport'] == null) {
throw new runtime.RequiredError(
'recipeImport',
'Required parameter "recipeImport" was null or undefined when calling apiRecipeImportImportRecipeCreate().'
);
}
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/recipe-import/{id}/import_recipe/`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters['id']))),
method: 'POST',
headers: headerParameters,
query: queryParameters,
body: RecipeImportToJSON(requestParameters['recipeImport']),
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => RecipeFromJSON(jsonValue));
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportImportRecipeCreate(requestParameters: ApiRecipeImportImportRecipeCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Recipe> {
const response = await this.apiRecipeImportImportRecipeCreateRaw(requestParameters, initOverrides);
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportListRaw(requestParameters: ApiRecipeImportListRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<PaginatedRecipeImportList>> {
const queryParameters: any = {};
if (requestParameters['page'] != null) {
queryParameters['page'] = requestParameters['page'];
}
if (requestParameters['pageSize'] != null) {
queryParameters['page_size'] = requestParameters['pageSize'];
}
const headerParameters: runtime.HTTPHeaders = {};
if (this.configuration && this.configuration.apiKey) {
headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiKeyAuth authentication
}
const response = await this.request({
path: `/api/recipe-import/`,
method: 'GET',
headers: headerParameters,
query: queryParameters,
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => PaginatedRecipeImportListFromJSON(jsonValue));
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportList(requestParameters: ApiRecipeImportListRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<PaginatedRecipeImportList> {
const response = await this.apiRecipeImportListRaw(requestParameters, initOverrides);
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportPartialUpdateRaw(requestParameters: ApiRecipeImportPartialUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<RecipeImport>> {
if (requestParameters['id'] == null) {
throw new runtime.RequiredError(
'id',
'Required parameter "id" was null or undefined when calling apiRecipeImportPartialUpdate().'
);
}
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/recipe-import/{id}/`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters['id']))),
method: 'PATCH',
headers: headerParameters,
query: queryParameters,
body: PatchedRecipeImportToJSON(requestParameters['patchedRecipeImport']),
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => RecipeImportFromJSON(jsonValue));
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportPartialUpdate(requestParameters: ApiRecipeImportPartialUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<RecipeImport> {
const response = await this.apiRecipeImportPartialUpdateRaw(requestParameters, initOverrides);
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportRetrieveRaw(requestParameters: ApiRecipeImportRetrieveRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<RecipeImport>> {
if (requestParameters['id'] == null) {
throw new runtime.RequiredError(
'id',
'Required parameter "id" was null or undefined when calling apiRecipeImportRetrieve().'
);
}
const queryParameters: any = {};
const headerParameters: runtime.HTTPHeaders = {};
if (this.configuration && this.configuration.apiKey) {
headerParameters["Authorization"] = await this.configuration.apiKey("Authorization"); // ApiKeyAuth authentication
}
const response = await this.request({
path: `/api/recipe-import/{id}/`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters['id']))),
method: 'GET',
headers: headerParameters,
query: queryParameters,
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => RecipeImportFromJSON(jsonValue));
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportRetrieve(requestParameters: ApiRecipeImportRetrieveRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<RecipeImport> {
const response = await this.apiRecipeImportRetrieveRaw(requestParameters, initOverrides);
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportUpdateRaw(requestParameters: ApiRecipeImportUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<RecipeImport>> {
if (requestParameters['id'] == null) {
throw new runtime.RequiredError(
'id',
'Required parameter "id" was null or undefined when calling apiRecipeImportUpdate().'
);
}
if (requestParameters['recipeImport'] == null) {
throw new runtime.RequiredError(
'recipeImport',
'Required parameter "recipeImport" was null or undefined when calling apiRecipeImportUpdate().'
);
}
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/recipe-import/{id}/`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters['id']))),
method: 'PUT',
headers: headerParameters,
query: queryParameters,
body: RecipeImportToJSON(requestParameters['recipeImport']),
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => RecipeImportFromJSON(jsonValue));
}
/**
* logs request counts to redis cache total/per user/
*/
async apiRecipeImportUpdate(requestParameters: ApiRecipeImportUpdateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<RecipeImport> {
const response = await this.apiRecipeImportUpdateRaw(requestParameters, initOverrides);
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/
@@ -10479,9 +10862,17 @@ export class ApiApi extends runtime.BaseAPI {
/**
* logs request counts to redis cache total/per user/
*/
async apiStorageListRaw(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<Array<Storage>>> {
async apiStorageListRaw(requestParameters: ApiStorageListRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<PaginatedStorageList>> {
const queryParameters: any = {};
if (requestParameters['page'] != null) {
queryParameters['page'] = requestParameters['page'];
}
if (requestParameters['pageSize'] != null) {
queryParameters['page_size'] = requestParameters['pageSize'];
}
const headerParameters: runtime.HTTPHeaders = {};
if (this.configuration && this.configuration.apiKey) {
@@ -10495,14 +10886,14 @@ export class ApiApi extends runtime.BaseAPI {
query: queryParameters,
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => jsonValue.map(StorageFromJSON));
return new runtime.JSONApiResponse(response, (jsonValue) => PaginatedStorageListFromJSON(jsonValue));
}
/**
* logs request counts to redis cache total/per user/
*/
async apiStorageList(initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<Array<Storage>> {
const response = await this.apiStorageListRaw(initOverrides);
async apiStorageList(requestParameters: ApiStorageListRequest = {}, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<PaginatedStorageList> {
const response = await this.apiStorageListRaw(requestParameters, initOverrides);
return await response.value();
}
@@ -11711,6 +12102,53 @@ export class ApiApi extends runtime.BaseAPI {
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/
async apiSyncPerformUpdateCreateRaw(requestParameters: ApiSyncPerformUpdateCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<runtime.ApiResponse<SyncLog>> {
if (requestParameters['id'] == null) {
throw new runtime.RequiredError(
'id',
'Required parameter "id" was null or undefined when calling apiSyncPerformUpdateCreate().'
);
}
if (requestParameters['sync'] == null) {
throw new runtime.RequiredError(
'sync',
'Required parameter "sync" was null or undefined when calling apiSyncPerformUpdateCreate().'
);
}
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/sync/{id}/perform_update/`.replace(`{${"id"}}`, encodeURIComponent(String(requestParameters['id']))),
method: 'POST',
headers: headerParameters,
query: queryParameters,
body: SyncToJSON(requestParameters['sync']),
}, initOverrides);
return new runtime.JSONApiResponse(response, (jsonValue) => SyncLogFromJSON(jsonValue));
}
/**
* logs request counts to redis cache total/per user/
*/
async apiSyncPerformUpdateCreate(requestParameters: ApiSyncPerformUpdateCreateRequest, initOverrides?: RequestInit | runtime.InitOverrideFunction): Promise<SyncLog> {
const response = await this.apiSyncPerformUpdateCreateRaw(requestParameters, initOverrides);
return await response.value();
}
/**
* logs request counts to redis cache total/per user/
*/

View File

@@ -0,0 +1,101 @@
/* tslint:disable */
/* eslint-disable */
/**
* Tandoor
* Tandoor API Docs
*
* The version of the OpenAPI document: 0.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
import type { RecipeImport } from './RecipeImport';
import {
RecipeImportFromJSON,
RecipeImportFromJSONTyped,
RecipeImportToJSON,
} from './RecipeImport';
/**
*
* @export
* @interface PaginatedRecipeImportList
*/
export interface PaginatedRecipeImportList {
/**
*
* @type {number}
* @memberof PaginatedRecipeImportList
*/
count: number;
/**
*
* @type {string}
* @memberof PaginatedRecipeImportList
*/
next?: string;
/**
*
* @type {string}
* @memberof PaginatedRecipeImportList
*/
previous?: string;
/**
*
* @type {Array<RecipeImport>}
* @memberof PaginatedRecipeImportList
*/
results: Array<RecipeImport>;
/**
*
* @type {Date}
* @memberof PaginatedRecipeImportList
*/
timestamp?: Date;
}
/**
* Check if a given object implements the PaginatedRecipeImportList interface.
*/
export function instanceOfPaginatedRecipeImportList(value: object): value is PaginatedRecipeImportList {
if (!('count' in value) || value['count'] === undefined) return false;
if (!('results' in value) || value['results'] === undefined) return false;
return true;
}
export function PaginatedRecipeImportListFromJSON(json: any): PaginatedRecipeImportList {
return PaginatedRecipeImportListFromJSONTyped(json, false);
}
export function PaginatedRecipeImportListFromJSONTyped(json: any, ignoreDiscriminator: boolean): PaginatedRecipeImportList {
if (json == null) {
return json;
}
return {
'count': json['count'],
'next': json['next'] == null ? undefined : json['next'],
'previous': json['previous'] == null ? undefined : json['previous'],
'results': ((json['results'] as Array<any>).map(RecipeImportFromJSON)),
'timestamp': json['timestamp'] == null ? undefined : (new Date(json['timestamp'])),
};
}
export function PaginatedRecipeImportListToJSON(value?: PaginatedRecipeImportList | null): any {
if (value == null) {
return value;
}
return {
'count': value['count'],
'next': value['next'],
'previous': value['previous'],
'results': ((value['results'] as Array<any>).map(RecipeImportToJSON)),
'timestamp': value['timestamp'] == null ? undefined : ((value['timestamp']).toISOString()),
};
}

View File

@@ -0,0 +1,101 @@
/* tslint:disable */
/* eslint-disable */
/**
* Tandoor
* Tandoor API Docs
*
* The version of the OpenAPI document: 0.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
import type { Storage } from './Storage';
import {
StorageFromJSON,
StorageFromJSONTyped,
StorageToJSON,
} from './Storage';
/**
*
* @export
* @interface PaginatedStorageList
*/
export interface PaginatedStorageList {
/**
*
* @type {number}
* @memberof PaginatedStorageList
*/
count: number;
/**
*
* @type {string}
* @memberof PaginatedStorageList
*/
next?: string;
/**
*
* @type {string}
* @memberof PaginatedStorageList
*/
previous?: string;
/**
*
* @type {Array<Storage>}
* @memberof PaginatedStorageList
*/
results: Array<Storage>;
/**
*
* @type {Date}
* @memberof PaginatedStorageList
*/
timestamp?: Date;
}
/**
* Check if a given object implements the PaginatedStorageList interface.
*/
export function instanceOfPaginatedStorageList(value: object): value is PaginatedStorageList {
if (!('count' in value) || value['count'] === undefined) return false;
if (!('results' in value) || value['results'] === undefined) return false;
return true;
}
export function PaginatedStorageListFromJSON(json: any): PaginatedStorageList {
return PaginatedStorageListFromJSONTyped(json, false);
}
export function PaginatedStorageListFromJSONTyped(json: any, ignoreDiscriminator: boolean): PaginatedStorageList {
if (json == null) {
return json;
}
return {
'count': json['count'],
'next': json['next'] == null ? undefined : json['next'],
'previous': json['previous'] == null ? undefined : json['previous'],
'results': ((json['results'] as Array<any>).map(StorageFromJSON)),
'timestamp': json['timestamp'] == null ? undefined : (new Date(json['timestamp'])),
};
}
export function PaginatedStorageListToJSON(value?: PaginatedStorageList | null): any {
if (value == null) {
return value;
}
return {
'count': value['count'],
'next': value['next'],
'previous': value['previous'],
'results': ((value['results'] as Array<any>).map(StorageToJSON)),
'timestamp': value['timestamp'] == null ? undefined : ((value['timestamp']).toISOString()),
};
}

View File

@@ -0,0 +1,107 @@
/* tslint:disable */
/* eslint-disable */
/**
* Tandoor
* Tandoor API Docs
*
* The version of the OpenAPI document: 0.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
/**
*
* @export
* @interface PatchedRecipeImport
*/
export interface PatchedRecipeImport {
/**
*
* @type {number}
* @memberof PatchedRecipeImport
*/
id?: number;
/**
*
* @type {string}
* @memberof PatchedRecipeImport
*/
name?: string;
/**
*
* @type {string}
* @memberof PatchedRecipeImport
*/
fileUid?: string;
/**
*
* @type {string}
* @memberof PatchedRecipeImport
*/
filePath?: string;
/**
*
* @type {Date}
* @memberof PatchedRecipeImport
*/
readonly createdAt?: Date;
/**
*
* @type {number}
* @memberof PatchedRecipeImport
*/
storage?: number;
/**
*
* @type {number}
* @memberof PatchedRecipeImport
*/
space?: number;
}
/**
* Check if a given object implements the PatchedRecipeImport interface.
*/
export function instanceOfPatchedRecipeImport(value: object): value is PatchedRecipeImport {
return true;
}
export function PatchedRecipeImportFromJSON(json: any): PatchedRecipeImport {
return PatchedRecipeImportFromJSONTyped(json, false);
}
export function PatchedRecipeImportFromJSONTyped(json: any, ignoreDiscriminator: boolean): PatchedRecipeImport {
if (json == null) {
return json;
}
return {
'id': json['id'] == null ? undefined : json['id'],
'name': json['name'] == null ? undefined : json['name'],
'fileUid': json['file_uid'] == null ? undefined : json['file_uid'],
'filePath': json['file_path'] == null ? undefined : json['file_path'],
'createdAt': json['created_at'] == null ? undefined : (new Date(json['created_at'])),
'storage': json['storage'] == null ? undefined : json['storage'],
'space': json['space'] == null ? undefined : json['space'],
};
}
export function PatchedRecipeImportToJSON(value?: Omit<PatchedRecipeImport, 'createdAt'> | null): any {
if (value == null) {
return value;
}
return {
'id': value['id'],
'name': value['name'],
'file_uid': value['fileUid'],
'file_path': value['filePath'],
'storage': value['storage'],
'space': value['space'],
};
}

View File

@@ -21,7 +21,7 @@ import {
} from './MethodEnum';
/**
*
* Adds nested create feature
* @export
* @interface PatchedStorage
*/
@@ -62,6 +62,18 @@ export interface PatchedStorage {
* @memberof PatchedStorage
*/
token?: string;
/**
*
* @type {string}
* @memberof PatchedStorage
*/
url?: string;
/**
*
* @type {string}
* @memberof PatchedStorage
*/
path?: string;
/**
*
* @type {number}
@@ -93,6 +105,8 @@ export function PatchedStorageFromJSONTyped(json: any, ignoreDiscriminator: bool
'username': json['username'] == null ? undefined : json['username'],
'password': json['password'] == null ? undefined : json['password'],
'token': json['token'] == null ? undefined : json['token'],
'url': json['url'] == null ? undefined : json['url'],
'path': json['path'] == null ? undefined : json['path'],
'createdBy': json['created_by'] == null ? undefined : json['created_by'],
};
}
@@ -109,6 +123,8 @@ export function PatchedStorageToJSON(value?: Omit<PatchedStorage, 'createdBy'> |
'username': value['username'],
'password': value['password'],
'token': value['token'],
'url': value['url'],
'path': value['path'],
};
}

View File

@@ -13,8 +13,15 @@
*/
import { mapValues } from '../runtime';
import type { Storage } from './Storage';
import {
StorageFromJSON,
StorageFromJSONTyped,
StorageToJSON,
} from './Storage';
/**
*
* Adds nested create feature
* @export
* @interface PatchedSync
*/
@@ -27,10 +34,10 @@ export interface PatchedSync {
id?: number;
/**
*
* @type {number}
* @type {Storage}
* @memberof PatchedSync
*/
storage?: number;
storage?: Storage;
/**
*
* @type {string}
@@ -81,7 +88,7 @@ export function PatchedSyncFromJSONTyped(json: any, ignoreDiscriminator: boolean
return {
'id': json['id'] == null ? undefined : json['id'],
'storage': json['storage'] == null ? undefined : json['storage'],
'storage': json['storage'] == null ? undefined : StorageFromJSON(json['storage']),
'path': json['path'] == null ? undefined : json['path'],
'active': json['active'] == null ? undefined : json['active'],
'lastChecked': json['last_checked'] == null ? undefined : (new Date(json['last_checked'])),
@@ -97,7 +104,7 @@ export function PatchedSyncToJSON(value?: Omit<PatchedSync, 'createdAt'|'updated
return {
'id': value['id'],
'storage': value['storage'],
'storage': StorageToJSON(value['storage']),
'path': value['path'],
'active': value['active'],
'last_checked': value['lastChecked'] == null ? undefined : ((value['lastChecked'] as any).toISOString()),

View File

@@ -0,0 +1,111 @@
/* tslint:disable */
/* eslint-disable */
/**
* Tandoor
* Tandoor API Docs
*
* The version of the OpenAPI document: 0.0.0
*
*
* NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
* https://openapi-generator.tech
* Do not edit the class manually.
*/
import { mapValues } from '../runtime';
/**
*
* @export
* @interface RecipeImport
*/
export interface RecipeImport {
/**
*
* @type {number}
* @memberof RecipeImport
*/
id?: number;
/**
*
* @type {string}
* @memberof RecipeImport
*/
name: string;
/**
*
* @type {string}
* @memberof RecipeImport
*/
fileUid?: string;
/**
*
* @type {string}
* @memberof RecipeImport
*/
filePath?: string;
/**
*
* @type {Date}
* @memberof RecipeImport
*/
readonly createdAt: Date;
/**
*
* @type {number}
* @memberof RecipeImport
*/
storage: number;
/**
*
* @type {number}
* @memberof RecipeImport
*/
space: number;
}
/**
* Check if a given object implements the RecipeImport interface.
*/
export function instanceOfRecipeImport(value: object): value is RecipeImport {
if (!('name' in value) || value['name'] === undefined) return false;
if (!('createdAt' in value) || value['createdAt'] === undefined) return false;
if (!('storage' in value) || value['storage'] === undefined) return false;
if (!('space' in value) || value['space'] === undefined) return false;
return true;
}
export function RecipeImportFromJSON(json: any): RecipeImport {
return RecipeImportFromJSONTyped(json, false);
}
export function RecipeImportFromJSONTyped(json: any, ignoreDiscriminator: boolean): RecipeImport {
if (json == null) {
return json;
}
return {
'id': json['id'] == null ? undefined : json['id'],
'name': json['name'],
'fileUid': json['file_uid'] == null ? undefined : json['file_uid'],
'filePath': json['file_path'] == null ? undefined : json['file_path'],
'createdAt': (new Date(json['created_at'])),
'storage': json['storage'],
'space': json['space'],
};
}
export function RecipeImportToJSON(value?: Omit<RecipeImport, 'createdAt'> | null): any {
if (value == null) {
return value;
}
return {
'id': value['id'],
'name': value['name'],
'file_uid': value['fileUid'],
'file_path': value['filePath'],
'storage': value['storage'],
'space': value['space'],
};
}

View File

@@ -21,7 +21,7 @@ import {
} from './MethodEnum';
/**
*
* Adds nested create feature
* @export
* @interface Storage
*/
@@ -62,6 +62,18 @@ export interface Storage {
* @memberof Storage
*/
token?: string;
/**
*
* @type {string}
* @memberof Storage
*/
url?: string;
/**
*
* @type {string}
* @memberof Storage
*/
path?: string;
/**
*
* @type {number}
@@ -95,6 +107,8 @@ export function StorageFromJSONTyped(json: any, ignoreDiscriminator: boolean): S
'username': json['username'] == null ? undefined : json['username'],
'password': json['password'] == null ? undefined : json['password'],
'token': json['token'] == null ? undefined : json['token'],
'url': json['url'] == null ? undefined : json['url'],
'path': json['path'] == null ? undefined : json['path'],
'createdBy': json['created_by'],
};
}
@@ -111,6 +125,8 @@ export function StorageToJSON(value?: Omit<Storage, 'createdBy'> | null): any {
'username': value['username'],
'password': value['password'],
'token': value['token'],
'url': value['url'],
'path': value['path'],
};
}

View File

@@ -13,8 +13,15 @@
*/
import { mapValues } from '../runtime';
import type { Storage } from './Storage';
import {
StorageFromJSON,
StorageFromJSONTyped,
StorageToJSON,
} from './Storage';
/**
*
* Adds nested create feature
* @export
* @interface Sync
*/
@@ -27,10 +34,10 @@ export interface Sync {
id?: number;
/**
*
* @type {number}
* @type {Storage}
* @memberof Sync
*/
storage: number;
storage: Storage;
/**
*
* @type {string}
@@ -84,7 +91,7 @@ export function SyncFromJSONTyped(json: any, ignoreDiscriminator: boolean): Sync
return {
'id': json['id'] == null ? undefined : json['id'],
'storage': json['storage'],
'storage': StorageFromJSON(json['storage']),
'path': json['path'] == null ? undefined : json['path'],
'active': json['active'] == null ? undefined : json['active'],
'lastChecked': json['last_checked'] == null ? undefined : (new Date(json['last_checked'])),
@@ -100,7 +107,7 @@ export function SyncToJSON(value?: Omit<Sync, 'createdAt'|'updatedAt'> | null):
return {
'id': value['id'],
'storage': value['storage'],
'storage': StorageToJSON(value['storage']),
'path': value['path'],
'active': value['active'],
'last_checked': value['lastChecked'] == null ? undefined : ((value['lastChecked'] as any).toISOString()),

View File

@@ -13,6 +13,13 @@
*/
import { mapValues } from '../runtime';
import type { Sync } from './Sync';
import {
SyncFromJSON,
SyncFromJSONTyped,
SyncToJSON,
} from './Sync';
/**
*
* @export
@@ -27,10 +34,10 @@ export interface SyncLog {
id?: number;
/**
*
* @type {number}
* @type {Sync}
* @memberof SyncLog
*/
sync: number;
readonly sync: Sync;
/**
*
* @type {string}
@@ -72,21 +79,20 @@ export function SyncLogFromJSONTyped(json: any, ignoreDiscriminator: boolean): S
return {
'id': json['id'] == null ? undefined : json['id'],
'sync': json['sync'],
'sync': SyncFromJSON(json['sync']),
'status': json['status'],
'msg': json['msg'] == null ? undefined : json['msg'],
'createdAt': (new Date(json['created_at'])),
};
}
export function SyncLogToJSON(value?: Omit<SyncLog, 'createdAt'> | null): any {
export function SyncLogToJSON(value?: Omit<SyncLog, 'sync'|'createdAt'> | null): any {
if (value == null) {
return value;
}
return {
'id': value['id'],
'sync': value['sync'],
'status': value['status'],
'msg': value['msg'],
};

View File

@@ -64,11 +64,13 @@ export * from './PaginatedPropertyList';
export * from './PaginatedPropertyTypeList';
export * from './PaginatedRecipeBookEntryList';
export * from './PaginatedRecipeBookList';
export * from './PaginatedRecipeImportList';
export * from './PaginatedRecipeOverviewList';
export * from './PaginatedShoppingListEntryList';
export * from './PaginatedShoppingListRecipeList';
export * from './PaginatedSpaceList';
export * from './PaginatedStepList';
export * from './PaginatedStorageList';
export * from './PaginatedSupermarketCategoryList';
export * from './PaginatedSupermarketCategoryRelationList';
export * from './PaginatedSupermarketList';
@@ -106,6 +108,7 @@ export * from './PatchedPropertyType';
export * from './PatchedRecipe';
export * from './PatchedRecipeBook';
export * from './PatchedRecipeBookEntry';
export * from './PatchedRecipeImport';
export * from './PatchedShoppingListEntry';
export * from './PatchedShoppingListRecipe';
export * from './PatchedSpace';
@@ -130,6 +133,7 @@ export * from './RecipeFlat';
export * from './RecipeFromSource';
export * from './RecipeFromSourceResponse';
export * from './RecipeImage';
export * from './RecipeImport';
export * from './RecipeOverview';
export * from './RecipeShoppingUpdate';
export * from './RecipeSimple';

View File

@@ -69,6 +69,7 @@
<database-model-col model="Sync"></database-model-col>
<database-model-col model="SyncLog"></database-model-col>
<database-model-col model="Storage"></database-model-col>
<database-model-col model="RecipeImport"></database-model-col>
</v-row>
</v-container>

View File

@@ -18,12 +18,15 @@
</div>
</template>
<template #append>
<v-btn class="float-right" icon="$create" color="create">
<v-btn class="float-right" icon="$create" color="create" v-if="!genericModel.model.disableCreate">
<i class="fa-solid fa-plus"></i>
<model-edit-dialog :close-after-create="false" :model="model"
@create="loadItems({page: tablePage, itemsPerPage: useUserPreferenceStore().deviceSettings.general_tableItemsPerPage, search: searchQuery})"></model-edit-dialog>
</v-btn>
</template>
<v-card-actions v-if="genericModel.model.name == 'RecipeImport'">
<v-btn prepend-icon="fa-solid fa-rotate" color="success" @click="importAllRecipes()">{{ $t('ImportAll') }}</v-btn>
</v-card-actions>
</v-card>
</v-col>
</v-row>
@@ -48,7 +51,7 @@
<v-icon icon="$menu"></v-icon>
<v-menu activator="parent" close-on-content-click>
<v-list density="compact">
<v-list-item prepend-icon="$edit" :to="{name: 'ModelEditPage', params: {model: model, id: item.id}}">
<v-list-item prepend-icon="$edit" :to="{name: 'ModelEditPage', params: {model: model, id: item.id}}" v-if="!genericModel.model.disableCreate && !genericModel.model.disableUpdate && !genericModel.model.disableDelete" >
{{ $t('Edit') }}
</v-list-item>
<v-list-item prepend-icon="fa-solid fa-arrows-to-dot" v-if="genericModel.model.isMerge" link>
@@ -64,6 +67,13 @@
v-if="genericModel.model.name == 'Unit'">
{{ $t('Ingredient Editor') }}
</v-list-item>
<v-list-item prepend-icon="fa-solid fa-rotate" v-if="genericModel.model.name == 'Sync'" link>
{{ $t('Import') }}
<sync-dialog :sync="item"></sync-dialog>
</v-list-item>
<v-list-item prepend-icon="fa-solid fa-rotate" v-if="genericModel.model.name == 'RecipeImport'" @click="importRecipe(item)">
{{ $t('Import') }}
</v-list-item>
</v-list>
</v-menu>
</v-btn>
@@ -77,22 +87,17 @@
<script setup lang="ts">
import {onBeforeMount, onMounted, PropType, ref, watch} from "vue";
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
import {onBeforeMount, PropType, ref, watch} from "vue";
import {ErrorMessageType, useMessageStore} from "@/stores/MessageStore";
import {useI18n} from "vue-i18n";
import {
EditorSupportedModels,
GenericModel,
getGenericModelFromString, getListModels,
Model, TFood,
} from "@/types/Models";
import {VDataTable} from "vuetify/components";
import {useUrlSearchParams} from "@vueuse/core";
import {EditorSupportedModels, GenericModel, getGenericModelFromString, Model,} from "@/types/Models";
import ModelEditDialog from "@/components/dialogs/ModelEditDialog.vue";
import {useRoute, useRouter} from "vue-router";
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
import ModelMergeDialog from "@/components/dialogs/ModelMergeDialog.vue";
import {VDataTableUpdateOptions} from "@/vuetify";
import SyncDialog from "@/components/dialogs/SyncDialog.vue";
import {ApiApi, RecipeImport} from "@/openapi";
const {t} = useI18n()
const router = useRouter()
@@ -198,6 +203,34 @@ function changeModel(m: Model) {
window.scrollTo({top: 0, behavior: 'smooth'})
}
// model specific functions
/**
* convert a RecipeImport to a "real" external recipes and reload the table
* @param item
*/
function importRecipe(item: RecipeImport){
let api = new ApiApi()
api.apiRecipeImportImportRecipeCreate({id: item.id!, recipeImport: item}).then(r => {
loadItems({page: 1, itemsPerPage: useUserPreferenceStore().deviceSettings.general_tableItemsPerPage, search: searchQuery.value})
}).catch(err => {
useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err)
})
}
/**
* convert all RecipeImports to "real" external recipes and reload the table (should be empty afterwards)
*/
function importAllRecipes(){
let api = new ApiApi()
api.apiRecipeImportImportAllCreate({recipeImport: {} as RecipeImport}).then(r => {
loadItems({page: 1, itemsPerPage: useUserPreferenceStore().deviceSettings.general_tableItemsPerPage, search: searchQuery.value})
}).catch(err => {
useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err)
})
}
</script>
<style scoped>

View File

@@ -7,7 +7,7 @@ import {
MealPlan,
MealType,
Property, PropertyType,
Recipe, RecipeBook, RecipeBookEntry, ShoppingListEntry,
Recipe, RecipeBook, RecipeBookEntry, RecipeImport, ShoppingListEntry,
Step,
Supermarket,
SupermarketCategory, Sync, SyncLog,
@@ -137,6 +137,7 @@ export type EditorSupportedModels =
| 'CustomFilter'
| 'Sync'
| 'SyncLog'
| 'RecipeImport'
| 'Storage'
| 'CookLog'
| 'ViewLog'
@@ -168,6 +169,7 @@ export type EditorSupportedTypes =
| CustomFilter
| Sync
| SyncLog
| RecipeImport
| Storage
| CookLog
| ViewLog
@@ -630,7 +632,7 @@ export const TStorage = {
disableListView: false,
toStringKeys: ['name'],
isPaginated: false,
isPaginated: true,
tableHeaders: [
{title: 'Name', key: 'name'},
@@ -681,6 +683,29 @@ export const TSyncLog = {
} as Model
registerModel(TSyncLog)
export const TRecipeImport = {
name: 'RecipeImport',
localizationKey: 'ExternalRecipeImport',
localizationKeyDescription: 'ExternalRecipeImportHelp',
icon: 'fa-solid fa-file-half-dashed',
disableListView: false,
toStringKeys: ['name'],
isPaginated: true,
disableCreate: true,
disableDelete: false,
disableUpdate: false,
tableHeaders: [
{title: 'Name', key: 'name'},
{title: 'Storage', key: 'storage.name'},
{title: 'Created', key: 'createdAt'},
{title: 'Actions', key: 'action', align: 'end'},
]
} as Model
registerModel(TRecipeImport)
export const TFoodInheritField = {
name: 'FoodInheritField',
localizationKey: 'FoodInherit',