chore: migrate remaining pages to script setup (#7310)

This commit is contained in:
Kuchenpirat
2026-03-24 16:07:08 +01:00
committed by GitHub
parent 27cb585c80
commit 18b3c4beab
57 changed files with 4160 additions and 4971 deletions

View File

@@ -34,93 +34,87 @@
</v-container>
</template>
<script lang="ts">
export default defineNuxtComponent({
<script setup lang="ts">
definePageMeta({
middleware: ["can-organize-only"],
setup() {
const i18n = useI18n();
const buttonLookup: { [key: string]: string } = {
recipes: i18n.t("general.recipes"),
recipeActions: i18n.t("recipe.recipe-actions"),
foods: i18n.t("general.foods"),
units: i18n.t("general.units"),
labels: i18n.t("data-pages.labels.labels"),
categories: i18n.t("category.categories"),
tags: i18n.t("tag.tags"),
tools: i18n.t("tool.tools"),
};
});
const route = useRoute();
const i18n = useI18n();
const buttonLookup: { [key: string]: string } = {
recipes: i18n.t("general.recipes"),
recipeActions: i18n.t("recipe.recipe-actions"),
foods: i18n.t("general.foods"),
units: i18n.t("general.units"),
labels: i18n.t("data-pages.labels.labels"),
categories: i18n.t("category.categories"),
tags: i18n.t("tag.tags"),
tools: i18n.t("tool.tools"),
};
const DATA_TYPE_OPTIONS = computed(() => [
{
text: i18n.t("general.recipes"),
value: "new",
to: "/group/data/recipes",
},
{
text: i18n.t("recipe.recipe-actions"),
value: "new",
to: "/group/data/recipe-actions",
divider: true,
},
{
text: i18n.t("general.foods"),
value: "url",
to: "/group/data/foods",
},
{
text: i18n.t("general.units"),
value: "new",
to: "/group/data/units",
},
{
text: i18n.t("data-pages.labels.labels"),
value: "new",
to: "/group/data/labels",
divider: true,
},
{
text: i18n.t("category.categories"),
value: "new",
to: "/group/data/categories",
},
{
text: i18n.t("tag.tags"),
value: "new",
to: "/group/data/tags",
},
{
text: i18n.t("tool.tools"),
value: "new",
to: "/group/data/tools",
},
]);
const route = useRoute();
const buttonText = computed(() => {
const last = route.path
.split("/")
.pop()
// convert hypenated-values to camelCase
?.replace(/-([a-z])/g, function (g) {
return g[1].toUpperCase();
});
if (last) {
return buttonLookup[last];
}
return i18n.t("data-pages.select-data");
});
useSeoMeta({
title: i18n.t("data-pages.data-management"),
});
return {
buttonText,
DATA_TYPE_OPTIONS,
};
const DATA_TYPE_OPTIONS = computed(() => [
{
text: i18n.t("general.recipes"),
value: "new",
to: "/group/data/recipes",
},
{
text: i18n.t("recipe.recipe-actions"),
value: "new",
to: "/group/data/recipe-actions",
divider: true,
},
{
text: i18n.t("general.foods"),
value: "url",
to: "/group/data/foods",
},
{
text: i18n.t("general.units"),
value: "new",
to: "/group/data/units",
},
{
text: i18n.t("data-pages.labels.labels"),
value: "new",
to: "/group/data/labels",
divider: true,
},
{
text: i18n.t("category.categories"),
value: "new",
to: "/group/data/categories",
},
{
text: i18n.t("tag.tags"),
value: "new",
to: "/group/data/tags",
},
{
text: i18n.t("tool.tools"),
value: "new",
to: "/group/data/tools",
},
]);
const buttonText = computed(() => {
const last = route.path
.split("/")
.pop()
// convert hypenated-values to camelCase
?.replace(/-([a-z])/g, function (g) {
return g[1].toUpperCase();
});
if (last) {
return buttonLookup[last];
}
return i18n.t("data-pages.select-data");
});
useSeoMeta({
title: i18n.t("data-pages.data-management"),
});
</script>

View File

@@ -19,7 +19,7 @@
</div>
</template>
<script setup lang="ts">
<script setup lang="ts">
import { useCategoryStore } from "~/composables/store";
import { validators } from "~/composables/use-validators";
import { fieldTypes } from "~/composables/forms";

View File

@@ -2,15 +2,10 @@
<div />
</template>
<script lang="ts">
export default defineNuxtComponent({
setup() {
const router = useRouter();
onMounted(() => {
// Force redirect to first valid page
router.push("/group/data/foods");
});
return {};
},
<script setup lang="ts">
const router = useRouter();
onMounted(() => {
// Force redirect to first valid page
router.push("/group/data/foods");
});
</script>

View File

@@ -226,7 +226,7 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import RecipeDataTable from "~/components/Domain/Recipe/RecipeDataTable.vue";
import RecipeOrganizerSelector from "~/components/Domain/Recipe/RecipeOrganizerSelector.vue";
import { useUserApi } from "~/composables/api";
@@ -249,295 +249,266 @@ enum MODES {
changeOwner = "changeOwner",
}
export default defineNuxtComponent({
components: { RecipeDataTable, RecipeOrganizerSelector, GroupExportData, RecipeSettingsSwitches, UserAvatar },
definePageMeta({
scrollToTop: true,
setup() {
const i18n = useI18n();
const auth = useMealieAuth();
const { $globals } = useNuxtApp();
});
useSeoMeta({
title: i18n.t("data-pages.recipes.recipe-data"),
});
const i18n = useI18n();
const auth = useMealieAuth();
const { $globals } = useNuxtApp();
const { getAllRecipes, refreshRecipes } = useRecipes(true, true, false, `householdId=${auth.user.value?.householdId || ""}`);
const selected = ref<Recipe[]>([]);
useSeoMeta({
title: i18n.t("data-pages.recipes.recipe-data"),
});
function resetAll() {
selected.value = [];
toSetTags.value = [];
toSetCategories.value = [];
loading.value = false;
}
const { refreshRecipes } = useRecipes(true, true, false, `householdId=${auth.user.value?.householdId || ""}`);
const selected = ref<Recipe[]>([]);
const headers = reactive({
id: false,
owner: false,
tags: true,
tools: true,
categories: true,
recipeServings: false,
recipeYieldQuantity: false,
recipeYield: false,
dateAdded: false,
});
function resetAll() {
selected.value = [];
toSetTags.value = [];
toSetCategories.value = [];
loading.value = false;
}
const headerLabels = {
id: i18n.t("general.id"),
owner: i18n.t("general.owner"),
tags: i18n.t("tag.tags"),
categories: i18n.t("recipe.categories"),
tools: i18n.t("tool.tools"),
recipeServings: i18n.t("recipe.recipe-servings"),
recipeYieldQuantity: i18n.t("recipe.recipe-yield"),
recipeYield: i18n.t("recipe.recipe-yield-text"),
dateAdded: i18n.t("general.date-added"),
};
const headers = reactive({
id: false,
owner: false,
tags: true,
tools: true,
categories: true,
recipeServings: false,
recipeYieldQuantity: false,
recipeYield: false,
dateAdded: false,
});
const actions: MenuItem[] = [
{
icon: $globals.icons.database,
text: i18n.t("export.export"),
event: "export-selected",
},
{
icon: $globals.icons.tags,
text: i18n.t("data-pages.recipes.tag"),
event: "tag-selected",
},
{
icon: $globals.icons.categories,
text: i18n.t("data-pages.recipes.categorize"),
event: "categorize-selected",
},
{
icon: $globals.icons.cog,
text: i18n.t("data-pages.recipes.update-settings"),
event: "update-settings",
},
{
icon: $globals.icons.user,
text: i18n.t("general.change-owner"),
event: "change-owner",
},
{
icon: $globals.icons.delete,
text: i18n.t("general.delete"),
event: "delete-selected",
},
];
const headerLabels = {
id: i18n.t("general.id"),
owner: i18n.t("general.owner"),
tags: i18n.t("tag.tags"),
categories: i18n.t("recipe.categories"),
tools: i18n.t("tool.tools"),
recipeServings: i18n.t("recipe.recipe-servings"),
recipeYieldQuantity: i18n.t("recipe.recipe-yield"),
recipeYield: i18n.t("recipe.recipe-yield-text"),
dateAdded: i18n.t("general.date-added"),
};
const api = useUserApi();
const loading = ref(false);
// ===============================================================
// Group Exports
const purgeExportsDialog = ref(false);
async function purgeExports() {
await api.bulk.purgeExports();
refreshExports();
}
const groupExports = ref<GroupDataExport[]>([]);
async function refreshExports() {
const { data } = await api.bulk.fetchExports();
if (data) {
groupExports.value = data;
}
}
onMounted(async () => {
await refreshExports();
});
// ===============================================================
// All Recipes
function selectAll() {
selected.value = allRecipes.value;
}
async function exportSelected() {
loading.value = true;
const { data } = await api.bulk.bulkExport({
recipes: selected.value.map((x: Recipe) => x.slug ?? ""),
exportType: "json",
});
if (data) {
console.log(data);
}
resetAll();
refreshExports();
}
const toSetTags = ref([]);
async function tagSelected() {
loading.value = true;
const recipes = selected.value.map((x: Recipe) => x.slug ?? "");
await api.bulk.bulkTag({ recipes, tags: toSetTags.value });
await refreshRecipes();
resetAll();
}
const toSetCategories = ref([]);
async function categorizeSelected() {
loading.value = true;
const recipes = selected.value.map((x: Recipe) => x.slug ?? "");
await api.bulk.bulkCategorize({ recipes, categories: toSetCategories.value });
await refreshRecipes();
resetAll();
}
async function deleteSelected() {
loading.value = true;
const recipes = selected.value.map((x: Recipe) => x.slug ?? "");
await api.bulk.bulkDelete({ recipes });
await refreshRecipes();
resetAll();
}
const recipeSettings = reactive<RecipeSettings>({
public: false,
showNutrition: false,
showAssets: false,
landscapeView: false,
disableComments: false,
locked: false,
});
async function updateSettings() {
loading.value = true;
const recipes = selected.value.map((x: Recipe) => x.slug ?? "");
await api.bulk.bulkSetSettings({ recipes, settings: recipeSettings });
await refreshRecipes();
resetAll();
}
async function changeOwner() {
if (!selected.value.length || !selectedOwner.value) {
return;
}
selected.value.forEach((r) => {
r.userId = selectedOwner.value;
});
loading.value = true;
await api.recipes.patchMany(selected.value);
await refreshRecipes();
resetAll();
}
// ============================================================
// Dialog Management
const dialog = reactive({
state: false,
title: i18n.t("data-pages.recipes.tag-recipes"),
mode: MODES.tag,
tag: "",
callback: () => {
// Stub function to be overwritten
return Promise.resolve();
},
icon: $globals.icons.tags,
});
function openDialog(mode: MODES) {
const titles: Record<MODES, string> = {
[MODES.tag]: i18n.t("data-pages.recipes.tag-recipes"),
[MODES.category]: i18n.t("data-pages.recipes.categorize-recipes"),
[MODES.export]: i18n.t("data-pages.recipes.export-recipes"),
[MODES.delete]: i18n.t("data-pages.recipes.delete-recipes"),
[MODES.updateSettings]: i18n.t("data-pages.recipes.update-settings"),
[MODES.changeOwner]: i18n.t("general.change-owner"),
};
const callbacks: Record<MODES, () => Promise<void>> = {
[MODES.tag]: tagSelected,
[MODES.category]: categorizeSelected,
[MODES.export]: exportSelected,
[MODES.delete]: deleteSelected,
[MODES.updateSettings]: updateSettings,
[MODES.changeOwner]: changeOwner,
};
const icons: Record<MODES, string> = {
[MODES.tag]: $globals.icons.tags,
[MODES.category]: $globals.icons.categories,
[MODES.export]: $globals.icons.database,
[MODES.delete]: $globals.icons.delete,
[MODES.updateSettings]: $globals.icons.cog,
[MODES.changeOwner]: $globals.icons.user,
};
dialog.mode = mode;
dialog.title = titles[mode];
dialog.callback = callbacks[mode];
dialog.icon = icons[mode];
dialog.state = true;
}
const { store: allUsers } = useUserStore();
const { store: households } = useHouseholdStore();
const selectedOwner = ref("");
const selectedOwnerHousehold = computed(() => {
if (!selectedOwner.value) {
return null;
}
const owner = allUsers.value.find(u => u.id === selectedOwner.value);
if (!owner) {
return null;
};
return households.value.find(h => h.id === owner.householdId);
});
return {
recipeSettings,
selectAll,
loading,
actions,
allRecipes,
categorizeSelected,
deleteSelected,
dialog,
exportSelected,
getAllRecipes,
headerLabels,
headers,
MODES,
openDialog,
selected,
tagSelected,
toSetCategories,
toSetTags,
groupExports,
purgeExportsDialog,
purgeExports,
allUsers,
selectedOwner,
selectedOwnerHousehold,
};
const actions: MenuItem[] = [
{
icon: $globals.icons.database,
text: i18n.t("export.export"),
event: "export-selected",
},
{
icon: $globals.icons.tags,
text: i18n.t("data-pages.recipes.tag"),
event: "tag-selected",
},
{
icon: $globals.icons.categories,
text: i18n.t("data-pages.recipes.categorize"),
event: "categorize-selected",
},
{
icon: $globals.icons.cog,
text: i18n.t("data-pages.recipes.update-settings"),
event: "update-settings",
},
{
icon: $globals.icons.user,
text: i18n.t("general.change-owner"),
event: "change-owner",
},
{
icon: $globals.icons.delete,
text: i18n.t("general.delete"),
event: "delete-selected",
},
];
const api = useUserApi();
const loading = ref(false);
// ===============================================================
// Group Exports
const purgeExportsDialog = ref(false);
async function purgeExports() {
await api.bulk.purgeExports();
refreshExports();
}
const groupExports = ref<GroupDataExport[]>([]);
async function refreshExports() {
const { data } = await api.bulk.fetchExports();
if (data) {
groupExports.value = data;
}
}
onMounted(async () => {
await refreshExports();
});
// ===============================================================
// All Recipes
function selectAll() {
selected.value = allRecipes.value;
}
async function exportSelected() {
loading.value = true;
const { data } = await api.bulk.bulkExport({
recipes: selected.value.map((x: Recipe) => x.slug ?? ""),
exportType: "json",
});
if (data) {
console.log(data);
}
resetAll();
refreshExports();
}
const toSetTags = ref([]);
async function tagSelected() {
loading.value = true;
const recipes = selected.value.map((x: Recipe) => x.slug ?? "");
await api.bulk.bulkTag({ recipes, tags: toSetTags.value });
await refreshRecipes();
resetAll();
}
const toSetCategories = ref([]);
async function categorizeSelected() {
loading.value = true;
const recipes = selected.value.map((x: Recipe) => x.slug ?? "");
await api.bulk.bulkCategorize({ recipes, categories: toSetCategories.value });
await refreshRecipes();
resetAll();
}
async function deleteSelected() {
loading.value = true;
const recipes = selected.value.map((x: Recipe) => x.slug ?? "");
await api.bulk.bulkDelete({ recipes });
await refreshRecipes();
resetAll();
}
const recipeSettings = reactive<RecipeSettings>({
public: false,
showNutrition: false,
showAssets: false,
landscapeView: false,
disableComments: false,
locked: false,
});
async function updateSettings() {
loading.value = true;
const recipes = selected.value.map((x: Recipe) => x.slug ?? "");
await api.bulk.bulkSetSettings({ recipes, settings: recipeSettings });
await refreshRecipes();
resetAll();
}
async function changeOwner() {
if (!selected.value.length || !selectedOwner.value) {
return;
}
selected.value.forEach((r) => {
r.userId = selectedOwner.value;
});
loading.value = true;
await api.recipes.patchMany(selected.value);
await refreshRecipes();
resetAll();
}
// ============================================================
// Dialog Management
const dialog = reactive({
state: false,
title: i18n.t("data-pages.recipes.tag-recipes"),
mode: MODES.tag,
tag: "",
callback: () => {
// Stub function to be overwritten
return Promise.resolve();
},
icon: $globals.icons.tags,
});
function openDialog(mode: MODES) {
const titles: Record<MODES, string> = {
[MODES.tag]: i18n.t("data-pages.recipes.tag-recipes"),
[MODES.category]: i18n.t("data-pages.recipes.categorize-recipes"),
[MODES.export]: i18n.t("data-pages.recipes.export-recipes"),
[MODES.delete]: i18n.t("data-pages.recipes.delete-recipes"),
[MODES.updateSettings]: i18n.t("data-pages.recipes.update-settings"),
[MODES.changeOwner]: i18n.t("general.change-owner"),
};
const callbacks: Record<MODES, () => Promise<void>> = {
[MODES.tag]: tagSelected,
[MODES.category]: categorizeSelected,
[MODES.export]: exportSelected,
[MODES.delete]: deleteSelected,
[MODES.updateSettings]: updateSettings,
[MODES.changeOwner]: changeOwner,
};
const icons: Record<MODES, string> = {
[MODES.tag]: $globals.icons.tags,
[MODES.category]: $globals.icons.categories,
[MODES.export]: $globals.icons.database,
[MODES.delete]: $globals.icons.delete,
[MODES.updateSettings]: $globals.icons.cog,
[MODES.changeOwner]: $globals.icons.user,
};
dialog.mode = mode;
dialog.title = titles[mode];
dialog.callback = callbacks[mode];
dialog.icon = icons[mode];
dialog.state = true;
}
const { store: allUsers } = useUserStore();
const { store: households } = useHouseholdStore();
const selectedOwner = ref("");
const selectedOwnerHousehold = computed(() => {
if (!selectedOwner.value) {
return null;
}
const owner = allUsers.value.find(u => u.id === selectedOwner.value);
if (!owner) {
return null;
};
return households.value.find(h => h.id === owner.householdId);
});
</script>

View File

@@ -43,24 +43,18 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useGroupSelf } from "~/composables/use-groups";
export default defineNuxtComponent({
definePageMeta({
middleware: ["can-manage-only"],
setup() {
const { group, actions: groupActions } = useGroupSelf();
const i18n = useI18n();
});
useSeoMeta({
title: i18n.t("group.group"),
});
const { group, actions: groupActions } = useGroupSelf();
const i18n = useI18n();
return {
group,
groupActions,
};
},
useSeoMeta({
title: i18n.t("group.group"),
});
</script>

View File

@@ -19,7 +19,7 @@
<BaseCardSectionTitle :title="$t('migration.new-migration')" />
<v-card
variant="outlined"
:loading="loading"
:loading="state.loading"
style="border-color: lightgrey;"
>
<v-card-title> {{ $t('migration.choose-migration-type') }} </v-card-title>
@@ -29,7 +29,7 @@
>
<div class="mb-2">
<BaseOverflowButton
v-model="migrationType"
v-model="state.migrationType"
mode="model"
:items="items"
/>
@@ -37,7 +37,7 @@
{{ content.text }}
<v-treeview
v-if="content.tree && Array.isArray(content.tree)"
:key="migrationType"
:key="state.migrationType"
density="compact"
:items="content.tree"
>
@@ -59,15 +59,15 @@
:text-btn="false"
@uploaded="setFileObject"
/>
{{ fileObject.name || $t('migration.no-file-selected') }}
{{ state.fileObject.name || $t('migration.no-file-selected') }}
</v-card-text>
<v-card-text>
<v-checkbox v-model="addMigrationTag">
<v-checkbox v-model="state.addMigrationTag">
<template #label>
<i18n-t keypath="migration.tag-all-recipes">
<template #tag-name>
<b class="mx-1"> {{ migrationType }} </b>
<b class="mx-1"> {{ state.migrationType }} </b>
</template>
</i18n-t>
</template>
@@ -76,7 +76,7 @@
<v-card-actions class="justify-end">
<BaseButton
:disabled="!fileObject.name"
:disabled="!state.fileObject.name"
submit
@click="startMigration"
>
@@ -88,14 +88,14 @@
<v-container class="$vuetify.display.smAndDown ? 'px-0': ''">
<BaseCardSectionTitle :title="$t('migration.previous-migrations')" />
<ReportTable
:items="reports"
:items="state.reports"
@delete="deleteReport"
/>
</v-container>
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import type { ReportSummary } from "~/lib/api/types/reports";
import type { MenuItem } from "~/components/global/BaseOverflowButton.vue";
import { useUserApi } from "~/composables/api";
@@ -127,398 +127,387 @@ const MIGRATIONS = {
cookn: "cookn",
};
export default defineNuxtComponent({
definePageMeta({
middleware: ["advanced-only"],
setup() {
const i18n = useI18n();
const { $globals } = useNuxtApp();
});
useSeoMeta({
title: i18n.t("settings.migrations"),
});
const i18n = useI18n();
const { $globals } = useNuxtApp();
const api = useUserApi();
useSeoMeta({
title: i18n.t("settings.migrations"),
});
const state = reactive({
addMigrationTag: false,
loading: false,
treeState: true,
migrationType: MIGRATIONS.mealie as SupportedMigrations,
fileObject: {} as File,
reports: [] as ReportSummary[],
});
const api = useUserApi();
const items: MenuItem[] = [
{
text: i18n.t("migration.mealie-pre-v1.title"),
value: MIGRATIONS.mealie,
divider: true,
},
{
text: i18n.t("migration.chowdown.title"),
value: MIGRATIONS.chowdown,
},
{
text: i18n.t("migration.copymethat.title"),
value: MIGRATIONS.copymethat,
},
{
text: i18n.t("migration.myrecipebox.title"),
value: MIGRATIONS.myrecipebox,
},
{
text: i18n.t("migration.nextcloud.title"),
value: MIGRATIONS.nextcloud,
},
{
text: i18n.t("migration.paprika.title"),
value: MIGRATIONS.paprika,
},
{
text: i18n.t("migration.plantoeat.title"),
value: MIGRATIONS.plantoeat,
},
{
text: i18n.t("migration.recipekeeper.title"),
value: MIGRATIONS.recipekeeper,
},
{
text: i18n.t("migration.tandoor.title"),
value: MIGRATIONS.tandoor,
},
{
text: i18n.t("migration.cookn.title"),
value: MIGRATIONS.cookn,
},
];
const _content: Record<string, MigrationContent> = {
[MIGRATIONS.mealie]: {
text: i18n.t("migration.mealie-pre-v1.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "mealie.zip",
children: [
{
title: "recipes",
icon: $globals.icons.folderOutline,
children: [
{
title: "recipe-name",
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe-name.json", icon: $globals.icons.codeJson },
{
title: "images",
icon: $globals.icons.folderOutline,
children: [
{ title: "original.webp", icon: $globals.icons.codeJson },
{ title: "full.jpg", icon: $globals.icons.fileImage },
{ title: "thumb.jpg", icon: $globals.icons.fileImage },
],
},
],
},
{
title: "recipe-name-1",
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe-name-1.json", icon: $globals.icons.codeJson },
{
title: "images",
icon: $globals.icons.folderOutline,
children: [
{ title: "original.webp", icon: $globals.icons.codeJson },
{ title: "full.jpg", icon: $globals.icons.fileImage },
{ title: "thumb.jpg", icon: $globals.icons.fileImage },
],
},
],
},
],
},
],
},
],
},
[MIGRATIONS.chowdown]: {
text: i18n.t("migration.chowdown.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "nextcloud.zip",
children: [
{
title: i18n.t("migration.recipe-1"),
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe.json", icon: $globals.icons.codeJson },
{ title: "full.jpg", icon: $globals.icons.fileImage },
{ title: "thumb.jpg", icon: $globals.icons.fileImage },
],
},
{
title: i18n.t("migration.recipe-2"),
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe.json", icon: $globals.icons.codeJson },
{ title: "full.jpg", icon: $globals.icons.fileImage },
{ title: "thumb.jpg", icon: $globals.icons.fileImage },
],
},
],
},
],
},
[MIGRATIONS.copymethat]: {
text: i18n.t("migration.copymethat.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "Copy_Me_That_20230306.zip",
children: [
{
title: "images",
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe_1_an5zy.jpg", icon: $globals.icons.fileImage },
{ title: "recipe_2_82el8.jpg", icon: $globals.icons.fileImage },
{ title: "recipe_3_j75qg.jpg", icon: $globals.icons.fileImage },
],
},
{ title: "recipes.html", icon: $globals.icons.codeJson },
],
},
],
},
[MIGRATIONS.myrecipebox]: {
text: i18n.t("migration.myrecipebox.description-long"),
acceptedFileType: ".csv",
tree: false,
},
[MIGRATIONS.nextcloud]: {
text: i18n.t("migration.nextcloud.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "nextcloud.zip",
children: [
{
title: i18n.t("migration.recipe-1"),
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe.json", icon: $globals.icons.codeJson },
{ title: "full.jpg", icon: $globals.icons.fileImage },
{ title: "thumb.jpg", icon: $globals.icons.fileImage },
],
},
{
title: i18n.t("migration.recipe-2"),
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe.json", icon: $globals.icons.codeJson },
{ title: "full.jpg", icon: $globals.icons.fileImage },
{ title: "thumb.jpg", icon: $globals.icons.fileImage },
],
},
],
},
],
},
[MIGRATIONS.paprika]: {
text: i18n.t("migration.paprika.description-long"),
acceptedFileType: ".zip",
tree: false,
},
[MIGRATIONS.plantoeat]: {
text: i18n.t("migration.plantoeat.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "plantoeat-recipes-508318_10-13-2023.zip",
children: [
{ title: "plantoeat-recipes-508318_10-13-2023.csv", icon: $globals.icons.codeJson },
],
},
],
},
[MIGRATIONS.recipekeeper]: {
text: i18n.t("migration.recipekeeper.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "recipekeeperhtml.zip",
children: [
{ title: "recipes.html", icon: $globals.icons.codeJson },
{
title: "images", icon: $globals.icons.folderOutline,
children: [
{ title: "image1.jpg", icon: $globals.icons.fileImage },
{ title: "image2.jpg", icon: $globals.icons.fileImage },
],
},
],
},
],
},
[MIGRATIONS.tandoor]: {
text: i18n.t("migration.tandoor.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "tandoor_default_export_full_2023-06-29.zip",
children: [
{
title: "1.zip",
icon: $globals.icons.zip,
children: [
{ title: "image.jpeg", icon: $globals.icons.fileImage },
{ title: "recipe.json", icon: $globals.icons.codeJson },
],
},
{
title: "2.zip",
icon: $globals.icons.zip,
children: [
{ title: "image.jpeg", icon: $globals.icons.fileImage },
{ title: "recipe.json", icon: $globals.icons.codeJson },
],
},
{
title: "3.zip",
icon: $globals.icons.zip,
children: [
{ title: "image.jpeg", icon: $globals.icons.fileImage },
{ title: "recipe.json", icon: $globals.icons.codeJson },
],
},
],
},
],
},
[MIGRATIONS.cookn]: {
text: i18n.t("migration.cookn.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "cookn.zip",
children: [
{ title: "temp_brand.dsv", icon: $globals.icons.codeJson },
{ title: "temp_chapter_desc.dsv", icon: $globals.icons.codeJson },
{ title: "temp_chapter.dsv", icon: $globals.icons.codeJson },
{ title: "temp_cookBook_desc.dsv", icon: $globals.icons.codeJson },
{ title: "temp_cookBook.dsv", icon: $globals.icons.codeJson },
{ title: "temp_food_brand.dsv", icon: $globals.icons.codeJson },
{ title: "temp_food_group.dsv", icon: $globals.icons.codeJson },
{ title: "temp_food.dsv", icon: $globals.icons.codeJson },
{ title: "temp_ingredient.dsv", icon: $globals.icons.codeJson },
{ title: "temp_media.dsv", icon: $globals.icons.codeJson },
{ title: "temp_nutrient.dsv", icon: $globals.icons.codeJson },
{ title: "temp_recipe_desc.dsv", icon: $globals.icons.codeJson },
{ title: "temp_recipe.dsv", icon: $globals.icons.codeJson },
{ title: "temp_unit_equivalent.dsv", icon: $globals.icons.codeJson },
{ title: "temp_unit.dsv", icon: $globals.icons.codeJson },
{ title: "images", icon: $globals.icons.fileImage },
],
},
],
},
};
const state = reactive({
addMigrationTag: false,
loading: false,
treeState: true,
migrationType: MIGRATIONS.mealie as SupportedMigrations,
fileObject: {} as File,
reports: [] as ReportSummary[],
});
function addIdToNode(counter: number, node: TreeNode): number {
node.id = counter;
counter += 1;
if (node.children) {
node.children.forEach((child: TreeNode) => {
counter = addIdToNode(counter, child);
});
}
return counter;
}
for (const key in _content) {
const migration = _content[key];
if (migration.tree && Array.isArray(migration.tree)) {
let counter = 1;
migration.tree.forEach((node: TreeNode) => {
counter = addIdToNode(counter, node);
});
}
}
console.log(_content);
function setFileObject(fileObject: File) {
state.fileObject = fileObject;
}
async function startMigration() {
state.loading = true;
const payload = {
addMigrationTag: state.addMigrationTag,
migrationType: state.migrationType,
archive: state.fileObject,
};
const { data } = await api.groupMigration.startMigration(payload);
state.loading = false;
if (data) {
state.reports.unshift(data);
}
}
async function getMigrationReports() {
const { data } = await api.groupReports.getAll("migration");
if (data) {
state.reports = data;
}
}
async function deleteReport(id: string) {
await api.groupReports.deleteOne(id);
getMigrationReports();
}
onMounted(() => {
getMigrationReports();
});
const content = computed(() => {
const data = _content[state.migrationType];
if (data) {
return data;
}
else {
return {
text: "",
acceptedFileType: ".zip",
tree: false,
};
}
});
return {
...toRefs(state),
items,
content,
setFileObject,
deleteReport,
startMigration,
getMigrationReports,
};
const items: MenuItem[] = [
{
text: i18n.t("migration.mealie-pre-v1.title"),
value: MIGRATIONS.mealie,
divider: true,
},
{
text: i18n.t("migration.chowdown.title"),
value: MIGRATIONS.chowdown,
},
{
text: i18n.t("migration.copymethat.title"),
value: MIGRATIONS.copymethat,
},
{
text: i18n.t("migration.myrecipebox.title"),
value: MIGRATIONS.myrecipebox,
},
{
text: i18n.t("migration.nextcloud.title"),
value: MIGRATIONS.nextcloud,
},
{
text: i18n.t("migration.paprika.title"),
value: MIGRATIONS.paprika,
},
{
text: i18n.t("migration.plantoeat.title"),
value: MIGRATIONS.plantoeat,
},
{
text: i18n.t("migration.recipekeeper.title"),
value: MIGRATIONS.recipekeeper,
},
{
text: i18n.t("migration.tandoor.title"),
value: MIGRATIONS.tandoor,
},
{
text: i18n.t("migration.cookn.title"),
value: MIGRATIONS.cookn,
},
];
const _content: Record<string, MigrationContent> = {
[MIGRATIONS.mealie]: {
text: i18n.t("migration.mealie-pre-v1.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "mealie.zip",
children: [
{
title: "recipes",
icon: $globals.icons.folderOutline,
children: [
{
title: "recipe-name",
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe-name.json", icon: $globals.icons.codeJson },
{
title: "images",
icon: $globals.icons.folderOutline,
children: [
{ title: "original.webp", icon: $globals.icons.codeJson },
{ title: "full.jpg", icon: $globals.icons.fileImage },
{ title: "thumb.jpg", icon: $globals.icons.fileImage },
],
},
],
},
{
title: "recipe-name-1",
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe-name-1.json", icon: $globals.icons.codeJson },
{
title: "images",
icon: $globals.icons.folderOutline,
children: [
{ title: "original.webp", icon: $globals.icons.codeJson },
{ title: "full.jpg", icon: $globals.icons.fileImage },
{ title: "thumb.jpg", icon: $globals.icons.fileImage },
],
},
],
},
],
},
],
},
],
},
[MIGRATIONS.chowdown]: {
text: i18n.t("migration.chowdown.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "nextcloud.zip",
children: [
{
title: i18n.t("migration.recipe-1"),
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe.json", icon: $globals.icons.codeJson },
{ title: "full.jpg", icon: $globals.icons.fileImage },
{ title: "thumb.jpg", icon: $globals.icons.fileImage },
],
},
{
title: i18n.t("migration.recipe-2"),
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe.json", icon: $globals.icons.codeJson },
{ title: "full.jpg", icon: $globals.icons.fileImage },
{ title: "thumb.jpg", icon: $globals.icons.fileImage },
],
},
],
},
],
},
[MIGRATIONS.copymethat]: {
text: i18n.t("migration.copymethat.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "Copy_Me_That_20230306.zip",
children: [
{
title: "images",
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe_1_an5zy.jpg", icon: $globals.icons.fileImage },
{ title: "recipe_2_82el8.jpg", icon: $globals.icons.fileImage },
{ title: "recipe_3_j75qg.jpg", icon: $globals.icons.fileImage },
],
},
{ title: "recipes.html", icon: $globals.icons.codeJson },
],
},
],
},
[MIGRATIONS.myrecipebox]: {
text: i18n.t("migration.myrecipebox.description-long"),
acceptedFileType: ".csv",
tree: false,
},
[MIGRATIONS.nextcloud]: {
text: i18n.t("migration.nextcloud.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "nextcloud.zip",
children: [
{
title: i18n.t("migration.recipe-1"),
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe.json", icon: $globals.icons.codeJson },
{ title: "full.jpg", icon: $globals.icons.fileImage },
{ title: "thumb.jpg", icon: $globals.icons.fileImage },
],
},
{
title: i18n.t("migration.recipe-2"),
icon: $globals.icons.folderOutline,
children: [
{ title: "recipe.json", icon: $globals.icons.codeJson },
{ title: "full.jpg", icon: $globals.icons.fileImage },
{ title: "thumb.jpg", icon: $globals.icons.fileImage },
],
},
],
},
],
},
[MIGRATIONS.paprika]: {
text: i18n.t("migration.paprika.description-long"),
acceptedFileType: ".zip",
tree: false,
},
[MIGRATIONS.plantoeat]: {
text: i18n.t("migration.plantoeat.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "plantoeat-recipes-508318_10-13-2023.zip",
children: [
{ title: "plantoeat-recipes-508318_10-13-2023.csv", icon: $globals.icons.codeJson },
],
},
],
},
[MIGRATIONS.recipekeeper]: {
text: i18n.t("migration.recipekeeper.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "recipekeeperhtml.zip",
children: [
{ title: "recipes.html", icon: $globals.icons.codeJson },
{
title: "images", icon: $globals.icons.folderOutline,
children: [
{ title: "image1.jpg", icon: $globals.icons.fileImage },
{ title: "image2.jpg", icon: $globals.icons.fileImage },
],
},
],
},
],
},
[MIGRATIONS.tandoor]: {
text: i18n.t("migration.tandoor.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "tandoor_default_export_full_2023-06-29.zip",
children: [
{
title: "1.zip",
icon: $globals.icons.zip,
children: [
{ title: "image.jpeg", icon: $globals.icons.fileImage },
{ title: "recipe.json", icon: $globals.icons.codeJson },
],
},
{
title: "2.zip",
icon: $globals.icons.zip,
children: [
{ title: "image.jpeg", icon: $globals.icons.fileImage },
{ title: "recipe.json", icon: $globals.icons.codeJson },
],
},
{
title: "3.zip",
icon: $globals.icons.zip,
children: [
{ title: "image.jpeg", icon: $globals.icons.fileImage },
{ title: "recipe.json", icon: $globals.icons.codeJson },
],
},
],
},
],
},
[MIGRATIONS.cookn]: {
text: i18n.t("migration.cookn.description-long"),
acceptedFileType: ".zip",
tree: [
{
icon: $globals.icons.zip,
title: "cookn.zip",
children: [
{ title: "temp_brand.dsv", icon: $globals.icons.codeJson },
{ title: "temp_chapter_desc.dsv", icon: $globals.icons.codeJson },
{ title: "temp_chapter.dsv", icon: $globals.icons.codeJson },
{ title: "temp_cookBook_desc.dsv", icon: $globals.icons.codeJson },
{ title: "temp_cookBook.dsv", icon: $globals.icons.codeJson },
{ title: "temp_food_brand.dsv", icon: $globals.icons.codeJson },
{ title: "temp_food_group.dsv", icon: $globals.icons.codeJson },
{ title: "temp_food.dsv", icon: $globals.icons.codeJson },
{ title: "temp_ingredient.dsv", icon: $globals.icons.codeJson },
{ title: "temp_media.dsv", icon: $globals.icons.codeJson },
{ title: "temp_nutrient.dsv", icon: $globals.icons.codeJson },
{ title: "temp_recipe_desc.dsv", icon: $globals.icons.codeJson },
{ title: "temp_recipe.dsv", icon: $globals.icons.codeJson },
{ title: "temp_unit_equivalent.dsv", icon: $globals.icons.codeJson },
{ title: "temp_unit.dsv", icon: $globals.icons.codeJson },
{ title: "images", icon: $globals.icons.fileImage },
],
},
],
},
};
function addIdToNode(counter: number, node: TreeNode): number {
node.id = counter;
counter += 1;
if (node.children) {
node.children.forEach((child: TreeNode) => {
counter = addIdToNode(counter, child);
});
}
return counter;
}
for (const key in _content) {
const migration = _content[key];
if (migration.tree && Array.isArray(migration.tree)) {
let counter = 1;
migration.tree.forEach((node: TreeNode) => {
counter = addIdToNode(counter, node);
});
}
}
console.log(_content);
function setFileObject(fileObject: File) {
state.fileObject = fileObject;
}
async function startMigration() {
state.loading = true;
const payload = {
addMigrationTag: state.addMigrationTag,
migrationType: state.migrationType,
archive: state.fileObject,
};
const { data } = await api.groupMigration.startMigration(payload);
state.loading = false;
if (data) {
state.reports.unshift(data);
}
}
async function getMigrationReports() {
const { data } = await api.groupReports.getAll("migration");
if (data) {
state.reports = data;
}
}
async function deleteReport(id: string) {
await api.groupReports.deleteOne(id);
getMigrationReports();
}
onMounted(() => {
getMigrationReports();
});
const content = computed(() => {
const data = _content[state.migrationType];
if (data) {
return data;
}
else {
return {
text: "",
acceptedFileType: ".zip",
tree: false,
};
}
});
</script>

View File

@@ -47,41 +47,31 @@
</v-container>
</template>
<script lang="ts">
<script setup lang="ts">
import { useUserApi } from "~/composables/api";
import type { ReportOut } from "~/lib/api/types/reports";
export default defineNuxtComponent({
setup() {
const route = useRoute();
const id = route.params.id as string;
const route = useRoute();
const id = route.params.id as string;
const api = useUserApi();
const api = useUserApi();
const report = ref<ReportOut | null>(null);
const report = ref<ReportOut | null>(null);
async function getReport() {
const { data } = await api.groupReports.getOne(id);
report.value = data ?? null;
}
async function getReport() {
const { data } = await api.groupReports.getOne(id);
report.value = data ?? null;
}
onMounted(async () => {
await getReport();
});
const itemHeaders = [
{ title: "Success", value: "success" },
{ title: "Message", value: "message" },
{ title: "Timestamp", value: "timestamp" },
];
return {
report,
id,
itemHeaders,
};
},
onMounted(async () => {
await getReport();
});
const itemHeaders = [
{ title: "Success", value: "success" },
{ title: "Message", value: "message" },
{ title: "Timestamp", value: "timestamp" },
];
</script>
<style lang="scss" scoped></style>