Skip to content

Commit

Permalink
feat: add reports to bulk recipe import (url) (mealie-recipes#1294)
Browse files Browse the repository at this point in the history
* remove unused docker and caddy configs

* add experimental nested configs

* switch to nest under docker-compose

* remove v-card

* bulk parser backend re-implementation

* refactor UI for bulk importer

* remove migration specific report text
  • Loading branch information
hay-kot authored May 26, 2022
1 parent d66d6c5 commit 010aafa
Show file tree
Hide file tree
Showing 15 changed files with 240 additions and 139 deletions.
9 changes: 8 additions & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,5 +46,12 @@
"python.linting.mypyEnabled": true,
"python.sortImports.path": "${workspaceFolder}/.venv/bin/isort",
"search.mode": "reuseEditor",
"python.testing.unittestArgs": ["-v", "-s", "./tests", "-p", "test_*.py"]
"python.testing.unittestArgs": ["-v", "-s", "./tests", "-p", "test_*.py"],
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.patterns": {
"package.json": "package-lock.json, yarn.lock, .eslintrc.js, tsconfig.json, .prettierrc, .editorconfig",
"pyproject.toml": "poetry.lock, alembic.ini, .pylintrc, .flake8",
"netlify.toml": "runtime.txt",
"docker-compose.yml": "Dockerfile, .dockerignore, docker-compose.dev.yml, docker-compose.yml"
}
}
15 changes: 0 additions & 15 deletions docs/Caddyfile

This file was deleted.

10 changes: 0 additions & 10 deletions docs/Dockerfile

This file was deleted.

11 changes: 0 additions & 11 deletions docs/docker-compose.yml

This file was deleted.

21 changes: 7 additions & 14 deletions frontend/pages/group/reports/_id.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,7 @@
<template #header>
<v-img max-height="200" max-width="200" class="mb-2" :src="require('~/static/svgs/data-reports.svg')"></v-img>
</template>
<template #title> Recipe Data Migrations</template>
Recipes can be migrated from another supported application to Mealie. This is a great way to get started with
Mealie.
<template #title> Report </template>
</BasePageTitle>
<v-container v-if="report">
<BaseCardSectionTitle :title="report.name"> </BaseCardSectionTitle>
Expand All @@ -31,8 +29,9 @@
</template>

