diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 12e4f40726..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -name: Bug report -about: Create a report to help us improve -title: '' -labels: '' -assignees: '' ---- - - diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index c12b5bf986..e181d3dd09 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -10,7 +10,19 @@ body: value: 'Before continuing, you must first have completed all [Troubleshooting Steps](https://docs.directus.io/getting-started/support/#troubleshooting-steps)' - type: markdown attributes: - value: Please double check if an issue describing this problem doesn't exist already. + value: Please confirm that an issue describing this problem doesn't exist already. + - type: textarea + attributes: + label: Describe the Bug + description: A clear and concise description of what the bug is. + validations: + required: true + - type: textarea + attributes: + label: To Reproduce + description: Steps to reproduce the behavior. Contributors should be able to follow the steps provided in order to reproduce the bug. + validations: + required: true - type: input attributes: label: What version of Directus are you using? @@ -47,15 +59,3 @@ body: description: 'For example: running locally, Docker, PaaS' validations: required: true - - type: textarea - attributes: - label: Describe the Bug - description: A clear and concise description of what the bug is. - validations: - required: true - - type: textarea - attributes: - label: To Reproduce - description: Steps to reproduce the behavior. Contributors should be able to follow the steps provided in order to reproduce the bug. - validations: - required: true diff --git a/api/cli.js b/api/cli.js index 02ff76db71..d7ce758fbc 100755 --- a/api/cli.js +++ b/api/cli.js @@ -1,2 +1,2 @@ #!/usr/bin/env node -return require('./dist/cli/index.js'); +require('./dist/cli/index.js'); diff --git a/api/package.json b/api/package.json index 3d972a631e..ff9587934a 100644 --- a/api/package.json +++ b/api/package.json @@ -1,6 +1,6 @@ { "name": "directus", - "version": "9.0.0-rc.80", + "version": "9.0.0-rc.81", "license": "GPL-3.0-only", "homepage": "https://github.com/directus/directus#readme", "description": "Directus is a real-time API and App dashboard for managing SQL database content.", @@ -69,15 +69,15 @@ "example.env" ], "dependencies": { - "@directus/app": "9.0.0-rc.80", - "@directus/drive": "9.0.0-rc.80", - "@directus/drive-azure": "9.0.0-rc.80", - "@directus/drive-gcs": "9.0.0-rc.80", - "@directus/drive-s3": "9.0.0-rc.80", - "@directus/format-title": "9.0.0-rc.80", - "@directus/schema": "9.0.0-rc.80", - "@directus/shared": "9.0.0-rc.80", - "@directus/specs": "9.0.0-rc.80", + "@directus/app": "9.0.0-rc.81", + "@directus/drive": "9.0.0-rc.81", + "@directus/drive-azure": "9.0.0-rc.81", + "@directus/drive-gcs": "9.0.0-rc.81", + "@directus/drive-s3": "9.0.0-rc.81", + "@directus/format-title": "9.0.0-rc.81", + "@directus/schema": "9.0.0-rc.81", + "@directus/shared": "9.0.0-rc.81", + "@directus/specs": "9.0.0-rc.81", "@godaddy/terminus": "^4.9.0", "@rollup/plugin-alias": "^3.1.2", "@rollup/plugin-virtual": "^2.0.3", @@ -89,7 +89,7 @@ "busboy": "^0.3.1", "camelcase": "^6.2.0", "chalk": "^4.1.1", - "commander": "^7.2.0", + "commander": "^8.0.0", "cookie-parser": "^1.4.5", "cors": "^2.8.5", "csv-parser": "^3.0.0", diff --git a/api/src/cli/index.ts b/api/src/cli/index.ts index f68bbe62c5..c2d6177d25 100644 --- a/api/src/cli/index.ts +++ b/api/src/cli/index.ts @@ -2,7 +2,7 @@ /* eslint-disable no-console */ -import program from 'commander'; +import { program } from 'commander'; import start from '../start'; import bootstrap from './commands/bootstrap'; import count from './commands/count'; diff --git a/api/src/database/migrations/20210519A-add-system-fk-triggers.ts b/api/src/database/migrations/20210519A-add-system-fk-triggers.ts index 33837d7849..2cf58f6a0c 100644 --- a/api/src/database/migrations/20210519A-add-system-fk-triggers.ts +++ b/api/src/database/migrations/20210519A-add-system-fk-triggers.ts @@ -1,5 +1,6 @@ import { Knex } from 'knex'; import logger from '../../logger'; +import SchemaInspector from 'knex-schema-inspector'; /** * Things to keep in mind: @@ -80,11 +81,23 @@ const updates = [ ]; export async function up(knex: Knex): Promise { + const inspector = SchemaInspector(knex); + + const foreignKeys = await inspector.foreignKeys(); + for (const update of updates) { for (const constraint of update.constraints) { + const existingForeignKey = foreignKeys.find( + (fk) => + fk.table === update.table && + fk.column === constraint.column && + fk.foreign_key_table === constraint.references.split('.')[0] && + fk.foreign_key_column === constraint.references.split('.')[1] + ); + try { await knex.schema.alterTable(update.table, (table) => { - table.dropForeign([constraint.column]); + table.dropForeign([constraint.column], existingForeignKey?.constraint_name || undefined); }); } catch (err) { logger.warn(`Couldn't drop foreign key ${update.table}.${constraint.column}->${constraint.references}`); diff --git a/api/src/database/migrations/20210626A-change-filesize-bigint.ts b/api/src/database/migrations/20210626A-change-filesize-bigint.ts new file mode 100644 index 0000000000..53544c34c5 --- /dev/null +++ b/api/src/database/migrations/20210626A-change-filesize-bigint.ts @@ -0,0 +1,13 @@ +import { Knex } from 'knex'; + +export async function up(knex: Knex): Promise { + await knex.schema.alterTable('directus_files', (table) => { + table.bigInteger('filesize').nullable().defaultTo(null).alter(); + }); +} + +export async function down(knex: Knex): Promise { + await knex.schema.alterTable('directus_files', (table) => { + table.integer('filesize').nullable().defaultTo(null).alter(); + }); +} diff --git a/api/src/database/system-data/app-access-permissions/app-access-permissions.yaml b/api/src/database/system-data/app-access-permissions/app-access-permissions.yaml index 77c6c82d5b..b4c4e15f9a 100644 --- a/api/src/database/system-data/app-access-permissions/app-access-permissions.yaml +++ b/api/src/database/system-data/app-access-permissions/app-access-permissions.yaml @@ -81,6 +81,7 @@ - id - first_name - last_name + - last_page - email - password - location diff --git a/api/src/env.ts b/api/src/env.ts index f2258da059..9b50dc1901 100644 --- a/api/src/env.ts +++ b/api/src/env.ts @@ -47,7 +47,7 @@ const defaults: Record = { CACHE_ENABLED: false, CACHE_STORE: 'memory', - CACHE_TTL: '10m', + CACHE_TTL: '5m', CACHE_NAMESPACE: 'system-cache', CACHE_AUTO_PURGE: false, CACHE_CONTROL_S_MAXAGE: '0', @@ -65,7 +65,7 @@ const defaults: Record = { TELEMETRY: true, ASSETS_CACHE_TTL: '30m', - ASSETS_TRANSFORM_MAX_CONCURRENT: 4, + ASSETS_TRANSFORM_MAX_CONCURRENT: 1, ASSETS_TRANSFORM_IMAGE_MAX_DIMENSION: 6000, }; diff --git a/api/src/extensions.ts b/api/src/extensions.ts index 045c6195ca..d1c94e60ed 100644 --- a/api/src/extensions.ts +++ b/api/src/extensions.ts @@ -2,7 +2,7 @@ import express, { Router } from 'express'; import path from 'path'; import { AppExtensionType, Extension, ExtensionType } from '@directus/shared/types'; import { - ensureExtensionsDirs, + ensureExtensionDirs, generateExtensionsEntry, getLocalExtensions, getPackageExtensions, @@ -31,7 +31,7 @@ let extensions: Extension[] = []; let extensionBundles: Partial> = {}; export async function initializeExtensions(): Promise { - await ensureExtensionsDirs(env.EXTENSIONS_PATH); + await ensureExtensionDirs(env.EXTENSIONS_PATH); extensions = await getExtensions(); if (!('DIRECTUS_DEV' in process.env)) { @@ -88,9 +88,10 @@ async function generateExtensionBundles() { const bundle = await rollup({ input: 'entry', external: Object.values(sharedDepsMapping), + makeAbsoluteExternalsRelative: false, plugins: [virtual({ entry }), alias({ entries: internalImports })], }); - const { output } = await bundle.generate({ format: 'es' }); + const { output } = await bundle.generate({ format: 'es', compact: true }); bundles[extensionType] = output[0].code; @@ -102,13 +103,14 @@ async function generateExtensionBundles() { async function getSharedDepsMapping(deps: string[]) { const appDir = await fse.readdir(path.join(resolvePackage('@directus/app'), 'dist')); + const adminUrl = env.PUBLIC_URL.endsWith('/') ? env.PUBLIC_URL + 'admin' : env.PUBLIC_URL + '/admin'; const depsMapping: Record = {}; for (const dep of deps) { const depName = appDir.find((file) => dep.replace(/\//g, '_') === file.substring(0, file.indexOf('.'))); if (depName) { - depsMapping[dep] = `${env.PUBLIC_URL}/admin/${depName}`; + depsMapping[dep] = `${adminUrl}/${depName}`; } else { logger.warn(`Couldn't find shared extension dependency "${dep}"`); } diff --git a/api/src/services/mail/index.ts b/api/src/services/mail/index.ts index 42c3c16f03..19efaf95bd 100644 --- a/api/src/services/mail/index.ts +++ b/api/src/services/mail/index.ts @@ -67,12 +67,7 @@ export class MailService { html = prettier.format(html as string, { parser: 'html', printWidth: 70, tabWidth: 0 }); } - try { - await this.mailer.sendMail({ ...emailOptions, from, html }); - } catch (error) { - logger.warn('[Email] Unexpected error while sending an email:'); - logger.warn(error); - } + await this.mailer.sendMail({ ...emailOptions, from, html }); } private async renderTemplate(template: string, variables: Record) { diff --git a/app/package.json b/app/package.json index ed85ceca04..3a68e8298d 100644 --- a/app/package.json +++ b/app/package.json @@ -1,6 +1,6 @@ { "name": "@directus/app", - "version": "9.0.0-rc.80", + "version": "9.0.0-rc.81", "private": false, "description": "Directus is an Open-Source Headless CMS & API for Managing Custom Databases", "author": "Rijk van Zanten ", @@ -28,10 +28,10 @@ }, "gitHead": "24621f3934dc77eb23441331040ed13c676ceffd", "devDependencies": { - "@directus/docs": "9.0.0-rc.80", - "@directus/extension-sdk": "9.0.0-rc.80", - "@directus/format-title": "9.0.0-rc.80", - "@directus/shared": "9.0.0-rc.80", + "@directus/docs": "9.0.0-rc.81", + "@directus/extension-sdk": "9.0.0-rc.81", + "@directus/format-title": "9.0.0-rc.81", + "@directus/shared": "9.0.0-rc.81", "@fullcalendar/core": "5.8.0", "@fullcalendar/daygrid": "5.8.0", "@fullcalendar/interaction": "5.8.0", @@ -53,13 +53,13 @@ "@types/mime-types": "2.1.0", "@types/ms": "0.7.31", "@types/qrcode": "1.4.0", - "@vitejs/plugin-vue": "1.2.3", + "@vitejs/plugin-vue": "1.2.4", "@vue/cli-plugin-babel": "4.5.13", "@vue/cli-plugin-router": "4.5.13", "@vue/cli-plugin-typescript": "4.5.13", "@vue/cli-plugin-vuex": "4.5.13", "@vue/cli-service": "4.5.13", - "@vue/compiler-sfc": "3.1.1", + "@vue/compiler-sfc": "3.1.2", "axios": "0.21.1", "base-64": "1.0.0", "codemirror": "5.62.0", @@ -71,13 +71,13 @@ "front-matter": "4.0.2", "html-entities": "2.3.2", "jsonlint-mod": "1.7.6", - "marked": "2.1.2", + "marked": "2.1.3", "micromustache": "8.0.3", "mime": "2.5.2", - "mitt": "2.1.0", + "mitt": "3.0.0", "nanoid": "3.1.23", "pinia": "2.0.0-beta.3", - "prettier": "2.3.1", + "prettier": "2.3.2", "pretty-ms": "7.0.1", "qrcode": "1.4.4", "rimraf": "3.0.2", @@ -85,7 +85,7 @@ "tinymce": "5.8.2", "typescript": "4.3.4", "vite": "2.3.8", - "vue": "3.1.1", + "vue": "3.1.2", "vue-i18n": "9.1.6", "vue-router": "4.0.10", "vuedraggable": "4.0.3" diff --git a/app/src/api.ts b/app/src/api.ts index e26e325abe..017b715330 100644 --- a/app/src/api.ts +++ b/app/src/api.ts @@ -38,15 +38,16 @@ export const onRequest = (config: AxiosRequestConfig): RequestConfig => { export const onResponse = (response: AxiosResponse | Response): AxiosResponse | Response => { const requestsStore = useRequestsStore(); - const id = (response.config as RequestConfig).id; - requestsStore.endRequest(id); + const id = (response.config as RequestConfig)?.id; + if (id) requestsStore.endRequest(id); return response; }; export const onError = async (error: RequestError): Promise => { const requestsStore = useRequestsStore(); - const id = (error.response.config as RequestConfig).id; - requestsStore.endRequest(id); + const id = (error.response?.config as RequestConfig)?.id; + + if (id) requestsStore.endRequest(id); // If a request fails with the unauthorized error, it either means that your user doesn't have // access, or that your session doesn't exist / has expired. diff --git a/app/src/assets/fonts/material-icons-outline.woff2 b/app/src/assets/fonts/material-icons-outline.woff2 index 6281714aee..0a08751e10 100644 Binary files a/app/src/assets/fonts/material-icons-outline.woff2 and b/app/src/assets/fonts/material-icons-outline.woff2 differ diff --git a/app/src/assets/fonts/material-icons.woff2 b/app/src/assets/fonts/material-icons.woff2 index 2463f891a0..f18fa5239f 100644 Binary files a/app/src/assets/fonts/material-icons.woff2 and b/app/src/assets/fonts/material-icons.woff2 differ diff --git a/app/src/components/v-detail/v-detail.vue b/app/src/components/v-detail/v-detail.vue index 946a362330..d3eb612a6c 100644 --- a/app/src/components/v-detail/v-detail.vue +++ b/app/src/components/v-detail/v-detail.vue @@ -1,9 +1,11 @@ @@ -42,21 +63,21 @@ import { useI18n } from 'vue-i18n'; import { defineComponent, PropType, computed, ref, provide } from 'vue'; import { useFieldsStore } from '@/stores/'; import { Field, FieldRaw } from '@/types'; -import { useElementSize } from '@/composables/use-element-size'; -import { clone, cloneDeep } from 'lodash'; +import { clone, cloneDeep, isNil, merge, omit } from 'lodash'; import { md } from '@/utils/md'; -import FormField from './form-field.vue'; import useFormFields from '@/composables/use-form-fields'; -import { ValidationError } from './types'; -import { translate } from '@/utils/translate-object-values'; +import { ValidationError } from '@/types'; +import { useElementSize } from '@/composables/use-element-size'; +import FormField from './form-field.vue'; type FieldValues = { [field: string]: any; }; export default defineComponent({ - emits: ['update:modelValue'], + name: 'v-form', components: { FormField }, + emits: ['update:modelValue'], props: { collection: { type: String, @@ -99,18 +120,35 @@ export default defineComponent({ type: Boolean, default: false, }, + group: { + type: Number, + default: null, + }, }, setup(props, { emit }) { const { t } = useI18n(); - const el = ref(); const fieldsStore = useFieldsStore(); const values = computed(() => { return Object.assign({}, props.initialValues, props.modelValue); }); - const { formFields, gridClass } = useForm(); + const el = ref(); + + const { width } = useElementSize(el); + + const gridClass = computed(() => { + if (el.value === null) return null; + + if (width.value > 792) { + return 'grid with-fill'; + } else { + return 'grid'; + } + }); + + const { formFields, getFieldsForGroup } = useForm(); const { toggleBatchField, batchActiveFields } = useBatch(); const firstEditableFieldIndex = computed(() => { @@ -136,9 +174,7 @@ export default defineComponent({ return { t, - el, formFields, - gridClass, values, setValue, batchActiveFields, @@ -147,6 +183,12 @@ export default defineComponent({ md, unknownValidationErrors, firstEditableFieldIndex, + isNil, + apply, + el, + gridClass, + omit, + getFieldsForGroup, }; function useForm() { @@ -165,36 +207,30 @@ export default defineComponent({ const { formFields } = useFormFields(fields); const formFieldsParsed = computed(() => { - return translate( - formFields.value.map((field: Field) => { - if ( - field.schema?.has_auto_increment === true || - (field.schema?.is_primary_key === true && props.primaryKey !== '+') - ) { - const fieldClone = cloneDeep(field) as any; - if (!fieldClone.meta) fieldClone.meta = {}; - fieldClone.meta.readonly = true; - return fieldClone; - } + const blockPrimaryKey = (field: Field) => { + if ( + field.schema?.has_auto_increment === true || + (field.schema?.is_primary_key === true && props.primaryKey !== '+') + ) { + const fieldClone = cloneDeep(field) as any; + if (!fieldClone.meta) fieldClone.meta = {}; + fieldClone.meta.readonly = true; + return fieldClone; + } - return field; - }) - ); + return field; + }; + + return formFields.value.map((field) => blockPrimaryKey(field)); }); - const { width } = useElementSize(el); + const formFieldsInGroup = computed(() => + formFieldsParsed.value.filter( + (field) => field.meta?.group === props.group || (props.group === null && isNil(field.meta?.group)) + ) + ); - const gridClass = computed(() => { - if (el.value === null) return null; - - if (width.value > 792) { - return 'grid with-fill'; - } else { - return 'grid'; - } - }); - - return { formFields: formFieldsParsed, gridClass, isDisabled }; + return { formFields: formFieldsInGroup, isDisabled, getFieldsForGroup }; function isDisabled(field: Field) { return ( @@ -204,6 +240,20 @@ export default defineComponent({ (props.batchMode && batchActiveFields.value.includes(field.field) === false) ); } + + function getFieldsForGroup(group: null | number): Field[] { + const fieldsInGroup: Field[] = formFieldsParsed.value.filter( + (field) => field.meta?.group === group || (group === null && isNil(field.meta)) + ); + + for (const field of fieldsInGroup) { + if (field.meta?.special?.includes('group')) { + fieldsInGroup.push(...getFieldsForGroup(field.meta!.id)); + } + } + + return fieldsInGroup; + } } function setValue(field: Field, value: any) { @@ -212,6 +262,10 @@ export default defineComponent({ emit('update:modelValue', edits); } + function apply(updates: { [field: string]: any }) { + emit('update:modelValue', merge({}, props.modelValue, updates)); + } + function unsetValue(field: Field) { if (field.field in (props.modelValue || {})) { const newEdits = { ...props.modelValue }; diff --git a/app/src/composables/use-form-fields/use-form-fields.ts b/app/src/composables/use-form-fields/use-form-fields.ts index 04cf4e0353..3930a0659f 100644 --- a/app/src/composables/use-form-fields/use-form-fields.ts +++ b/app/src/composables/use-form-fields/use-form-fields.ts @@ -7,6 +7,7 @@ import { Field } from '@/types'; import { getDefaultInterfaceForType } from '@/utils/get-default-interface-for-type'; import { clone, orderBy } from 'lodash'; import { computed, ComputedRef, Ref } from 'vue'; +import { translate } from '@/utils/translate-object-values'; export default function useFormFields(fields: Ref): { formFields: ComputedRef } { const { interfaces } = getInterfaces(); @@ -60,6 +61,8 @@ export default function useFormFields(fields: Ref): { formFields: Compu formFields = orderBy(formFields, 'meta.sort'); + formFields = translate(formFields); + return formFields; }); diff --git a/app/src/interfaces/group-divider/group-divider.vue b/app/src/interfaces/group-divider/group-divider.vue new file mode 100644 index 0000000000..fc3c96efe1 --- /dev/null +++ b/app/src/interfaces/group-divider/group-divider.vue @@ -0,0 +1,124 @@ + + + + + diff --git a/app/src/interfaces/group-divider/index.ts b/app/src/interfaces/group-divider/index.ts new file mode 100644 index 0000000000..923b360b42 --- /dev/null +++ b/app/src/interfaces/group-divider/index.ts @@ -0,0 +1,76 @@ +import { defineInterface } from '@/interfaces/define'; +import InterfaceGroupDivider from './group-divider.vue'; + +export default defineInterface({ + id: 'group-divider', + name: '$t:interfaces.presentation-divider.divider', + description: '$t:interfaces.presentation-divider.description', + icon: 'remove', + component: InterfaceGroupDivider, + hideLabel: true, + hideLoader: true, + types: ['alias'], + groups: ['group'], + options: [ + { + field: 'color', + name: '$t:color', + type: 'string', + meta: { + width: 'half', + interface: 'select-color', + }, + }, + { + field: 'icon', + name: '$t:icon', + type: 'string', + meta: { + width: 'half', + interface: 'select-icon', + }, + }, + { + field: 'title', + name: '$t:title', + type: 'string', + meta: { + width: 'full', + interface: 'input', + options: { + placeholder: '$t:interfaces.presentation-divider.title_placeholder', + }, + }, + }, + { + field: 'marginTop', + name: '$t:interfaces.presentation-divider.margin_top', + type: 'boolean', + meta: { + width: 'half', + interface: 'boolean', + options: { + label: '$t:interfaces.presentation-divider.margin_top_label', + }, + }, + schema: { + default_value: false, + }, + }, + { + field: 'inlineTitle', + name: '$t:interfaces.presentation-divider.inline_title', + type: 'boolean', + meta: { + width: 'half', + interface: 'boolean', + options: { + label: '$t:interfaces.presentation-divider.inline_title_label', + }, + }, + schema: { + default_value: false, + }, + }, + ], +}); diff --git a/app/src/interfaces/group-raw/group-raw.vue b/app/src/interfaces/group-raw/group-raw.vue new file mode 100644 index 0000000000..183add69f8 --- /dev/null +++ b/app/src/interfaces/group-raw/group-raw.vue @@ -0,0 +1,67 @@ + + + diff --git a/app/src/interfaces/group-raw/index.ts b/app/src/interfaces/group-raw/index.ts new file mode 100644 index 0000000000..b327c80483 --- /dev/null +++ b/app/src/interfaces/group-raw/index.ts @@ -0,0 +1,13 @@ +import { defineInterface } from '../define'; +import InterfaceGroupRaw from './group-raw.vue'; + +export default defineInterface({ + id: 'group-raw', + name: '$t:interfaces.group-raw.name', + description: '$t:interfaces.group-raw.description', + icon: 'view_in_ar', + component: InterfaceGroupRaw, + groups: ['group'], + types: ['alias'], + options: [], +}); diff --git a/app/src/interfaces/list-o2m-tree-view/nested-draggable.vue b/app/src/interfaces/list-o2m-tree-view/nested-draggable.vue index f30e0df37d..365571629d 100644 --- a/app/src/interfaces/list-o2m-tree-view/nested-draggable.vue +++ b/app/src/interfaces/list-o2m-tree-view/nested-draggable.vue @@ -179,10 +179,6 @@ export default defineComponent({ } } -.flip-list-move { - transition: transform 0.5s; -} - .ghost .preview { background-color: var(--primary-alt); box-shadow: 0 !important; diff --git a/app/src/interfaces/translations/options.vue b/app/src/interfaces/translations/options.vue index 27dc529aaa..0b15e07289 100644 --- a/app/src/interfaces/translations/options.vue +++ b/app/src/interfaces/translations/options.vue @@ -16,7 +16,7 @@
-

