mirror of
https://github.com/TandoorRecipes/recipes.git
synced 2026-01-01 04:10:06 -05:00
importer stuff
This commit is contained in:
@@ -106,14 +106,14 @@ def get_from_scraper(scrape, request):
|
|||||||
|
|
||||||
# assign image
|
# assign image
|
||||||
try:
|
try:
|
||||||
recipe_json['image'] = parse_image(scrape.image()) or None
|
recipe_json['image_url'] = parse_image(scrape.image()) or None
|
||||||
except Exception:
|
except Exception:
|
||||||
recipe_json['image'] = None
|
recipe_json['image_url'] = None
|
||||||
if not recipe_json['image']:
|
if not recipe_json['image_url']:
|
||||||
try:
|
try:
|
||||||
recipe_json['image'] = parse_image(scrape.schema.data.get('image')) or ''
|
recipe_json['image_url'] = parse_image(scrape.schema.data.get('image')) or ''
|
||||||
except Exception:
|
except Exception:
|
||||||
recipe_json['image'] = ''
|
recipe_json['image_url'] = ''
|
||||||
|
|
||||||
# assign keywords
|
# assign keywords
|
||||||
try:
|
try:
|
||||||
|
|||||||
@@ -1609,7 +1609,7 @@ class SourceImportRecipeSerializer(serializers.Serializer):
|
|||||||
servings_text = serializers.CharField()
|
servings_text = serializers.CharField()
|
||||||
working_time = serializers.IntegerField()
|
working_time = serializers.IntegerField()
|
||||||
waiting_time = serializers.IntegerField()
|
waiting_time = serializers.IntegerField()
|
||||||
image = serializers.URLField()
|
image_url = serializers.URLField()
|
||||||
keywords = SourceImportKeywordSerializer(many=True)
|
keywords = SourceImportKeywordSerializer(many=True)
|
||||||
|
|
||||||
properties = serializers.ListField(child=SourceImportPropertySerializer())
|
properties = serializers.ListField(child=SourceImportPropertySerializer())
|
||||||
|
|||||||
@@ -7,8 +7,6 @@ models/AccessToken.ts
|
|||||||
models/AuthToken.ts
|
models/AuthToken.ts
|
||||||
models/AutoMealPlan.ts
|
models/AutoMealPlan.ts
|
||||||
models/Automation.ts
|
models/Automation.ts
|
||||||
models/AutomationTypeEnum.ts
|
|
||||||
models/BaseUnitEnum.ts
|
|
||||||
models/BookmarkletImport.ts
|
models/BookmarkletImport.ts
|
||||||
models/BookmarkletImportList.ts
|
models/BookmarkletImportList.ts
|
||||||
models/ConnectorConfigConfig.ts
|
models/ConnectorConfigConfig.ts
|
||||||
@@ -34,16 +32,6 @@ models/MealPlan.ts
|
|||||||
models/MealType.ts
|
models/MealType.ts
|
||||||
models/MethodEnum.ts
|
models/MethodEnum.ts
|
||||||
models/NutritionInformation.ts
|
models/NutritionInformation.ts
|
||||||
models/OpenDataCategory.ts
|
|
||||||
models/OpenDataConversion.ts
|
|
||||||
models/OpenDataFood.ts
|
|
||||||
models/OpenDataFoodProperty.ts
|
|
||||||
models/OpenDataProperty.ts
|
|
||||||
models/OpenDataStore.ts
|
|
||||||
models/OpenDataStoreCategory.ts
|
|
||||||
models/OpenDataUnit.ts
|
|
||||||
models/OpenDataUnitTypeEnum.ts
|
|
||||||
models/OpenDataVersion.ts
|
|
||||||
models/PaginatedAutomationList.ts
|
models/PaginatedAutomationList.ts
|
||||||
models/PaginatedBookmarkletImportListList.ts
|
models/PaginatedBookmarkletImportListList.ts
|
||||||
models/PaginatedCookLogList.ts
|
models/PaginatedCookLogList.ts
|
||||||
@@ -90,13 +78,6 @@ models/PatchedInviteLink.ts
|
|||||||
models/PatchedKeyword.ts
|
models/PatchedKeyword.ts
|
||||||
models/PatchedMealPlan.ts
|
models/PatchedMealPlan.ts
|
||||||
models/PatchedMealType.ts
|
models/PatchedMealType.ts
|
||||||
models/PatchedOpenDataCategory.ts
|
|
||||||
models/PatchedOpenDataConversion.ts
|
|
||||||
models/PatchedOpenDataFood.ts
|
|
||||||
models/PatchedOpenDataProperty.ts
|
|
||||||
models/PatchedOpenDataStore.ts
|
|
||||||
models/PatchedOpenDataUnit.ts
|
|
||||||
models/PatchedOpenDataVersion.ts
|
|
||||||
models/PatchedProperty.ts
|
models/PatchedProperty.ts
|
||||||
models/PatchedPropertyType.ts
|
models/PatchedPropertyType.ts
|
||||||
models/PatchedRecipe.ts
|
models/PatchedRecipe.ts
|
||||||
@@ -154,6 +135,7 @@ models/SupermarketCategoryRelation.ts
|
|||||||
models/Sync.ts
|
models/Sync.ts
|
||||||
models/SyncLog.ts
|
models/SyncLog.ts
|
||||||
models/ThemeEnum.ts
|
models/ThemeEnum.ts
|
||||||
|
models/TypeEnum.ts
|
||||||
models/Unit.ts
|
models/Unit.ts
|
||||||
models/UnitConversion.ts
|
models/UnitConversion.ts
|
||||||
models/User.ts
|
models/User.ts
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -13,13 +13,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { mapValues } from '../runtime';
|
import { mapValues } from '../runtime';
|
||||||
import type { AutomationTypeEnum } from './AutomationTypeEnum';
|
import type { TypeEnum } from './TypeEnum';
|
||||||
import {
|
import {
|
||||||
AutomationTypeEnumFromJSON,
|
TypeEnumFromJSON,
|
||||||
AutomationTypeEnumFromJSONTyped,
|
TypeEnumFromJSONTyped,
|
||||||
AutomationTypeEnumToJSON,
|
TypeEnumToJSON,
|
||||||
AutomationTypeEnumToJSONTyped,
|
TypeEnumToJSONTyped,
|
||||||
} from './AutomationTypeEnum';
|
} from './TypeEnum';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -35,10 +35,10 @@ export interface Automation {
|
|||||||
id?: number;
|
id?: number;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {AutomationTypeEnum}
|
* @type {TypeEnum}
|
||||||
* @memberof Automation
|
* @memberof Automation
|
||||||
*/
|
*/
|
||||||
type: AutomationTypeEnum;
|
type: TypeEnum;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -111,7 +111,7 @@ export function AutomationFromJSONTyped(json: any, ignoreDiscriminator: boolean)
|
|||||||
return {
|
return {
|
||||||
|
|
||||||
'id': json['id'] == null ? undefined : json['id'],
|
'id': json['id'] == null ? undefined : json['id'],
|
||||||
'type': AutomationTypeEnumFromJSON(json['type']),
|
'type': TypeEnumFromJSON(json['type']),
|
||||||
'name': json['name'] == null ? undefined : json['name'],
|
'name': json['name'] == null ? undefined : json['name'],
|
||||||
'description': json['description'] == null ? undefined : json['description'],
|
'description': json['description'] == null ? undefined : json['description'],
|
||||||
'param1': json['param_1'] == null ? undefined : json['param_1'],
|
'param1': json['param_1'] == null ? undefined : json['param_1'],
|
||||||
@@ -135,7 +135,7 @@ export function AutomationToJSONTyped(value?: Omit<Automation, 'created_by'> | n
|
|||||||
return {
|
return {
|
||||||
|
|
||||||
'id': value['id'],
|
'id': value['id'],
|
||||||
'type': AutomationTypeEnumToJSON(value['type']),
|
'type': TypeEnumToJSON(value['type']),
|
||||||
'name': value['name'],
|
'name': value['name'],
|
||||||
'description': value['description'],
|
'description': value['description'],
|
||||||
'param_1': value['param1'],
|
'param_1': value['param1'],
|
||||||
|
|||||||
@@ -13,13 +13,13 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import { mapValues } from '../runtime';
|
import { mapValues } from '../runtime';
|
||||||
import type { AutomationTypeEnum } from './AutomationTypeEnum';
|
import type { TypeEnum } from './TypeEnum';
|
||||||
import {
|
import {
|
||||||
AutomationTypeEnumFromJSON,
|
TypeEnumFromJSON,
|
||||||
AutomationTypeEnumFromJSONTyped,
|
TypeEnumFromJSONTyped,
|
||||||
AutomationTypeEnumToJSON,
|
TypeEnumToJSON,
|
||||||
AutomationTypeEnumToJSONTyped,
|
TypeEnumToJSONTyped,
|
||||||
} from './AutomationTypeEnum';
|
} from './TypeEnum';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
@@ -35,10 +35,10 @@ export interface PatchedAutomation {
|
|||||||
id?: number;
|
id?: number;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {AutomationTypeEnum}
|
* @type {TypeEnum}
|
||||||
* @memberof PatchedAutomation
|
* @memberof PatchedAutomation
|
||||||
*/
|
*/
|
||||||
type?: AutomationTypeEnum;
|
type?: TypeEnum;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {string}
|
* @type {string}
|
||||||
@@ -109,7 +109,7 @@ export function PatchedAutomationFromJSONTyped(json: any, ignoreDiscriminator: b
|
|||||||
return {
|
return {
|
||||||
|
|
||||||
'id': json['id'] == null ? undefined : json['id'],
|
'id': json['id'] == null ? undefined : json['id'],
|
||||||
'type': json['type'] == null ? undefined : AutomationTypeEnumFromJSON(json['type']),
|
'type': json['type'] == null ? undefined : TypeEnumFromJSON(json['type']),
|
||||||
'name': json['name'] == null ? undefined : json['name'],
|
'name': json['name'] == null ? undefined : json['name'],
|
||||||
'description': json['description'] == null ? undefined : json['description'],
|
'description': json['description'] == null ? undefined : json['description'],
|
||||||
'param1': json['param_1'] == null ? undefined : json['param_1'],
|
'param1': json['param_1'] == null ? undefined : json['param_1'],
|
||||||
@@ -133,7 +133,7 @@ export function PatchedAutomationToJSONTyped(value?: Omit<PatchedAutomation, 'cr
|
|||||||
return {
|
return {
|
||||||
|
|
||||||
'id': value['id'],
|
'id': value['id'],
|
||||||
'type': AutomationTypeEnumToJSON(value['type']),
|
'type': TypeEnumToJSON(value['type']),
|
||||||
'name': value['name'],
|
'name': value['name'],
|
||||||
'description': value['description'],
|
'description': value['description'],
|
||||||
'param_1': value['param1'],
|
'param_1': value['param1'],
|
||||||
|
|||||||
@@ -100,7 +100,7 @@ export interface SourceImportRecipe {
|
|||||||
* @type {string}
|
* @type {string}
|
||||||
* @memberof SourceImportRecipe
|
* @memberof SourceImportRecipe
|
||||||
*/
|
*/
|
||||||
image: string;
|
imageUrl: string;
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @type {Array<SourceImportKeyword>}
|
* @type {Array<SourceImportKeyword>}
|
||||||
@@ -128,7 +128,7 @@ export function instanceOfSourceImportRecipe(value: object): value is SourceImpo
|
|||||||
if (!('servingsText' in value) || value['servingsText'] === undefined) return false;
|
if (!('servingsText' in value) || value['servingsText'] === undefined) return false;
|
||||||
if (!('workingTime' in value) || value['workingTime'] === undefined) return false;
|
if (!('workingTime' in value) || value['workingTime'] === undefined) return false;
|
||||||
if (!('waitingTime' in value) || value['waitingTime'] === undefined) return false;
|
if (!('waitingTime' in value) || value['waitingTime'] === undefined) return false;
|
||||||
if (!('image' in value) || value['image'] === undefined) return false;
|
if (!('imageUrl' in value) || value['imageUrl'] === undefined) return false;
|
||||||
if (!('keywords' in value) || value['keywords'] === undefined) return false;
|
if (!('keywords' in value) || value['keywords'] === undefined) return false;
|
||||||
if (!('properties' in value) || value['properties'] === undefined) return false;
|
if (!('properties' in value) || value['properties'] === undefined) return false;
|
||||||
return true;
|
return true;
|
||||||
@@ -153,7 +153,7 @@ export function SourceImportRecipeFromJSONTyped(json: any, ignoreDiscriminator:
|
|||||||
'servingsText': json['servings_text'],
|
'servingsText': json['servings_text'],
|
||||||
'workingTime': json['working_time'],
|
'workingTime': json['working_time'],
|
||||||
'waitingTime': json['waiting_time'],
|
'waitingTime': json['waiting_time'],
|
||||||
'image': json['image'],
|
'imageUrl': json['image_url'],
|
||||||
'keywords': ((json['keywords'] as Array<any>).map(SourceImportKeywordFromJSON)),
|
'keywords': ((json['keywords'] as Array<any>).map(SourceImportKeywordFromJSON)),
|
||||||
'properties': ((json['properties'] as Array<any>).map(SourceImportPropertyFromJSON)),
|
'properties': ((json['properties'] as Array<any>).map(SourceImportPropertyFromJSON)),
|
||||||
};
|
};
|
||||||
@@ -179,7 +179,7 @@ export function SourceImportRecipeToJSONTyped(value?: SourceImportRecipe | null,
|
|||||||
'servings_text': value['servingsText'],
|
'servings_text': value['servingsText'],
|
||||||
'working_time': value['workingTime'],
|
'working_time': value['workingTime'],
|
||||||
'waiting_time': value['waitingTime'],
|
'waiting_time': value['waitingTime'],
|
||||||
'image': value['image'],
|
'image_url': value['imageUrl'],
|
||||||
'keywords': ((value['keywords'] as Array<any>).map(SourceImportKeywordToJSON)),
|
'keywords': ((value['keywords'] as Array<any>).map(SourceImportKeywordToJSON)),
|
||||||
'properties': ((value['properties'] as Array<any>).map(SourceImportPropertyToJSON)),
|
'properties': ((value['properties'] as Array<any>).map(SourceImportPropertyToJSON)),
|
||||||
};
|
};
|
||||||
|
|||||||
70
vue3/src/openapi/models/TypeEnum.ts
Normal file
70
vue3/src/openapi/models/TypeEnum.ts
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* * `FOOD_ALIAS` - Food Alias
|
||||||
|
* * `UNIT_ALIAS` - Unit Alias
|
||||||
|
* * `KEYWORD_ALIAS` - Keyword Alias
|
||||||
|
* * `DESCRIPTION_REPLACE` - Description Replace
|
||||||
|
* * `INSTRUCTION_REPLACE` - Instruction Replace
|
||||||
|
* * `NEVER_UNIT` - Never Unit
|
||||||
|
* * `TRANSPOSE_WORDS` - Transpose Words
|
||||||
|
* * `FOOD_REPLACE` - Food Replace
|
||||||
|
* * `UNIT_REPLACE` - Unit Replace
|
||||||
|
* * `NAME_REPLACE` - Name Replace
|
||||||
|
* @export
|
||||||
|
*/
|
||||||
|
export const TypeEnum = {
|
||||||
|
FoodAlias: 'FOOD_ALIAS',
|
||||||
|
UnitAlias: 'UNIT_ALIAS',
|
||||||
|
KeywordAlias: 'KEYWORD_ALIAS',
|
||||||
|
DescriptionReplace: 'DESCRIPTION_REPLACE',
|
||||||
|
InstructionReplace: 'INSTRUCTION_REPLACE',
|
||||||
|
NeverUnit: 'NEVER_UNIT',
|
||||||
|
TransposeWords: 'TRANSPOSE_WORDS',
|
||||||
|
FoodReplace: 'FOOD_REPLACE',
|
||||||
|
UnitReplace: 'UNIT_REPLACE',
|
||||||
|
NameReplace: 'NAME_REPLACE'
|
||||||
|
} as const;
|
||||||
|
export type TypeEnum = typeof TypeEnum[keyof typeof TypeEnum];
|
||||||
|
|
||||||
|
|
||||||
|
export function instanceOfTypeEnum(value: any): boolean {
|
||||||
|
for (const key in TypeEnum) {
|
||||||
|
if (Object.prototype.hasOwnProperty.call(TypeEnum, key)) {
|
||||||
|
if (TypeEnum[key as keyof typeof TypeEnum] === value) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TypeEnumFromJSON(json: any): TypeEnum {
|
||||||
|
return TypeEnumFromJSONTyped(json, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TypeEnumFromJSONTyped(json: any, ignoreDiscriminator: boolean): TypeEnum {
|
||||||
|
return json as TypeEnum;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TypeEnumToJSON(value?: TypeEnum | null): any {
|
||||||
|
return value as any;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function TypeEnumToJSONTyped(value: any, ignoreDiscriminator: boolean): TypeEnum {
|
||||||
|
return value as TypeEnum;
|
||||||
|
}
|
||||||
|
|
||||||
@@ -4,8 +4,6 @@ export * from './AccessToken';
|
|||||||
export * from './AuthToken';
|
export * from './AuthToken';
|
||||||
export * from './AutoMealPlan';
|
export * from './AutoMealPlan';
|
||||||
export * from './Automation';
|
export * from './Automation';
|
||||||
export * from './AutomationTypeEnum';
|
|
||||||
export * from './BaseUnitEnum';
|
|
||||||
export * from './BookmarkletImport';
|
export * from './BookmarkletImport';
|
||||||
export * from './BookmarkletImportList';
|
export * from './BookmarkletImportList';
|
||||||
export * from './ConnectorConfigConfig';
|
export * from './ConnectorConfigConfig';
|
||||||
@@ -31,16 +29,6 @@ export * from './MealPlan';
|
|||||||
export * from './MealType';
|
export * from './MealType';
|
||||||
export * from './MethodEnum';
|
export * from './MethodEnum';
|
||||||
export * from './NutritionInformation';
|
export * from './NutritionInformation';
|
||||||
export * from './OpenDataCategory';
|
|
||||||
export * from './OpenDataConversion';
|
|
||||||
export * from './OpenDataFood';
|
|
||||||
export * from './OpenDataFoodProperty';
|
|
||||||
export * from './OpenDataProperty';
|
|
||||||
export * from './OpenDataStore';
|
|
||||||
export * from './OpenDataStoreCategory';
|
|
||||||
export * from './OpenDataUnit';
|
|
||||||
export * from './OpenDataUnitTypeEnum';
|
|
||||||
export * from './OpenDataVersion';
|
|
||||||
export * from './PaginatedAutomationList';
|
export * from './PaginatedAutomationList';
|
||||||
export * from './PaginatedBookmarkletImportListList';
|
export * from './PaginatedBookmarkletImportListList';
|
||||||
export * from './PaginatedCookLogList';
|
export * from './PaginatedCookLogList';
|
||||||
@@ -87,13 +75,6 @@ export * from './PatchedInviteLink';
|
|||||||
export * from './PatchedKeyword';
|
export * from './PatchedKeyword';
|
||||||
export * from './PatchedMealPlan';
|
export * from './PatchedMealPlan';
|
||||||
export * from './PatchedMealType';
|
export * from './PatchedMealType';
|
||||||
export * from './PatchedOpenDataCategory';
|
|
||||||
export * from './PatchedOpenDataConversion';
|
|
||||||
export * from './PatchedOpenDataFood';
|
|
||||||
export * from './PatchedOpenDataProperty';
|
|
||||||
export * from './PatchedOpenDataStore';
|
|
||||||
export * from './PatchedOpenDataUnit';
|
|
||||||
export * from './PatchedOpenDataVersion';
|
|
||||||
export * from './PatchedProperty';
|
export * from './PatchedProperty';
|
||||||
export * from './PatchedPropertyType';
|
export * from './PatchedPropertyType';
|
||||||
export * from './PatchedRecipe';
|
export * from './PatchedRecipe';
|
||||||
@@ -151,6 +132,7 @@ export * from './SupermarketCategoryRelation';
|
|||||||
export * from './Sync';
|
export * from './Sync';
|
||||||
export * from './SyncLog';
|
export * from './SyncLog';
|
||||||
export * from './ThemeEnum';
|
export * from './ThemeEnum';
|
||||||
|
export * from './TypeEnum';
|
||||||
export * from './Unit';
|
export * from './Unit';
|
||||||
export * from './UnitConversion';
|
export * from './UnitConversion';
|
||||||
export * from './User';
|
export * from './User';
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
|
|
||||||
<v-stepper-window>
|
<v-stepper-window>
|
||||||
<v-stepper-window-item value="1">
|
<v-stepper-window-item value="1">
|
||||||
<v-card>
|
<v-card :loading="loading">
|
||||||
<v-card-text>
|
<v-card-text>
|
||||||
<v-text-field :label="$t('Website') + ' (https://...)'" @paste="nextTick(loadRecipeFromUrl())" v-model="importUrl">
|
<v-text-field :label="$t('Website') + ' (https://...)'" @paste="nextTick(loadRecipeFromUrl())" v-model="importUrl">
|
||||||
<template #append>
|
<template #append>
|
||||||
@@ -44,13 +44,13 @@
|
|||||||
<v-row>
|
<v-row>
|
||||||
<v-col cols="12" md="6">
|
<v-col cols="12" md="6">
|
||||||
<h2 class="text-h5">{{ $t('Selected') }}</h2>
|
<h2 class="text-h5">{{ $t('Selected') }}</h2>
|
||||||
<v-img max-height="30vh" :src="importResponse.recipe.image"></v-img>
|
<v-img max-height="30vh" :src="importResponse.recipe.imageUrl"></v-img>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col cols="12" md="6">
|
<v-col cols="12" md="6">
|
||||||
<h2 class="text-h5">{{ $t('Available') }}</h2>
|
<h2 class="text-h5">{{ $t('Available') }}</h2>
|
||||||
<v-row dense>
|
<v-row dense>
|
||||||
<v-col cols="4" v-for="i in importResponse.images">
|
<v-col cols="4" v-for="i in importResponse.images">
|
||||||
<v-img max-height="10vh" cover aspect-ratio="1" :src="i" @click="importResponse.recipe.image = i"></v-img>
|
<v-img max-height="10vh" cover aspect-ratio="1" :src="i" @click="importResponse.recipe.imageUrl = i"></v-img>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
</v-col>
|
</v-col>
|
||||||
@@ -72,9 +72,9 @@
|
|||||||
<v-row>
|
<v-row>
|
||||||
<v-col class="text-center">
|
<v-col class="text-center">
|
||||||
<v-btn-group border divided>
|
<v-btn-group border divided>
|
||||||
<v-btn prepend-icon="fa-solid fa-shuffle" @click="autoSortIngredients()">Auto Sort</v-btn>
|
<v-btn prepend-icon="fa-solid fa-shuffle" @click="autoSortIngredients()">{{ $t('Auto_Sort') }}</v-btn>
|
||||||
<v-btn prepend-icon="fa-solid fa-maximize" @click="splitAllSteps('\n')">Split All</v-btn>
|
<v-btn prepend-icon="fa-solid fa-maximize" @click="splitAllSteps('\n')">{{ $t('Split') }}</v-btn>
|
||||||
<v-btn prepend-icon="fa-solid fa-minimize" @click="mergeAllSteps()">Merge All</v-btn>
|
<v-btn prepend-icon="fa-solid fa-minimize" @click="mergeAllSteps()">{{ $t('Merge') }}</v-btn>
|
||||||
</v-btn-group>
|
</v-btn-group>
|
||||||
</v-col>
|
</v-col>
|
||||||
</v-row>
|
</v-row>
|
||||||
@@ -97,9 +97,12 @@
|
|||||||
<v-row>
|
<v-row>
|
||||||
<v-col>
|
<v-col>
|
||||||
<v-list>
|
<v-list>
|
||||||
<v-list-item v-for="i in s.ingredients">
|
<vue-draggable v-model="s.ingredients" group="ingredients" drag-class="drag-handle">
|
||||||
{{ i.amount }} {{ i.unit.name }} {{ i.food.name }}
|
<v-list-item v-for="i in s.ingredients">
|
||||||
</v-list-item>
|
<v-icon size="small" class="drag-handle cursor-grab" icon="$dragHandle"></v-icon>
|
||||||
|
{{ i.amount }} {{ i.unit.name }} {{ i.food.name }}
|
||||||
|
</v-list-item>
|
||||||
|
</vue-draggable>
|
||||||
</v-list>
|
</v-list>
|
||||||
</v-col>
|
</v-col>
|
||||||
<v-col>
|
<v-col>
|
||||||
@@ -114,7 +117,10 @@
|
|||||||
|
|
||||||
</v-stepper-window-item>
|
</v-stepper-window-item>
|
||||||
<v-stepper-window-item value="5">
|
<v-stepper-window-item value="5">
|
||||||
<v-btn @click="createRecipeFromImport()">Import</v-btn>
|
<v-card :loading="loading">
|
||||||
|
<v-card-title></v-card-title>
|
||||||
|
<v-btn @click="createRecipeFromImport()">{{ $t('Import') }}</v-btn>
|
||||||
|
</v-card>
|
||||||
</v-stepper-window-item>
|
</v-stepper-window-item>
|
||||||
</v-stepper-window>
|
</v-stepper-window>
|
||||||
|
|
||||||
@@ -139,10 +145,12 @@ import {ApiApi, RecipeFromSourceResponse, SourceImportStep} from "@/openapi";
|
|||||||
import {ErrorMessageType, MessageType, useMessageStore} from "@/stores/MessageStore";
|
import {ErrorMessageType, MessageType, useMessageStore} from "@/stores/MessageStore";
|
||||||
import {useRouter} from "vue-router";
|
import {useRouter} from "vue-router";
|
||||||
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
import {useUserPreferenceStore} from "@/stores/UserPreferenceStore";
|
||||||
|
import {VueDraggable} from "vue-draggable-plus";
|
||||||
|
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
|
||||||
const stepper = ref("1")
|
const stepper = ref("1")
|
||||||
|
const loading = ref(false)
|
||||||
const importUrl = ref("")
|
const importUrl = ref("")
|
||||||
|
|
||||||
const importResponse = ref({} as RecipeFromSourceResponse)
|
const importResponse = ref({} as RecipeFromSourceResponse)
|
||||||
@@ -152,6 +160,7 @@ const importResponse = ref({} as RecipeFromSourceResponse)
|
|||||||
*/
|
*/
|
||||||
function loadRecipeFromUrl() {
|
function loadRecipeFromUrl() {
|
||||||
let api = new ApiApi()
|
let api = new ApiApi()
|
||||||
|
loading.value = true
|
||||||
api.apiRecipeFromSourceCreate({recipeFromSource: {url: importUrl.value}}).then(r => {
|
api.apiRecipeFromSourceCreate({recipeFromSource: {url: importUrl.value}}).then(r => {
|
||||||
importResponse.value = r
|
importResponse.value = r
|
||||||
if (r.duplicates.length == 0) {
|
if (r.duplicates.length == 0) {
|
||||||
@@ -160,6 +169,8 @@ function loadRecipeFromUrl() {
|
|||||||
}
|
}
|
||||||
}).catch(err => {
|
}).catch(err => {
|
||||||
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
useMessageStore().addError(ErrorMessageType.FETCH_ERROR, err)
|
||||||
|
}).finally(() => {
|
||||||
|
loading.value = false
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,12 +179,21 @@ function loadRecipeFromUrl() {
|
|||||||
*/
|
*/
|
||||||
function createRecipeFromImport() {
|
function createRecipeFromImport() {
|
||||||
let api = new ApiApi()
|
let api = new ApiApi()
|
||||||
console.log(importResponse.value)
|
|
||||||
api.apiRecipeCreate({recipe: importResponse.value.recipe}).then(r => {
|
if (importResponse.value.recipe) {
|
||||||
router.push({name: 'view_recipe', params: {id: r.id}})
|
loading.value = true
|
||||||
}).catch(err => {
|
importResponse.value.recipe.keywords = importResponse.value.recipe.keywords.filter(k => k.importKeyword)
|
||||||
useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err)
|
|
||||||
})
|
api.apiRecipeCreate({recipe: importResponse.value.recipe}).then(r => {
|
||||||
|
api.apiRecipeImageUpdate({id: r.id, imageUrl: importResponse.value.recipe?.imageUrl}).then(rI => {
|
||||||
|
router.push({name: 'view_recipe', params: {id: r.id}})
|
||||||
|
}).finally(() => {
|
||||||
|
loading.value = false
|
||||||
|
})
|
||||||
|
}).catch(err => {
|
||||||
|
useMessageStore().addError(ErrorMessageType.CREATE_ERROR, err)
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -181,8 +201,8 @@ function createRecipeFromImport() {
|
|||||||
* @param step step to delete
|
* @param step step to delete
|
||||||
*/
|
*/
|
||||||
function deleteStep(step: SourceImportStep) {
|
function deleteStep(step: SourceImportStep) {
|
||||||
if(importResponse.value.recipe){
|
if (importResponse.value.recipe) {
|
||||||
importResponse.value.recipe.steps.splice(importResponse.value.recipe.steps.findIndex(x => x === step),1)
|
importResponse.value.recipe.steps.splice(importResponse.value.recipe.steps.findIndex(x => x === step), 1)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -285,7 +305,7 @@ function autoSortIngredients() {
|
|||||||
s.ingredients.push(i)
|
s.ingredients.push(i)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
if(!found){
|
if (!found) {
|
||||||
importResponse.value.recipe!.steps[0].ingredients.push(i)
|
importResponse.value.recipe!.steps[0].ingredients.push(i)
|
||||||
}
|
}
|
||||||
// TODO implement a new "second try" algorithm if no exact match was found
|
// TODO implement a new "second try" algorithm if no exact match was found
|
||||||
|
|||||||
@@ -1,43 +1,35 @@
|
|||||||
<template>
|
<template>
|
||||||
<v-container class="ps-0 pe-0 pt-0">
|
<v-container :class="{'ps-0 pe-0 pt-0': mobile}">
|
||||||
<RecipeView :recipe="recipe"></RecipeView>
|
<RecipeView :recipe="recipe"></RecipeView>
|
||||||
</v-container>
|
</v-container>
|
||||||
|
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script lang="ts">
|
<script setup lang="ts">
|
||||||
import {defineComponent} from 'vue'
|
import {defineComponent, onMounted, ref} from 'vue'
|
||||||
import {ApiApi, Recipe} from "@/openapi";
|
import {ApiApi, Recipe} from "@/openapi";
|
||||||
import RecipeView from "@/components/display/RecipeView.vue";
|
import RecipeView from "@/components/display/RecipeView.vue";
|
||||||
|
import {useDisplay} from "vuetify";
|
||||||
|
|
||||||
export default defineComponent({
|
const props = defineProps({
|
||||||
name: "RecipeSearchPage",
|
id: {type: String, required: true}
|
||||||
components: {RecipeView},
|
|
||||||
watch: {
|
|
||||||
id: function (newValue) {
|
|
||||||
this.refreshData(newValue)
|
|
||||||
},
|
|
||||||
},
|
|
||||||
props: {
|
|
||||||
id: {type: String, required: true}
|
|
||||||
},
|
|
||||||
data() {
|
|
||||||
return {
|
|
||||||
recipe: {} as Recipe
|
|
||||||
}
|
|
||||||
},
|
|
||||||
mounted() {
|
|
||||||
this.refreshData(this.id)
|
|
||||||
},
|
|
||||||
methods: {
|
|
||||||
refreshData(recipeId: string) {
|
|
||||||
const api = new ApiApi()
|
|
||||||
api.apiRecipeRetrieve({id: Number(recipeId)}).then(r => {
|
|
||||||
this.recipe = r
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const {mobile} = useDisplay()
|
||||||
|
|
||||||
|
const recipe = ref({} as Recipe)
|
||||||
|
|
||||||
|
onMounted(() => {
|
||||||
|
refreshData(props.id)
|
||||||
|
})
|
||||||
|
|
||||||
|
function refreshData(recipeId: string) {
|
||||||
|
const api = new ApiApi()
|
||||||
|
api.apiRecipeRetrieve({id: Number(recipeId)}).then(r => {
|
||||||
|
recipe.value = r
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
<style scoped>
|
||||||
|
|||||||
@@ -1,3 +1,7 @@
|
|||||||
|
import {getCookie} from "@/utils/cookie";
|
||||||
|
import {Recipe, RecipeFromJSON, RecipeImageFromJSON, UserFileFromJSON} from "@/openapi";
|
||||||
|
import {ErrorMessageType, PreparedMessage, useMessageStore} from "@/stores/MessageStore";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a nested property of an object given a dot-notation path.
|
* Gets a nested property of an object given a dot-notation path.
|
||||||
*
|
*
|
||||||
@@ -6,13 +10,42 @@
|
|||||||
* @returns The value of the nested property, or `undefined` if not found.
|
* @returns The value of the nested property, or `undefined` if not found.
|
||||||
*/
|
*/
|
||||||
export function getNestedProperty(object: any, path: string): any {
|
export function getNestedProperty(object: any, path: string): any {
|
||||||
const pathParts = path.split('.');
|
const pathParts = path.split('.');
|
||||||
|
|
||||||
|
return pathParts.reduce((obj, key) => {
|
||||||
|
if (obj && typeof obj === 'object') {
|
||||||
|
return obj[key]
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
}, object);
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO just some partial code
|
||||||
|
/**
|
||||||
|
* I currently don't know how to do this properly through the API client so this
|
||||||
|
* helper function uploads files for now
|
||||||
|
*/
|
||||||
|
export function uploadRecipeImage(recipeId: number, file: File) {
|
||||||
|
let formData = new FormData()
|
||||||
|
formData.append('image', file)
|
||||||
|
|
||||||
|
//TODO proper URL finding (sub path setups)
|
||||||
|
// TODO maybe better use existing URL clients response functions for parsing
|
||||||
|
|
||||||
|
fetch('/api/recipe/' + recipeId + '/image/', {
|
||||||
|
method: 'PUT',
|
||||||
|
headers: {'X-CSRFToken': getCookie('csrftoken')},
|
||||||
|
body: formData
|
||||||
|
}).then(r => {
|
||||||
|
r.json().then(r => {
|
||||||
|
return RecipeImageFromJSON(r)
|
||||||
|
})
|
||||||
|
|
||||||
|
}).catch(err => {
|
||||||
|
useMessageStore().addError(ErrorMessageType.UPDATE_ERROR, err)
|
||||||
|
}).finally(() => {
|
||||||
|
|
||||||
|
})
|
||||||
|
|
||||||
return pathParts.reduce((obj, key) => {
|
|
||||||
if (obj && typeof obj === 'object') {
|
|
||||||
return obj[key]
|
|
||||||
} else {
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
}, object);
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user