diff --git a/api/package-lock.json b/api/package-lock.json index ae99de930d..3f4a5c2147 100644 --- a/api/package-lock.json +++ b/api/package-lock.json @@ -1,6 +1,6 @@ { "name": "directus", - "version": "9.0.0-beta.13", + "version": "9.0.0-rc.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/api/package.json b/api/package.json index 91dd7268f0..b0aa37e80c 100644 --- a/api/package.json +++ b/api/package.json @@ -1,6 +1,6 @@ { "name": "directus", - "version": "9.0.0-beta.13", + "version": "9.0.0-rc.0", "license": "GPL-3.0-only", "homepage": "https://github.com/directus/next#readme", "description": "Directus is a real-time API and App dashboard for managing SQL database content.", diff --git a/api/src/cli/utils/drivers.ts b/api/src/cli/utils/drivers.ts index b33bd3d3c6..d2542fa3c6 100644 --- a/api/src/cli/utils/drivers.ts +++ b/api/src/cli/utils/drivers.ts @@ -1,9 +1,9 @@ export const drivers = { - sqlite3: 'SQLite', - mysql: 'MySQL / MariaDB / Aurora', pg: 'PostgreSQL / Redshift', - oracledb: 'Oracle Database', - mssql: 'Microsoft SQL Server', + mysql: 'MySQL / MariaDB / Aurora', + sqlite3: 'SQLite (Beta)', + oracledb: 'Oracle Database (Alpha)', + mssql: 'Microsoft SQL Server (Alpha)', }; export function getDriverForClient(client: string): keyof typeof drivers | null { diff --git a/api/src/controllers/auth.ts b/api/src/controllers/auth.ts index ac02da283c..b8a21e79b2 100644 --- a/api/src/controllers/auth.ts +++ b/api/src/controllers/auth.ts @@ -215,7 +215,7 @@ router.get( '/oauth', asyncHandler(async (req, res, next) => { const providers = toArray(env.OAUTH_PROVIDERS); - res.locals.payload = { data: providers.length > 0 ? providers : null }; + res.locals.payload = { data: env.OAUTH_PROVIDERS ? providers : null }; return next(); }), respond diff --git a/api/src/controllers/permissions.ts b/api/src/controllers/permissions.ts index ca8a6b91b3..568bae09b9 100644 --- a/api/src/controllers/permissions.ts +++ b/api/src/controllers/permissions.ts @@ -49,7 +49,7 @@ router.get( router.get( '/me', asyncHandler(async (req, res, next) => { - if (!req.accountability?.user || !req.accountability?.role) { + if (!req.accountability?.user) { throw new InvalidCredentialsException(); } diff --git a/api/src/controllers/users.ts b/api/src/controllers/users.ts index 2e0888141e..b3b7ce4eb1 100644 --- a/api/src/controllers/users.ts +++ b/api/src/controllers/users.ts @@ -58,11 +58,21 @@ router.get( if (!req.accountability?.user) { throw new InvalidCredentialsException(); } + const service = new UsersService({ accountability: req.accountability }); - const item = await service.readByKey(req.accountability.user, req.sanitizedQuery); + try { + const item = await service.readByKey(req.accountability.user, req.sanitizedQuery); + res.locals.payload = { data: item || null }; + } catch (error) { + if (error instanceof ForbiddenException) { + res.locals.payload = { data: { id: req.accountability.user } }; + return next(); + } + + throw error; + } - res.locals.payload = { data: item || null }; return next(); }), respond diff --git a/api/src/database/seeds/03-fields/05-files.yaml b/api/src/database/seeds/03-fields/05-files.yaml index 27554000c0..6d3a4aff64 100644 --- a/api/src/database/seeds/03-fields/05-files.yaml +++ b/api/src/database/seeds/03-fields/05-files.yaml @@ -101,7 +101,7 @@ fields: display: user - collection: directus_files field: modified_on - interface: dateTime + interface: datetime locked: true special: date-updated width: half @@ -111,4 +111,4 @@ fields: display: datetime - collection: directus_files field: created_by - display: user \ No newline at end of file + display: user diff --git a/api/src/utils/parse-filter.ts b/api/src/utils/parse-filter.ts index 92c8888648..ea4a1e4f64 100644 --- a/api/src/utils/parse-filter.ts +++ b/api/src/utils/parse-filter.ts @@ -1,12 +1,16 @@ import { Filter, Accountability } from '../types'; import { deepMap } from './deep-map'; +import { toArray } from '../utils/to-array'; export function parseFilter(filter: Filter, accountability: Accountability | null) { return deepMap(filter, (val: any, key: string) => { if (val === 'true') return true; if (val === 'false') return false; - if (key === '_in' || key === '_nin') return val.split(',').filter((val: any) => val); + if (key === '_in' || key === '_nin') { + if (typeof val === 'string' && val.includes(',')) return val.split(','); + else return toArray(val); + } if (val === '$NOW') return new Date(); if (val === '$CURRENT_USER') return accountability?.user || null; diff --git a/api/src/utils/sanitize-query.ts b/api/src/utils/sanitize-query.ts index 9597ce5a2a..adae6792a3 100644 --- a/api/src/utils/sanitize-query.ts +++ b/api/src/utils/sanitize-query.ts @@ -1,6 +1,7 @@ import { Accountability, Query, Sort, Filter, Meta } from '../types'; import logger from '../logger'; import { parseFilter } from '../utils/parse-filter'; +import { flatten } from 'lodash'; export function sanitizeQuery( rawQuery: Record, @@ -75,6 +76,9 @@ function sanitizeFields(rawFields: any) { if (typeof rawFields === 'string') fields = rawFields.split(','); else if (Array.isArray(rawFields)) fields = rawFields as string[]; + // Case where array item includes CSV (fe fields[]=id,name): + fields = flatten(fields.map((field) => (field.includes(',') ? field.split(',') : field))); + return fields; } diff --git a/api/src/utils/validate-query.ts b/api/src/utils/validate-query.ts index 3b66e5dda3..a55a85c992 100644 --- a/api/src/utils/validate-query.ts +++ b/api/src/utils/validate-query.ts @@ -15,7 +15,7 @@ const querySchema = Joi.object({ offset: Joi.number(), page: Joi.number(), single: Joi.boolean(), - meta: Joi.array().items(Joi.string().valid('total_count', 'result_count')), + meta: Joi.array().items(Joi.string().valid('total_count', 'filter_count')), search: Joi.string(), export: Joi.string().valid('json', 'csv'), deep: Joi.link('#query'), diff --git a/app/package-lock.json b/app/package-lock.json index 015b67ced1..cc1b6b1812 100644 --- a/app/package-lock.json +++ b/app/package-lock.json @@ -1,6 +1,6 @@ { "name": "@directus/app", - "version": "9.0.0-beta.13", + "version": "9.0.0-rc.0", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -6601,51 +6601,6 @@ "tslint": "^5.20.1", "webpack": "^4.0.0", "yorkie": "^2.0.0" - }, - "dependencies": { - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "optional": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, - "fork-ts-checker-webpack-plugin-v5": { - "version": "npm:fork-ts-checker-webpack-plugin@5.2.0", - "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.0.tgz", - "integrity": "sha512-NEKcI0+osT5bBFZ1SFGzJMQETjQWZrSvMO1g0nAR/w0t328Z41eN8BJEIZyFCl2HsuiJpa9AN474Nh2qLVwGLQ==", - "dev": true, - "optional": true, - "requires": { - "@babel/code-frame": "^7.8.3", - "@types/json-schema": "^7.0.5", - "chalk": "^4.1.0", - "cosmiconfig": "^6.0.0", - "deepmerge": "^4.2.2", - "fs-extra": "^9.0.0", - "memfs": "^3.1.2", - "minimatch": "^3.0.4", - "schema-utils": "2.7.0", - "semver": "^7.3.2", - "tapable": "^1.0.0" - } - }, - "schema-utils": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", - "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", - "dev": true, - "optional": true, - "requires": { - "@types/json-schema": "^7.0.4", - "ajv": "^6.12.2", - "ajv-keywords": "^3.4.1" - } - } } }, "@vue/cli-plugin-unit-jest": { @@ -6785,17 +6740,6 @@ "unique-filename": "^1.1.1" } }, - "chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "optional": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } - }, "cliui": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", @@ -6879,18 +6823,6 @@ "graceful-fs": "^4.1.6" } }, - "loader-utils": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", - "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", - "dev": true, - "optional": true, - "requires": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - } - }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -7004,18 +6936,6 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true }, - "vue-loader-v16": { - "version": "npm:vue-loader@16.0.0-beta.8", - "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.0.0-beta.8.tgz", - "integrity": "sha512-oouKUQWWHbSihqSD7mhymGPX1OQ4hedzAHyvm8RdyHh6m3oIvoRF+NM45i/bhNOlo8jCnuJhaSUf/6oDjv978g==", - "dev": true, - "optional": true, - "requires": { - "chalk": "^4.1.0", - "hash-sum": "^2.0.0", - "loader-utils": "^2.0.0" - } - }, "wrap-ansi": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", @@ -11744,6 +11664,51 @@ } } }, + "fork-ts-checker-webpack-plugin-v5": { + "version": "npm:fork-ts-checker-webpack-plugin@5.2.0", + "resolved": "https://registry.npmjs.org/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-5.2.0.tgz", + "integrity": "sha512-NEKcI0+osT5bBFZ1SFGzJMQETjQWZrSvMO1g0nAR/w0t328Z41eN8BJEIZyFCl2HsuiJpa9AN474Nh2qLVwGLQ==", + "dev": true, + "optional": true, + "requires": { + "@babel/code-frame": "^7.8.3", + "@types/json-schema": "^7.0.5", + "chalk": "^4.1.0", + "cosmiconfig": "^6.0.0", + "deepmerge": "^4.2.2", + "fs-extra": "^9.0.0", + "memfs": "^3.1.2", + "minimatch": "^3.0.4", + "schema-utils": "2.7.0", + "semver": "^7.3.2", + "tapable": "^1.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "schema-utils": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-2.7.0.tgz", + "integrity": "sha512-0ilKFI6QQF5nxDZLFn2dMjvc4hjg/Wkg7rHd3jK6/A4a1Hl9VFdQWvgB1UMGoU94pad1P/8N7fMcEnLnSiju8A==", + "dev": true, + "optional": true, + "requires": { + "@types/json-schema": "^7.0.4", + "ajv": "^6.12.2", + "ajv-keywords": "^3.4.1" + } + } + } + }, "form-data": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", @@ -20377,6 +20342,43 @@ } } }, + "vue-loader-v16": { + "version": "npm:vue-loader@16.0.0-beta.8", + "resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.0.0-beta.8.tgz", + "integrity": "sha512-oouKUQWWHbSihqSD7mhymGPX1OQ4hedzAHyvm8RdyHh6m3oIvoRF+NM45i/bhNOlo8jCnuJhaSUf/6oDjv978g==", + "dev": true, + "optional": true, + "requires": { + "chalk": "^4.1.0", + "hash-sum": "^2.0.0", + "loader-utils": "^2.0.0" + }, + "dependencies": { + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dev": true, + "optional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "loader-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz", + "integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==", + "dev": true, + "optional": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + } + } + }, "vue-router": { "version": "3.4.6", "resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.4.6.tgz", diff --git a/app/package.json b/app/package.json index 36bcdfb5fb..bd84dc559c 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "@directus/app", - "version": "9.0.0-beta.13", + "version": "9.0.0-rc.0", "private": false, "description": "Directus is an Open-Source Headless CMS & API for Managing Custom Databases", "author": "Rijk van Zanten ", diff --git a/app/src/app.vue b/app/src/app.vue index 1af46b55dd..3d63279fbb 100644 --- a/app/src/app.vue +++ b/app/src/app.vue @@ -14,15 +14,7 @@ - - - - {{ $t('no_app_access_copy') }} - - - + @@ -48,7 +40,7 @@ export default defineComponent({ const userStore = useUserStore(); const settingsStore = useSettingsStore(); - const { hydrating, drawerOpen } = toRefs(appStore.state); + const { hydrating, sidebarOpen } = toRefs(appStore.state); const brandStyle = computed(() => { return { @@ -73,9 +65,9 @@ export default defineComponent({ if (newWidth === oldWidth) return; if (newWidth >= 1424) { - if (drawerOpen.value === false) drawerOpen.value = true; + if (sidebarOpen.value === false) sidebarOpen.value = true; } else { - if (drawerOpen.value === true) drawerOpen.value = false; + if (sidebarOpen.value === true) sidebarOpen.value = false; } }, { immediate: true } @@ -88,7 +80,7 @@ export default defineComponent({ document.body.classList.remove('light'); document.body.classList.remove('auto'); - if (newUser !== undefined && newUser !== null) { + if (newUser !== undefined && newUser !== null && newUser.theme) { document.body.classList.add(newUser.theme); } else { // Default to light mode @@ -108,11 +100,6 @@ export default defineComponent({ return settingsStore.state?.settings?.custom_css || ''; }); - const appAccess = computed(() => { - if (!userStore.state.currentUser) return true; - return userStore.state.currentUser?.role?.app_access || false; - }); - const error = computed(() => appStore.state.error); /** @@ -124,7 +111,7 @@ export default defineComponent({ axios, }); - return { hydrating, brandStyle, appAccess, error, customCSS }; + return { hydrating, brandStyle, error, customCSS }; }, }); diff --git a/app/src/components/register.ts b/app/src/components/register.ts index f7a3d66826..53c643919b 100644 --- a/app/src/components/register.ts +++ b/app/src/components/register.ts @@ -22,8 +22,7 @@ import VInput from './v-input/'; import VItemGroup, { VItem } from './v-item-group'; import VList, { VListGroup, VListItem, VListItemContent, VListItemHint, VListItemIcon, VListItemText } from './v-list/'; import VMenu from './v-menu/'; -import VModal from './v-modal/'; -import VModalHeading from './v-modal/v-modal-heading.vue'; +import VDrawer from './v-drawer/'; import VNotice from './v-notice/'; import VOverlay from './v-overlay/'; import VPagination from './v-pagination/'; @@ -73,8 +72,7 @@ Vue.component('v-list-item-text', VListItemText); Vue.component('v-list-item', VListItem); Vue.component('v-list', VList); Vue.component('v-menu', VMenu); -Vue.component('v-modal', VModal); -Vue.component('v-modal-heading', VModalHeading); +Vue.component('v-drawer', VDrawer); Vue.component('v-notice', VNotice); Vue.component('v-overlay', VOverlay); Vue.component('v-pagination', VPagination); @@ -104,14 +102,14 @@ Vue.component('transition-expand', TransitionExpand); import RenderDisplay from '@/views/private/components/render-display'; import RenderTemplate from '@/views/private/components/render-template'; -import DrawerDetail from '@/views/private/components/drawer-detail/'; -import FilterDrawerDetail from '@/views/private/components/filter-drawer-detail'; +import SidebarDetail from '@/views/private/components/sidebar-detail/'; +import FilterSidebarDetail from '@/views/private/components/filter-sidebar-detail'; import UserPopover from '@/views/private/components/user-popover'; import ValueNull from '@/views/private/components/value-null'; Vue.component('render-display', RenderDisplay); Vue.component('render-template', RenderTemplate); -Vue.component('filter-drawer-detail', FilterDrawerDetail); -Vue.component('drawer-detail', DrawerDetail); +Vue.component('filter-sidebar-detail', FilterSidebarDetail); +Vue.component('sidebar-detail', SidebarDetail); Vue.component('user-popover', UserPopover); Vue.component('value-null', ValueNull); diff --git a/app/src/components/transition/dialog/transition-dialog.vue b/app/src/components/transition/dialog/transition-dialog.vue index 41ba222234..451d0ed13b 100644 --- a/app/src/components/transition/dialog/transition-dialog.vue +++ b/app/src/components/transition/dialog/transition-dialog.vue @@ -5,24 +5,34 @@ diff --git a/app/src/components/v-dialog/v-dialog.vue b/app/src/components/v-dialog/v-dialog.vue index 0a734c2630..a411cd4d69 100644 --- a/app/src/components/v-dialog/v-dialog.vue +++ b/app/src/components/v-dialog/v-dialog.vue @@ -3,7 +3,7 @@ -
+
@@ -30,6 +30,11 @@ export default defineComponent({ type: Boolean, default: false, }, + placement: { + type: String, + default: 'center', + validator: (val: string) => ['center', 'right'].includes(val), + }, }, setup(props, { emit }) { const dialog = ref(null); @@ -92,11 +97,32 @@ export default defineComponent({ left: 0; z-index: 500; display: flex; - align-items: center; - justify-content: center; width: 100%; height: 100%; - transition: opacity var(--medium) var(--transition); + + ::v-deep > * { + z-index: 2; + box-shadow: 0px 4px 12px rgba(38, 50, 56, 0.1); + } + + &.center { + align-items: center; + justify-content: center; + + &.nudge > ::v-deep *:not(:first-child) { + animation: nudge 200ms; + } + } + + &.right { + align-items: center; + justify-content: flex-end; + + &.nudge > ::v-deep *:not(:first-child) { + transform-origin: right; + animation: shake 200ms; + } + } ::v-deep .v-card { --v-card-min-width: 540px; @@ -112,15 +138,6 @@ export default defineComponent({ .v-overlay { --v-overlay-z-index: 1; } - - &.nudge { - animation: nudge 200ms; - } - - ::v-deep > * { - z-index: 2; - box-shadow: 0px 4px 12px rgba(38, 50, 56, 0.1); - } } @keyframes nudge { @@ -136,4 +153,18 @@ export default defineComponent({ transform: scale(1); } } + +@keyframes shake { + 0% { + transform: scaleX(1); + } + + 50% { + transform: scaleX(0.98); + } + + 100% { + transform: scaleX(1); + } +} diff --git a/app/src/components/v-drawer/index.ts b/app/src/components/v-drawer/index.ts new file mode 100644 index 0000000000..789569bf51 --- /dev/null +++ b/app/src/components/v-drawer/index.ts @@ -0,0 +1,4 @@ +import VDrawer from './v-drawer.vue'; + +export { VDrawer }; +export default VDrawer; diff --git a/app/src/components/v-modal/v-modal.vue b/app/src/components/v-drawer/v-drawer.vue similarity index 53% rename from app/src/components/v-modal/v-modal.vue rename to app/src/components/v-drawer/v-drawer.vue index fcce7ff4c3..1a5cb99bfd 100644 --- a/app/src/components/v-modal/v-modal.vue +++ b/app/src/components/v-drawer/v-drawer.vue @@ -1,20 +1,23 @@ diff --git a/app/src/components/v-form/v-form.vue b/app/src/components/v-form/v-form.vue index 959e66f79b..8535bb817b 100644 --- a/app/src/components/v-form/v-form.vue +++ b/app/src/components/v-form/v-form.vue @@ -139,10 +139,10 @@ export default defineComponent({ const gridClass = computed(() => { if (el.value === null) return null; - if (width.value > 588 && width.value <= 792) { - return 'grid'; - } else { + if (width.value > 792) { return 'grid with-fill'; + } else { + return 'grid'; } return null; diff --git a/app/src/components/v-input/v-input.vue b/app/src/components/v-input/v-input.vue index b1802baa03..1ffa81823c 100644 --- a/app/src/components/v-input/v-input.vue +++ b/app/src/components/v-input/v-input.vue @@ -161,7 +161,7 @@ export default defineComponent({ } } - if (props.slug === true) { + if (props.dbSafe === true) { const dbSafeCharacters = 'abcdefghijklmnopqrstuvwxyz01234567890-_~ '.split(''); const isAllowed = dbSafeCharacters.includes(key) || systemKeys.includes(key); diff --git a/app/src/components/v-modal/index.ts b/app/src/components/v-modal/index.ts deleted file mode 100644 index c3a4ca2b16..0000000000 --- a/app/src/components/v-modal/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -import VModal from './v-modal.vue'; - -export { VModal }; -export default VModal; diff --git a/app/src/components/v-modal/readme.md b/app/src/components/v-modal/readme.md deleted file mode 100644 index 9818b9ca27..0000000000 --- a/app/src/components/v-modal/readme.md +++ /dev/null @@ -1,73 +0,0 @@ -# Modal - -A modal is basically an elaborate pre-configured dialog. It supports an optional left sidebar that allows for easier tab usage. - -## Usage - -```html - - Hello, world! - -``` - -```html - - - - Hello, world! - -``` - -```html - - - - - - - Hello, world! - I'm page 2! - I'm page 3! - - - - -``` - -## Props - -| Prop | Description | Default | -|--------------|-----------------------------------------------------------------|---------| -| `title`* | Title for the modal | | -| `subtitle` | Optional subtitle for the modal | | -| `active` | If the modal is active. Used in `v-model` | `false` | -| `persistent` | Prevent the user from exiting the modal by clicking the overlay | `false` | - -## Events - -| Event | Description | Value | -|----------|--------------------------|-----------| -| `toggle` | Sync the `v-model` value | `boolean` | - -## Slots -| Slot | Description | Data | -|-------------|--------------------------------------------------------|-------------------------| -| _default_ | Modal content | | -| `activator` | Element to enable the modal | `{ on: () => void }` | -| `sidebar` | Sidebar content for the modal. Often used for `v-tabs` | | -| `footer` | Footer content. Often used for action buttons | `{ close: () => void }` | - -## CSS Variables -n/a diff --git a/app/src/components/v-modal/v-modal-heading.vue b/app/src/components/v-modal/v-modal-heading.vue deleted file mode 100644 index 87e523381e..0000000000 --- a/app/src/components/v-modal/v-modal-heading.vue +++ /dev/null @@ -1,34 +0,0 @@ - - - - - diff --git a/app/src/components/v-modal/v-modal.story.ts b/app/src/components/v-modal/v-modal.story.ts deleted file mode 100644 index c9d9ba61b4..0000000000 --- a/app/src/components/v-modal/v-modal.story.ts +++ /dev/null @@ -1,84 +0,0 @@ -import withPadding from '../../../.storybook/decorators/with-padding'; -import readme from './readme.md'; -import { defineComponent, ref } from '@vue/composition-api'; - -export default { - title: 'Components / Modal', - parameters: { - notes: readme, - }, - decorators: [withPadding], -}; - -export const basic = () => - defineComponent({ - setup() { - const active = ref(false); - return { active }; - }, - template: ` -
- - - -

Hello world!

- - -
- -
- `, - }); - -export const withNav = () => - defineComponent({ - setup() { - const active = ref(false); - const current = ref(['hello']); - return { active, current }; - }, - template: ` -
- - - - - - - -

Hello world!

-
- - -

I'm a modal with tabs

-
-
- - - -
- -
- `, - }); diff --git a/app/src/components/v-modal/v-modal.test.ts b/app/src/components/v-modal/v-modal.test.ts deleted file mode 100644 index 944a497925..0000000000 --- a/app/src/components/v-modal/v-modal.test.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { shallowMount, createLocalVue } from '@vue/test-utils'; -import VueCompositionAPI from '@vue/composition-api'; - -import VModal from './v-modal.vue'; -import VDialog from '@/components/v-dialog/'; -import VIcon from '@/components/v-icon/'; - -const localVue = createLocalVue(); -localVue.use(VueCompositionAPI); -localVue.component('v-dialog', VDialog); -localVue.component('v-icon', VIcon); - -describe('Components / Modal', () => { - it('Renders', () => { - const component = shallowMount(VModal, { - localVue, - propsData: { - title: 'My Modal', - }, - }); - - expect(component.isVueInstance()).toBe(true); - }); -}); diff --git a/app/src/components/v-upload/v-upload.vue b/app/src/components/v-upload/v-upload.vue index 0b7a9ef4a7..0b0d3b69e8 100644 --- a/app/src/components/v-upload/v-upload.vue +++ b/app/src/components/v-upload/v-upload.vue @@ -52,7 +52,7 @@ - import { defineComponent, ref, computed, watch } from '@vue/composition-api'; import uploadFiles from '@/utils/upload-files'; -import ModalCollection from '@/views/private/components/modal-collection'; +import DrawerCollection from '@/views/private/components/drawer-collection'; import api from '@/api'; import useItem from '@/composables/use-item'; export default defineComponent({ - components: { ModalCollection }, + components: { DrawerCollection }, props: { multiple: { type: Boolean, diff --git a/app/src/hydrate.ts b/app/src/hydrate.ts index 76909ba75a..603ed6a16a 100644 --- a/app/src/hydrate.ts +++ b/app/src/hydrate.ts @@ -57,11 +57,11 @@ export async function hydrate(stores = useStores()) { */ await userStore.hydrate(); - setLanguage((userStore.state.currentUser?.language as Language) || 'en-US'); - - await Promise.all(stores.filter(({ id }) => id !== 'userStore').map((store) => store.hydrate?.())); - - await registerModules(); + if (userStore.state.currentUser?.role) { + await setLanguage((userStore.state.currentUser?.language as Language) || 'en-US'); + await Promise.all(stores.filter(({ id }) => id !== 'userStore').map((store) => store.hydrate?.())); + await registerModules(); + } } catch (error) { appStore.state.error = error; } finally { diff --git a/app/src/interfaces/file/file.vue b/app/src/interfaces/file/file.vue index a44af12941..f1ef5bd0f6 100644 --- a/app/src/interfaces/file/file.vue +++ b/app/src/interfaces/file/file.vue @@ -79,7 +79,7 @@ - import { defineComponent, ref, watch, computed } from '@vue/composition-api'; -import ModalCollection from '@/views/private/components/modal-collection'; +import DrawerCollection from '@/views/private/components/drawer-collection'; import api from '@/api'; import readableMimeType from '@/utils/readable-mime-type'; import getRootPath from '@/utils/get-root-path'; @@ -124,7 +124,7 @@ type FileInfo = { }; export default defineComponent({ - components: { ModalCollection }, + components: { DrawerCollection }, props: { value: { type: String, diff --git a/app/src/interfaces/files/files.vue b/app/src/interfaces/files/files.vue index 816816208f..78daf1b616 100644 --- a/app/src/interfaces/files/files.vue +++ b/app/src/interfaces/files/files.vue @@ -34,7 +34,7 @@
- - import { defineComponent, ref, computed, toRefs, PropType } from '@vue/composition-api'; import { Header as TableHeader } from '@/components/v-table/types'; -import ModalCollection from '@/views/private/components/modal-collection'; -import ModalItem from '@/views/private/components/modal-item'; +import DrawerCollection from '@/views/private/components/drawer-collection'; +import DrawerItem from '@/views/private/components/drawer-item'; import { get } from 'lodash'; import i18n from '@/lang'; @@ -83,7 +83,7 @@ import usePreview from '@/interfaces/many-to-many/use-preview'; import useEdit from '@/interfaces/many-to-many/use-edit'; export default defineComponent({ - components: { ModalCollection, ModalItem }, + components: { DrawerCollection, DrawerItem }, props: { primaryKey: { type: [Number, String], diff --git a/app/src/interfaces/icon/icon.vue b/app/src/interfaces/icon/icon.vue index e9791ba2d1..5ad613c35d 100644 --- a/app/src/interfaces/icon/icon.vue +++ b/app/src/interfaces/icon/icon.vue @@ -91,6 +91,8 @@ export default defineComponent({ }; function setIcon(icon: string | null) { + searchQuery.value = ''; + emit('input', icon); } }, diff --git a/app/src/interfaces/many-to-many/many-to-many.vue b/app/src/interfaces/many-to-many/many-to-many.vue index 1f61eed428..111ae8d351 100644 --- a/app/src/interfaces/many-to-many/many-to-many.vue +++ b/app/src/interfaces/many-to-many/many-to-many.vue @@ -42,7 +42,7 @@ - - import { defineComponent, ref, computed, watch, PropType, toRefs } from '@vue/composition-api'; -import ModalItem from '@/views/private/components/modal-item'; -import ModalCollection from '@/views/private/components/modal-collection'; +import DrawerItem from '@/views/private/components/drawer-item'; +import DrawerCollection from '@/views/private/components/drawer-collection'; import { get } from 'lodash'; import useActions from './use-actions'; @@ -80,7 +80,7 @@ import useSelection from './use-selection'; import useSort from './use-sort'; export default defineComponent({ - components: { ModalItem, ModalCollection }, + components: { DrawerItem, DrawerCollection }, props: { value: { type: Array as PropType<(number | string | Record)[] | null>, diff --git a/app/src/interfaces/many-to-one/many-to-one.vue b/app/src/interfaces/many-to-one/many-to-one.vue index 7691ea4c1a..b1ebb701be 100644 --- a/app/src/interfaces/many-to-one/many-to-one.vue +++ b/app/src/interfaces/many-to-one/many-to-one.vue @@ -82,7 +82,7 @@ - - - - diff --git a/app/src/interfaces/one-to-many/one-to-many.vue b/app/src/interfaces/one-to-many/one-to-many.vue index dd015bacc1..6bb1128d19 100644 --- a/app/src/interfaces/one-to-many/one-to-many.vue +++ b/app/src/interfaces/one-to-many/one-to-many.vue @@ -42,7 +42,7 @@ - - )[] | null>, diff --git a/app/src/interfaces/translations/translations.vue b/app/src/interfaces/translations/translations.vue index ae397188da..ebb5c79740 100644 --- a/app/src/interfaces/translations/translations.vue +++ b/app/src/interfaces/translations/translations.vue @@ -1,46 +1,43 @@ diff --git a/app/src/interfaces/user/user.vue b/app/src/interfaces/user/user.vue index d27b434db9..a8da9f1a2d 100644 --- a/app/src/interfaces/user/user.vue +++ b/app/src/interfaces/user/user.vue @@ -72,7 +72,7 @@ - -
- - + + diff --git a/app/src/layouts/tabular/tabular.vue b/app/src/layouts/tabular/tabular.vue index ea4f236ef1..5b44c8e8ea 100644 --- a/app/src/layouts/tabular/tabular.vue +++ b/app/src/layouts/tabular/tabular.vue @@ -49,8 +49,8 @@ - - + + diff --git a/app/src/modules/activity/routes/collection.vue b/app/src/modules/activity/routes/collection.vue index 88db83f952..295a2b47fd 100644 --- a/app/src/modules/activity/routes/collection.vue +++ b/app/src/modules/activity/routes/collection.vue @@ -31,12 +31,12 @@ - @@ -47,8 +47,8 @@ import ActivityNavigation from '../components/navigation.vue'; import { i18n } from '@/lang'; import usePreset from '@/composables/use-preset'; import marked from 'marked'; -import FilterDrawerDetail from '@/views/private/components/filter-drawer-detail'; -import LayoutDrawerDetail from '@/views/private/components/layout-drawer-detail'; +import FilterSidebarDetail from '@/views/private/components/filter-sidebar-detail'; +import LayoutSidebarDetail from '@/views/private/components/layout-sidebar-detail'; import SearchInput from '@/views/private/components/search-input'; import { nanoid } from 'nanoid'; @@ -58,7 +58,7 @@ type Item = { export default defineComponent({ name: 'activity-collection', - components: { ActivityNavigation, FilterDrawerDetail, LayoutDrawerDetail, SearchInput }, + components: { ActivityNavigation, FilterSidebarDetail, LayoutSidebarDetail, SearchInput }, props: { primaryKey: { type: String, diff --git a/app/src/modules/activity/routes/item.vue b/app/src/modules/activity/routes/item.vue index 7be7b344a8..dbe60c6285 100644 --- a/app/src/modules/activity/routes/item.vue +++ b/app/src/modules/activity/routes/item.vue @@ -1,14 +1,14 @@