<script lang="ts">
import { defineComponent, useRoute, reactive, toRefs, onMounted } from "@nuxtjs/composition-api";
import { defineComponent, useRoute, ref, onMounted } from "@nuxtjs/composition-api";
import { useUserApi } from "~/composables/api";
import { ReportOut } from "~/types/api-types/reports";
export default defineComponent({
setup() {
Expand All @@ -41,16 +40,11 @@ export default defineComponent({
const api = useUserApi();
const state = reactive({
report: {},
});
const report = ref<ReportOut | null>(null);
async function getReport() {
const { data } = await api.groupReports.getOne(id);
if (data) {
state.report = data;
}
report.value = data ?? null;
}
onMounted(async () => {
Expand All @@ -64,13 +58,12 @@ export default defineComponent({
];
return {
...toRefs(state),
report,
id,
itemHeaders,
};
},
});
</script>

<style lang="scss" scoped>
</style>
<style lang="scss" scoped></style>
138 changes: 98 additions & 40 deletions frontend/pages/recipe/create/bulk.vue
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
<template>
<div>
<v-card flat>
<div flat>
<v-card-title class="headline"> Recipe Bulk Importer </v-card-title>
<v-card-text>
The Bulk recipe importer allows you to import multiple recipes at once by queing the sites on the backend and
running the task in the background. This can be useful when initially migrating to Mealie, or when you want to
import a large number of recipes.
</v-card-text>
</v-card>
</div>
<section class="mt-2">
<v-row v-for="(bulkUrl, idx) in bulkUrls" :key="'bulk-url' + idx" class="my-1" dense>
<v-row v-for="(_, idx) in bulkUrls" :key="'bulk-url' + idx" class="my-1" dense>
<v-col cols="12" xs="12" sm="12" md="12">
<v-text-field
v-model="bulkUrls[idx].url"
Expand All @@ -26,46 +26,48 @@
class="rounded-lg"
>
<template #append>
<v-btn color="error" icon x-small @click="bulkUrls.splice(idx, 1)">
<v-btn style="margin-top: -2px" icon small @click="bulkUrls.splice(idx, 1)">
<v-icon>
{{ $globals.icons.delete }}
</v-icon>
</v-btn>
</template>
</v-text-field>
</v-col>
<v-col cols="12" xs="12" sm="6">
<RecipeOrganizerSelector
v-model="bulkUrls[idx].categories"
:items="allCategories || []"
selector-type="category"
:input-attrs="{
filled: true,
singleLine: true,
dense: true,
rounded: true,
class: 'rounded-lg',
hideDetails: true,
clearable: true,
}"
/>
</v-col>
<v-col cols="12" xs="12" sm="6">
<RecipeOrganizerSelector
v-model="bulkUrls[idx].tags"
:items="allTags || []"
selector-type="tag"
:input-attrs="{
filled: true,
singleLine: true,
dense: true,
rounded: true,
class: 'rounded-lg',
hideDetails: true,
clearable: true,
}"
/>
</v-col>
<template v-if="showCatTags">
<v-col cols="12" xs="12" sm="6">
<RecipeOrganizerSelector
v-model="bulkUrls[idx].categories"
:items="allCategories || []"
selector-type="category"
:input-attrs="{
filled: true,
singleLine: true,
dense: true,
rounded: true,
class: 'rounded-lg',
hideDetails: true,
clearable: true,
}"
/>
</v-col>
<v-col cols="12" xs="12" sm="6">
<RecipeOrganizerSelector
v-model="bulkUrls[idx].tags"
:items="allTags || []"
selector-type="tag"
:input-attrs="{
filled: true,
singleLine: true,
dense: true,
rounded: true,
class: 'rounded-lg',
hideDetails: true,
clearable: true,
}"
/>
</v-col>
</template>
</v-row>
<v-card-actions class="justify-end">
<BaseButton
Expand All @@ -78,32 +80,56 @@
Clear
</BaseButton>
<v-spacer></v-spacer>
<BaseButton color="info" @click="bulkUrls.push({ url: '', categories: [], tags: [] })">
<template #icon> {{ $globals.icons.createAlt }} </template> New
<BaseButton class="mr-1" color="info" @click="bulkUrls.push({ url: '', categories: [], tags: [] })">
<template #icon> {{ $globals.icons.createAlt }} </template>
New
</BaseButton>
<RecipeDialogBulkAdd v-model="bulkDialog" @bulk-data="assignUrls" />
</v-card-actions>
<div class="px-1">
<v-checkbox v-model="showCatTags" hide-details label="Set Categories and Tags " />
</div>
<v-card-actions class="justify-end">
<BaseButton :disabled="bulkUrls.length === 0 || lockBulkImport" @click="bulkCreate">
<template #icon> {{ $globals.icons.check }} </template> Submit
<template #icon> {{ $globals.icons.check }} </template>
Submit
</BaseButton>
</v-card-actions>
</section>
<section class="mt-12">
<BaseCardSectionTitle title="Bulk Imports"> </BaseCardSectionTitle>
<ReportTable :items="reports" @delete="deleteReport" />
</section>
</div>
</template>

<script lang="ts">
import { defineComponent, reactive, toRefs, ref } from "@nuxtjs/composition-api";
import { whenever } from "@vueuse/shared";
import { useUserApi } from "~/composables/api";
import { alert } from "~/composables/use-toast";
import RecipeOrganizerSelector from "~/components/Domain/Recipe/RecipeOrganizerSelector.vue";
import { useCategories, useTags } from "~/composables/recipes";
import { ReportSummary } from "~/types/api-types/reports";
import RecipeDialogBulkAdd from "~/components/Domain/Recipe/RecipeDialogBulkAdd.vue";
export default defineComponent({
components: { RecipeOrganizerSelector },
components: { RecipeOrganizerSelector, RecipeDialogBulkAdd },
setup() {
const state = reactive({
error: false,
loading: false,
showCatTags: false,
bulkDialog: false,
});
whenever(
() => !state.showCatTags,
() => {
console.log("showCatTags changed");
}
);
const api = useUserApi();
const bulkUrls = ref([{ url: "", categories: [], tags: [] }]);
Expand All @@ -122,6 +148,8 @@ export default defineComponent({
} else {
alert.error("Bulk import process has failed");
}
fetchReports();
}
const { allTags, useAsyncGetAll: getAllTags } = useTags();
Expand All @@ -130,7 +158,37 @@ export default defineComponent({
getAllTags();
getAllCategories();
// =========================================================
// Reports
const reports = ref<ReportSummary[]>([]);
async function fetchReports() {
const { data } = await api.groupReports.getAll("bulk_import");
reports.value = data ?? [];
}
async function deleteReport(id: string) {
console.log(id);
const { response } = await api.groupReports.deleteOne(id);
if (response?.status === 200) {
fetchReports();
} else {
alert.error("Report deletion failed");
}
}
fetchReports();
function assignUrls(urls: string[]) {
bulkUrls.value = urls.map((url) => ({ url, categories: [], tags: [] }));
}
return {
assignUrls,
reports,
deleteReport,
allTags,
allCategories,
bulkCreate,
Expand Down
4 changes: 2 additions & 2 deletions frontend/pages/recipe/create/debug.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div>
<v-form ref="domUrlForm" @submit.prevent="debugUrl(recipeUrl)">
<v-card flat>
<div>
<v-card-title class="headline"> Recipe Debugger </v-card-title>
<v-card-text>
Grab the URL of the recipe you want to debug and paste it here. The URL will be scraped by the recipe scraper
Expand Down Expand Up @@ -32,7 +32,7 @@
</BaseButton>
</div>
</v-card-actions>
</v-card>
</div>
</v-form>
<section v-if="debugData">
<v-checkbox v-model="debugTreeView" label="Tree View"></v-checkbox>
Expand Down
4 changes: 2 additions & 2 deletions frontend/pages/recipe/create/new.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<template>
<v-card flat>
<div>
<v-card-title class="headline"> Create Recipe </v-card-title>
<v-card-text>
Create a recipe by providing the name. All recipes must have unique names.
Expand Down Expand Up @@ -31,7 +31,7 @@
/>
</div>
</v-card-actions>
</v-card>
</div>
</template>
<script lang="ts">
import { defineComponent, reactive, toRefs, ref, useRouter } from "@nuxtjs/composition-api";
Expand Down
4 changes: 2 additions & 2 deletions frontend/pages/recipe/create/url.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<template>
<div>
<v-form ref="domUrlForm" @submit.prevent="createByUrl(recipeUrl, importKeywordsAsTags)">
<v-card flat>
<div>
<v-card-title class="headline"> Scrape Recipe </v-card-title>
<v-card-text>
Scrape a recipe by url. Provide the url for the site you want to scrape, and Mealie will attempt to scrape the
Expand All @@ -27,7 +27,7 @@
<BaseButton :disabled="recipeUrl === null" rounded block type="submit" :loading="loading" />
</div>
</v-card-actions>
</v-card>
</div>
</v-form>
<v-expand-transition>
<v-alert v-show="error" color="error" class="mt-6 white--text">
Expand Down
4 changes: 2 additions & 2 deletions frontend/pages/recipe/create/zip.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<template>
<v-form>
<v-card flat>
<div>
<v-card-title class="headline"> Import from Zip </v-card-title>
<v-card-text>
Import a single recipe that was exported from another Mealie instance.
Expand All @@ -25,7 +25,7 @@
<BaseButton :disabled="newRecipeZip === null" large rounded block :loading="loading" @click="createByZip" />
</div>
</v-card-actions>
</v-card>
</div>
</v-form>
</template>

Expand Down
2 changes: 1 addition & 1 deletion frontend/types/api-types/reports.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
/* Do not modify it by hand - just update the pydantic models and then re-run the script
*/

export type ReportCategory = "backup" | "restore" | "migration";
export type ReportCategory = "backup" | "restore" | "migration" | "bulk_import";
export type ReportSummaryStatus = "in-progress" | "success" | "failure" | "partial";

export interface ReportCreate {
Expand Down
Loading

0 comments on commit 010aafa

Please sign in to comment.