Scope knowledge and image libraries by brand
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
<script setup lang="ts">
|
||||
import { imagesApi } from '@/lib/api'
|
||||
import { useCompanyStore } from '@/stores/company'
|
||||
import type { ScheduleCoverMode, ScheduleCoverRandomScope } from '@geo/shared-types'
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
import { computed, watch } from 'vue'
|
||||
@@ -24,10 +25,12 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const companyStore = useCompanyStore()
|
||||
const currentBrandId = computed(() => companyStore.currentBrandId)
|
||||
|
||||
const foldersQuery = useQuery({
|
||||
queryKey: ['images', 'folders', 'cover-source'],
|
||||
enabled: computed(() => !props.disabled),
|
||||
queryKey: computed(() => ['images', 'folders', 'cover-source', currentBrandId.value]),
|
||||
enabled: computed(() => !props.disabled && Boolean(currentBrandId.value)),
|
||||
queryFn: () => imagesApi.listFolders(),
|
||||
})
|
||||
|
||||
@@ -38,6 +41,13 @@ const folderOptions = computed(() =>
|
||||
})),
|
||||
)
|
||||
|
||||
watch(
|
||||
currentBrandId,
|
||||
() => {
|
||||
emit('update:randomFolderId', null)
|
||||
},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => props.mode,
|
||||
(mode) => {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
<script setup lang="ts">
|
||||
import { imagesApi } from '@/lib/api'
|
||||
import { formatBytes, formatPercentage } from '@/lib/display'
|
||||
import { useCompanyStore } from '@/stores/company'
|
||||
import type { ImageAssetItem } from '@geo/shared-types'
|
||||
import { useQuery } from '@tanstack/vue-query'
|
||||
import { computed, ref, watch } from 'vue'
|
||||
@@ -20,6 +21,8 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const { t } = useI18n()
|
||||
const companyStore = useCompanyStore()
|
||||
const currentBrandId = computed(() => companyStore.currentBrandId)
|
||||
|
||||
// State
|
||||
const selectedFolderId = ref<number | null>(null)
|
||||
@@ -31,7 +34,8 @@ const selectedId = ref<number | null>(null)
|
||||
|
||||
// Queries
|
||||
const foldersQuery = useQuery({
|
||||
queryKey: ['images', 'folders'],
|
||||
queryKey: computed(() => ['images', 'folders', currentBrandId.value]),
|
||||
enabled: computed(() => Boolean(currentBrandId.value)),
|
||||
queryFn: () => imagesApi.listFolders(),
|
||||
})
|
||||
|
||||
@@ -40,6 +44,7 @@ const imagesQuery = useQuery({
|
||||
'images',
|
||||
'list',
|
||||
'picker',
|
||||
currentBrandId.value,
|
||||
{
|
||||
folder_id: selectedFolderId.value,
|
||||
q: debouncedSearch.value,
|
||||
@@ -47,6 +52,7 @@ const imagesQuery = useQuery({
|
||||
page_size: pageSize.value,
|
||||
},
|
||||
]),
|
||||
enabled: computed(() => Boolean(currentBrandId.value)),
|
||||
queryFn: () =>
|
||||
imagesApi.list({
|
||||
folder_id: selectedFolderId.value ?? undefined,
|
||||
@@ -77,6 +83,12 @@ watch(searchKeyword, () => {
|
||||
}, 300)
|
||||
})
|
||||
|
||||
watch(currentBrandId, () => {
|
||||
selectedFolderId.value = null
|
||||
selectedId.value = null
|
||||
currentPage.value = 1
|
||||
})
|
||||
|
||||
function handleSelect(image: ImageAssetItem) {
|
||||
selectedId.value = image.id
|
||||
emit('select', image)
|
||||
|
||||
@@ -5,6 +5,7 @@ import { computed, watch } from 'vue'
|
||||
import MarkdownPreview from '@/components/MarkdownPreview.vue'
|
||||
import { knowledgeApi } from '@/lib/api'
|
||||
import { formatDateTime } from '@/lib/display'
|
||||
import { useCompanyStore } from '@/stores/company'
|
||||
|
||||
const props = defineProps<{
|
||||
open: boolean
|
||||
@@ -16,10 +17,12 @@ const emit = defineEmits<{
|
||||
}>()
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
const enabled = computed(() => props.open && Boolean(props.itemId))
|
||||
const companyStore = useCompanyStore()
|
||||
const currentBrandId = computed(() => companyStore.currentBrandId)
|
||||
const enabled = computed(() => props.open && Boolean(props.itemId) && Boolean(currentBrandId.value))
|
||||
|
||||
const detailQuery = useQuery({
|
||||
queryKey: computed(() => ['knowledge', 'detail', props.itemId]),
|
||||
queryKey: computed(() => ['knowledge', 'detail', currentBrandId.value, props.itemId]),
|
||||
enabled,
|
||||
queryFn: () => knowledgeApi.detail(props.itemId as number),
|
||||
})
|
||||
|
||||
@@ -4,6 +4,7 @@ import { useQuery } from '@tanstack/vue-query'
|
||||
import { computed } from 'vue'
|
||||
|
||||
import { knowledgeApi } from '@/lib/api'
|
||||
import { useCompanyStore } from '@/stores/company'
|
||||
|
||||
interface TreeNode {
|
||||
title: string
|
||||
@@ -29,8 +30,12 @@ const emit = defineEmits<{
|
||||
'update:modelValue': [value: number[]]
|
||||
}>()
|
||||
|
||||
const companyStore = useCompanyStore()
|
||||
const currentBrandId = computed(() => companyStore.currentBrandId)
|
||||
|
||||
const groupsQuery = useQuery({
|
||||
queryKey: ['knowledge', 'groups', 'selector'],
|
||||
queryKey: computed(() => ['knowledge', 'groups', 'selector', currentBrandId.value]),
|
||||
enabled: computed(() => Boolean(currentBrandId.value)),
|
||||
queryFn: () => knowledgeApi.listGroups(),
|
||||
})
|
||||
|
||||
|
||||
@@ -355,6 +355,8 @@ const currentBrandScopedPathPatterns = [
|
||||
/^\/api\/tenant\/enterprise-sites\/[^/]+\/publish(?:\/|$)/,
|
||||
/^\/api\/tenant\/media-supply\/orders(?:\/|$)/,
|
||||
/^\/api\/tenant\/prompt-rules(?:\/|$)/,
|
||||
/^\/api\/tenant\/knowledge(?:\/|$)/,
|
||||
/^\/api\/tenant\/images(?:\/|$)/,
|
||||
]
|
||||
|
||||
function shouldAttachCurrentBrandHeader(url: unknown): boolean {
|
||||
@@ -362,6 +364,9 @@ function shouldAttachCurrentBrandHeader(url: unknown): boolean {
|
||||
return false
|
||||
}
|
||||
const pathname = normalizeRequestPath(url)
|
||||
if (pathname === '/api/tenant/images/storage-usage') {
|
||||
return false
|
||||
}
|
||||
return currentBrandScopedPathPatterns.some((pattern) => pattern.test(pathname))
|
||||
}
|
||||
|
||||
|
||||
@@ -18,11 +18,14 @@ import { imagesApi } from '@/lib/api'
|
||||
import { formatBytes, formatDateTime, formatPercentage } from '@/lib/display'
|
||||
import { formatError } from '@/lib/errors'
|
||||
import { IMAGE_UPLOAD_ACCEPT, useImageUploadProgress } from '@/lib/image-webp'
|
||||
import { useCompanyStore } from '@/stores/company'
|
||||
import type { ImageAssetItem, ImageFolder } from '@geo/shared-types'
|
||||
|
||||
const { t } = useI18n()
|
||||
const queryClient = useQueryClient()
|
||||
const imageUploadProgress = useImageUploadProgress()
|
||||
const companyStore = useCompanyStore()
|
||||
const currentBrandId = computed(() => companyStore.currentBrandId)
|
||||
|
||||
// State
|
||||
const selectedFolderId = ref<number | null>(null) // null means "All" or is handled by folders query
|
||||
@@ -51,7 +54,8 @@ const fileInput = ref<HTMLInputElement | null>(null)
|
||||
|
||||
// Queries
|
||||
const foldersQuery = useQuery({
|
||||
queryKey: ['images', 'folders'],
|
||||
queryKey: computed(() => ['images', 'folders', currentBrandId.value]),
|
||||
enabled: computed(() => Boolean(currentBrandId.value)),
|
||||
queryFn: () => imagesApi.listFolders(),
|
||||
})
|
||||
|
||||
@@ -59,6 +63,7 @@ const imagesQuery = useQuery({
|
||||
queryKey: computed(() => [
|
||||
'images',
|
||||
'list',
|
||||
currentBrandId.value,
|
||||
{
|
||||
folder_id: debouncedSearch.value ? undefined : selectedFolderId.value,
|
||||
q: debouncedSearch.value,
|
||||
@@ -66,6 +71,7 @@ const imagesQuery = useQuery({
|
||||
page_size: pageSize.value,
|
||||
},
|
||||
]),
|
||||
enabled: computed(() => Boolean(currentBrandId.value)),
|
||||
queryFn: () =>
|
||||
imagesApi.list({
|
||||
folder_id: debouncedSearch.value ? undefined : (selectedFolderId.value ?? undefined),
|
||||
@@ -76,7 +82,8 @@ const imagesQuery = useQuery({
|
||||
})
|
||||
|
||||
const allImagesCountQuery = useQuery({
|
||||
queryKey: ['images', 'list', 'all-count'],
|
||||
queryKey: computed(() => ['images', 'list', 'all-count', currentBrandId.value]),
|
||||
enabled: computed(() => Boolean(currentBrandId.value)),
|
||||
queryFn: () =>
|
||||
imagesApi.list({
|
||||
page: 1,
|
||||
@@ -181,6 +188,17 @@ watch(searchKeyword, () => {
|
||||
}, 300)
|
||||
})
|
||||
|
||||
watch(currentBrandId, () => {
|
||||
selectedFolderId.value = null
|
||||
movingImage.value = null
|
||||
previewingImage.value = null
|
||||
renamingImage.value = null
|
||||
moveModalOpen.value = false
|
||||
previewModalOpen.value = false
|
||||
renameImageModalOpen.value = false
|
||||
currentPage.value = 1
|
||||
})
|
||||
|
||||
function handleFolderSelect(id: number | null) {
|
||||
if (debouncedSearch.value) return
|
||||
selectedFolderId.value = id
|
||||
|
||||
@@ -16,6 +16,7 @@ import KnowledgeDetailDrawer from '@/components/KnowledgeDetailDrawer.vue'
|
||||
import { knowledgeApi } from '@/lib/api'
|
||||
import { formatDateTime } from '@/lib/display'
|
||||
import { formatError } from '@/lib/errors'
|
||||
import { useCompanyStore } from '@/stores/company'
|
||||
|
||||
type KnowledgeSourceType = 'document' | 'website' | 'text'
|
||||
type KnowledgeGroupLevel = 'root' | 'child'
|
||||
@@ -35,6 +36,8 @@ interface TreeNode {
|
||||
}
|
||||
|
||||
const queryClient = useQueryClient()
|
||||
const companyStore = useCompanyStore()
|
||||
const currentBrandId = computed(() => companyStore.currentBrandId)
|
||||
|
||||
const selectedGroupId = ref<number | null>(null)
|
||||
const groupModalOpen = ref(false)
|
||||
@@ -59,12 +62,14 @@ const urlsText = ref('')
|
||||
const textItems = ref([{ name: '', content: '' }])
|
||||
|
||||
const groupsQuery = useQuery({
|
||||
queryKey: ['knowledge', 'groups'],
|
||||
queryKey: computed(() => ['knowledge', 'groups', currentBrandId.value]),
|
||||
enabled: computed(() => Boolean(currentBrandId.value)),
|
||||
queryFn: () => knowledgeApi.listGroups(),
|
||||
})
|
||||
|
||||
const itemsQuery = useQuery({
|
||||
queryKey: computed(() => ['knowledge', 'items', selectedGroupId.value]),
|
||||
queryKey: computed(() => ['knowledge', 'items', currentBrandId.value, selectedGroupId.value]),
|
||||
enabled: computed(() => Boolean(currentBrandId.value)),
|
||||
queryFn: () => knowledgeApi.listItems(selectedGroupId.value ?? undefined),
|
||||
refetchInterval: (query) => {
|
||||
const items = query.state.data as KnowledgeItem[] | undefined
|
||||
@@ -267,6 +272,18 @@ const retryItemMutation = useMutation({
|
||||
onError: (error) => message.error(formatError(error)),
|
||||
})
|
||||
|
||||
watch(
|
||||
currentBrandId,
|
||||
() => {
|
||||
selectedGroupId.value = null
|
||||
groupModalOpen.value = false
|
||||
editingGroup.value = null
|
||||
itemModalOpen.value = false
|
||||
previewItemId.value = null
|
||||
previewDrawerOpen.value = false
|
||||
},
|
||||
)
|
||||
|
||||
watch(
|
||||
() => groupsQuery.data.value,
|
||||
(groups) => {
|
||||
|
||||
Reference in New Issue
Block a user