fix(media): refresh the media list when images are added from the search
Validated images were copied into the project but the list behind the popup only reloaded on close, so nothing seemed to happen. Reload it right away and show the Assets group.
223eea8 parent: c803802 modified
web/src/project/ResourcesPage.vue +7 -1 | @@ -56,6 +56,12 @@ function closeAdd() { | ||
| 56 | 56 | else load(); |
| 57 | 57 | } |
| 58 | 58 | |
| 59 | +// des images validées dans la popup apparaissent derrière, sans attendre sa fermeture | |
| 60 | +async function onAdded() { | |
| 61 | + await load(); | |
| 62 | + tab.value = "Assets"; | |
| 63 | +} | |
| 64 | + | |
| 59 | 65 | // un téléchargement YouTube qui se termine arrive dans la liste |
| 60 | 66 | const downloaded = computed(() => store.project?.runtime.assets.downloads.filter((d) => d.finished).length ?? 0); |
| 61 | 67 | watch(downloaded, (n, before) => { if (n > before) load(); }); |
| @@ -146,7 +152,7 @@ async function toLibrary(item: Item, category: string) { | ||
| 146 | 152 | </div> |
| 147 | 153 | <span v-if="!items.length" class="nothing">{{ t("common.nothingYet") }}</span> |
| 148 | 154 | </div> |
| 149 | - <AddMediaModal v-if="adding && store.project?.id === pid" v-model:tab="addTab" :uploading="uploading" @files="uploadFiles" @close="closeAdd" /> | |
| 155 | + <AddMediaModal v-if="adding && store.project?.id === pid" v-model:tab="addTab" :uploading="uploading" @files="uploadFiles" @added="onAdded" @close="closeAdd" /> | |
| 150 | 156 | <MediaLightbox v-model="zoom" :items="zoomable"> |
| 151 | 157 | <template #actions="{ item }"><button class="link-btn" @click="reveal(item.rel)">{{ t("common.showInExplorer") }}</button></template> |
| 152 | 158 | </MediaLightbox> |
| @@ -56,6 +56,12 @@ function closeAdd() { | |||
| 56 | else load(); | 56 | else load(); |
| 57 | } | 57 | } |
| 58 | 58 | ||
| 59 | +// des images validées dans la popup apparaissent derrière, sans attendre sa fermeture | ||
| 60 | +async function onAdded() { | ||
| 61 | + await load(); | ||
| 62 | + tab.value = "Assets"; | ||
| 63 | +} | ||
| 64 | + | ||
| 59 | // un téléchargement YouTube qui se termine arrive dans la liste | 65 | // un téléchargement YouTube qui se termine arrive dans la liste |
| 60 | const downloaded = computed(() => store.project?.runtime.assets.downloads.filter((d) => d.finished).length ?? 0); | 66 | const downloaded = computed(() => store.project?.runtime.assets.downloads.filter((d) => d.finished).length ?? 0); |
| 61 | watch(downloaded, (n, before) => { if (n > before) load(); }); | 67 | watch(downloaded, (n, before) => { if (n > before) load(); }); |
| @@ -146,7 +152,7 @@ async function toLibrary(item: Item, category: string) { | |||
| 146 | </div> | 152 | </div> |
| 147 | <span v-if="!items.length" class="nothing">{{ t("common.nothingYet") }}</span> | 153 | <span v-if="!items.length" class="nothing">{{ t("common.nothingYet") }}</span> |
| 148 | </div> | 154 | </div> |
| 149 | - <AddMediaModal v-if="adding && store.project?.id === pid" v-model:tab="addTab" :uploading="uploading" @files="uploadFiles" @close="closeAdd" /> | 155 | + <AddMediaModal v-if="adding && store.project?.id === pid" v-model:tab="addTab" :uploading="uploading" @files="uploadFiles" @added="onAdded" @close="closeAdd" /> |
| 150 | <MediaLightbox v-model="zoom" :items="zoomable"> | 156 | <MediaLightbox v-model="zoom" :items="zoomable"> |
| 151 | <template #actions="{ item }"><button class="link-btn" @click="reveal(item.rel)">{{ t("common.showInExplorer") }}</button></template> | 157 | <template #actions="{ item }"><button class="link-btn" @click="reveal(item.rel)">{{ t("common.showInExplorer") }}</button></template> |
| 152 | </MediaLightbox> | 158 | </MediaLightbox> |
modified
web/src/project/media/AddMediaModal.vue +2 -2 | @@ -14,7 +14,7 @@ import YoutubeTab from "./YoutubeTab.vue"; | ||
| 14 | 14 | |
| 15 | 15 | const tab = defineModel<AddTab>("tab", { required: true }); |
| 16 | 16 | defineProps<{ uploading: number | null }>(); |
| 17 | -const emit = defineEmits<{ close: []; files: [files: File[]] }>(); | |
| 17 | +const emit = defineEmits<{ close: []; files: [files: File[]]; added: [] }>(); | |
| 18 | 18 | const { t } = useI18n(); |
| 19 | 19 | |
| 20 | 20 | const title = computed(() => t(`media.add.tabs.${tab.value}.label`)); |
| @@ -60,7 +60,7 @@ function onPick(e: Event) { | ||
| 60 | 60 | <input ref="input" type="file" multiple hidden @change="onPick"> |
| 61 | 61 | </template> |
| 62 | 62 | <YoutubeTab v-else-if="tab === 'youtube'" /> |
| 63 | - <ImagesTab v-else-if="tab === 'images'" /> | |
| 63 | + <ImagesTab v-else-if="tab === 'images'" @added="emit('added')" /> | |
| 64 | 64 | <DocTab v-else /> |
| 65 | 65 | </Modal> |
| 66 | 66 | </template> |
| @@ -14,7 +14,7 @@ import YoutubeTab from "./YoutubeTab.vue"; | |||
| 14 | 14 | ||
| 15 | const tab = defineModel<AddTab>("tab", { required: true }); | 15 | const tab = defineModel<AddTab>("tab", { required: true }); |
| 16 | defineProps<{ uploading: number | null }>(); | 16 | defineProps<{ uploading: number | null }>(); |
| 17 | -const emit = defineEmits<{ close: []; files: [files: File[]] }>(); | 17 | +const emit = defineEmits<{ close: []; files: [files: File[]]; added: [] }>(); |
| 18 | const { t } = useI18n(); | 18 | const { t } = useI18n(); |
| 19 | 19 | ||
| 20 | const title = computed(() => t(`media.add.tabs.${tab.value}.label`)); | 20 | const title = computed(() => t(`media.add.tabs.${tab.value}.label`)); |
| @@ -60,7 +60,7 @@ function onPick(e: Event) { | |||
| 60 | <input ref="input" type="file" multiple hidden @change="onPick"> | 60 | <input ref="input" type="file" multiple hidden @change="onPick"> |
| 61 | </template> | 61 | </template> |
| 62 | <YoutubeTab v-else-if="tab === 'youtube'" /> | 62 | <YoutubeTab v-else-if="tab === 'youtube'" /> |
| 63 | - <ImagesTab v-else-if="tab === 'images'" /> | 63 | + <ImagesTab v-else-if="tab === 'images'" @added="emit('added')" /> |
| 64 | <DocTab v-else /> | 64 | <DocTab v-else /> |
| 65 | </Modal> | 65 | </Modal> |
| 66 | </template> | 66 | </template> |
modified
web/src/project/media/ImagesTab.vue +2 -0 | @@ -14,6 +14,7 @@ import type { ImagesState } from "../types"; | ||
| 14 | 14 | import CheckBox from "./CheckBox.vue"; |
| 15 | 15 | import DestPicker from "./DestPicker.vue"; |
| 16 | 16 | |
| 17 | +const emit = defineEmits<{ added: [] }>(); | |
| 17 | 18 | const { t } = useI18n(); |
| 18 | 19 | const base = `/api/projects/${store.project!.id}/assets`; |
| 19 | 20 | const state = ref<ImagesState>({ messages: [], results: [], busy: false, error: null, activity: null }); |
| @@ -81,6 +82,7 @@ async function validate() { | ||
| 81 | 82 | receive(out); |
| 82 | 83 | const dest = out.results.find((r) => r.added)?.added ?? ""; |
| 83 | 84 | toast(t("sourcing.images.added", { dest }, out.added)); |
| 85 | + if (out.added) emit("added"); | |
| 84 | 86 | } catch (e) { |
| 85 | 87 | toast((e as Error).message, true); |
| 86 | 88 | } |
| @@ -14,6 +14,7 @@ import type { ImagesState } from "../types"; | |||
| 14 | import CheckBox from "./CheckBox.vue"; | 14 | import CheckBox from "./CheckBox.vue"; |
| 15 | import DestPicker from "./DestPicker.vue"; | 15 | import DestPicker from "./DestPicker.vue"; |
| 16 | 16 | ||
| 17 | +const emit = defineEmits<{ added: [] }>(); | ||
| 17 | const { t } = useI18n(); | 18 | const { t } = useI18n(); |
| 18 | const base = `/api/projects/${store.project!.id}/assets`; | 19 | const base = `/api/projects/${store.project!.id}/assets`; |
| 19 | const state = ref<ImagesState>({ messages: [], results: [], busy: false, error: null, activity: null }); | 20 | const state = ref<ImagesState>({ messages: [], results: [], busy: false, error: null, activity: null }); |
| @@ -81,6 +82,7 @@ async function validate() { | |||
| 81 | receive(out); | 82 | receive(out); |
| 82 | const dest = out.results.find((r) => r.added)?.added ?? ""; | 83 | const dest = out.results.find((r) => r.added)?.added ?? ""; |
| 83 | toast(t("sourcing.images.added", { dest }, out.added)); | 84 | toast(t("sourcing.images.added", { dest }, out.added)); |
| 85 | + if (out.added) emit("added"); | ||
| 84 | } catch (e) { | 86 | } catch (e) { |
| 85 | toast((e as Error).message, true); | 87 | toast((e as Error).message, true); |
| 86 | } | 88 | } |