{{ $t('translations_display_template') }}

+

{{ t('translations_display_template') }}

- - Сигурни ли сте, че искате да изтриете "{bookmark}" отметката? Това действие не може да бъде отменено. + Сигурни ли сте, че искате да изтриете "{bookmark}" отметката? Действието не може да бъде отменено. logoutReason: SIGN_OUT: Отписан SESSION_EXPIRED: Сесията е изтекла @@ -53,16 +58,16 @@ os_version: Версия на ОС os_uptime: Време от старт на ОС os_totalmem: Памет на ОС archive: Архивиране -archive_confirm: Сигурни ли сте, че искате да изтриете този запис? +archive_confirm: Сигурни ли сте, че искате да изтриете записа? archive_confirm_count: >- - Няма избрани записи | Сигурни ли сте, че искате да архивирате този запис? | Сигурни ли сте, че искате да архивирате тези {count} записа? + Няма избрани записи | Сигурни ли сте, че искате да архивирате записа? | Сигурни ли сте, че искате да архивирате тези {count} записа? reset_system_permissions_to: 'Нулиране на системните позволения към:' -reset_system_permissions_copy: Това действие може да презапише потребителските позволения които са приложени към системните колекции. Сигурни ли сте? +reset_system_permissions_copy: Действието може да презапише потребителските позволения, които са приложени към системните колекции. Сигурни ли сте? the_following_are_minimum_permissions: Следните са минималните изисквани позволения за достъп до "Приложението". Може да бъдат добавяни повече, но не и по-малко. app_access_minimum: Минимум за достъп до приложението recommended_defaults: Препоръчителни unarchive: Разархивиране -unarchive_confirm: Сигурни ли сте, че искате да разархивирате този запис? +unarchive_confirm: Сигурни ли сте, че искате да разархивирате записа? nested_files_folders_will_be_moved: Вложените файлове и папки ще бъдат преместени една папка по-нагоре. unknown_validation_errors: 'Има грешки при валидацията на следните скрити полета:' validationError: @@ -81,14 +86,14 @@ validationError: null: Стойността трябва да е null nnull: Стойността не трябва да е null required: Изисква се стойност - unique: Изисква се уникална стойност + unique: Само уникални стойности regex: Стойността е неправилно форматирана all_access: Пълен достъп no_access: Без достъп use_custom: Персонализиран nullable: Може да е null allow_null_value: Може да е NULL -enter_value_to_replace_nulls: Въвеждане на нова стойност, която да замени NULL в това поле. +enter_value_to_replace_nulls: Въвеждане на нова стойност, която да замени NULL в полето. field_standard: Стандартно field_presentation: Презентационни и псевдоними field_file: Единствен файл @@ -101,10 +106,10 @@ field_translations: Преводи item_permissions: Позволения по запис field_permissions: Позволения по поле field_validation: Валидация по поле -field_presets: Стойност на полета +field_presets: Стойности на полета permissions_for_role: 'Записи, които ролята "{role}" има позволение за {action}.' fields_for_role: 'Полета, които ролята "{role}" има позволение за {action}.' -validation_for_role: 'Правила, които ролята "{role}" трябва да спазва, при {action} на полетo.' +validation_for_role: 'Правила, които ролята "{role}" трябва да спазва, при {action} на полета.' presets_for_role: 'Стойности за полета по подразбиране, за ролята "{role}".' presentation_and_aliases: Презентационни и псевдоними revision_post_update: Ето как ще изглежда записът след промяната... @@ -118,14 +123,14 @@ field_create_success: 'Създадено поле: "{field}"' field_update_success: 'Обновено поле: "{field}"' duplicate_where_to: Къде искате да дублирате полето? language: Език -global: Глобални +global: Глобален admins_have_all_permissions: Администраторите имат всички позволения camera: Камера exposure: Експозиция shutter: Затвор iso: ISO focal_length: Фокусно разстояние -schema_setup_key: Име на колоната в базата данни, както и име на полето в API +schema_setup_key: Име на колоната в базата от данни, както и име на полето в API create_field: Създаване на поле creating_new_field: 'Ново поле ({collection})' field_in_collection: '{field} ({collection})' @@ -150,7 +155,7 @@ time: Час timestamp: Времеви печат uuid: UUID hash: Хеш -not_available_for_type: Не е налично за този тип +not_available_for_type: Не е налично за типа create_translations: Създаване на преводи auto_refresh: Автоматично опресняване refresh_interval: Интервал за опресняване @@ -158,7 +163,7 @@ no_refresh: Да не се опреснява refresh_interval_seconds: Моментално опресняване | Всяка секунда | Всеки {seconds} секунди refresh_interval_minutes: Всяка минута | Всеки {minutes} минути auto_generate: Автоматично генериране -this_will_auto_setup_fields_relations: Автоматично настройване на задължителните полета и релации. +this_will_auto_setup_fields_relations: Автоматично настройване и генериране на задължителните полета и релации. click_here: Натиснете тук to_manually_setup_translations: за ръчна настройка на преводи. click_to_manage_translated_fields: >- @@ -205,7 +210,7 @@ edit_raw_value: Редактиране в суров вид enter_raw_value: Въвеждане на стойността в суров вид... clear_value: Изчистване на стойност reset_to_default: Възстановяване към начално състояние -undo_changes: Отмяна на промените +undo_changes: Отмяна и напускане notifications: Известия show_all_activity: Показване на цялата активност page_not_found: Страницата не е намерена @@ -216,7 +221,7 @@ display: Показване settings_update_success: Настройките са обновени title: Заглавие revision_delta_created: Създаден -revision_delta_created_externally: Външно създаден +revision_delta_created_externally: Създадено отвън revision_delta_updated: '1 поле е обновено | {count} полета са обновени' revision_delta_deleted: Изтрито revision_delta_reverted: Възстановен @@ -231,7 +236,7 @@ item_create_success: Създаден запис | Създадени запис item_update_success: Обновен запис | Обновени записи item_delete_success: Изтрит запис | Изтрити записи this_collection: Тази колекция -related_collection: Релационна колекция +related_collection: Релативна колекция related_collections: Релационни колекции translations_collection: Колекция с преводи languages_collection: Колекция с езици @@ -249,7 +254,7 @@ submit: Изпращане move_to_folder: Преместване в папка move: Преместване system: Система -add_field_related: Добавяне на поле към релационната колекция +add_field_related: Добавяне на поле към релативната колекция interface: Интерфейс today: Днес yesterday: Вчера @@ -312,7 +317,7 @@ creating_new_collection: Създаване на колекция created_by: Създадено от created_on: Създаден на creating_collection_info: Именуване на колекцията и настройка на уникално ключово поле... -creating_collection_system: Включване и применуване на някои от следните незадължителни полета. +creating_collection_system: Включване и преименуване на някои от следните незадължителни полета. auto_increment_integer: Автоматично следващо число generated_uuid: Генериран UUID manual_string: Ръчно въвеждане на стойност @@ -321,9 +326,9 @@ save_and_stay: Запазване и оставане save_as_copy: Запазване като копие add_existing: Добавяне на съществуващ creating_items: Създаване на записи -enable_create_button: Включване на бутона за създаване +enable_create_button: Показване на бутон за създаване selecting_items: Избор на записи -enable_select_button: Включване на бутона за избор +enable_select_button: Показване на бутон за избор comments: Коментари no_comments: Все още няма коментари click_to_expand: Натиснете за разширяване @@ -375,7 +380,7 @@ file_moved: Файлът е преместен collection_created: Колекцията е създадена modified_on: Променен на card_size: Големина на картите -sort_field: Поле за сортиране +sort_field: Сортиране по поле add_sort_field: Добавяне на поле за сортиране sort: Сортиране status: Статус @@ -415,12 +420,12 @@ bookmark_name: Име на отметка... create_bookmark: Създаване на отметка edit_bookmark: Редактиране на отметката bookmarks: Отметки -presets: Готови изгледи +presets: Заготовки unexpected_error: Неочаквана грешка unexpected_error_copy: Възникна неочаквана грешка, опитайте отново по-късно. copy_details: Копиране на детайли no_app_access: Без достъп до приложението -no_app_access_copy: Не е позволено използването на администраторското приложение от този потребител. +no_app_access_copy: Не е позволено използването на администраторското приложение от потребителя. password_reset_sent: Изпратена ви е сигурна връзка за възстановяване на вашата парола password_reset_successful: Успешно нулирана парола back: Назад @@ -440,7 +445,7 @@ start_end_of_count_filtered_items: '{start}-{end} от {count} филтрира one_item: '1 запис' one_filtered_item: '1 филтриран запис' delete_collection_are_you_sure: >- - Сигурни ли сте, че искате да изтриете тази колекция? Това действие ще изтрие колекцията и всички нейни записи. Действието е постоянно. + Сигурни ли сте, че искате да изтриете колекцията? Всички записи и самата колекция ще бъдат изтрити. Действието е постоянно. collections_shown: Показани колекции visible_collections: Видими колекции hidden_collections: Скрити колекции @@ -471,12 +476,16 @@ operators: gt: По-голямо от lte: По-малко или равно gte: По-голямо или равно на - in: Е сред - nin: Не е сред + in: Е едно от + nin: Не е едно от null: Е null nnull: Не е null contains: Съдържа ncontains: Не съдържа + starts_with: Започва с + nstarts_with: Не започва с + ends_with: Завършва с + nends_with: Не завършва с between: Е между nbetween: Не е между empty: Е празно @@ -500,7 +509,7 @@ rows: Редове columns: Колони collection_setup: Настройки на колекция optional_system_fields: Незадължителни системни полета -value_unique: Изисква се уникална стойност +value_unique: Само уникални стойности all_activity: Цялата активност create_item: Създаване на запис display_template: Шаблон при показване @@ -521,9 +530,9 @@ clear_filters: Изчистване на филтрите saves_automatically: Автоматично запазване role: Роля user: Потребител -no_presets: Няма подготвени изгледи -no_presets_copy: Все още няма запазени подготвени изгледи или отметки. -no_presets_cta: Добавяне на подготвен изглед +no_presets: Няма заготовки +no_presets_copy: Все още няма запазени заготовки или отметки. +no_presets_cta: Добавяне на заготовка create: Създаване on_create: При създаване on_update: При промяна @@ -531,7 +540,7 @@ read: Четене update: Обновяване select_fields: Избор на полета format_text: Форматиране на текст -bold: Удебелен +bold: Удебеляване toggle: Превключване icon_on: Активна икона icon_off: Неактивна икона @@ -559,7 +568,7 @@ wysiwyg_options: alignright: Подравняване отдясно forecolor: Основен цвят backcolor: Цвят на фона - bold: Удебелен + bold: Удебеляване italic: Курсив underline: Подчертан strikethrough: Зачеркнат @@ -616,47 +625,47 @@ settings_data_model: Модел на данни settings_permissions: Роли и позволения settings_project: Настройки на проект settings_webhooks: Уеб-куки -settings_presets: Изгледи и отметки +settings_presets: Заготовки и отметки one_or_more_options_are_missing: Липсват една или повече опции scope: Обхват select: Избор... layout: Оформление tree_view: Дървовиден изглед changes_are_permanent: Промените са постоянни -preset_name_placeholder: По подразбиране когато е празно... +preset_name_placeholder: Използва се за основна, ако е празно... preset_search_placeholder: Заявка за търсене... -editing_preset: Редактиране на подготвени изгледи +editing_preset: Редактиране на заготовка layout_preview: Предварителен преглед layout_setup: Настройка на оформление -unsaved_changes: Незапазени промени -unsaved_changes_copy: Сигурни ли сте, че искате да напуснете тази страница? +unsaved_changes: Има незапазени промени +unsaved_changes_copy: Сигурни ли сте, че искате да отмените промените и напуснете тази страница? discard_changes: Отмяна на промените keep_editing: Продължаване на редакцията -page_help_collections_overview: '**Обзор на колекциите** — Показва всички налични колекции до които имате достъп.' +page_help_collections_overview: '**Обзор на колекциите** — Показване на всички налични колекции до които имате достъп.' page_help_collections_collection: >- - **Преглед на записи** — Показва всички записи от {collection}, до които имате достъп. Дава възможност за персонализиране на оформлението, филтрите и подредбата, така, че да се впишат по-добре към вашите нужди, дори имате възможност да добавите отметки с тези конфигурации за по-бърз достъп. + **Преглед на записи** — Показване на всички записи от {collection}, до които имате достъп. Дава възможност за персонализиране на оформлението, филтрите и подредбата, така, че да се впишат по-добре към вашите нужди, дори имате възможност да добавите отметки с тези конфигурации за по-бърз достъп. page_help_collections_item: >- - **Детайли за запис** — Формуляр за преглед и управление на този запис. Страничният панел също съдържа и пълна история на ревизиите и коментарите към него. + **Детайли за запис** — Формуляр за преглед и управление на записа. Страничният панел също съдържа и пълна история на ревизиите и коментарите към него. page_help_activity_collection: >- **Емисия на активността** — Подробен списък на активността за съдържанието, потребителите и системата. page_help_docs_global: >- - **Обзор на документацията** — Показва документи, специфични за този проект, версия и схема. + **Обзор на документацията** — Показване на документи, специфични за проекта, версия и схема. page_help_files_collection: >- - **Файлов архив** — Показва всички налични файлове, добавени към този проект. Дава възможност за персонализиране на оформлението, филтрите и подредбата, така, че да се впишат по-добре към вашите нужди, дори имате възможност да добавите отметки с тези конфигурации за по-бърз достъп. + **Файлов архив** — Показване на всички налични файлове, добавени към проекта. Дава възможност за персонализиране на оформлението, филтрите и подредбата, така, че да се впишат по-добре към вашите нужди, дори имате възможност да добавите отметки с тези конфигурации за по-бърз достъп. page_help_files_item: >- **Детайли за файл** — Формуляр за управление на мета-данните, редактиране на оригиналния файл и обновяване на настройките при достъп. page_help_settings_project: "**Настройки за проекта** — Глобални настройки и конфигурация на вашият проект." page_help_settings_datamodel_collections: >- - **Модел на данни: Колекции** — Показва всички налични колекции. Това включва видими, невидими и системни, както и все още неконтролираните таблици от базата данни, които могат да бъдат добавяни като колекции. + **Модел на данни: Колекции** — Показване на всички налични колекции. Включително видими, невидими и системни, както и все още неконфигурираните таблици в базата от данни, които могат да бъдат добавяни като колекции. page_help_settings_datamodel_fields: >- **Модел на данни: Колекция** — Формуляр за управление на тази колекция и нейните полета. -page_help_settings_roles_collection: '**Преглед на роли** — Показва администраторската, публичната и всички потребителски роли.' +page_help_settings_roles_collection: '**Преглед на роли** — Показване на администраторската, публичната и всички потребителски роли.' page_help_settings_roles_item: "**Детайли за роля** — Управление на позволенията на ролята, както и някои други настройки." page_help_settings_presets_collection: >- - **Преглед на изгледите** — Показва списък с всички предварително подготвени изгледи, включително за отделните: потребител, роля, и глобални отметки, както и изгледите по подразбиране. + **Преглед на заготовките** — Показване на списък от всички заготовки от изгледи, включително за отделните: потребител, роля, и глобални отметки, както и изгледите по подразбиране. page_help_settings_presets_item: >- - **Детайли за подготвените изгледи** — Формуляр за управление на отметките и подготвените изгледи по подразбиране към колекциите. -page_help_settings_webhooks_collection: '**Преглед на уеб-куки** — Показва всички уеб-куки в проекта.' + **Детайли за заготовка** — Формуляр за управление на отметките и заготовките от изгледи по подразбиране отнасящи се за колекциите. +page_help_settings_webhooks_collection: '**Преглед на уеб-куки** — Показване на всички уеб-куки в проекта.' page_help_settings_webhooks_item: '**Детайли за уеб-кука** — Формуляр за създаване и управление на уеб-куките в проекта.' page_help_users_collection: '**Потребители** — Показване на всички потребители в системата на проекта.' page_help_users_item: >- @@ -664,11 +673,11 @@ page_help_users_item: >- activity_feed: Емисия на активността add_new: Добави нов запис create_new: Създаване -all: Всички -none: Никое +all: Всичко +none: Нищо no_layout_collection_selected_yet: Все още не е избран изглед/колекция batch_delete_confirm: >- - Няма избрани записи | Наистина ли искате да изтриете този запис? Това действие не може да бъде отменено. | Наистина ли искате да изтриете тези {count} записа? Това действие не може да бъде отменено. + Няма избрани записи | Наистина ли искате да изтриете записа? Действието не може да бъде отменено. | Наистина ли искате да изтриете тези {count} записа? Това действие не може да бъде отменено. cancel: Отмяна collection: Колекция collections: Колекции @@ -691,13 +700,13 @@ fields: icon: Икона note: Бележка display_template: Шаблон при показване - hidden: Скрито + hidden: Скриване singleton: Сек translations: Преводи на името на колекцията archive_app_filter: Филтър за архиви archive_value: Стойност при архивиране unarchive_value: Стойност при разархивиране - sort_field: Поле за сортиране + sort_field: Сортиране по поле accountability: Следене за активност и ревизии directus_files: $thumbnail: Умалена картинка @@ -746,7 +755,7 @@ fields: project_url: URL на проекта project_color: Цвят на проекта project_logo: Лого на проекта - public_foreground: Публично изображение + public_foreground: Основно изображение public_background: Фоново изображение public_note: Публично съобщение auth_password_policy: Политика за пароли @@ -758,9 +767,9 @@ fields: collection: Име на колекцията icon: Икона на колекцията note: Бележка - hidden: Скрито + hidden: Скриване singleton: Сек - translation: Превод на името на полето + translation: Превод за името на полето display_template: Шаблон directus_roles: name: Име на роля @@ -796,14 +805,16 @@ referential_action_set_null: Зануляване на {field} referential_action_set_default: Задаване на {field} към стойността по подразбиране choose_action: Изберете действие continue: Продължение +continue_as: >- + {name} в момента е оторизиран. Ако разпознавате профила, изберете бутона за продължение. editing_role: 'Роля - {role}' creating_webhook: Създаване на уеб-кука default: По подразбиране delete: Изтриване delete_are_you_sure: >- - Това действие е постоянно и не може да бъде отменено. Сигурни ли сте, че искате да продължите? + Действието е постоянно и не може да бъде отменено. Сигурни ли сте, че искате да продължите? delete_field_are_you_sure: >- - Сигурни ли сте, че искате да изтриете "{field}" полето? Това действие не може да бъде отменено. + Сигурни ли сте, че искате да изтриете полето "{field}"? Действието не може да бъде отменено. description: Описание done: Готово duplicate: Дублиране @@ -814,7 +825,7 @@ field: Поле | Полета file: Файл file_library: Файлов архив forgot_password: Забравена парола -hidden: Скрито +hidden: Скриване icon: Икона info: Информация normal: Нормално @@ -854,6 +865,7 @@ template: Шаблон translation: Превод value: Стойност view_project: Преглед на проект +weeks: { } report_error: Докладване на грешка interfaces: presentation-links: @@ -871,6 +883,11 @@ interfaces: allow_other: Други show_more: 'Показване на още {count}' items_shown: Показани записи + select-multiple-checkbox-tree: + name: Дърво от отметки + description: Избор измежду множество опции чрез вложени отметки + value_combining: Комбинация от стойности + value_combining_note: Контрол върху стойността за запазване при направен избор. input-code: code: Код description: Писане или споделяне на кодови откъси @@ -888,14 +905,14 @@ interfaces: color: Цвят description: Въвеждане или избор на стойност за цвят placeholder: Избор на цвят... - preset_colors: Предварително зададени цветове + preset_colors: Заготовки от цветове preset_colors_add_label: Добавяне на нов цвят... name_placeholder: Въвеждане името на цвета... datetime: datetime: Дата и час description: Въвеждане на дати и часове include_seconds: Вклчване на секундите - set_to_now: Задаване като сега + set_to_now: Задаване на сега use_24: Използване на 24 часов формат system-display-template: display-template: Шаблон при показване @@ -916,8 +933,8 @@ interfaces: choices_placeholder: Добавяне на избор allow_other: Други allow_other_label: Позволяване на други стойности - allow_none: Позволяване на нищо - allow_none_label: Текст за "Позволяване на нищо" + allow_none: Празен избор + allow_none_label: Позволяване на празен избор choices_name_placeholder: Въвеждане на име... choices_value_placeholder: Въвеждане на стойност... select-multiple-dropdown: @@ -965,9 +982,9 @@ interfaces: imageToken: Токън за изображенията imageToken_label: Какъв (статичен) токън да се добави, към адресите на изображенията presentation-notice: - notice: Бележка - description: Показване на кратка бележка - text: Въвеждане на бележката... + notice: Пояснение + description: Показване на кратко пояснение + text: Въвеждане на пояснението... list-o2m: one-to-many: Един към много description: Избор на множество свързани записи @@ -1001,7 +1018,7 @@ interfaces: alphabetize_label: Винаги в азбучен ред add_tags: Добавяне на етикет... input: - input: Въвеждане + input: Текстово поле description: Ръчно въвеждане на стойност trim: Почистване trim_label: Почистване на краищата от интервали @@ -1044,7 +1061,7 @@ interfaces: options_override: Наслагване на опции input-autocomplete-api: input-autocomplete-api: Поле с автоматично дописване (API) - description: Автоматично дописване на стойности от външно API. + description: Автоматично дописване на стойности чрез външно API. results_path: Път до резултатите value_path: Път до стойността trigger: Задействане @@ -1086,7 +1103,7 @@ displays: filesize: Големина на файла description: Показване на големината на файл formatted-value: - formatted-value: Формат на стойността + formatted-value: Форматиране на стойност description: Показване на форматирана стойност на текст format_title: Формат на заглавие format_title_label: Автоматично форматиране на регистъра @@ -1097,18 +1114,18 @@ displays: icon: icon: Икона description: Показване като икона - filled: Изпълнен - filled_label: Използване на вариант с изпълване + filled: Запълване + filled_label: Използване на изпълнен вариант image: image: Изображение description: Показване на малко изображение circle: Кръг - circle_label: Показване като кръг + circle_label: Показване в кръгла форма labels: labels: Етикети description: Въвеждане както на единичен, така и на множество етикети - default_foreground: Преден план по подразбиране - default_background: Фон по подразбиране + default_foreground: Основен цвят по подразбиране + default_background: Фонов цвят по подразбиране format_label: Форматиране на всеки етикет show_as_dot: Показване като точка choices_value_placeholder: Въвеждане на стойност... @@ -1120,14 +1137,14 @@ displays: extension_only_label: Показване само на разширението rating: rating: Оценка - description: Показване на числото като звезди до максималната стойност + description: Показване на числото, като брой звезди до максималната стойност simple: Опростен simple_label: Показване на звездите в опростен вид raw: raw: Стойност в суров вид related-values: related-values: Релативни стойности - description: Показване на релативни стойности + description: Показване на релативните стойности user: user: Потребител description: Показване на потребител от Directus diff --git a/app/src/lang/translations/en-US.yaml b/app/src/lang/translations/en-US.yaml index 525e0af880..aa61494001 100644 --- a/app/src/lang/translations/en-US.yaml +++ b/app/src/lang/translations/en-US.yaml @@ -3,6 +3,7 @@ item_revision: Item Revision duplicate_field: Duplicate Field half_width: Half Width full_width: Full Width +group: Group fill_width: Fill Width field_name_translations: Field Name Translations enter_password_to_enable_tfa: Enter your password to enable Two-Factor Authentication @@ -106,6 +107,7 @@ field_m2a: M2A Relationship field_o2m: O2M Relationship field_m2m: M2M Relationship field_translations: Translations +field_group: Field Group item_permissions: Item Permissions field_permissions: Field Permissions field_validation: Field Validation @@ -1077,6 +1079,9 @@ interfaces: value_path: Value Path trigger: Trigger rate: Rate + group-raw: + name: Raw Fields + description: Show the fields as normal. displays: boolean: boolean: Boolean diff --git a/app/src/lang/translations/ko-KR.yaml b/app/src/lang/translations/ko-KR.yaml index ed97d539c0..e1a568a423 100644 --- a/app/src/lang/translations/ko-KR.yaml +++ b/app/src/lang/translations/ko-KR.yaml @@ -1 +1,137 @@ --- +edit_field: 필드 편집 +item_revision: 아이템 리비전 +duplicate_field: 중복 필드 +field_name_translations: 항목 명 번역 +enter_password_to_enable_tfa: 암호를 입력하여 이중 인증을 활성화하십시오 +add_field: 필드 추가 +role_name: 권한 이름 +branch: 브랜치 +indeterminate: 불확정 상태 +children: 하위 +required: 필수 사항 +requires_value: 필수 항목 +create_preset: 사전설정 생성 +create_role: 역할 생성 +create_user: 사용자 생성 +create_webhook: 웹훅 생성 +invite_users: 사용자 초대 +invite: 초대 +emails: 이메일 +connection_poor: 연결 상태 불량 +rename_folder: 폴더 이름 변경 +delete_folder: 폴더 삭제 +prefix: 접두사 +suffix: 접미사 +reset_bookmark: 북마크 초기화 +rename_bookmark: 북마크 이름 변경 +update_bookmark: 북마크 업데이트 +delete_bookmark: 북마크 삭제 +delete_bookmark_copy: >- + 정말로 이 계정을 삭제하시겠습니까? 이 작업은 취소할 수 없습니다. +logoutReason: + SIGN_OUT: 로그아웃 + SESSION_EXPIRED: 세션 만료 +public: 공개 +not_allowed: 허용되지 않음 +validationError: + unique: 생산Key는 유일해야만 합니다. +all_access: 모든 액세스 +no_access: 접근 불가 +use_custom: 직접 설정 +nullable: NULL허용 +field_standard: 표준 +field_file: 단일 파일 +field_files: 여러 파일들 +field_translations: 번역 +delete_field: 필드 삭제 +language: 언어 +global: 글로벌 +camera: 카메라 +exposure: 노출 +shutter: 셔터 +iso: ISO +focal_length: 초점 거리 +create_field: 필드 생성 +reset_page_preferences: 앱 환경설정 초기화 +hidden_field: 숨김 필드 +hidden_on_detail: 실행 시 숨김 +key: 키 +alias: 별칭 +auto_generate: 자동 생성 +click_here: 여기를 클릭하세요 +fields_group: 필드 그룹 +no_collections_found: 컬렉션 없음 +search_collection: 컬렉션 검색 +new_field: '새 필드' +new_collection: '새 컬렉션' +choose_a_type: 유형을 선택... +default_value: 기본값 +standard_field: 표준 항목들 +single_file: 단일 파일 +multiple_files: 여러 파일들 +invalid_item: 비정상적인 아이템 +next: 다음 +field_name: 필드 이름 +translations: 번역 +note: 메모 +enter_a_value: 값 입력 +length: 길이 +unique: 고유 +post_comment_success: 댓글 작성됨 +format: 형식 +export_collection: '컬렉션 내보내기' +last_page: 마지막 페이지 +last_access: 최근 접속 +submit: 확인 +move_to_folder: 폴더로 이동 +move: 이동 +system: 시스템 +interface: 인터페이스 +today: 오늘 +yesterday: 어제 +delete_comment: 댓글 삭제 +month: 월 +year: 년 +select_all: 모두 선택 +months: + january: 1월 + february: 2월 + march: 3월 + april: 4월 + may: 5월 + june: 6월 + july: 7월 + august: 8월 + september: 9월 + october: 10월 + november: 11월 + december: 12월 +drag_mode: 끌기 모드 +type: 타입 +creating_new_collection: 새 컬렉션 만들기 +value_unique: 생산Key는 유일해야만 합니다. +wysiwyg_options: + selectall: 모두 선택 +fields: + directus_collections: + note: 메모 + directus_users: + language: 언어 + last_page: 마지막 페이지 + last_access: 최근 접속 + directus_fields: + note: 메모 + translation: 항목 명 번역 + directus_roles: + name: 권한 이름 +interfaces: + select-dropdown: + choices_value_placeholder: 값 입력 + system-interface: + interface: 인터페이스 +displays: + datetime: + format: 형식 + labels: + choices_value_placeholder: 값 입력 diff --git a/app/src/modules/settings/routes/data-model/field-detail/components/field.vue b/app/src/modules/settings/routes/data-model/field-detail/components/field.vue index 23de0fe964..cf7b988f21 100644 --- a/app/src/modules/settings/routes/data-model/field-detail/components/field.vue +++ b/app/src/modules/settings/routes/data-model/field-detail/components/field.vue @@ -11,7 +11,7 @@
-
+
{{ t('note') }}
diff --git a/app/src/modules/settings/routes/data-model/field-detail/field-detail.vue b/app/src/modules/settings/routes/data-model/field-detail/field-detail.vue index 3251a50a3b..aace116f3e 100644 --- a/app/src/modules/settings/routes/data-model/field-detail/field-detail.vue +++ b/app/src/modules/settings/routes/data-model/field-detail/field-detail.vue @@ -134,6 +134,7 @@ import useCollection from '@/composables/use-collection'; import { getLocalTypeForField } from '../get-local-type'; import { notify } from '@/utils/notify'; import formatTitle from '@directus/format-title'; +import { localTypes } from '@/types'; import { initLocalStore, state, clearLocalStore } from './store'; import { unexpectedError } from '@/utils/unexpected-error'; @@ -159,9 +160,7 @@ export default defineComponent({ required: true, }, type: { - type: String as PropType< - 'standard' | 'file' | 'files' | 'm2o' | 'o2m' | 'm2m' | 'm2a' | 'presentation' | 'translations' - >, + type: String as PropType, default: null, }, }, @@ -193,8 +192,7 @@ export default defineComponent({ const localType = computed(() => { if (props.field === '+') return props.type; - let type: 'standard' | 'file' | 'files' | 'o2m' | 'm2m' | 'm2a' | 'm2o' | 'presentation' | 'translations' = - 'standard'; + let type: typeof localTypes[number]; type = getLocalTypeForField(props.collection, props.field); return type; @@ -257,7 +255,7 @@ export default defineComponent({ }, ]; - if (props.type !== 'presentation') { + if (props.type !== 'presentation' && props.type !== 'group') { tabs.push({ text: t('display'), value: 'display', @@ -392,7 +390,7 @@ export default defineComponent({ await Promise.all( state.relations.map((relation) => { - const relationExists = !!relationsStore.getRelationForField(relation.collection, relation.field); + const relationExists = !!relationsStore.getRelationForField(relation.collection!, relation.field!); if (relationExists) { return api.patch(`/relations/${relation.collection}/${relation.field}`, relation); diff --git a/app/src/modules/settings/routes/data-model/field-detail/store.ts b/app/src/modules/settings/routes/data-model/field-detail/store.ts index bb771b9ae1..5dba1b26b3 100644 --- a/app/src/modules/settings/routes/data-model/field-detail/store.ts +++ b/app/src/modules/settings/routes/data-model/field-detail/store.ts @@ -152,6 +152,7 @@ function initLocalStore(collection: string, field: string, type: typeof localTyp else if (type === 'm2m' || type === 'files' || type === 'translations') useM2M(); else if (type === 'o2m') useO2M(); else if (type === 'presentation') usePresentation(); + else if (type === 'group') useGroup(); else if (type === 'm2a') useM2A(); else useStandard(); @@ -1041,6 +1042,15 @@ function initLocalStore(collection: string, field: string, type: typeof localTyp }; } + function useGroup() { + delete state.fieldData.schema; + state.fieldData.type = 'alias'; + state.fieldData.meta = { + ...(state.fieldData.meta || {}), + special: ['alias', 'no-data', 'group'], + }; + } + function useStandard() { watch( () => state.fieldData.type, diff --git a/app/src/modules/settings/routes/data-model/fields/components/field-select-menu.vue b/app/src/modules/settings/routes/data-model/fields/components/field-select-menu.vue new file mode 100644 index 0000000000..5f9d286627 --- /dev/null +++ b/app/src/modules/settings/routes/data-model/fields/components/field-select-menu.vue @@ -0,0 +1,109 @@ + + + diff --git a/app/src/modules/settings/routes/data-model/fields/components/field-select.vue b/app/src/modules/settings/routes/data-model/fields/components/field-select.vue index 230dab4bd5..1946406e5b 100644 --- a/app/src/modules/settings/routes/data-model/fields/components/field-select.vue +++ b/app/src/modules/settings/routes/data-model/fields/components/field-select.vue @@ -1,5 +1,5 @@