From 3d476139f303fb2bed8e4617ae3f2a3e8f897abc Mon Sep 17 00:00:00 2001 From: rijkvanzanten Date: Tue, 8 Sep 2020 10:38:57 -0400 Subject: [PATCH 01/14] Fix no options notice for empty options array --- .../routes/data-model/field-detail/components/display.vue | 2 +- .../routes/data-model/field-detail/components/interface.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/src/modules/settings/routes/data-model/field-detail/components/display.vue b/app/src/modules/settings/routes/data-model/field-detail/components/display.vue index 195fbe889b..ebc644936b 100644 --- a/app/src/modules/settings/routes/data-model/field-detail/components/display.vue +++ b/app/src/modules/settings/routes/data-model/field-detail/components/display.vue @@ -11,7 +11,7 @@ @@ -175,12 +175,12 @@ export default defineComponent({ }, setup(props) { const { folders } = useFolders(); - const layout = ref(null); + const layoutRef = ref(null); const selection = ref([]); const userStore = useUserStore(); - const { viewType, viewOptions, viewQuery, filters, searchQuery } = usePreset(ref('directus_files')); + const { layout, layoutOptions, layoutQuery, filters, searchQuery } = usePreset(ref('directus_files')); const { batchLink } = useLinks(); const { confirmDelete, deleting, batchDelete } = useBatchDelete(); const { breadcrumb, title } = useBreadcrumb(); @@ -252,9 +252,9 @@ export default defineComponent({ filters, layout, selection, - viewOptions, - viewQuery, - viewType, + layoutOptions, + layoutQuery, + layout, filtersWithFolderAndType, searchQuery, marked, @@ -281,7 +281,7 @@ export default defineComponent({ await api.delete(`/files/${batchPrimaryKeys}`); - await layout.value?.refresh(); + await layoutRef.value?.refresh(); selection.value = []; deleting.value = false; @@ -371,7 +371,7 @@ export default defineComponent({ } function refresh() { - layout.value?.refresh(); + layoutRef.value?.refresh(); } function clearFilters() { diff --git a/app/src/modules/settings/routes/presets/browse/browse.vue b/app/src/modules/settings/routes/presets/browse/browse.vue index a94077c99e..df18aa9d0c 100644 --- a/app/src/modules/settings/routes/presets/browse/browse.vue +++ b/app/src/modules/settings/routes/presets/browse/browse.vue @@ -110,7 +110,7 @@ type PresetRaw = { user: null | { first_name: string; last_name: string }; role: null | { name: string }; collection: string; - view_type: string; + layout: string; }; type Preset = { @@ -176,7 +176,7 @@ export default defineComponent({ } const collection = collectionsStore.getCollection(preset.collection)?.name; - const layout = layouts.find((l) => l.id === preset.view_type)?.name; + const layout = layouts.find((l) => l.id === preset.layout)?.name; return { id: preset.id, @@ -203,7 +203,7 @@ export default defineComponent({ 'user.last_name', 'role.name', 'collection', - 'view_type', + 'layout', ], limit: -1, }, diff --git a/app/src/modules/settings/routes/presets/detail.vue b/app/src/modules/settings/routes/presets/detail.vue index 2bb4329321..c0830bdba6 100644 --- a/app/src/modules/settings/routes/presets/detail.vue +++ b/app/src/modules/settings/routes/presets/detail.vue @@ -66,8 +66,8 @@ v-if="values.layout && values.collection" :is="`layout-${values.layout}`" :collection="values.collection" - :view-options.sync="viewOptions" - :view-query.sync="viewQuery" + :layout-options.sync="layoutOptions" + :layout-query.sync="layoutQuery" :filters="values.filters || []" @update:filters="edits.filters = $event" readonly @@ -116,9 +116,9 @@ type FormattedPreset = { layout: string | null; name: string | null; - view_query: Record | null; + layout_query: Record | null; - view_options: Record | null; + layout_options: Record | null; filters: readonly Filter[] | null; }; @@ -141,7 +141,7 @@ export default defineComponent({ const { loading: rolesLoading, roles } = useRoles(); const { loading: presetLoading, error, preset } = usePreset(); const { fields } = useForm(); - const { edits, hasEdits, initialValues, values, viewQuery, viewOptions } = useValues(); + const { edits, hasEdits, initialValues, values, layoutQuery, layoutOptions } = useValues(); const { save, saving } = useSave(); const { deleting, deleteAndQuit, confirmDelete } = useDelete(); @@ -158,8 +158,8 @@ export default defineComponent({ initialValues, saving, save, - viewQuery, - viewOptions, + layoutQuery, + layoutOptions, hasEdits, deleting, deleteAndQuit, @@ -180,9 +180,9 @@ export default defineComponent({ if (edits.value.name) editsParsed.title = edits.value.name; if (edits.value.name?.length === 0) editsParsed.title = null; if (edits.value.collection) editsParsed.collection = edits.value.collection; - if (edits.value.layout) editsParsed.view_type = edits.value.layout; - if (edits.value.view_query) editsParsed.view_query = edits.value.view_query; - if (edits.value.view_options) editsParsed.view_options = edits.value.view_options; + if (edits.value.layout) editsParsed.layout = edits.value.layout; + if (edits.value.layout_query) editsParsed.layout_query = edits.value.layout_query; + if (edits.value.layout_options) editsParsed.layout_options = edits.value.layout_options; if (edits.value.filters) editsParsed.filters = edits.value.filters; if (edits.value.scope) { @@ -253,11 +253,11 @@ export default defineComponent({ // eslint-disable-next-line @typescript-eslint/no-non-null-assertion id: preset.value.id!, collection: preset.value.collection, - layout: preset.value.view_type, + layout: preset.value.layout, name: preset.value.title, scope: scope, - view_query: preset.value.view_query, - view_options: preset.value.view_options, + layout_query: preset.value.layout_query, + layout_options: preset.value.layout_options, filters: preset.value.filters, }; @@ -271,43 +271,43 @@ export default defineComponent({ }; }); - const viewQuery = computed({ + const layoutQuery = computed({ get() { - if (!values.value.view_query) return null; + if (!values.value.layout_query) return null; if (!values.value.layout) return null; - return values.value.view_query[values.value.layout]; + return values.value.layout_query[values.value.layout]; }, set(newQuery) { edits.value = { ...edits.value, - view_query: { - ...edits.value.view_query, + layout_query: { + ...edits.value.layout_query, [values.value.layout]: newQuery, }, }; }, }); - const viewOptions = computed({ + const layoutOptions = computed({ get() { - if (!values.value.view_options) return null; + if (!values.value.layout_options) return null; if (!values.value.layout) return null; - return values.value.view_options[values.value.layout]; + return values.value.layout_options[values.value.layout]; }, set(newOptions) { edits.value = { ...edits.value, - view_options: { - ...edits.value.view_options, + layout_options: { + ...edits.value.layout_options, [values.value.layout]: newOptions, }, }; }, }); - return { edits, initialValues, values, viewQuery, viewOptions, hasEdits }; + return { edits, initialValues, values, layoutQuery, layoutOptions, hasEdits }; } function usePreset() { diff --git a/app/src/modules/settings/routes/webhooks/browse.vue b/app/src/modules/settings/routes/webhooks/browse.vue index e29c96c2ac..2e9b58f4ee 100644 --- a/app/src/modules/settings/routes/webhooks/browse.vue +++ b/app/src/modules/settings/routes/webhooks/browse.vue @@ -12,51 +12,8 @@ - -
- - Pre-Release: Feature not yet available - + Pre-Release: Feature not yet available
From 0b8fa5033649188882761c5c745908aa2bd23ae1 Mon Sep 17 00:00:00 2001 From: rijkvanzanten Date: Tue, 8 Sep 2020 11:59:54 -0400 Subject: [PATCH 12/14] Fix displays not showing up --- app/src/interfaces/dropdown/index.ts | 2 +- .../routes/data-model/field-detail/components/display.vue | 5 +++-- .../routes/data-model/field-detail/components/interface.vue | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/app/src/interfaces/dropdown/index.ts b/app/src/interfaces/dropdown/index.ts index 958165085a..ea097df3eb 100644 --- a/app/src/interfaces/dropdown/index.ts +++ b/app/src/interfaces/dropdown/index.ts @@ -82,5 +82,5 @@ export default defineInterface(({ i18n }) => ({ }, }, ], - recommendedDisplays: ['badge'], + recommendedDisplays: ['labels'], })); diff --git a/app/src/modules/settings/routes/data-model/field-detail/components/display.vue b/app/src/modules/settings/routes/data-model/field-detail/components/display.vue index 635de72203..11c28f61f7 100644 --- a/app/src/modules/settings/routes/data-model/field-detail/components/display.vue +++ b/app/src/modules/settings/routes/data-model/field-detail/components/display.vue @@ -32,6 +32,7 @@ import { defineComponent, computed } from '@vue/composition-api'; import { getDisplays } from '@/displays'; import { getInterfaces } from '@/interfaces'; import { FancySelectItem } from '@/components/v-fancy-select/types'; +import { clone } from 'lodash'; import { state, availableDisplays } from '../store'; @@ -51,7 +52,7 @@ export default defineComponent({ }); const selectItems = computed(() => { - const recommended = selectedInterface.value?.recommendedDisplays || []; + const recommended = clone(selectedInterface.value?.recommendedDisplays) || []; recommended.push('raw', 'formatted-value'); @@ -75,7 +76,7 @@ export default defineComponent({ ...recommended.map((key) => displayItems.find((item) => item.value === key)), { divider: true }, ...displayItems.filter((item) => recommended.includes(item.value as string) === false), - ]; + ].filter((i) => i); } else { return displayItems; } diff --git a/app/src/modules/settings/routes/data-model/field-detail/components/interface.vue b/app/src/modules/settings/routes/data-model/field-detail/components/interface.vue index 1314df33dd..e9990b95ea 100644 --- a/app/src/modules/settings/routes/data-model/field-detail/components/interface.vue +++ b/app/src/modules/settings/routes/data-model/field-detail/components/interface.vue @@ -90,7 +90,7 @@ export default defineComponent({ ...recommended.map((key) => interfaceItems.find((item) => item.value === key)), { divider: true }, ...interfaceItems.filter((item) => recommended.includes(item.value as string) === false), - ]; + ].filter((i) => i); } else { return interfaceItems; } From 1ca6e63c34e747d9da44ae30eff357931defd09c Mon Sep 17 00:00:00 2001 From: rijkvanzanten Date: Tue, 8 Sep 2020 12:15:12 -0400 Subject: [PATCH 13/14] Fix meta query not returning when only requesting single field --- api/src/middleware/sanitize-query.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/src/middleware/sanitize-query.ts b/api/src/middleware/sanitize-query.ts index c1354f91ce..9edd803967 100644 --- a/api/src/middleware/sanitize-query.ts +++ b/api/src/middleware/sanitize-query.ts @@ -131,4 +131,6 @@ function sanitizeMeta(rawMeta: any) { if (Array.isArray(rawMeta)) { return rawMeta; } + + return [rawMeta]; } From 8811d2a3b47c958250a222797d023815cd999147 Mon Sep 17 00:00:00 2001 From: rijkvanzanten Date: Tue, 8 Sep 2020 12:21:18 -0400 Subject: [PATCH 14/14] Fix limit=0 case --- api/src/database/run-ast.ts | 6 +++--- api/src/middleware/sanitize-query.ts | 6 +++--- api/src/utils/apply-query.ts | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/api/src/database/run-ast.ts b/api/src/database/run-ast.ts index 221462ad61..c2eba3bc13 100644 --- a/api/src/database/run-ast.ts +++ b/api/src/database/run-ast.ts @@ -43,7 +43,7 @@ export default async function runAST(ast: AST, query = ast.query) { let dbQuery = database.select([...toplevelFields, ...tempFields]).from(ast.name); // Query defaults - query.limit = query.limit || 100; + query.limit = typeof query.limit === 'number' ? query.limit : 100; if (query.limit === -1) { delete query.limit; @@ -119,7 +119,7 @@ export default async function runAST(ast: AST, query = ast.query) { * `n` items in total. This limit will then be re-applied in the stitching process * down below */ - if (batchQuery.limit) { + if (typeof batchQuery.limit === 'number') { tempLimit = batchQuery.limit; batchQuery.limit = -1; } @@ -168,7 +168,7 @@ export default async function runAST(ast: AST, query = ast.query) { }); // Reapply LIMIT query on a per-record basis - if (tempLimit) { + if (typeof tempLimit === 'number') { resultsForCurrentRecord = resultsForCurrentRecord.slice(0, tempLimit); } diff --git a/api/src/middleware/sanitize-query.ts b/api/src/middleware/sanitize-query.ts index 9edd803967..ebedf8ee25 100644 --- a/api/src/middleware/sanitize-query.ts +++ b/api/src/middleware/sanitize-query.ts @@ -16,10 +16,10 @@ const sanitizeQuery: RequestHandler = (req, res, next) => { fields: sanitizeFields(req.query.fields) || ['*'], }; - if (req.query.limit) { + if (req.query.limit !== undefined) { const limit = sanitizeLimit(req.query.limit); - if (limit) { + if (typeof limit === 'number') { query.limit = limit; } } @@ -103,7 +103,7 @@ function sanitizeFilter(rawFilter: any, accountability: Accountability | null) { } function sanitizeLimit(rawLimit: any) { - if (!rawLimit) return null; + if (rawLimit === undefined || rawLimit === null) return null; return Number(rawLimit); } diff --git a/api/src/utils/apply-query.ts b/api/src/utils/apply-query.ts index d96ad3dfbf..f2162c2eb5 100644 --- a/api/src/utils/apply-query.ts +++ b/api/src/utils/apply-query.ts @@ -11,7 +11,7 @@ export default async function applyQuery(collection: string, dbQuery: QueryBuild dbQuery.orderBy(query.sort); } - if (query.limit && !query.offset) { + if (typeof query.limit === 'number' && !query.offset) { dbQuery.limit(query.limit); } @@ -109,14 +109,14 @@ export function applyFilter(dbQuery: QueryBuilder, filter: Filter) { } if (operator === '_empty') { - dbQuery.andWhere(query => { + dbQuery.andWhere((query) => { query.whereNull(key); query.orWhere(key, '=', ''); }); } if (operator === '_nempty') { - dbQuery.andWhere(query => { + dbQuery.andWhere((query) => { query.whereNotNull(key); query.orWhere(key, '!=', ''); });