mirror of
https://github.com/directus/directus.git
synced 2026-02-16 22:41:21 -05:00
Finalize interface names (#5521)
* Rename button-links->presentation-links * Rename checkboxes->select-multiple-checkbox * Rename code->input-code * Rename checkboxes files * Rename color->select-color * Rename divider->presentation-divider * Rename dropdown-multiselect->select-multiple-dropdown * Rename hash->input-hash * Rename icon->select-icon * Rename image->file-image * Rename m2a-builder->list-m2a * Rename many-to-many->list-m2m * Rename many-to-one->select-dropdown-m2o * Rename markdown->input-rich-text-md * Rename notice->presentation-notice * Rename one-to-many->list-o2m * Rename radio-buttons->select-radio * Rename repeater->list * Rename text-input->input * Rename textarea->input-multiline * Rename toggle->boolean * Rename tree-view->list-o2m-tree-view * Rename wysiwyg->input-rich-text-html * Use correct interfaces in system defaults * Rename collection->system-collection * Rename collections->system-collections * Rename display-template->system-display-template * Rename field->system-field * Rename interface->system-interface * Rename interface-options->system-interface-options * Rename scope->interface-scope * Rename tfa-setup->system-mfa-setup * Fix oversights * Remove old todo * Some more tweaks * Add migration, fix dropdown name in system use * Merge numeric + input * Replace dropdown->select-dropdown in app use * Merge slug->input, user->select-dropdown-m2o * Fix type issue * Fix seeder field name
This commit is contained in:
@@ -1,26 +0,0 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceDisplayTemplate from './display-template.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'display-template',
|
||||
name: '$t:interfaces.display-template.display-template',
|
||||
description: '$t:interfaces.display-template.description',
|
||||
icon: 'arrow_drop_down_circle',
|
||||
component: InterfaceDisplayTemplate,
|
||||
types: ['string'],
|
||||
system: true,
|
||||
options: [
|
||||
{
|
||||
field: 'collectionField',
|
||||
name: '$t:interfaces.display-template.collection_field',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'text-input',
|
||||
},
|
||||
schema: {
|
||||
default_value: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceOptions from './interface-options.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'interface-options',
|
||||
name: '$t:interfaces.interface-options.interface-options',
|
||||
description: '$t:interfaces.interface-options.description',
|
||||
icon: 'box',
|
||||
component: InterfaceOptions,
|
||||
types: ['string'],
|
||||
options: [],
|
||||
system: true,
|
||||
});
|
||||
@@ -1,13 +0,0 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceInterface from './interface.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'interface',
|
||||
name: '$t:interfaces.interface.interface',
|
||||
description: '$t:interfaces.interface.description',
|
||||
icon: 'box',
|
||||
component: InterfaceInterface,
|
||||
types: ['string'],
|
||||
system: true,
|
||||
options: [],
|
||||
});
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceCollection from './collection.vue';
|
||||
import InterfaceSystemCollection from './system-collection.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'collection',
|
||||
name: '$t:interfaces.collection.collection',
|
||||
description: '$t:interfaces.collection.description',
|
||||
id: 'system-collection',
|
||||
name: '$t:interfaces.system-collection.collection',
|
||||
description: '$t:interfaces.system-collection.description',
|
||||
icon: 'featured_play_list',
|
||||
component: InterfaceCollection,
|
||||
component: InterfaceSystemCollection,
|
||||
types: ['string'],
|
||||
options: [
|
||||
{
|
||||
@@ -15,9 +15,9 @@ export default defineInterface({
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.collection.include_system_collections',
|
||||
label: '$t:interfaces.system-collection.include_system_collections',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceCollections from './collections.vue';
|
||||
import InterfaceSystemCollections from './system-collections.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'collections',
|
||||
name: '$t:interfaces.collections.collections',
|
||||
description: '$t:interfaces.collections.description',
|
||||
id: 'system-collections',
|
||||
name: '$t:interfaces.system-collections.collections',
|
||||
description: '$t:interfaces.system-collections.description',
|
||||
icon: 'featured_play_list',
|
||||
component: InterfaceCollections,
|
||||
component: InterfaceSystemCollections,
|
||||
types: ['json', 'csv'],
|
||||
options: [
|
||||
{
|
||||
@@ -15,9 +15,9 @@ export default defineInterface({
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.collections.include_system_collections',
|
||||
label: '$t:interfaces.system-collections.include_system_collections',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -2,7 +2,13 @@
|
||||
<v-notice v-if="items.length === 0">
|
||||
{{ $t('no_collections') }}
|
||||
</v-notice>
|
||||
<interface-checkboxes v-else :choices="items" @input="$listeners.input" :value="value" :disabled="disabled" />
|
||||
<interface-select-multiple-checkbox
|
||||
v-else
|
||||
:choices="items"
|
||||
@input="$listeners.input"
|
||||
:value="value"
|
||||
:disabled="disabled"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
26
app/src/interfaces/_system/system-display-template/index.ts
Normal file
26
app/src/interfaces/_system/system-display-template/index.ts
Normal file
@@ -0,0 +1,26 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceSystemDisplayTemplate from './system-display-template.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'system-display-template',
|
||||
name: '$t:interfaces.system-display-template.display-template',
|
||||
description: '$t:interfaces.system-display-template.description',
|
||||
icon: 'arrow_drop_down_circle',
|
||||
component: InterfaceSystemDisplayTemplate,
|
||||
types: ['string'],
|
||||
system: true,
|
||||
options: [
|
||||
{
|
||||
field: 'collectionField',
|
||||
name: '$t:interfaces.system-display-template.collection_field',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'input',
|
||||
},
|
||||
schema: {
|
||||
default_value: null,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1,9 +1,9 @@
|
||||
<template>
|
||||
<v-notice v-if="!collectionField" type="warning">
|
||||
{{ $t('interfaces.display-template.collection_field_not_setup') }}
|
||||
{{ $t('interfaces.system-display-template.collection_field_not_setup') }}
|
||||
</v-notice>
|
||||
<v-notice v-else-if="collection === null" type="warning">
|
||||
{{ $t('interfaces.display-template.select_a_collection') }}
|
||||
{{ $t('interfaces.system-display-template.select_a_collection') }}
|
||||
</v-notice>
|
||||
<v-field-template v-else :collection="collection" @input="$listeners.input" :value="value" :disabled="disabled" />
|
||||
</template>
|
||||
@@ -1,11 +1,11 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceField from './field.vue';
|
||||
import InterfaceSystemField from './system-field.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'field',
|
||||
id: 'system-field',
|
||||
name: '$t:field',
|
||||
icon: 'box',
|
||||
component: InterfaceField,
|
||||
component: InterfaceSystemField,
|
||||
types: ['string'],
|
||||
options: [],
|
||||
system: true,
|
||||
13
app/src/interfaces/_system/system-interface-options/index.ts
Normal file
13
app/src/interfaces/_system/system-interface-options/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceSystemInterfaceOptions from './system-interface-options.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'system-interface-options',
|
||||
name: '$t:interfaces.system-interface-options.interface-options',
|
||||
description: '$t:interfaces.system-interface-options.description',
|
||||
icon: 'box',
|
||||
component: InterfaceSystemInterfaceOptions,
|
||||
types: ['string'],
|
||||
options: [],
|
||||
system: true,
|
||||
});
|
||||
13
app/src/interfaces/_system/system-interface/index.ts
Normal file
13
app/src/interfaces/_system/system-interface/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceSystemInterface from './system-interface.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'system-interface',
|
||||
name: '$t:interfaces.system-interface.interface',
|
||||
description: '$t:interfaces.system-interface.description',
|
||||
icon: 'box',
|
||||
component: InterfaceSystemInterface,
|
||||
types: ['string'],
|
||||
system: true,
|
||||
options: [],
|
||||
});
|
||||
@@ -7,7 +7,7 @@
|
||||
:items="items"
|
||||
@input="$listeners.input"
|
||||
:value="value"
|
||||
:placeholder="$t('interfaces.interface.placeholder')"
|
||||
:placeholder="$t('interfaces.system-interface.placeholder')"
|
||||
/>
|
||||
</template>
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceTFASetup from './tfa-setup.vue';
|
||||
import InterfaceSystemMFASetup from './system-mfa-setup.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'tfa-setup',
|
||||
name: 'tfa-setup',
|
||||
id: 'system-mfa-setup',
|
||||
name: 'mfa-setup',
|
||||
icon: 'box',
|
||||
component: InterfaceTFASetup,
|
||||
component: InterfaceSystemMFASetup,
|
||||
types: ['text'],
|
||||
options: [],
|
||||
system: true,
|
||||
@@ -1,11 +1,11 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import Scope from './scope.vue';
|
||||
import InterfaceSystemScope from './system-scope.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'scope',
|
||||
id: 'system-scope',
|
||||
name: '$t:scope',
|
||||
icon: 'arrow_drop_down_circle',
|
||||
component: Scope,
|
||||
component: InterfaceSystemScope,
|
||||
types: ['string'],
|
||||
options: [],
|
||||
});
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceToggle from './toggle.vue';
|
||||
import InterfaceBoolean from './boolean.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'toggle',
|
||||
name: '$t:interfaces.toggle.toggle',
|
||||
description: '$t:interfaces.toggle.description',
|
||||
id: 'boolean',
|
||||
name: '$t:interfaces.boolean.toggle',
|
||||
description: '$t:interfaces.boolean.description',
|
||||
icon: 'check_box',
|
||||
component: InterfaceToggle,
|
||||
component: InterfaceBoolean,
|
||||
types: ['boolean'],
|
||||
recommendedDisplays: ['boolean'],
|
||||
options: [
|
||||
@@ -16,7 +16,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
schema: {
|
||||
default_value: 'check_box',
|
||||
@@ -28,7 +28,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
schema: {
|
||||
default_value: 'check_box_outline_blank',
|
||||
@@ -40,13 +40,13 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
placeholder: '$t:interfaces.toggle.label_placeholder',
|
||||
placeholder: '$t:interfaces.boolean.label_placeholder',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
default_value: '$t:interfaces.toggle.label_default',
|
||||
default_value: '$t:interfaces.boolean.label_default',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -55,7 +55,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'color',
|
||||
interface: 'select-color',
|
||||
},
|
||||
schema: {
|
||||
default_value: '#00C897',
|
||||
@@ -15,7 +15,7 @@ export default defineInterface({
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
},
|
||||
schema: {
|
||||
default_value: false,
|
||||
@@ -27,7 +27,7 @@ export default defineInterface({
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
},
|
||||
schema: {
|
||||
default_value: true,
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceImage from './image.vue';
|
||||
import InterfaceFileImage from './file-image.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'image',
|
||||
name: '$t:interfaces.image.image',
|
||||
description: '$t:interfaces.image.description',
|
||||
id: 'file-image',
|
||||
name: '$t:interfaces.file-image.image',
|
||||
description: '$t:interfaces.file-image.description',
|
||||
icon: 'insert_photo',
|
||||
component: InterfaceImage,
|
||||
component: InterfaceFileImage,
|
||||
types: ['uuid'],
|
||||
groups: ['file'],
|
||||
relational: true,
|
||||
@@ -1,13 +0,0 @@
|
||||
import { defineInterface } from '../define';
|
||||
import InterfaceIcon from './icon.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'icon',
|
||||
name: '$t:interfaces.icon.icon',
|
||||
description: '$t:interfaces.icon.description',
|
||||
icon: 'insert_emoticon',
|
||||
component: InterfaceIcon,
|
||||
types: ['string'],
|
||||
options: [],
|
||||
recommendedDisplays: ['icon'],
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import CodeMirror from 'codemirror';
|
||||
import 'codemirror/mode/meta';
|
||||
import InterfaceCode from './code.vue';
|
||||
import InterfaceCode from './input-code.vue';
|
||||
|
||||
const choicesMap = CodeMirror.modeInfo.reduce((acc: Record<string, string>, choice) => {
|
||||
if (['JSON', 'JSON-LD'].includes(choice.name)) {
|
||||
@@ -28,9 +28,9 @@ const choices = Object.entries(choicesMap).map(([key, value]) => ({
|
||||
}));
|
||||
|
||||
export default defineInterface({
|
||||
id: 'code',
|
||||
name: '$t:interfaces.code.code',
|
||||
description: '$t:interfaces.code.description',
|
||||
id: 'input-code',
|
||||
name: '$t:interfaces.input-code.code',
|
||||
description: '$t:interfaces.input-code.description',
|
||||
icon: 'code',
|
||||
component: InterfaceCode,
|
||||
types: ['string', 'json', 'text'],
|
||||
@@ -41,17 +41,17 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'dropdown',
|
||||
interface: 'select-dropdown',
|
||||
options: { choices },
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'lineNumber',
|
||||
name: '$t:interfaces.code.line_number',
|
||||
name: '$t:interfaces.input-code.line_number',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
},
|
||||
schema: {
|
||||
default_value: false,
|
||||
@@ -63,9 +63,9 @@ export default defineInterface({
|
||||
type: 'text',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'code',
|
||||
interface: 'input-code',
|
||||
options: {
|
||||
placeholder: '$t:interfaces.code.placeholder',
|
||||
placeholder: '$t:interfaces.input-code.placeholder',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="interface-code codemirror-custom-styles" :class="{ disabled }">
|
||||
<div class="input-code codemirror-custom-styles" :class="{ disabled }">
|
||||
<textarea ref="codemirrorEl" :value="stringValue" />
|
||||
|
||||
<v-button small icon secondary v-if="template" v-tooltip.left="$t('fill_template')" @click="fillTemplate">
|
||||
@@ -289,7 +289,7 @@ export default defineComponent({
|
||||
<style lang="scss" scoped>
|
||||
@import '~codemirror/addon/lint/lint.css';
|
||||
|
||||
.interface-code {
|
||||
.input-code {
|
||||
position: relative;
|
||||
width: 100%;
|
||||
font-size: 14px;
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceHash from './hash.vue';
|
||||
import InterfaceInputHash from './input-hash.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'hash',
|
||||
name: '$t:interfaces.hash.hash',
|
||||
description: '$t:interfaces.hash.description',
|
||||
id: 'input-hash',
|
||||
name: '$t:interfaces.input-hash.hash',
|
||||
description: '$t:interfaces.input-hash.description',
|
||||
icon: 'fingerprint',
|
||||
component: InterfaceHash,
|
||||
component: InterfaceInputHash,
|
||||
types: ['hash'],
|
||||
options: [
|
||||
{
|
||||
@@ -15,7 +15,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
placeholder: '$t:enter_a_placeholder',
|
||||
},
|
||||
@@ -23,13 +23,13 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'masked',
|
||||
name: '$t:interfaces.hash.masked',
|
||||
name: '$t:interfaces.input-hash.masked',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.hash.masked_label',
|
||||
label: '$t:interfaces.input-hash.masked_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceTextarea from './textarea.vue';
|
||||
import InterfaceInputMultiline from './input-multiline.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'textarea',
|
||||
name: '$t:interfaces.textarea.textarea',
|
||||
description: '$t:interfaces.textarea.description',
|
||||
id: 'input-multiline',
|
||||
name: '$t:interfaces.input-multiline.textarea',
|
||||
description: '$t:interfaces.input-multiline.description',
|
||||
icon: 'text_fields',
|
||||
component: InterfaceTextarea,
|
||||
component: InterfaceInputMultiline,
|
||||
types: ['text'],
|
||||
options: [
|
||||
{
|
||||
@@ -15,7 +15,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
placeholder: '$t:enter_a_placeholder',
|
||||
},
|
||||
@@ -23,13 +23,13 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'trim',
|
||||
name: '$t:interfaces.text-input.trim',
|
||||
name: '$t:interfaces.input.trim',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.text-input.trim_label',
|
||||
label: '$t:interfaces.input.trim_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -42,7 +42,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'dropdown',
|
||||
interface: 'select-dropdown',
|
||||
options: {
|
||||
choices: [
|
||||
{ text: '$t:sans_serif', value: 'sans-serif' },
|
||||
@@ -57,13 +57,13 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'clear',
|
||||
name: '$t:interfaces.text-input.clear',
|
||||
name: '$t:interfaces.input.clear',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.text-input.clear_label',
|
||||
label: '$t:interfaces.input.clear_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -2,19 +2,19 @@ import { defineInterface } from '@/interfaces/define';
|
||||
import { AsyncComponent } from 'vue';
|
||||
|
||||
const InterfaceWYSIWYG = () =>
|
||||
import(/* webpackChunkName: 'interface-wysiwyg', webpackPrefetch: true */ './wysiwyg.vue');
|
||||
import(/* webpackChunkName: 'interface-input-rich-text-html', webpackPrefetch: true */ './input-rich-text-html.vue');
|
||||
|
||||
export default defineInterface({
|
||||
id: 'wysiwyg',
|
||||
name: '$t:interfaces.wysiwyg.wysiwyg',
|
||||
description: '$t:interfaces.wysiwyg.description',
|
||||
id: 'input-rich-text-html',
|
||||
name: '$t:interfaces.input-rich-text-html.wysiwyg',
|
||||
description: '$t:interfaces.input-rich-text-html.description',
|
||||
icon: 'format_quote',
|
||||
component: InterfaceWYSIWYG as AsyncComponent,
|
||||
types: ['text'],
|
||||
options: [
|
||||
{
|
||||
field: 'toolbar',
|
||||
name: '$t:interfaces.wysiwyg.toolbar',
|
||||
name: '$t:interfaces.input-rich-text-html.toolbar',
|
||||
type: 'json',
|
||||
schema: {
|
||||
default_value: [
|
||||
@@ -38,7 +38,7 @@ export default defineInterface({
|
||||
},
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'dropdown-multiselect',
|
||||
interface: 'select-multiple-dropdown',
|
||||
options: {
|
||||
choices: [
|
||||
{
|
||||
@@ -227,7 +227,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'dropdown',
|
||||
interface: 'select-dropdown',
|
||||
options: {
|
||||
choices: [
|
||||
{ text: '$t:sans_serif', value: 'sans-serif' },
|
||||
@@ -242,7 +242,7 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'customFormats',
|
||||
name: '$t:interfaces.wysiwyg.custom_formats',
|
||||
name: '$t:interfaces.input-rich-text-html.custom_formats',
|
||||
type: 'json',
|
||||
meta: {
|
||||
interface: 'code',
|
||||
@@ -266,7 +266,7 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'tinymceOverrides',
|
||||
name: '$t:interfaces.wysiwyg.options_override',
|
||||
name: '$t:interfaces.input-rich-text-html.options_override',
|
||||
type: 'json',
|
||||
meta: {
|
||||
interface: 'code',
|
||||
@@ -277,12 +277,12 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'imageToken',
|
||||
name: '$t:interfaces.markdown.imageToken',
|
||||
name: '$t:interfaces.input-rich-text-md.imageToken',
|
||||
type: 'string',
|
||||
meta: {
|
||||
note: '$t:interfaces.markdown.imageToken_label',
|
||||
note: '$t:interfaces.input-rich-text-md.imageToken_label',
|
||||
width: 'full',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -47,7 +47,7 @@
|
||||
|
||||
<v-drawer v-model="codeDrawerOpen" :title="$t('wysiwyg_options.source_code')" @cancel="closeCodeDrawer" icon="code">
|
||||
<div class="content">
|
||||
<interface-code v-model="code" language="htmlmixed"></interface-code>
|
||||
<interface-input-code v-model="code" language="htmlmixed"></interface-input-code>
|
||||
</div>
|
||||
|
||||
<template #actions>
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceMarkdown from './markdown.vue';
|
||||
import InterfaceInputRichTextMD from './input-rich-text-md.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'markdown',
|
||||
name: '$t:interfaces.markdown.markdown',
|
||||
description: '$t:interfaces.markdown.description',
|
||||
id: 'input-rich-text-md',
|
||||
name: '$t:interfaces.input-rich-text-md.markdown',
|
||||
description: '$t:interfaces.input-rich-text-md.description',
|
||||
icon: 'functions',
|
||||
component: InterfaceMarkdown,
|
||||
component: InterfaceInputRichTextMD,
|
||||
types: ['text'],
|
||||
options: [
|
||||
{
|
||||
@@ -15,7 +15,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'textarea',
|
||||
interface: 'input-multiline',
|
||||
options: {
|
||||
placeholder: '$t:enter_a_placeholder',
|
||||
},
|
||||
@@ -23,14 +23,14 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'customSyntax',
|
||||
name: '$t:interfaces.markdown.customSyntax',
|
||||
name: '$t:interfaces.input-rich-text-md.customSyntax',
|
||||
type: 'json',
|
||||
meta: {
|
||||
note: '$t:interfaces.markdown.customSyntax_label',
|
||||
note: '$t:interfaces.input-rich-text-md.customSyntax_label',
|
||||
width: 'full',
|
||||
interface: 'repeater',
|
||||
interface: 'list',
|
||||
options: {
|
||||
addLabel: '$t:interfaces.markdown.customSyntax_add',
|
||||
addLabel: '$t:interfaces.input-rich-text-md.customSyntax_add',
|
||||
template: '{{ name }}',
|
||||
fields: [
|
||||
{
|
||||
@@ -38,7 +38,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
name: '$t:name',
|
||||
meta: {
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
width: 'half',
|
||||
},
|
||||
},
|
||||
@@ -47,7 +47,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
name: '$t:icon',
|
||||
meta: {
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
width: 'half',
|
||||
},
|
||||
},
|
||||
@@ -56,7 +56,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
name: '$t:prefix',
|
||||
meta: {
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
width: 'half',
|
||||
},
|
||||
},
|
||||
@@ -65,16 +65,16 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
name: '$t:suffix',
|
||||
meta: {
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
width: 'half',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'box',
|
||||
type: 'string',
|
||||
name: '$t:interfaces.markdown.box',
|
||||
name: '$t:interfaces.input-rich-text-md.box',
|
||||
meta: {
|
||||
interface: 'radio-buttons',
|
||||
interface: 'select-radio',
|
||||
width: 'half',
|
||||
options: {
|
||||
choices: [
|
||||
@@ -99,12 +99,12 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'imageToken',
|
||||
name: '$t:interfaces.markdown.imageToken',
|
||||
name: '$t:interfaces.input-rich-text-md.imageToken',
|
||||
type: 'string',
|
||||
meta: {
|
||||
note: '$t:interfaces.markdown.imageToken_label',
|
||||
note: '$t:interfaces.input-rich-text-md.imageToken_label',
|
||||
width: 'full',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="interface-markdown" :class="view[0]" ref="markdownInterface">
|
||||
<div class="interface-input-rich-text-md" :class="view[0]" ref="markdownInterface">
|
||||
<div class="toolbar">
|
||||
<v-menu show-arrow placement="bottom-start">
|
||||
<template #activator="{ toggle }">
|
||||
@@ -308,7 +308,7 @@ export default defineComponent({
|
||||
<style lang="scss" scoped>
|
||||
@import '@/styles/mixins/form-grid';
|
||||
|
||||
.interface-markdown {
|
||||
.interface-input-rich-text-md {
|
||||
--v-button-background-color: transparent;
|
||||
--v-button-color: var(--foreground-normal);
|
||||
--v-button-background-color-hover: var(--border-normal);
|
||||
@@ -324,7 +324,7 @@ textarea {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.interface-markdown ::v-deep .CodeMirror {
|
||||
.interface-input-rich-text-md ::v-deep .CodeMirror {
|
||||
border: none;
|
||||
border-radius: 0;
|
||||
|
||||
@@ -345,7 +345,7 @@ textarea {
|
||||
}
|
||||
}
|
||||
|
||||
.interface-markdown.preview {
|
||||
.interface-input-rich-text-md.preview {
|
||||
::v-deep .CodeMirror {
|
||||
display: none;
|
||||
}
|
||||
13
app/src/interfaces/input/index.ts
Normal file
13
app/src/interfaces/input/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceInput from './input.vue';
|
||||
import Options from './options.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'input',
|
||||
name: '$t:interfaces.input.input',
|
||||
description: '$t:interfaces.input.description',
|
||||
icon: 'text_fields',
|
||||
component: InterfaceInput,
|
||||
types: ['string', 'uuid', 'bigInteger', 'integer', 'float', 'decimal'],
|
||||
options: Options,
|
||||
});
|
||||
@@ -6,10 +6,11 @@
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:trim="trim"
|
||||
:type="masked ? 'password' : 'text'"
|
||||
:type="inputType"
|
||||
:class="font"
|
||||
:db-safe="dbSafe"
|
||||
@input="$listeners.input"
|
||||
:slug="slug"
|
||||
>
|
||||
<template v-if="iconLeft" #prepend><v-icon :name="iconLeft" /></template>
|
||||
<template #append>
|
||||
@@ -41,6 +42,10 @@ export default defineComponent({
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
clear: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
@@ -85,6 +90,10 @@ export default defineComponent({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
slug: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const charsRemaining = computed(() => {
|
||||
@@ -99,7 +108,13 @@ export default defineComponent({
|
||||
return 100 - (props.value.length / +props.length) * 100;
|
||||
});
|
||||
|
||||
return { charsRemaining, percentageRemaining };
|
||||
const inputType = computed(() => {
|
||||
if (props.masked) return 'password';
|
||||
if (['bigInteger', 'integer', 'float', 'decimal'].includes(props.type)) return 'number';
|
||||
return 'text';
|
||||
});
|
||||
|
||||
return { inputType, charsRemaining, percentageRemaining };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
234
app/src/interfaces/input/options.vue
Normal file
234
app/src/interfaces/input/options.vue
Normal file
@@ -0,0 +1,234 @@
|
||||
<template>
|
||||
<v-form :fields="fields" v-model="options" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, PropType } from '@vue/composition-api';
|
||||
import { Field } from '@/types';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
fieldData: {
|
||||
type: Object as PropType<Field>,
|
||||
default: null,
|
||||
},
|
||||
value: {
|
||||
type: Object,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const options = computed({
|
||||
get() {
|
||||
return props.value || {};
|
||||
},
|
||||
set(options: Record<string, unknown>) {
|
||||
emit('input', options);
|
||||
},
|
||||
});
|
||||
|
||||
const textOptions = [
|
||||
{
|
||||
field: 'placeholder',
|
||||
name: '$t:placeholder',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'input',
|
||||
options: {
|
||||
placeholder: '$t:enter_a_placeholder',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'font',
|
||||
name: '$t:font',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'select-dropdown',
|
||||
options: {
|
||||
choices: [
|
||||
{ text: '$t:sans_serif', value: 'sans-serif' },
|
||||
{ text: '$t:monospace', value: 'monospace' },
|
||||
{ text: '$t:serif', value: 'serif' },
|
||||
],
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
default_value: 'sans-serif',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'iconLeft',
|
||||
name: '$t:icon_left',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'iconRight',
|
||||
name: '$t:icon_right',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'trim',
|
||||
name: '$t:interfaces.input.trim',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.input.trim_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
default_value: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'masked',
|
||||
name: '$t:interfaces.input.mask',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.input.mask_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
default_value: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'clear',
|
||||
name: '$t:interfaces.input.clear',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.input.clear_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
default_value: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'slug',
|
||||
name: '$t:interfaces.input.slug',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.input.slug_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
default_value: false,
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const numberOptions = [
|
||||
{
|
||||
field: 'min',
|
||||
name: '$t:interfaces.input.minimum_value',
|
||||
type: 'integer',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'input',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'max',
|
||||
name: '$t:interfaces.input.maximum_value',
|
||||
type: 'integer',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'input',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'step',
|
||||
name: '$t:interfaces.input.step_interval',
|
||||
type: 'integer',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'input',
|
||||
},
|
||||
schema: {
|
||||
default_value: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'placeholder',
|
||||
name: '$t:placeholder',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'input',
|
||||
options: {
|
||||
placeholder: '$t:enter_a_placeholder',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'iconLeft',
|
||||
name: '$t:icon_left',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'iconRight',
|
||||
name: '$t:icon_right',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'font',
|
||||
name: '$t:font',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'select-dropdown',
|
||||
options: {
|
||||
choices: [
|
||||
{ text: '$t:sans_serif', value: 'sans-serif' },
|
||||
{ text: '$t:monospace', value: 'monospace' },
|
||||
{ text: '$t:serif', value: 'serif' },
|
||||
],
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
default_value: 'sans-serif',
|
||||
},
|
||||
},
|
||||
];
|
||||
|
||||
const fields = computed(() => {
|
||||
if (['bigInteger', 'integer', 'float', 'decimal'].includes(props.fieldData?.type)) {
|
||||
return numberOptions;
|
||||
}
|
||||
|
||||
return textOptions;
|
||||
});
|
||||
|
||||
return { fields, options };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -1,11 +1,11 @@
|
||||
import { defineInterface } from '../define';
|
||||
import InterfaceManyToAny from './m2a-builder.vue';
|
||||
import InterfaceListM2A from './list-m2a.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'm2a-builder',
|
||||
name: '$t:m2a_builder',
|
||||
id: 'list-m2a',
|
||||
name: '$t:list-m2a',
|
||||
icon: 'note_add',
|
||||
component: InterfaceManyToAny,
|
||||
component: InterfaceListM2A,
|
||||
relational: true,
|
||||
types: ['alias'],
|
||||
groups: ['m2a'],
|
||||
@@ -1,13 +1,13 @@
|
||||
import { defineInterface } from '../define';
|
||||
import InterfaceManyToMany from './many-to-many.vue';
|
||||
import InterfaceListM2M from './list-m2m.vue';
|
||||
import Options from './options.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'many-to-many',
|
||||
name: '$t:interfaces.many-to-many.many-to-many',
|
||||
description: '$t:interfaces.many-to-many.description',
|
||||
id: 'list-m2m',
|
||||
name: '$t:interfaces.list-m2m.many-to-many',
|
||||
description: '$t:interfaces.list-m2m.description',
|
||||
icon: 'note_add',
|
||||
component: InterfaceManyToMany,
|
||||
component: InterfaceListM2M,
|
||||
relational: true,
|
||||
types: ['alias'],
|
||||
groups: ['m2m', 'files'],
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<v-notice type="warning" v-if="junctionCollection === null">
|
||||
{{ $t('interfaces.one-to-many.no_collection') }}
|
||||
{{ $t('interfaces.list-o2m.no_collection') }}
|
||||
</v-notice>
|
||||
<div v-else class="form-grid">
|
||||
<div class="field full">
|
||||
@@ -1,15 +1,15 @@
|
||||
import { defineInterface } from '../define';
|
||||
import Options from './options.vue';
|
||||
import InterfaceTreeView from './tree-view.vue';
|
||||
import InterfaceListO2MTreeView from './list-o2m-tree-view.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'tree-view',
|
||||
id: 'list-o2m-tree-view',
|
||||
name: '$t:tree_view',
|
||||
description: '$t:interfaces.tree-view.description',
|
||||
description: '$t:interfaces.list-o2m-tree-view.description',
|
||||
icon: 'account_tree',
|
||||
types: ['alias'],
|
||||
groups: ['o2m'],
|
||||
relational: true,
|
||||
component: InterfaceTreeView,
|
||||
component: InterfaceListO2MTreeView,
|
||||
options: Options,
|
||||
});
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<v-notice type="warning" v-if="relation.many_collection !== relation.one_collection">
|
||||
{{ $t('interfaces.tree-view.recursive_only') }}
|
||||
{{ $t('interfaces.list-o2m-tree-view.recursive_only') }}
|
||||
</v-notice>
|
||||
|
||||
<div v-else class="tree-view">
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<v-notice class="full" type="warning" v-if="collection === null">
|
||||
{{ $t('interfaces.one-to-many.no_collection') }}
|
||||
{{ $t('interfaces.list-o2m.no_collection') }}
|
||||
</v-notice>
|
||||
<div v-else class="form-grid">
|
||||
<div class="field full">
|
||||
<p class="type-label">{{ $t('interfaces.many-to-one.display_template') }}</p>
|
||||
<p class="type-label">{{ $t('interfaces.select-dropdown-m2o.display_template') }}</p>
|
||||
<v-field-template :collection="collection" v-model="template" :depth="1"></v-field-template>
|
||||
</div>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
import { defineInterface } from '../define';
|
||||
import InterfaceOneToMany from './one-to-many.vue';
|
||||
import InterfaceListO2M from './list-o2m.vue';
|
||||
import Options from './options.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'one-to-many',
|
||||
name: '$t:interfaces.one-to-many.one-to-many',
|
||||
description: '$t:interfaces.one-to-many.description',
|
||||
id: 'list-o2m',
|
||||
name: '$t:interfaces.list-o2m.one-to-many',
|
||||
description: '$t:interfaces.list-o2m.description',
|
||||
icon: 'arrow_right_alt',
|
||||
component: InterfaceOneToMany,
|
||||
component: InterfaceListO2M,
|
||||
types: ['alias'],
|
||||
groups: ['o2m'],
|
||||
relational: true,
|
||||
@@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<v-notice type="warning" v-if="relatedCollection === null">
|
||||
{{ $t('interfaces.one-to-many.no_collection') }}
|
||||
{{ $t('interfaces.list-o2m.no_collection') }}
|
||||
</v-notice>
|
||||
<div v-else class="form-grid">
|
||||
<div class="field full">
|
||||
@@ -1,13 +1,13 @@
|
||||
import { defineInterface } from '../define';
|
||||
import RepeaterOptions from './options.vue';
|
||||
import InterfaceRepeater from './repeater.vue';
|
||||
import InterfaceList from './list.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'repeater',
|
||||
name: '$t:interfaces.repeater.repeater',
|
||||
description: '$t:interfaces.repeater.description',
|
||||
id: 'list',
|
||||
name: '$t:interfaces.list.repeater',
|
||||
description: '$t:interfaces.list.description',
|
||||
icon: 'replay',
|
||||
component: InterfaceRepeater,
|
||||
component: InterfaceList,
|
||||
types: ['json'],
|
||||
options: RepeaterOptions,
|
||||
});
|
||||
@@ -6,12 +6,12 @@
|
||||
</div>
|
||||
|
||||
<div class="grid-element half">
|
||||
<p class="type-label">{{ $t('interfaces.repeater.add_label') }}</p>
|
||||
<p class="type-label">{{ $t('interfaces.list.add_label') }}</p>
|
||||
<v-input class="input" v-model="addLabel" :placeholder="$t('create_new')" />
|
||||
</div>
|
||||
|
||||
<div class="grid-element full">
|
||||
<p class="type-label">{{ $t('interfaces.repeater.edit_fields') }}</p>
|
||||
<p class="type-label">{{ $t('interfaces.list.edit_fields') }}</p>
|
||||
<repeater v-model="repeaterValue" :template="`{{ field }} — {{ interface }}`" :fields="repeaterFields" />
|
||||
</div>
|
||||
</div>
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed } from '@vue/composition-api';
|
||||
import Repeater from './repeater.vue';
|
||||
import Repeater from './list.vue';
|
||||
import { Field, FieldMeta } from '@/types';
|
||||
import i18n from '@/lang';
|
||||
import { fieldTypes } from '@/modules/settings/routes/data-model/field-detail/components/schema.vue';
|
||||
@@ -58,13 +58,13 @@ export default defineComponent({
|
||||
field: 'field',
|
||||
type: 'string',
|
||||
meta: {
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
width: 'half',
|
||||
sort: 2,
|
||||
options: {
|
||||
dbSafe: true,
|
||||
font: 'monospace',
|
||||
placeholder: i18n.t('interfaces.repeater.field_name_placeholder'),
|
||||
placeholder: i18n.t('interfaces.list.field_name_placeholder'),
|
||||
},
|
||||
},
|
||||
schema: null,
|
||||
@@ -74,7 +74,7 @@ export default defineComponent({
|
||||
field: 'width',
|
||||
type: 'string',
|
||||
meta: {
|
||||
interface: 'dropdown',
|
||||
interface: 'select-dropdown',
|
||||
width: 'half',
|
||||
sort: 3,
|
||||
options: {
|
||||
@@ -97,7 +97,7 @@ export default defineComponent({
|
||||
field: 'type',
|
||||
type: 'string',
|
||||
meta: {
|
||||
interface: 'dropdown',
|
||||
interface: 'select-dropdown',
|
||||
width: 'half',
|
||||
sort: 4,
|
||||
options: {
|
||||
@@ -111,7 +111,7 @@ export default defineComponent({
|
||||
field: 'interface',
|
||||
type: 'string',
|
||||
meta: {
|
||||
interface: 'interface',
|
||||
interface: 'system-interface',
|
||||
width: 'half',
|
||||
sort: 5,
|
||||
options: {
|
||||
@@ -125,11 +125,11 @@ export default defineComponent({
|
||||
field: 'note',
|
||||
type: 'string',
|
||||
meta: {
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
width: 'full',
|
||||
sort: 6,
|
||||
options: {
|
||||
placeholder: i18n.t('interfaces.repeater.field_note_placeholder'),
|
||||
placeholder: i18n.t('interfaces.list.field_note_placeholder'),
|
||||
},
|
||||
},
|
||||
schema: null,
|
||||
@@ -139,7 +139,7 @@ export default defineComponent({
|
||||
field: 'options',
|
||||
type: 'string',
|
||||
meta: {
|
||||
interface: 'interface-options',
|
||||
interface: 'system-interface-options',
|
||||
width: 'full',
|
||||
sort: 7,
|
||||
options: {
|
||||
@@ -1,92 +0,0 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceNumeric from './numeric.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'numeric',
|
||||
name: '$t:interfaces.numeric.numeric',
|
||||
description: '$t:interfaces.numeric.description',
|
||||
icon: 'dialpad',
|
||||
component: InterfaceNumeric,
|
||||
types: ['integer', 'decimal', 'float', 'bigInteger'],
|
||||
options: [
|
||||
{
|
||||
field: 'min',
|
||||
name: '$t:interfaces.numeric.minimum_value',
|
||||
type: 'integer',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'numeric',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'max',
|
||||
name: '$t:interfaces.numeric.maximum_value',
|
||||
type: 'integer',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'numeric',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'step',
|
||||
name: '$t:interfaces.numeric.step_interval',
|
||||
type: 'integer',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'numeric',
|
||||
},
|
||||
schema: {
|
||||
default_value: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'placeholder',
|
||||
name: '$t:placeholder',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
options: {
|
||||
placeholder: '$t:enter_a_placeholder',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'iconLeft',
|
||||
name: '$t:icon_left',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'iconRight',
|
||||
name: '$t:icon_right',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'font',
|
||||
name: '$t:font',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'dropdown',
|
||||
options: {
|
||||
choices: [
|
||||
{ text: '$t:sans_serif', value: 'sans-serif' },
|
||||
{ text: '$t:monospace', value: 'monospace' },
|
||||
{ text: '$t:serif', value: 'serif' },
|
||||
],
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
default_value: 'sans-serif',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1,81 +0,0 @@
|
||||
<template>
|
||||
<v-input
|
||||
type="number"
|
||||
:class="font"
|
||||
:value="value"
|
||||
:placeholder="placeholder"
|
||||
:disabled="disabled"
|
||||
:min="min"
|
||||
:max="max"
|
||||
:step="step"
|
||||
@input="$listeners.input"
|
||||
>
|
||||
<template v-if="iconLeft" #prepend>
|
||||
<v-icon :name="iconLeft" />
|
||||
</template>
|
||||
<template v-if="iconRight" #append>
|
||||
<v-icon :name="iconRight" />
|
||||
</template>
|
||||
</v-input>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from '@vue/composition-api';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
value: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
min: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
max: {
|
||||
type: Number,
|
||||
default: null,
|
||||
},
|
||||
iconLeft: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
iconRight: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
step: {
|
||||
type: Number,
|
||||
default: 1,
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
font: {
|
||||
type: String as PropType<'sans-serif' | 'serif' | 'monospace'>,
|
||||
default: 'sans-serif',
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.v-input {
|
||||
&.monospace {
|
||||
--v-input-font-family: var(--family-monospace);
|
||||
}
|
||||
|
||||
&.serif {
|
||||
--v-input-font-family: var(--family-serif);
|
||||
}
|
||||
|
||||
&.sans-serif {
|
||||
--v-input-font-family: var(--family-sans-serif);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceDivider from './divider.vue';
|
||||
import InterfacePresentationDivider from './presentation-divider.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'divider',
|
||||
name: '$t:interfaces.divider.divider',
|
||||
description: '$t:interfaces.divider.description',
|
||||
id: 'presentation-divider',
|
||||
name: '$t:interfaces.presentation-divider.divider',
|
||||
description: '$t:interfaces.presentation-divider.description',
|
||||
icon: 'remove',
|
||||
component: InterfaceDivider,
|
||||
component: InterfacePresentationDivider,
|
||||
hideLabel: true,
|
||||
hideLoader: true,
|
||||
types: ['alias'],
|
||||
@@ -18,7 +18,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'color',
|
||||
interface: 'select-color',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -27,7 +27,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -36,21 +36,21 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
placeholder: '$t:interfaces.divider.title_placeholder',
|
||||
placeholder: '$t:interfaces.presentation-divider.title_placeholder',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'marginTop',
|
||||
name: '$t:interfaces.divider.margin_top',
|
||||
name: '$t:interfaces.presentation-divider.margin_top',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.divider.margin_top_label',
|
||||
label: '$t:interfaces.presentation-divider.margin_top_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -59,13 +59,13 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'inlineTitle',
|
||||
name: '$t:interfaces.divider.inline_title',
|
||||
name: '$t:interfaces.presentation-divider.inline_title',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.divider.inline_title_label',
|
||||
label: '$t:interfaces.presentation-divider.inline_title_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceButtonLinks from './button-links.vue';
|
||||
import InterfacePresentationLinks from './presentation-links.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'button-links',
|
||||
name: '$t:interfaces.button-links.button-links',
|
||||
description: '$t:interfaces.button-links.description',
|
||||
id: 'presentation-links',
|
||||
name: '$t:interfaces.presentation-links.presentation-links',
|
||||
description: '$t:interfaces.presentation-links.description',
|
||||
icon: 'smart_button',
|
||||
component: InterfaceButtonLinks,
|
||||
component: InterfacePresentationLinks,
|
||||
hideLabel: true,
|
||||
hideLoader: true,
|
||||
types: ['alias'],
|
||||
@@ -15,10 +15,10 @@ export default defineInterface({
|
||||
{
|
||||
field: 'links',
|
||||
type: 'json',
|
||||
name: '$t:interfaces.button-links.links',
|
||||
name: '$t:interfaces.presentation-links.links',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'repeater',
|
||||
interface: 'list',
|
||||
options: {
|
||||
placeholder: '$t:title',
|
||||
template: '{{ label }}',
|
||||
@@ -29,7 +29,7 @@ export default defineInterface({
|
||||
name: '$t:label',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
placeholder: '$t:label',
|
||||
},
|
||||
@@ -41,7 +41,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -50,7 +50,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'dropdown',
|
||||
interface: 'select-dropdown',
|
||||
default_value: 'normal',
|
||||
options: {
|
||||
choices: [
|
||||
@@ -73,7 +73,7 @@ export default defineInterface({
|
||||
name: '$t:url',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
font: 'monospace',
|
||||
placeholder: 'https://example.com/articles/{{ id }}/{{ slug }}',
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<div class="button-links">
|
||||
<div class="presentation-links">
|
||||
<v-button
|
||||
v-for="(link, index) in linksParsed"
|
||||
:key="index"
|
||||
@@ -56,7 +56,7 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.button-links {
|
||||
.presentation-links {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceNotice from './notice.vue';
|
||||
import InterfacePresentationNotice from './presentation-notice.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'notice',
|
||||
name: '$t:interfaces.notice.notice',
|
||||
description: '$t:interfaces.notice.description',
|
||||
id: 'presentation-notice',
|
||||
name: '$t:interfaces.presentation-notice.notice',
|
||||
description: '$t:interfaces.presentation-notice.description',
|
||||
icon: 'info',
|
||||
component: InterfaceNotice,
|
||||
component: InterfacePresentationNotice,
|
||||
hideLabel: true,
|
||||
hideLoader: true,
|
||||
types: ['alias'],
|
||||
@@ -18,7 +18,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'dropdown',
|
||||
interface: 'select-dropdown',
|
||||
options: {
|
||||
choices: [
|
||||
{ text: '$t:normal', value: 'normal' },
|
||||
@@ -39,7 +39,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -48,9 +48,9 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'textarea',
|
||||
interface: 'input-multiline',
|
||||
options: {
|
||||
placeholder: '$t:interfaces.notice.text',
|
||||
placeholder: '$t:interfaces.presentation-notice.text',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -10,9 +10,9 @@ it's name and options.
|
||||
|
||||
```js
|
||||
export default defineInterface({
|
||||
id: 'text-input',
|
||||
id: 'input',
|
||||
register: ({ i18n }) => ({
|
||||
name: i18n.t('text-input'),
|
||||
name: i18n.t('input'),
|
||||
icon: 'box',
|
||||
component: InterfaceTextInput,
|
||||
}),
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceColor from './color.vue';
|
||||
import InterfaceColor from './select-color.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'color',
|
||||
name: '$t:interfaces.color.color',
|
||||
description: '$t:interfaces.color.description',
|
||||
id: 'select-color',
|
||||
name: '$t:interfaces.select-color.color',
|
||||
description: '$t:interfaces.select-color.description',
|
||||
icon: 'palette',
|
||||
component: InterfaceColor,
|
||||
types: ['string'],
|
||||
@@ -12,13 +12,13 @@ export default defineInterface({
|
||||
options: [
|
||||
{
|
||||
field: 'presets',
|
||||
name: '$t:interfaces.color.preset_colors',
|
||||
name: '$t:interfaces.select-color.preset_colors',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'repeater',
|
||||
interface: 'list',
|
||||
options: {
|
||||
addLabel: '$t:interfaces.color.preset_colors_add_label',
|
||||
addLabel: '$t:interfaces.select-color.preset_colors_add_label',
|
||||
template: '{{ name }} - {{ color }}',
|
||||
fields: [
|
||||
{
|
||||
@@ -26,10 +26,10 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
name: '$t:name',
|
||||
meta: {
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
width: 'half',
|
||||
options: {
|
||||
placeholder: '$t:interfaces.color.name_placeholder',
|
||||
placeholder: '$t:interfaces.select-color.name_placeholder',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -38,7 +38,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
name: '$t:color',
|
||||
meta: {
|
||||
interface: 'color',
|
||||
interface: 'select-color',
|
||||
width: 'half',
|
||||
},
|
||||
},
|
||||
@@ -1,13 +1,13 @@
|
||||
import { defineInterface } from '../define';
|
||||
import InterfaceManyToOne from './many-to-one.vue';
|
||||
import InterfaceSelectDropdownM2O from './select-dropdown-m2o.vue';
|
||||
import Options from './options.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'many-to-one',
|
||||
name: '$t:interfaces.many-to-one.many-to-one',
|
||||
description: '$t:interfaces.many-to-one.description',
|
||||
id: 'select-dropdown-m2o',
|
||||
name: '$t:interfaces.select-dropdown-m2o.many-to-one',
|
||||
description: '$t:interfaces.select-dropdown-m2o.description',
|
||||
icon: 'arrow_right_alt',
|
||||
component: InterfaceManyToOne,
|
||||
component: InterfaceSelectDropdownM2O,
|
||||
types: ['uuid', 'string', 'text', 'integer', 'bigInteger'],
|
||||
relational: true,
|
||||
groups: ['m2o'],
|
||||
@@ -1,10 +1,10 @@
|
||||
<template>
|
||||
<v-notice class="full" type="warning" v-if="collection === null">
|
||||
{{ $t('interfaces.one-to-many.no_collection') }}
|
||||
{{ $t('interfaces.list-o2m.no_collection') }}
|
||||
</v-notice>
|
||||
<div v-else class="form-grid">
|
||||
<div class="field full">
|
||||
<p class="type-label">{{ $t('interfaces.many-to-one.display_template') }}</p>
|
||||
<p class="type-label">{{ $t('interfaces.select-dropdown-m2o.display_template') }}</p>
|
||||
<v-field-template :collection="relatedCollection" v-model="template" :depth="2"></v-field-template>
|
||||
</div>
|
||||
</div>
|
||||
@@ -92,6 +92,7 @@ import api from '@/api';
|
||||
import DrawerItem from '@/views/private/components/drawer-item';
|
||||
import DrawerCollection from '@/views/private/components/drawer-collection';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
import adjustFieldsForDisplays from '@/utils/adjust-fields-for-displays';
|
||||
|
||||
/**
|
||||
* @NOTE
|
||||
@@ -347,7 +348,10 @@ export default defineComponent({
|
||||
|
||||
const requiredFields = computed(() => {
|
||||
if (!displayTemplate.value) return null;
|
||||
return getFieldsFromTemplate(displayTemplate.value);
|
||||
return adjustFieldsForDisplays(
|
||||
getFieldsFromTemplate(displayTemplate.value),
|
||||
relatedCollection.value.collection
|
||||
);
|
||||
});
|
||||
|
||||
return { onPreviewClick, displayTemplate, requiredFields };
|
||||
@@ -449,6 +453,7 @@ export default defineComponent({
|
||||
.preview {
|
||||
display: block;
|
||||
flex-grow: 1;
|
||||
height: calc(100% - 16px);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceDropdown from './dropdown.vue';
|
||||
import InterfaceSelectDropdown from './select-dropdown.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'dropdown',
|
||||
id: 'select-dropdown',
|
||||
name: '$t:dropdown',
|
||||
description: '$t:interfaces.dropdown.description',
|
||||
description: '$t:interfaces.select-dropdown.description',
|
||||
icon: 'arrow_drop_down_circle',
|
||||
component: InterfaceDropdown,
|
||||
component: InterfaceSelectDropdown,
|
||||
types: ['string'],
|
||||
options: [
|
||||
{
|
||||
@@ -15,9 +15,9 @@ export default defineInterface({
|
||||
name: '$t:choices',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'repeater',
|
||||
interface: 'list',
|
||||
options: {
|
||||
placeholder: '$t:interfaces.dropdown.choices_placeholder',
|
||||
placeholder: '$t:interfaces.select-dropdown.choices_placeholder',
|
||||
template: '{{ text }}',
|
||||
fields: [
|
||||
{
|
||||
@@ -25,10 +25,10 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
name: '$t:text',
|
||||
meta: {
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
width: 'half',
|
||||
options: {
|
||||
placeholder: '$t:interfaces.dropdown.choices_name_placeholder',
|
||||
placeholder: '$t:interfaces.select-dropdown.choices_name_placeholder',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -37,10 +37,10 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
name: '$t:value',
|
||||
meta: {
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
font: 'monospace',
|
||||
placeholder: '$t:interfaces.dropdown.choices_value_placeholder',
|
||||
placeholder: '$t:interfaces.select-dropdown.choices_value_placeholder',
|
||||
},
|
||||
width: 'half',
|
||||
},
|
||||
@@ -51,13 +51,13 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'allowOther',
|
||||
name: '$t:interfaces.dropdown.allow_other',
|
||||
name: '$t:interfaces.select-dropdown.allow_other',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.dropdown.allow_other_label',
|
||||
label: '$t:interfaces.select-dropdown.allow_other_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -66,13 +66,13 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'allowNone',
|
||||
name: '$t:interfaces.dropdown.allow_none',
|
||||
name: '$t:interfaces.select-dropdown.allow_none',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.dropdown.allow_none_label',
|
||||
label: '$t:interfaces.select-dropdown.allow_none_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -85,7 +85,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -94,7 +94,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
placeholder: '$t:enter_a_placeholder',
|
||||
},
|
||||
13
app/src/interfaces/select-icon/index.ts
Normal file
13
app/src/interfaces/select-icon/index.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { defineInterface } from '../define';
|
||||
import InterfaceSelectIcon from './select-icon.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'select-icon',
|
||||
name: '$t:interfaces.select-icon.icon',
|
||||
description: '$t:interfaces.select-icon.description',
|
||||
icon: 'insert_emoticon',
|
||||
component: InterfaceSelectIcon,
|
||||
types: ['string'],
|
||||
options: [],
|
||||
recommendedDisplays: ['icon'],
|
||||
});
|
||||
@@ -3,7 +3,7 @@
|
||||
<template #activator="{ active, activate }">
|
||||
<v-input
|
||||
:disabled="disabled"
|
||||
:placeholder="value ? formatTitle(value) : $t('interfaces.icon.search_for_icon')"
|
||||
:placeholder="value ? formatTitle(value) : $t('interfaces.select-icon.search_for_icon')"
|
||||
v-model="searchQuery"
|
||||
@focus="activate"
|
||||
:class="{ 'has-value': value }"
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceCheckboxes from './checkboxes.vue';
|
||||
import InterfaceSelectMultipleCheckboxes from './select-multiple-checkbox.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'checkboxes',
|
||||
name: '$t:interfaces.checkboxes.checkboxes',
|
||||
id: 'select-multiple-checkbox',
|
||||
name: '$t:interfaces.select-multiple-checkbox.checkboxes',
|
||||
icon: 'check_box',
|
||||
component: InterfaceCheckboxes,
|
||||
description: '$t:interfaces.checkboxes.description',
|
||||
component: InterfaceSelectMultipleCheckboxes,
|
||||
description: '$t:interfaces.select-multiple-checkbox.description',
|
||||
types: ['json', 'csv'],
|
||||
options: [
|
||||
{
|
||||
@@ -15,7 +15,7 @@ export default defineInterface({
|
||||
name: '$t:choices',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'repeater',
|
||||
interface: 'list',
|
||||
options: {
|
||||
template: '{{ text }}',
|
||||
fields: [
|
||||
@@ -25,9 +25,9 @@ export default defineInterface({
|
||||
name: '$t:text',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
placeholder: '$t:interfaces.dropdown.choices_name_placeholder',
|
||||
placeholder: '$t:interfaces.select-dropdown.choices_name_placeholder',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -37,10 +37,10 @@ export default defineInterface({
|
||||
name: '$t:value',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
font: 'monospace',
|
||||
placeholder: '$t:interfaces.dropdown.choices_name_placeholder',
|
||||
placeholder: '$t:interfaces.select-dropdown.choices_name_placeholder',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -50,11 +50,11 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'allowOther',
|
||||
name: '$t:interfaces.checkboxes.allow_other',
|
||||
name: '$t:interfaces.select-multiple-checkbox.allow_other',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:enable_custom_values',
|
||||
},
|
||||
@@ -69,7 +69,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'color',
|
||||
interface: 'select-color',
|
||||
},
|
||||
schema: {
|
||||
default_value: '#00C897',
|
||||
@@ -81,7 +81,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
schema: {
|
||||
default_value: 'check_box',
|
||||
@@ -93,7 +93,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
schema: {
|
||||
default_value: 'check_box_outline_blank',
|
||||
@@ -101,11 +101,11 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'itemsShown',
|
||||
name: '$t:interfaces.checkboxes.items_shown',
|
||||
name: '$t:interfaces.select-multiple-checkbox.items_shown',
|
||||
type: 'integer',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'numeric',
|
||||
interface: 'input',
|
||||
},
|
||||
schema: {
|
||||
default_value: 8,
|
||||
@@ -25,7 +25,7 @@
|
||||
<v-detail
|
||||
v-if="hideChoices && showAll === false"
|
||||
:class="gridClass"
|
||||
:label="$t(`interfaces.checkboxes.show_more`, { count: hiddenCount })"
|
||||
:label="$t(`interfaces.select-multiple-checkbox.show_more`, { count: hiddenCount })"
|
||||
@toggle="showAll = true"
|
||||
></v-detail>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceDropdownMultiselect from './dropdown-multiselect.vue';
|
||||
import InterfaceSelectMultipleDropdown from './select-multiple-dropdown.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'dropdown-multiselect',
|
||||
name: '$t:interfaces.dropdown-multiselect.dropdown-multiselect',
|
||||
description: '$t:interfaces.dropdown-multiselect.description',
|
||||
id: 'select-multiple-dropdown',
|
||||
name: '$t:interfaces.select-multiple-dropdown.select-multiple-dropdown',
|
||||
description: '$t:interfaces.select-multiple-dropdown.description',
|
||||
icon: 'arrow_drop_down_circle',
|
||||
component: InterfaceDropdownMultiselect,
|
||||
component: InterfaceSelectMultipleDropdown,
|
||||
types: ['json', 'csv'],
|
||||
options: [
|
||||
{
|
||||
@@ -15,9 +15,9 @@ export default defineInterface({
|
||||
name: '$t:choices',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'repeater',
|
||||
interface: 'list',
|
||||
options: {
|
||||
placeholder: '$t:interfaces.dropdown.choices_placeholder',
|
||||
placeholder: '$t:interfaces.select-dropdown.choices_placeholder',
|
||||
template: '{{ text }}',
|
||||
fields: [
|
||||
{
|
||||
@@ -26,9 +26,9 @@ export default defineInterface({
|
||||
name: '$t:text',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
placeholder: '$t:interfaces.dropdown.choices_name_placeholder',
|
||||
placeholder: '$t:interfaces.select-dropdown.choices_name_placeholder',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -38,10 +38,10 @@ export default defineInterface({
|
||||
name: '$t:value',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
font: 'monospace',
|
||||
placeholder: '$t:interfaces.dropdown.choices_value_placeholder',
|
||||
placeholder: '$t:interfaces.select-dropdown.choices_value_placeholder',
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -51,13 +51,13 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'allowOther',
|
||||
name: '$t:interfaces.dropdown.allow_other',
|
||||
name: '$t:interfaces.select-dropdown.allow_other',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.dropdown.allow_other_label',
|
||||
label: '$t:interfaces.select-dropdown.allow_other_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -66,13 +66,13 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'allowNone',
|
||||
name: '$t:interfaces.dropdown.allow_none',
|
||||
name: '$t:interfaces.select-dropdown.allow_none',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.dropdown.allow_none_label',
|
||||
label: '$t:interfaces.select-dropdown.allow_none_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -85,7 +85,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
placeholder: '$t:enter_a_placeholder',
|
||||
},
|
||||
@@ -97,7 +97,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
},
|
||||
],
|
||||
@@ -1,12 +1,12 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceRadioButtons from './radio-buttons.vue';
|
||||
import InterfaceSelectRadio from './select-radio.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'radio-buttons',
|
||||
name: '$t:interfaces.radio-buttons.radio-buttons',
|
||||
description: '$t:interfaces.radio-buttons.description',
|
||||
id: 'select-radio',
|
||||
name: '$t:interfaces.select-radio.radio-buttons',
|
||||
description: '$t:interfaces.select-radio.description',
|
||||
icon: 'radio_button_checked',
|
||||
component: InterfaceRadioButtons,
|
||||
component: InterfaceSelectRadio,
|
||||
types: ['string'],
|
||||
recommendedDisplays: ['badge'],
|
||||
options: [
|
||||
@@ -16,7 +16,7 @@ export default defineInterface({
|
||||
name: '$t:choices',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'repeater',
|
||||
interface: 'list',
|
||||
options: {
|
||||
template: '{{ text }}',
|
||||
fields: [
|
||||
@@ -26,7 +26,7 @@ export default defineInterface({
|
||||
name: '$t:text',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -35,7 +35,7 @@ export default defineInterface({
|
||||
name: '$t:value',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
font: 'monospace',
|
||||
},
|
||||
@@ -51,7 +51,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
schema: {
|
||||
default_value: 'radio_button_checked',
|
||||
@@ -63,7 +63,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
schema: {
|
||||
default_value: 'radio_button_unchecked',
|
||||
@@ -75,18 +75,18 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'color',
|
||||
interface: 'select-color',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'allowOther',
|
||||
name: '$t:interfaces.dropdown.allow_other',
|
||||
name: '$t:interfaces.select-dropdown.allow_other',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.dropdown.allow_other_label',
|
||||
label: '$t:interfaces.select-dropdown.allow_other_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -11,29 +11,29 @@ export default defineInterface({
|
||||
options: [
|
||||
{
|
||||
field: 'minValue',
|
||||
name: '$t:interfaces.numeric.minimum_value',
|
||||
name: '$t:interfaces.input.minimum_value',
|
||||
type: 'integer',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'numeric',
|
||||
interface: 'input',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'maxValue',
|
||||
name: '$t:interfaces.numeric.maximum_value',
|
||||
name: '$t:interfaces.input.maximum_value',
|
||||
type: 'integer',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'numeric',
|
||||
interface: 'input',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'stepInterval',
|
||||
name: '$t:interfaces.numeric.step_interval',
|
||||
name: '$t:interfaces.input.step_interval',
|
||||
type: 'integer',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'numeric',
|
||||
interface: 'input',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -42,7 +42,7 @@ export default defineInterface({
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,42 +0,0 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceSlug from './slug.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'slug',
|
||||
name: '$t:interfaces.slug.slug',
|
||||
description: '$t:interfaces.slug.description',
|
||||
icon: 'link',
|
||||
component: InterfaceSlug,
|
||||
types: ['string'],
|
||||
options: [
|
||||
{
|
||||
field: 'placeholder',
|
||||
name: '$t:placeholder',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'text-input',
|
||||
options: {
|
||||
placeholder: '$t:enter_a_placeholder',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'iconLeft',
|
||||
name: '$t:icon_left',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'iconRight',
|
||||
name: '$t:icon_right',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1,49 +0,0 @@
|
||||
<template>
|
||||
<v-input
|
||||
:value="value"
|
||||
:disabled="disabled"
|
||||
:placeholder="placeholder"
|
||||
:iconLeft="iconLeft"
|
||||
:iconRight="iconRight"
|
||||
@input="$emit('input', $event)"
|
||||
slug
|
||||
>
|
||||
<template v-if="iconLeft" #prepend><v-icon :name="iconLeft" /></template>
|
||||
<template v-if="iconRight" #append><v-icon :name="iconRight" /></template>
|
||||
</v-input>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from '@vue/composition-api';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: null,
|
||||
},
|
||||
iconLeft: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
iconRight: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.v-input {
|
||||
--v-input-font-family: var(--family-monospace);
|
||||
}
|
||||
</style>
|
||||
@@ -24,7 +24,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'text-input',
|
||||
interface: 'input',
|
||||
options: {
|
||||
placeholder: '$t:enter_a_placeholder',
|
||||
},
|
||||
@@ -36,7 +36,7 @@ export default defineInterface({
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.tags.alphabetize_label',
|
||||
},
|
||||
@@ -47,13 +47,13 @@ export default defineInterface({
|
||||
},
|
||||
{
|
||||
field: 'allowCustom',
|
||||
name: '$t:interfaces.dropdown.allow_other',
|
||||
name: '$t:interfaces.select-dropdown.allow_other',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
interface: 'boolean',
|
||||
options: {
|
||||
label: '$t:interfaces.dropdown.allow_other_label',
|
||||
label: '$t:interfaces.select-dropdown.allow_other_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
@@ -66,7 +66,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'dropdown',
|
||||
interface: 'select-dropdown',
|
||||
options: {
|
||||
allowNone: true,
|
||||
choices: [
|
||||
@@ -83,7 +83,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'dropdown',
|
||||
interface: 'select-dropdown',
|
||||
options: {
|
||||
allowNone: true,
|
||||
choices: [
|
||||
@@ -100,7 +100,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
@@ -109,7 +109,7 @@ export default defineInterface({
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
interface: 'select-icon',
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
@@ -1,106 +0,0 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceTextInput from './text-input.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'text-input',
|
||||
name: '$t:interfaces.text-input.text-input',
|
||||
description: '$t:interfaces.text-input.description',
|
||||
icon: 'text_fields',
|
||||
component: InterfaceTextInput,
|
||||
types: ['string', 'uuid'],
|
||||
options: [
|
||||
{
|
||||
field: 'placeholder',
|
||||
name: '$t:placeholder',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
options: {
|
||||
placeholder: '$t:enter_a_placeholder',
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'font',
|
||||
name: '$t:font',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'dropdown',
|
||||
options: {
|
||||
choices: [
|
||||
{ text: '$t:sans_serif', value: 'sans-serif' },
|
||||
{ text: '$t:monospace', value: 'monospace' },
|
||||
{ text: '$t:serif', value: 'serif' },
|
||||
],
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
default_value: 'sans-serif',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'iconLeft',
|
||||
name: '$t:icon_left',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'iconRight',
|
||||
name: '$t:icon_right',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'icon',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'trim',
|
||||
name: '$t:interfaces.text-input.trim',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
options: {
|
||||
label: '$t:interfaces.text-input.trim_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
default_value: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'masked',
|
||||
name: '$t:interfaces.text-input.mask',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
options: {
|
||||
label: '$t:interfaces.text-input.mask_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
default_value: false,
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'clear',
|
||||
name: '$t:interfaces.text-input.clear',
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
options: {
|
||||
label: '$t:interfaces.text-input.clear_label',
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
default_value: false,
|
||||
},
|
||||
},
|
||||
],
|
||||
});
|
||||
@@ -1,34 +0,0 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import InterfaceUser from './user.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'user',
|
||||
name: '$t:interfaces.user.user',
|
||||
description: '$t:interfaces.user.description',
|
||||
icon: 'person',
|
||||
component: InterfaceUser,
|
||||
types: ['uuid'],
|
||||
relational: true,
|
||||
options: [
|
||||
{
|
||||
field: 'selectMode',
|
||||
name: '$t:interfaces.user.select_mode',
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'full',
|
||||
interface: 'dropdown',
|
||||
options: {
|
||||
choices: [
|
||||
{ text: '$t:interfaces.user.modes.auto', value: 'auto' },
|
||||
{ text: '$t:interfaces.user.modes.dropdown', value: 'dropdown' },
|
||||
{ text: '$t:interfaces.user.modes.modal', value: 'modal' },
|
||||
],
|
||||
},
|
||||
},
|
||||
schema: {
|
||||
default_value: 'auto',
|
||||
},
|
||||
},
|
||||
],
|
||||
recommendedDisplays: ['user'],
|
||||
});
|
||||
@@ -1,359 +0,0 @@
|
||||
<template>
|
||||
<div class="user">
|
||||
<v-menu v-model="menuActive" attached :disabled="disabled">
|
||||
<template #activator="{ active }">
|
||||
<v-skeleton-loader type="input" v-if="loadingCurrent" />
|
||||
<v-input
|
||||
:active="active"
|
||||
v-else
|
||||
:placeholder="$t('select_an_item')"
|
||||
:disabled="disabled"
|
||||
@click="onPreviewClick"
|
||||
>
|
||||
<template #input v-if="currentUser">
|
||||
<div class="preview">
|
||||
{{ userName(currentUser) }}
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template #append v-if="!disabled">
|
||||
<template v-if="currentUser">
|
||||
<v-icon name="open_in_new" class="edit" v-tooltip="$t('edit')" @click.stop="editModalActive = true" />
|
||||
<v-icon name="close" class="deselect" @click.stop="$emit('input', null)" v-tooltip="$t('deselect')" />
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-icon class="add" name="add" v-tooltip="$t('create_item')" @click.stop="editModalActive = true" />
|
||||
<v-icon class="expand" :class="{ active }" name="expand_more" />
|
||||
</template>
|
||||
</template>
|
||||
</v-input>
|
||||
</template>
|
||||
|
||||
<v-list>
|
||||
<template v-if="usersLoading">
|
||||
<v-list-item v-for="n in 10" :key="`loader-${n}`">
|
||||
<v-list-item-content>
|
||||
<v-skeleton-loader type="text" />
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
|
||||
<template v-else>
|
||||
<v-list-item v-for="item in users" :key="item.id" :active="value === item.id" @click="setCurrent(item)">
|
||||
<v-list-item-content>
|
||||
{{ userName(item) }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
|
||||
<drawer-item
|
||||
:active.sync="editModalActive"
|
||||
collection="directus_users"
|
||||
:primary-key="currentPrimaryKey"
|
||||
:edits="edits"
|
||||
@input="stageEdits"
|
||||
v-if="!disabled"
|
||||
/>
|
||||
|
||||
<drawer-collection
|
||||
:active.sync="selectModalActive"
|
||||
collection="directus_users"
|
||||
:selection="selection"
|
||||
@input="stageSelection"
|
||||
v-if="!disabled"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed, ref, watch, PropType } from '@vue/composition-api';
|
||||
import useCollection from '@/composables/use-collection';
|
||||
import api from '@/api';
|
||||
import DrawerItem from '@/views/private/components/drawer-item';
|
||||
import DrawerCollection from '@/views/private/components/drawer-collection';
|
||||
import { userName } from '@/utils/user-name';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
|
||||
export default defineComponent({
|
||||
components: { DrawerItem, DrawerCollection },
|
||||
props: {
|
||||
value: {
|
||||
type: [String, Object],
|
||||
default: null,
|
||||
},
|
||||
selectMode: {
|
||||
type: String as PropType<'auto' | 'dropdown' | 'modal'>,
|
||||
default: 'auto',
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const { usesMenu, menuActive } = useMenu();
|
||||
const { info: collectionInfo } = useCollection(ref('directus_users'));
|
||||
const { selection, stageSelection, selectModalActive } = useSelection();
|
||||
const { onPreviewClick } = usePreview();
|
||||
const { totalCount, loading: usersLoading, fetchUsers, users } = useUsers();
|
||||
|
||||
const { setCurrent, currentUser, loading: loadingCurrent, currentPrimaryKey } = useCurrent();
|
||||
|
||||
const { edits, stageEdits } = useEdits();
|
||||
|
||||
const editModalActive = ref(false);
|
||||
|
||||
return {
|
||||
collectionInfo,
|
||||
currentUser,
|
||||
users,
|
||||
usersLoading,
|
||||
loadingCurrent,
|
||||
menuActive,
|
||||
onPreviewClick,
|
||||
selection,
|
||||
selectModalActive,
|
||||
setCurrent,
|
||||
totalCount,
|
||||
stageSelection,
|
||||
useMenu,
|
||||
currentPrimaryKey,
|
||||
edits,
|
||||
stageEdits,
|
||||
editModalActive,
|
||||
userName,
|
||||
};
|
||||
|
||||
function useCurrent() {
|
||||
const currentUser = ref<Record<string, any> | null>(null);
|
||||
const loading = ref(false);
|
||||
|
||||
watch(
|
||||
() => props.value,
|
||||
(newValue) => {
|
||||
// When the newly configured value is a primitive, assume it's the primary key
|
||||
// of the item and fetch it from the API to render the preview
|
||||
if (newValue !== null && newValue !== currentUser.value?.id && typeof newValue === 'string') {
|
||||
fetchCurrent();
|
||||
}
|
||||
|
||||
// If the value isn't a primary key, the current value will be set by the editing
|
||||
// handlers in useEdit()
|
||||
|
||||
if (newValue === null) {
|
||||
currentUser.value = null;
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
const currentPrimaryKey = computed<string | number>(() => {
|
||||
if (!currentUser.value) return '+';
|
||||
if (!props.value) return '+';
|
||||
|
||||
if (typeof props.value === 'object') return props.value?.id;
|
||||
return props.value;
|
||||
});
|
||||
|
||||
return { setCurrent, currentUser, loading, currentPrimaryKey };
|
||||
|
||||
function setCurrent(item: Record<string, any>) {
|
||||
currentUser.value = item;
|
||||
emit('input', item.id);
|
||||
}
|
||||
|
||||
async function fetchCurrent() {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await api.get(`/users/${props.value}`, {
|
||||
params: {
|
||||
fields: ['id', 'email', 'first_name', 'last_name'],
|
||||
},
|
||||
});
|
||||
|
||||
currentUser.value = response.data.data;
|
||||
} catch (err) {
|
||||
unexpectedError(err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function useUsers() {
|
||||
const totalCount = ref<number | null>(null);
|
||||
|
||||
const users = ref<Record<string, any>[] | null>(null);
|
||||
const loading = ref(false);
|
||||
|
||||
fetchTotalCount();
|
||||
users.value = null;
|
||||
|
||||
return { totalCount, fetchUsers, users, loading };
|
||||
|
||||
async function fetchUsers() {
|
||||
if (users.value !== null) return;
|
||||
|
||||
loading.value = true;
|
||||
|
||||
const fields = ['id', 'email', 'first_name', 'last_name'];
|
||||
|
||||
try {
|
||||
const response = await api.get(`/users`, {
|
||||
params: {
|
||||
fields: fields,
|
||||
limit: -1,
|
||||
},
|
||||
});
|
||||
|
||||
users.value = response.data.data;
|
||||
} catch (err) {
|
||||
unexpectedError(err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
|
||||
async function fetchTotalCount() {
|
||||
const response = await api.get(`/users`, {
|
||||
params: {
|
||||
limit: 0,
|
||||
meta: 'total_count',
|
||||
},
|
||||
});
|
||||
|
||||
totalCount.value = response.data.meta.total_count;
|
||||
}
|
||||
}
|
||||
|
||||
function useMenu() {
|
||||
const menuActive = ref(false);
|
||||
const usesMenu = computed(() => {
|
||||
if (props.selectMode === 'modal') return false;
|
||||
if (props.selectMode === 'dropdown') return true;
|
||||
|
||||
// auto
|
||||
if (totalCount.value && totalCount.value > 100) return false;
|
||||
return true;
|
||||
});
|
||||
|
||||
return { menuActive, usesMenu };
|
||||
}
|
||||
|
||||
function usePreview() {
|
||||
return { onPreviewClick };
|
||||
|
||||
function onPreviewClick() {
|
||||
if (props.disabled) return;
|
||||
|
||||
if (usesMenu.value === true) {
|
||||
const newActive = !menuActive.value;
|
||||
menuActive.value = newActive;
|
||||
if (newActive === true) fetchUsers();
|
||||
} else {
|
||||
selectModalActive.value = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function useSelection() {
|
||||
const selectModalActive = ref(false);
|
||||
|
||||
const selection = computed<(number | string)[]>(() => {
|
||||
if (!props.value) return [];
|
||||
|
||||
return [props.value];
|
||||
});
|
||||
|
||||
return { selection, stageSelection, selectModalActive };
|
||||
|
||||
function stageSelection(newSelection: (number | string)[]) {
|
||||
if (newSelection.length === 0) {
|
||||
emit('input', null);
|
||||
} else {
|
||||
emit('input', newSelection[0]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function useEdits() {
|
||||
const edits = computed(() => {
|
||||
// If the current value isn't a primitive, it means we've already staged some changes
|
||||
// This ensures we continue on those changes instead of starting over
|
||||
if (props.value && typeof props.value === 'object') {
|
||||
return props.value;
|
||||
}
|
||||
|
||||
return {};
|
||||
});
|
||||
|
||||
return { edits, stageEdits };
|
||||
|
||||
function stageEdits(newEdits: Record<string, any>) {
|
||||
// Make sure we stage the primary key if it exists. This is needed to have the API
|
||||
// update the existing item instead of create a new one
|
||||
if (currentPrimaryKey.value && currentPrimaryKey.value !== '+') {
|
||||
emit('input', {
|
||||
id: currentPrimaryKey.value,
|
||||
...newEdits,
|
||||
});
|
||||
} else {
|
||||
if ('id' in newEdits && newEdits.id === '+') {
|
||||
delete newEdits.id;
|
||||
}
|
||||
|
||||
emit('input', newEdits);
|
||||
}
|
||||
|
||||
currentUser.value = {
|
||||
...currentUser.value,
|
||||
...newEdits,
|
||||
};
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.many-to-one {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.v-skeleton-loader {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.preview {
|
||||
display: block;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.expand {
|
||||
transition: transform var(--fast) var(--transition);
|
||||
|
||||
&.active {
|
||||
transform: scaleY(-1);
|
||||
}
|
||||
}
|
||||
|
||||
.edit {
|
||||
margin-right: 4px;
|
||||
|
||||
&:hover {
|
||||
--v-icon-color: var(--foreground-normal);
|
||||
}
|
||||
}
|
||||
|
||||
.add:hover {
|
||||
--v-icon-color: var(--primary);
|
||||
}
|
||||
|
||||
.deselect:hover {
|
||||
--v-icon-color: var(--danger);
|
||||
}
|
||||
</style>
|
||||
Reference in New Issue
Block a user