mirror of
https://github.com/directus/directus.git
synced 2026-01-28 01:17:55 -05:00
Change print width to 120 (#671)
* Increase line-width to 120 * Auto-fix 100->120 columns
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"htmlWhitespaceSensitivity": "ignore",
|
||||
"printWidth": 100,
|
||||
"printWidth": 120,
|
||||
"singleQuote": true,
|
||||
"useTabs": true
|
||||
}
|
||||
|
||||
@@ -13,9 +13,7 @@ interface HTMLExpandElement extends HTMLElement {
|
||||
|
||||
export default function (expandedParentClass = '', xAxis = false) {
|
||||
const sizeProperty = xAxis ? 'width' : ('height' as 'width' | 'height');
|
||||
const offsetProperty = `offset${capitalizeFirst(sizeProperty)}` as
|
||||
| 'offsetHeight'
|
||||
| 'offsetWidth';
|
||||
const offsetProperty = `offset${capitalizeFirst(sizeProperty)}` as 'offsetHeight' | 'offsetWidth';
|
||||
|
||||
return {
|
||||
beforeEnter(el: HTMLExpandElement) {
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
withKnobs,
|
||||
text,
|
||||
boolean,
|
||||
number,
|
||||
color,
|
||||
optionsKnob as options,
|
||||
} from '@storybook/addon-knobs';
|
||||
import { withKnobs, text, boolean, number, color, optionsKnob as options } from '@storybook/addon-knobs';
|
||||
import Vue from 'vue';
|
||||
import VAvatar from './v-avatar.vue';
|
||||
import VIcon from '../v-icon/';
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
<template>
|
||||
<span class="v-breadcrumb">
|
||||
<span
|
||||
v-for="(item, index) in items"
|
||||
:key="item.name"
|
||||
class="section"
|
||||
:class="{ disabled: item.disabled }"
|
||||
>
|
||||
<span v-for="(item, index) in items" :key="item.name" class="section" :class="{ disabled: item.disabled }">
|
||||
<v-icon v-if="index > 0" name="chevron_right" small />
|
||||
<router-link v-if="!item.disabled" :to="item.to" class="section-link">
|
||||
<v-icon v-if="item.icon" :name="item.icon" small />
|
||||
|
||||
@@ -1,12 +1,4 @@
|
||||
import {
|
||||
withKnobs,
|
||||
text,
|
||||
boolean,
|
||||
number,
|
||||
color,
|
||||
select,
|
||||
optionsKnob as options,
|
||||
} from '@storybook/addon-knobs';
|
||||
import { withKnobs, text, boolean, number, color, select, optionsKnob as options } from '@storybook/addon-knobs';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import Vue from 'vue';
|
||||
import VButton from './v-button.vue';
|
||||
|
||||
@@ -335,9 +335,7 @@ body {
|
||||
&.activated {
|
||||
--v-button-color: var(--v-button-color-activated) !important;
|
||||
--v-button-background-color: var(--v-button-background-color-activated) !important;
|
||||
--v-button-background-color-hover: var(
|
||||
--v-button-background-color-activated
|
||||
) !important;
|
||||
--v-button-background-color-hover: var(--v-button-background-color-activated) !important;
|
||||
}
|
||||
|
||||
&.tile {
|
||||
|
||||
@@ -1,18 +1,8 @@
|
||||
<template>
|
||||
<span
|
||||
v-if="_active"
|
||||
class="v-chip"
|
||||
:class="[sizeClass, { outlined, label, disabled, close }]"
|
||||
@click="onClick"
|
||||
>
|
||||
<span v-if="_active" class="v-chip" :class="[sizeClass, { outlined, label, disabled, close }]" @click="onClick">
|
||||
<span class="chip-content">
|
||||
<slot />
|
||||
<span
|
||||
v-if="close"
|
||||
class="close-outline"
|
||||
:class="{ disabled }"
|
||||
@click.stop="onCloseClick"
|
||||
>
|
||||
<span v-if="close" class="close-outline" :class="{ disabled }" @click.stop="onCloseClick">
|
||||
<v-icon class="close" :name="closeIcon" x-small />
|
||||
</span>
|
||||
</span>
|
||||
|
||||
@@ -3,12 +3,7 @@ import readme from './readme.md';
|
||||
import withPadding from '../../../.storybook/decorators/with-padding';
|
||||
import { withKnobs, boolean } from '@storybook/addon-knobs';
|
||||
import { defineComponent } from '@vue/composition-api';
|
||||
import VList, {
|
||||
VListItem,
|
||||
VListItemContent,
|
||||
VListItemTitle,
|
||||
VListItemIcon,
|
||||
} from '@/components/v-list';
|
||||
import VList, { VListItem, VListItemContent, VListItemTitle, VListItemIcon } from '@/components/v-list';
|
||||
import VIcon from '@/components/v-icon/';
|
||||
|
||||
export default {
|
||||
|
||||
@@ -20,11 +20,7 @@
|
||||
<div class="description">{{ item.description }}</div>
|
||||
</div>
|
||||
|
||||
<v-icon
|
||||
v-if="value === item.value && disabled === false"
|
||||
name="cancel"
|
||||
@click.stop="toggle(item)"
|
||||
/>
|
||||
<v-icon v-if="value === item.value && disabled === false" name="cancel" @click.stop="toggle(item)" />
|
||||
</div>
|
||||
</transition-group>
|
||||
</div>
|
||||
|
||||
@@ -101,9 +101,7 @@ export default defineComponent({
|
||||
function useForm() {
|
||||
const fields = computed(() => {
|
||||
if (props.collection) {
|
||||
return fieldsStore.state.fields.filter(
|
||||
(field) => field.collection === props.collection
|
||||
);
|
||||
return fieldsStore.state.fields.filter((field) => field.collection === props.collection);
|
||||
}
|
||||
|
||||
if (props.fields) {
|
||||
@@ -231,9 +229,7 @@ export default defineComponent({
|
||||
|
||||
function toggleBatchField(field: Field) {
|
||||
if (batchActiveFields.value.includes(field.field)) {
|
||||
batchActiveFields.value = batchActiveFields.value.filter(
|
||||
(fieldKey) => fieldKey !== field.field
|
||||
);
|
||||
batchActiveFields.value = batchActiveFields.value.filter((fieldKey) => fieldKey !== field.field);
|
||||
|
||||
unsetValue(field);
|
||||
} else {
|
||||
@@ -264,10 +260,7 @@ body {
|
||||
|
||||
&.with-fill {
|
||||
grid-template-columns:
|
||||
[start] minmax(0, var(--v-form-column-max-width)) [half] minmax(
|
||||
0,
|
||||
var(--v-form-column-max-width)
|
||||
)
|
||||
[start] minmax(0, var(--v-form-column-max-width)) [half] minmax(0, var(--v-form-column-max-width))
|
||||
[full] 1fr [fill];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -12,9 +12,7 @@
|
||||
d="M24.02 42.98L47.28 14c-.9-.68-9.85-8-23.28-8S1.62 13.32.72 14l23.26 28.98.02.02.02-.02z"
|
||||
/>
|
||||
<path d="M0 0h48v48H0z" fill="none" />
|
||||
<path
|
||||
d="M9.58 25.03l14.41 17.95.01.02.01-.02 14.41-17.95C37.7 24.47 32.2 20 24 20s-13.7 4.47-14.42 5.03z"
|
||||
/>
|
||||
<path d="M9.58 25.03l14.41 17.95.01.02.01-.02 14.41-17.95C37.7 24.47 32.2 20 24 20s-13.7 4.47-14.42 5.03z" />
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
withKnobs,
|
||||
text,
|
||||
boolean,
|
||||
number,
|
||||
color,
|
||||
optionsKnob as options,
|
||||
} from '@storybook/addon-knobs';
|
||||
import { withKnobs, text, boolean, number, color, optionsKnob as options } from '@storybook/addon-knobs';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import Vue from 'vue';
|
||||
import VIcon from '../v-icon/';
|
||||
|
||||
@@ -96,8 +96,7 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
const customIconName = computed<string | null>(() => {
|
||||
if (customIcons.includes(props.name))
|
||||
return `custom-icon-${props.name}`.replace(/_/g, '-');
|
||||
if (customIcons.includes(props.name)) return `custom-icon-${props.name}`.replace(/_/g, '-');
|
||||
return null;
|
||||
});
|
||||
|
||||
|
||||
@@ -25,18 +25,10 @@ describe('Input', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(component.find('.v-input > .prepend-outer > div ').html()).toBe(
|
||||
'<div>prepend-outer</div>'
|
||||
);
|
||||
expect(component.find('.v-input > .append-outer > div ').html()).toBe(
|
||||
'<div>append-outer</div>'
|
||||
);
|
||||
expect(component.find('.v-input > .input > .prepend > div ').html()).toBe(
|
||||
'<div>prepend</div>'
|
||||
);
|
||||
expect(component.find('.v-input > .input > .append > div ').html()).toBe(
|
||||
'<div>append</div>'
|
||||
);
|
||||
expect(component.find('.v-input > .prepend-outer > div ').html()).toBe('<div>prepend-outer</div>');
|
||||
expect(component.find('.v-input > .append-outer > div ').html()).toBe('<div>append-outer</div>');
|
||||
expect(component.find('.v-input > .input > .prepend > div ').html()).toBe('<div>prepend</div>');
|
||||
expect(component.find('.v-input > .input > .append > div ').html()).toBe('<div>append</div>');
|
||||
});
|
||||
|
||||
it('Renders prefix / suffix', async () => {
|
||||
|
||||
@@ -73,9 +73,7 @@ export default defineComponent({
|
||||
return 'li';
|
||||
});
|
||||
|
||||
const isClickable = computed(() =>
|
||||
Boolean(props.to || props.href || listeners.click !== undefined)
|
||||
);
|
||||
const isClickable = computed(() => Boolean(props.to || props.href || listeners.click !== undefined));
|
||||
|
||||
return { component, isClickable };
|
||||
},
|
||||
@@ -102,14 +100,8 @@ body {
|
||||
--v-list-item-color: var(--v-list-color, var(--foreground-normal));
|
||||
--v-list-item-color-hover: var(--v-list-color-hover, var(--foreground-normal));
|
||||
--v-list-item-color-active: var(--v-list-color-active, var(--foreground-normal));
|
||||
--v-list-item-background-color-hover: var(
|
||||
--v-list-background-color-hover,
|
||||
var(--background-normal-alt)
|
||||
);
|
||||
--v-list-item-background-color-active: var(
|
||||
--v-list-background-color-active,
|
||||
var(--background-normal-alt)
|
||||
);
|
||||
--v-list-item-background-color-hover: var(--v-list-background-color-hover, var(--background-normal-alt));
|
||||
--v-list-item-background-color-active: var(--v-list-background-color-active, var(--background-normal-alt));
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
@@ -215,36 +215,16 @@ export const withSubtitle = () =>
|
||||
default: boolean('Dense', false, 'List Item 3'),
|
||||
},
|
||||
lines0: {
|
||||
default: select(
|
||||
'Lines',
|
||||
{ One: 1, Two: 2, Three: 3, Off: null },
|
||||
null,
|
||||
'List Item 0'
|
||||
),
|
||||
default: select('Lines', { One: 1, Two: 2, Three: 3, Off: null }, null, 'List Item 0'),
|
||||
},
|
||||
lines1: {
|
||||
default: select(
|
||||
'Lines',
|
||||
{ One: 1, Two: 2, Three: 3, Off: null },
|
||||
null,
|
||||
'List Item 1'
|
||||
),
|
||||
default: select('Lines', { One: 1, Two: 2, Three: 3, Off: null }, null, 'List Item 1'),
|
||||
},
|
||||
lines2: {
|
||||
default: select(
|
||||
'Lines',
|
||||
{ One: 1, Two: 2, Three: 3, Off: null },
|
||||
null,
|
||||
'List Item 2'
|
||||
),
|
||||
default: select('Lines', { One: 1, Two: 2, Three: 3, Off: null }, null, 'List Item 2'),
|
||||
},
|
||||
lines3: {
|
||||
default: select(
|
||||
'Lines',
|
||||
{ One: 1, Two: 2, Three: 3, Off: null },
|
||||
null,
|
||||
'List Item 3'
|
||||
),
|
||||
default: select('Lines', { One: 1, Two: 2, Three: 3, Off: null }, null, 'List Item 3'),
|
||||
},
|
||||
nav: {
|
||||
default: boolean('Nav', false, 'Full List'),
|
||||
@@ -253,12 +233,7 @@ export const withSubtitle = () =>
|
||||
default: text('Subtitle 3', '', 'Full List'),
|
||||
},
|
||||
lines: {
|
||||
default: select(
|
||||
'Lines',
|
||||
{ One: 1, Two: 2, Three: 3, Off: null },
|
||||
null,
|
||||
'Full List'
|
||||
),
|
||||
default: select('Lines', { One: 1, Two: 2, Three: 3, Off: null }, null, 'Full List'),
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
@@ -272,8 +247,7 @@ export const withSubtitle = () =>
|
||||
},
|
||||
2: {
|
||||
title: 'List Item 2',
|
||||
subtitle:
|
||||
"This is yet another example of a list subtitle. It's of medium length.",
|
||||
subtitle: "This is yet another example of a list subtitle. It's of medium length.",
|
||||
},
|
||||
},
|
||||
};
|
||||
@@ -311,12 +285,7 @@ export const withIconsToo = () =>
|
||||
default: boolean('Subtitle', false, 'Full List'),
|
||||
},
|
||||
lines: {
|
||||
default: select(
|
||||
'Lines',
|
||||
{ One: 1, Two: 2, Three: 3, Off: null },
|
||||
null,
|
||||
'Full List'
|
||||
),
|
||||
default: select('Lines', { One: 1, Two: 2, Three: 3, Off: null }, null, 'Full List'),
|
||||
},
|
||||
leftIconCenter: {
|
||||
default: boolean('Left Icon Centered', false, 'Full List'),
|
||||
@@ -349,8 +318,7 @@ export const withIconsToo = () =>
|
||||
},
|
||||
2: {
|
||||
title: 'List Item 2',
|
||||
subtitle:
|
||||
"This is yet another example of a list subtitle. It's of medium length.",
|
||||
subtitle: "This is yet another example of a list subtitle. It's of medium length.",
|
||||
checked: false,
|
||||
},
|
||||
3: {
|
||||
|
||||
@@ -15,12 +15,7 @@
|
||||
<slot name="header:append" />
|
||||
</header>
|
||||
<div class="content" :class="{ 'no-padding': noPadding }">
|
||||
<v-overlay
|
||||
v-if="$slots.sidebar"
|
||||
absolute
|
||||
:active="sidebarActive"
|
||||
@click="sidebarActive = false"
|
||||
/>
|
||||
<v-overlay v-if="$slots.sidebar" absolute :active="sidebarActive" @click="sidebarActive = false" />
|
||||
<nav
|
||||
v-if="$slots.sidebar"
|
||||
class="sidebar"
|
||||
|
||||
@@ -1,11 +1,4 @@
|
||||
import {
|
||||
withKnobs,
|
||||
color,
|
||||
optionsKnob as options,
|
||||
number,
|
||||
text,
|
||||
boolean,
|
||||
} from '@storybook/addon-knobs';
|
||||
import { withKnobs, color, optionsKnob as options, number, text, boolean } from '@storybook/addon-knobs';
|
||||
|
||||
import Vue from 'vue';
|
||||
import VProgressCircular from './v-progress-circular.vue';
|
||||
|
||||
@@ -7,12 +7,7 @@
|
||||
:close-on-content-click="closeOnContentClick"
|
||||
>
|
||||
<template #activator="{ toggle, active }">
|
||||
<div
|
||||
v-if="inline"
|
||||
class="inline-display"
|
||||
:class="{ placeholder: !displayValue }"
|
||||
@click="toggle"
|
||||
>
|
||||
<div v-if="inline" class="inline-display" :class="{ placeholder: !displayValue }" @click="toggle">
|
||||
{{ displayValue || placeholder }}
|
||||
<v-icon name="expand_more" :class="{ active }" />
|
||||
</div>
|
||||
@@ -65,11 +60,7 @@
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item
|
||||
v-if="allowOther && multiple === false"
|
||||
:active="usesOtherValue"
|
||||
@click.stop
|
||||
>
|
||||
<v-list-item v-if="allowOther && multiple === false" :active="usesOtherValue" @click.stop>
|
||||
<v-list-item-content>
|
||||
<input
|
||||
class="other-input"
|
||||
@@ -101,9 +92,7 @@
|
||||
:placeholder="$t('other')"
|
||||
v-focus
|
||||
@input="setOtherValue(otherValue.key, $event.target.value)"
|
||||
@blur="
|
||||
otherValue.value.length === 0 && setOtherValue(otherValue.key, null)
|
||||
"
|
||||
@blur="otherValue.value.length === 0 && setOtherValue(otherValue.key, null)"
|
||||
/>
|
||||
</v-list-item-content>
|
||||
<v-list-item-icon>
|
||||
@@ -188,11 +177,7 @@ export default defineComponent({
|
||||
const { _items } = useItems();
|
||||
const { displayValue } = useDisplayValue();
|
||||
const { value } = toRefs(props);
|
||||
const { otherValue, usesOtherValue } = useCustomSelection(
|
||||
value as Ref<string>,
|
||||
_items,
|
||||
emit
|
||||
);
|
||||
const { otherValue, usesOtherValue } = useCustomSelection(value as Ref<string>, _items, emit);
|
||||
const { otherValues, addOtherValue, setOtherValue } = useCustomSelectionMultiple(
|
||||
value as Ref<string[]>,
|
||||
_items,
|
||||
|
||||
@@ -46,12 +46,7 @@ body {
|
||||
left: 0;
|
||||
z-index: 1;
|
||||
height: 100%;
|
||||
background: linear-gradient(
|
||||
90deg,
|
||||
transparent,
|
||||
var(--v-skeleton-loader-color),
|
||||
transparent
|
||||
);
|
||||
background: linear-gradient(90deg, transparent, var(--v-skeleton-loader-color), transparent);
|
||||
transform: translateX(-100%);
|
||||
opacity: 0.5;
|
||||
animation: loading 1.5s infinite;
|
||||
|
||||
@@ -4,15 +4,7 @@
|
||||
<slot name="prepend" :value="value" />
|
||||
</div>
|
||||
<div class="slider">
|
||||
<input
|
||||
type="range"
|
||||
:value="value"
|
||||
:max="max"
|
||||
:min="min"
|
||||
:step="step"
|
||||
@change="onChange"
|
||||
@input="onInput"
|
||||
/>
|
||||
<input type="range" :value="value" :max="max" :min="min" :step="step" @change="onChange" @input="onInput" />
|
||||
<div class="fill" />
|
||||
<div v-if="showTicks" class="ticks">
|
||||
<span class="tick" v-for="i in (max - min) / step + 1" :key="i" />
|
||||
|
||||
@@ -205,14 +205,11 @@ describe('Table / Header', () => {
|
||||
},
|
||||
},
|
||||
scopedSlots: {
|
||||
'header.col2':
|
||||
'<template slot-scope="{header}"><p>{{ header.text }}</p></template>',
|
||||
'header.col2': '<template slot-scope="{header}"><p>{{ header.text }}</p></template>',
|
||||
},
|
||||
});
|
||||
|
||||
expect(component.find('.table-header th:nth-child(2) .content > span > *').html()).toEqual(
|
||||
'<p>Column 2</p>'
|
||||
);
|
||||
expect(component.find('.table-header th:nth-child(2) .content > span > *').html()).toEqual('<p>Column 2</p>');
|
||||
});
|
||||
|
||||
it('Sets the dragging state correctly based on mouse interaction', async () => {
|
||||
|
||||
@@ -65,9 +65,7 @@ describe('Table / Row', () => {
|
||||
},
|
||||
});
|
||||
|
||||
expect(component.find('.table-row td:nth-child(2) > *').html()).toEqual(
|
||||
'<p>Test 1 Col 2</p>'
|
||||
);
|
||||
expect(component.find('.table-row td:nth-child(2) > *').html()).toEqual('<p>Test 1 Col 2</p>');
|
||||
});
|
||||
|
||||
it('Adds the align class', async () => {
|
||||
|
||||
@@ -9,21 +9,12 @@
|
||||
}"
|
||||
>
|
||||
<td v-if="showManualSort" class="manual cell">
|
||||
<v-icon
|
||||
name="drag_handle"
|
||||
class="drag-handle"
|
||||
:class="{ 'sorted-manually': sortedManually }"
|
||||
/>
|
||||
<v-icon name="drag_handle" class="drag-handle" :class="{ 'sorted-manually': sortedManually }" />
|
||||
</td>
|
||||
<td v-if="showSelect" class="select cell" @click.stop>
|
||||
<v-checkbox :inputValue="isSelected" @change="toggleSelect" />
|
||||
</td>
|
||||
<td
|
||||
class="cell"
|
||||
:class="getClassesForCell(header)"
|
||||
v-for="header in headers"
|
||||
:key="header.value"
|
||||
>
|
||||
<td class="cell" :class="getClassesForCell(header)" v-for="header in headers" :key="header.value">
|
||||
<slot :name="`item.${header.value}`" :item="item">{{ item[header.value] }}</slot>
|
||||
</td>
|
||||
|
||||
|
||||
@@ -820,9 +820,7 @@ export const serverSort = () => ({
|
||||
(this as any).loading = true;
|
||||
|
||||
setTimeout(() => {
|
||||
(this as any).items = [...(this as any).items].sort((a, b) =>
|
||||
a[sort.by!] > b[sort.by!] ? 1 : -1
|
||||
);
|
||||
(this as any).items = [...(this as any).items].sort((a, b) => (a[sort.by!] > b[sort.by!] ? 1 : -1));
|
||||
|
||||
if (sort.desc === true) {
|
||||
(this as any).items.reverse();
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
<template>
|
||||
<v-list-item
|
||||
v-if="vertical"
|
||||
class="v-tab vertical"
|
||||
:active="active"
|
||||
:disabled="disabled"
|
||||
@click="onClick"
|
||||
>
|
||||
<v-list-item v-if="vertical" class="v-tab vertical" :active="active" :disabled="disabled" @click="onClick">
|
||||
<slot v-bind="{ active, toggle }" />
|
||||
</v-list-item>
|
||||
<div v-else class="v-tab horizontal" :class="{ active, disabled }" @click="onClick">
|
||||
|
||||
@@ -21,11 +21,7 @@ describe('Textarea', () => {
|
||||
|
||||
await component.vm.$nextTick();
|
||||
|
||||
expect(component.find('.v-textarea').classes()).toEqual([
|
||||
'v-textarea',
|
||||
'disabled',
|
||||
'full-width',
|
||||
]);
|
||||
expect(component.find('.v-textarea').classes()).toEqual(['v-textarea', 'disabled', 'full-width']);
|
||||
});
|
||||
|
||||
it('Emits just the value for the input event', async () => {
|
||||
|
||||
@@ -115,11 +115,7 @@ export function useGroupableParent(
|
||||
items.value = [...items.value, item];
|
||||
|
||||
// If you're required to select a value, make sure a value is selected on first render
|
||||
if (
|
||||
selection.value.length === 0 &&
|
||||
options?.mandatory?.value === true &&
|
||||
items.value.length === 1
|
||||
) {
|
||||
if (selection.value.length === 0 && options?.mandatory?.value === true && items.value.length === 1) {
|
||||
selection.value = [getValueForItem(item)];
|
||||
}
|
||||
}
|
||||
@@ -167,11 +163,7 @@ export function useGroupableParent(
|
||||
}
|
||||
|
||||
// Don't add it if when we're already at the maximum number of selections
|
||||
if (
|
||||
options?.max?.value &&
|
||||
options.max.value !== -1 &&
|
||||
selection.value.length >= options.max.value
|
||||
) {
|
||||
if (options?.max?.value && options.max.value !== -1 && selection.value.length >= options.max.value) {
|
||||
// Even though we don't alter selection, we should flush the internal active state of
|
||||
// the children to make sure we don't have any invalid internal active states
|
||||
updateChildren();
|
||||
|
||||
@@ -5,28 +5,21 @@ import useUserStore from '@/stores/user';
|
||||
|
||||
import { Filter, CollectionPreset } from '@/stores/collection-presets/types';
|
||||
|
||||
export function useCollectionPreset(
|
||||
collection: Ref<string>,
|
||||
bookmark: Ref<number | null> = ref(null)
|
||||
) {
|
||||
export function useCollectionPreset(collection: Ref<string>, bookmark: Ref<number | null> = ref(null)) {
|
||||
const collectionPresetsStore = useCollectionPresetStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const bookmarkExists = computed(() => {
|
||||
if (!bookmark.value) return false;
|
||||
|
||||
return !!collectionPresetsStore.state.collectionPresets.find(
|
||||
(preset) => preset.id === bookmark.value
|
||||
);
|
||||
return !!collectionPresetsStore.state.collectionPresets.find((preset) => preset.id === bookmark.value);
|
||||
});
|
||||
|
||||
const localPreset = ref<CollectionPreset>({});
|
||||
initLocalPreset();
|
||||
|
||||
const savePreset = async (preset?: Partial<CollectionPreset>) => {
|
||||
const updatedValues = await collectionPresetsStore.savePreset(
|
||||
preset ? preset : localPreset.value
|
||||
);
|
||||
const updatedValues = await collectionPresetsStore.savePreset(preset ? preset : localPreset.value);
|
||||
|
||||
localPreset.value.id = updatedValues.id;
|
||||
|
||||
|
||||
@@ -8,9 +8,7 @@ export function useCollection(collection: Ref<string>) {
|
||||
const fieldsStore = useFieldsStore();
|
||||
|
||||
const info = computed(() => {
|
||||
return collectionsStore.state.collections.find(
|
||||
({ collection: key }) => key === collection.value
|
||||
);
|
||||
return collectionsStore.state.collections.find(({ collection: key }) => key === collection.value);
|
||||
});
|
||||
|
||||
const fields = computed<Field[]>(() => {
|
||||
@@ -20,9 +18,7 @@ export function useCollection(collection: Ref<string>) {
|
||||
const primaryKeyField = computed(() => {
|
||||
// Every collection has a primary key; rules of the land
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
return fields.value?.find(
|
||||
(field) => field.collection === collection.value && field.primary_key === true
|
||||
)!;
|
||||
return fields.value?.find((field) => field.collection === collection.value && field.primary_key === true)!;
|
||||
});
|
||||
|
||||
const ownerField = computed(() => {
|
||||
@@ -54,9 +50,7 @@ export function useCollection(collection: Ref<string>) {
|
||||
|
||||
const statuses = Object.values(statusField.value?.options?.status_mapping || {});
|
||||
return (
|
||||
(statuses.find((status) => (status as Status).soft_delete === true) as
|
||||
| Status
|
||||
| undefined)?.value || null
|
||||
(statuses.find((status) => (status as Status).soft_delete === true) as Status | undefined)?.value || null
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -46,11 +46,7 @@ export function useCustomSelection(currentValue: Ref<string>, items: Items, emit
|
||||
return { otherValue, usesOtherValue };
|
||||
}
|
||||
|
||||
export function useCustomSelectionMultiple(
|
||||
currentValues: Ref<string[]>,
|
||||
items: Items,
|
||||
emit: EmitFunction
|
||||
) {
|
||||
export function useCustomSelectionMultiple(currentValues: Ref<string[]>, items: Items, emit: EmitFunction) {
|
||||
type OtherValue = {
|
||||
key: string;
|
||||
value: string;
|
||||
|
||||
@@ -17,9 +17,7 @@ export function useItem(collection: Ref<string>, primaryKey: Ref<string | number
|
||||
const softDeleting = ref(false);
|
||||
const edits = ref({});
|
||||
const isNew = computed(() => primaryKey.value === '+');
|
||||
const isBatch = computed(
|
||||
() => typeof primaryKey.value === 'string' && primaryKey.value.includes(',')
|
||||
);
|
||||
const isBatch = computed(() => typeof primaryKey.value === 'string' && primaryKey.value.includes(','));
|
||||
|
||||
const endpoint = computed(() => {
|
||||
const currentProjectKey = useProjectsStore().state.currentProjectKey;
|
||||
@@ -149,9 +147,7 @@ export function useItem(collection: Ref<string>, primaryKey: Ref<string | number
|
||||
title: i18n.t('item_create_success'),
|
||||
text: i18n.tc('item_in', isBatch.value ? 2 : 1, {
|
||||
collection: collection.value,
|
||||
primaryKey: isBatch.value
|
||||
? (primaryKey.value as string).split(',').join(', ')
|
||||
: primaryKey.value,
|
||||
primaryKey: isBatch.value ? (primaryKey.value as string).split(',').join(', ') : primaryKey.value,
|
||||
}),
|
||||
type: 'success',
|
||||
});
|
||||
@@ -162,9 +158,7 @@ export function useItem(collection: Ref<string>, primaryKey: Ref<string | number
|
||||
title: i18n.t('item_create_failed'),
|
||||
text: i18n.tc('item_in', isBatch.value ? 2 : 1, {
|
||||
collection: collection.value,
|
||||
primaryKey: isBatch.value
|
||||
? (primaryKey.value as string).split(',').join(', ')
|
||||
: primaryKey.value,
|
||||
primaryKey: isBatch.value ? (primaryKey.value as string).split(',').join(', ') : primaryKey.value,
|
||||
}),
|
||||
type: 'error',
|
||||
});
|
||||
@@ -201,9 +195,7 @@ export function useItem(collection: Ref<string>, primaryKey: Ref<string | number
|
||||
title: i18n.tc('item_delete_success', isBatch.value ? 2 : 1),
|
||||
text: i18n.tc('item_in', isBatch.value ? 2 : 1, {
|
||||
collection: collection.value,
|
||||
primaryKey: isBatch.value
|
||||
? (primaryKey.value as string).split(',').join(', ')
|
||||
: primaryKey.value,
|
||||
primaryKey: isBatch.value ? (primaryKey.value as string).split(',').join(', ') : primaryKey.value,
|
||||
}),
|
||||
type: 'success',
|
||||
});
|
||||
@@ -212,9 +204,7 @@ export function useItem(collection: Ref<string>, primaryKey: Ref<string | number
|
||||
title: i18n.tc('item_delete_failed', isBatch.value ? 2 : 1),
|
||||
text: i18n.tc('item_in', isBatch.value ? 2 : 1, {
|
||||
collection: collection.value,
|
||||
primaryKey: isBatch.value
|
||||
? (primaryKey.value as string).split(',').join(', ')
|
||||
: primaryKey.value,
|
||||
primaryKey: isBatch.value ? (primaryKey.value as string).split(',').join(', ') : primaryKey.value,
|
||||
}),
|
||||
type: 'error',
|
||||
});
|
||||
|
||||
@@ -240,8 +240,7 @@ export function useItems(collection: Ref<string>, query: Query) {
|
||||
if (!pk) return;
|
||||
|
||||
const move = newIndex > oldIndex ? 'down' : 'up';
|
||||
const selectionRange =
|
||||
move === 'down' ? [oldIndex + 1, newIndex + 1] : [newIndex, oldIndex];
|
||||
const selectionRange = move === 'down' ? [oldIndex + 1, newIndex + 1] : [newIndex, oldIndex];
|
||||
|
||||
const updates = items.value.slice(...selectionRange).map((toBeUpdatedItem: any) => {
|
||||
const sortValue = getPositionForItem(toBeUpdatedItem);
|
||||
|
||||
@@ -13,11 +13,7 @@ export async function useTimeFromNow(date: Date | number, autoUpdate = 60000) {
|
||||
if (autoUpdate !== 0) {
|
||||
onMounted(() => {
|
||||
interval = window.setInterval(async () => {
|
||||
formattedDate.value = await localizedFormatDistance(
|
||||
date,
|
||||
new Date(),
|
||||
formatOptions
|
||||
);
|
||||
formattedDate.value = await localizedFormatDistance(date, new Date(), formatOptions);
|
||||
}, autoUpdate);
|
||||
});
|
||||
|
||||
|
||||
@@ -116,9 +116,7 @@ export function onEvent({
|
||||
}) {
|
||||
event.stopPropagation();
|
||||
const path = event.composedPath();
|
||||
const isClickOutside = path
|
||||
? path.indexOf(el) < 0
|
||||
: el.contains(event.target as Element) === false;
|
||||
const isClickOutside = path ? path.indexOf(el) < 0 : el.contains(event.target as Element) === false;
|
||||
|
||||
if (isClickOutside === false) return;
|
||||
|
||||
|
||||
@@ -1,14 +1,7 @@
|
||||
import { createLocalVue } from '@vue/test-utils';
|
||||
import VueCompositionAPI from '@vue/composition-api';
|
||||
import VButton from '../../components/v-button';
|
||||
import Tooltip, {
|
||||
getTooltip,
|
||||
animateIn,
|
||||
animateOut,
|
||||
onLeaveTooltip,
|
||||
updateTooltip,
|
||||
onEnterTooltip,
|
||||
} from './tooltip';
|
||||
import Tooltip, { getTooltip, animateIn, animateOut, onLeaveTooltip, updateTooltip, onEnterTooltip } from './tooltip';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(VueCompositionAPI);
|
||||
@@ -157,9 +150,7 @@ describe('Tooltip', () => {
|
||||
inverted: false,
|
||||
});
|
||||
expect(tooltip.className).toBe('right');
|
||||
expect(tooltip.getAttribute('style')).toBe(
|
||||
'transform: translate(10px, calc(0px - 50%));'
|
||||
);
|
||||
expect(tooltip.getAttribute('style')).toBe('transform: translate(10px, calc(0px - 50%));');
|
||||
});
|
||||
|
||||
test('right start', () => {
|
||||
@@ -172,9 +163,7 @@ describe('Tooltip', () => {
|
||||
inverted: false,
|
||||
});
|
||||
expect(tooltip.className).toBe('start right');
|
||||
expect(tooltip.getAttribute('style')).toBe(
|
||||
'transform: translate(10px, calc(20px - 100%));'
|
||||
);
|
||||
expect(tooltip.getAttribute('style')).toBe('transform: translate(10px, calc(20px - 100%));');
|
||||
});
|
||||
|
||||
test('right end', () => {
|
||||
@@ -187,9 +176,7 @@ describe('Tooltip', () => {
|
||||
inverted: false,
|
||||
});
|
||||
expect(tooltip.className).toBe('end right');
|
||||
expect(tooltip.getAttribute('style')).toBe(
|
||||
'transform: translate(10px, calc(-20px - 0%));'
|
||||
);
|
||||
expect(tooltip.getAttribute('style')).toBe('transform: translate(10px, calc(-20px - 0%));');
|
||||
});
|
||||
|
||||
test('bottom', () => {
|
||||
@@ -202,9 +189,7 @@ describe('Tooltip', () => {
|
||||
inverted: false,
|
||||
});
|
||||
expect(tooltip.className).toBe('bottom');
|
||||
expect(tooltip.getAttribute('style')).toBe(
|
||||
'transform: translate(calc(0px - 50%), 10px);'
|
||||
);
|
||||
expect(tooltip.getAttribute('style')).toBe('transform: translate(calc(0px - 50%), 10px);');
|
||||
});
|
||||
|
||||
test('bottom start', () => {
|
||||
@@ -217,9 +202,7 @@ describe('Tooltip', () => {
|
||||
inverted: false,
|
||||
});
|
||||
expect(tooltip.className).toBe('start bottom');
|
||||
expect(tooltip.getAttribute('style')).toBe(
|
||||
'transform: translate(calc(20px - 100%), 10px);'
|
||||
);
|
||||
expect(tooltip.getAttribute('style')).toBe('transform: translate(calc(20px - 100%), 10px);');
|
||||
});
|
||||
|
||||
test('bottom end', () => {
|
||||
@@ -232,9 +215,7 @@ describe('Tooltip', () => {
|
||||
inverted: false,
|
||||
});
|
||||
expect(tooltip.className).toBe('end bottom');
|
||||
expect(tooltip.getAttribute('style')).toBe(
|
||||
'transform: translate(calc(-20px - 0%), 10px);'
|
||||
);
|
||||
expect(tooltip.getAttribute('style')).toBe('transform: translate(calc(-20px - 0%), 10px);');
|
||||
});
|
||||
|
||||
test('left', () => {
|
||||
|
||||
@@ -37,11 +37,7 @@ export function onLeaveTooltip() {
|
||||
};
|
||||
}
|
||||
|
||||
export function updateTooltip(
|
||||
element: HTMLElement,
|
||||
binding: DirectiveBinding,
|
||||
tooltip: HTMLElement
|
||||
) {
|
||||
export function updateTooltip(element: HTMLElement, binding: DirectiveBinding, tooltip: HTMLElement) {
|
||||
const offset = 10;
|
||||
const arrowAlign = 20;
|
||||
|
||||
|
||||
@@ -18,9 +18,7 @@ export const basic = () =>
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const value = computed<string | null>(() =>
|
||||
handler(props.val, null, { type: 'string' })
|
||||
);
|
||||
const value = computed<string | null>(() => handler(props.val, null, { type: 'string' }));
|
||||
return { value };
|
||||
},
|
||||
template: `
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
<template>
|
||||
<img
|
||||
v-if="src"
|
||||
:src="src"
|
||||
role="presentation"
|
||||
:alt="value && value.title"
|
||||
:class="{ circle }"
|
||||
/>
|
||||
<img v-if="src" :src="src" role="presentation" :alt="value && value.title" :class="{ circle }" />
|
||||
<span v-else>--</span>
|
||||
</template>
|
||||
|
||||
@@ -36,10 +30,7 @@ export default defineComponent({
|
||||
setup(props) {
|
||||
const src = computed(() => {
|
||||
if (props.value === null) return null;
|
||||
return (
|
||||
props.value?.data?.thumbnails?.find((thumb) => thumb.key === 'directus-small-crop')
|
||||
?.url || null
|
||||
);
|
||||
return props.value?.data?.thumbnails?.find((thumb) => thumb.key === 'directus-small-crop')?.url || null;
|
||||
});
|
||||
|
||||
return { src };
|
||||
|
||||
@@ -56,9 +56,7 @@ describe('Displays / Status Badge', () => {
|
||||
});
|
||||
|
||||
expect(component.exists()).toBe(true);
|
||||
expect(component.attributes('style')).toBe(
|
||||
'background-color: rgb(171, 202, 188); color: rgb(150, 100, 125);'
|
||||
);
|
||||
expect(component.attributes('style')).toBe('background-color: rgb(171, 202, 188); color: rgb(150, 100, 125);');
|
||||
});
|
||||
|
||||
it('Sets status to null if interface options are missing', () => {
|
||||
|
||||
@@ -30,10 +30,7 @@ export default defineDisplay(({ i18n }) => ({
|
||||
|
||||
if (!relatedCollection) return [];
|
||||
|
||||
const fields = adjustFieldsForDisplays(
|
||||
getFieldsFromTemplate(options.template),
|
||||
relatedCollection
|
||||
);
|
||||
const fields = adjustFieldsForDisplays(getFieldsFromTemplate(options.template), relatedCollection);
|
||||
|
||||
if (fields.includes(primaryKeyField.value.field) === false) {
|
||||
fields.push(primaryKeyField.value.field);
|
||||
|
||||
@@ -8,17 +8,9 @@
|
||||
</template>
|
||||
|
||||
<v-list dense>
|
||||
<v-list-item
|
||||
v-for="item in value"
|
||||
:key="item[primaryKeyField]"
|
||||
:to="getLinkForItem(item)"
|
||||
>
|
||||
<v-list-item v-for="item in value" :key="item[primaryKeyField]" :to="getLinkForItem(item)">
|
||||
<v-list-item-content>
|
||||
<render-template
|
||||
:template="template"
|
||||
:item="item"
|
||||
:collection="relatedCollection"
|
||||
/>
|
||||
<render-template :template="template" :item="item" :collection="relatedCollection" />
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
:alt="value && `${value.first_name} ${value.last_name}`"
|
||||
:class="{ circle }"
|
||||
/>
|
||||
<span v-if="display === 'name' || display === 'both'">
|
||||
{{ value.first_name }} {{ value.last_name }}
|
||||
</span>
|
||||
<span v-if="display === 'name' || display === 'both'">{{ value.first_name }} {{ value.last_name }}</span>
|
||||
</user-popover>
|
||||
</span>
|
||||
</template>
|
||||
@@ -58,9 +56,7 @@ export default defineComponent({
|
||||
const src = computed(() => {
|
||||
if (props.value === null) return null;
|
||||
return (
|
||||
props.value?.avatar?.data?.thumbnails?.find(
|
||||
(thumb) => thumb.key === 'directus-small-crop'
|
||||
)?.url || null
|
||||
props.value?.avatar?.data?.thumbnails?.find((thumb) => thumb.key === 'directus-small-crop')?.url || null
|
||||
);
|
||||
});
|
||||
|
||||
|
||||
@@ -57,9 +57,7 @@ export async function hydrate(stores = useStores()) {
|
||||
|
||||
setLanguage((userStore.state.currentUser?.locale as Language) || 'en-US');
|
||||
|
||||
await Promise.all(
|
||||
stores.filter(({ id }) => id !== 'userStore').map((store) => store.hydrate?.())
|
||||
);
|
||||
await Promise.all(stores.filter(({ id }) => id !== 'userStore').map((store) => store.hydrate?.()));
|
||||
} catch (error) {
|
||||
appStore.state.error = error;
|
||||
} finally {
|
||||
|
||||
@@ -121,11 +121,7 @@ export default defineComponent({
|
||||
return 'grid-1';
|
||||
});
|
||||
|
||||
const { otherValues, addOtherValue, setOtherValue } = useCustomSelectionMultiple(
|
||||
value,
|
||||
choices,
|
||||
emit
|
||||
);
|
||||
const { otherValues, addOtherValue, setOtherValue } = useCustomSelectionMultiple(value, choices, emit);
|
||||
|
||||
return { gridClass, otherValues, addOtherValue, setOtherValue };
|
||||
},
|
||||
|
||||
@@ -2,11 +2,7 @@
|
||||
<div class="interface-code codemirror-custom-styles">
|
||||
<textarea ref="codemirrorEl" :value="stringValue" />
|
||||
|
||||
<v-button
|
||||
v-if="template"
|
||||
v-tooltip="$t('interfaces.code.fill_template')"
|
||||
@click="fillTemplate"
|
||||
>
|
||||
<v-button v-if="template" v-tooltip="$t('interfaces.code.fill_template')" @click="fillTemplate">
|
||||
<v-icon name="playlist_add" />
|
||||
</v-button>
|
||||
|
||||
@@ -24,14 +20,7 @@
|
||||
<script lang="ts">
|
||||
import CodeMirror from 'codemirror';
|
||||
|
||||
import {
|
||||
defineComponent,
|
||||
computed,
|
||||
ref,
|
||||
onMounted,
|
||||
onUnmounted,
|
||||
watch,
|
||||
} from '@vue/composition-api';
|
||||
import { defineComponent, computed, ref, onMounted, onUnmounted, watch } from '@vue/composition-api';
|
||||
|
||||
import 'codemirror/mode/meta';
|
||||
import 'codemirror/addon/search/searchcursor.js';
|
||||
|
||||
@@ -11,21 +11,14 @@
|
||||
maxlength="7"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-input
|
||||
type="color"
|
||||
class="html-color-select"
|
||||
v-model="hexValue"
|
||||
ref="htmlColorInput"
|
||||
/>
|
||||
<v-input type="color" class="html-color-select" v-model="hexValue" ref="htmlColorInput" />
|
||||
<v-button
|
||||
@click="activateColorPicker"
|
||||
class="swatch"
|
||||
:icon="true"
|
||||
:style="{
|
||||
'--v-button-background-color': isValidColor ? hexValue : 'transparent',
|
||||
border: isValidColor
|
||||
? 'none'
|
||||
: 'var(--border-width) solid var(--border-normal)',
|
||||
border: isValidColor ? 'none' : 'var(--border-width) solid var(--border-normal)',
|
||||
}"
|
||||
>
|
||||
<v-icon v-if="!isValidColor" name="colorize" />
|
||||
@@ -161,9 +154,7 @@ export default defineComponent({
|
||||
(htmlColorInput.value?.$el as HTMLElement).getElementsByTagName('input')[0].click();
|
||||
}
|
||||
|
||||
const isValidColor = computed<boolean>(
|
||||
() => hexValue.value != null && color.isHex(hexValue.value as string)
|
||||
);
|
||||
const isValidColor = computed<boolean>(() => hexValue.value != null && color.isHex(hexValue.value as string));
|
||||
|
||||
const { rgb, hsl, hexValue } = useColor();
|
||||
|
||||
@@ -307,8 +298,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
/* stylelint-disable indentation */
|
||||
&:not(:last-child)::v-deep
|
||||
.input:not(.active):not(:focus-within):not(:hover):not(:active):not(:focus) {
|
||||
&:not(:last-child)::v-deep .input:not(.active):not(:focus-within):not(:hover):not(:active):not(:focus) {
|
||||
border-right-color: transparent;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,22 +23,13 @@
|
||||
<v-select :placeholder="$t('date')" :items="dates" v-model="localValue.date" />
|
||||
</div>
|
||||
<div class="year">
|
||||
<v-select
|
||||
:placeholder="$t('year')"
|
||||
:items="years"
|
||||
v-model="localValue.year"
|
||||
allow-other
|
||||
/>
|
||||
<v-select :placeholder="$t('year')" :items="years" v-model="localValue.year" allow-other />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<v-divider v-if="type === 'datetime'" />
|
||||
|
||||
<div
|
||||
class="time-selects"
|
||||
v-if="type === 'datetime' || type === 'time'"
|
||||
:class="{ seconds: includeSeconds }"
|
||||
>
|
||||
<div class="time-selects" v-if="type === 'datetime' || type === 'time'" :class="{ seconds: includeSeconds }">
|
||||
<div class="hour">
|
||||
<v-select :items="hours" v-model="localValue.hours" />
|
||||
</div>
|
||||
@@ -88,9 +79,7 @@ export default defineComponent({
|
||||
default: null,
|
||||
},
|
||||
type: {
|
||||
type: String as PropType<
|
||||
'datetime' | 'time' | 'date' | 'datetime_created' | 'datetime_updated'
|
||||
>,
|
||||
type: String as PropType<'datetime' | 'time' | 'date' | 'datetime_created' | 'datetime_updated'>,
|
||||
required: true,
|
||||
validator: (val: string) =>
|
||||
['datetime', 'date', 'time', 'datetime_created', 'datetime_updated'].includes(val),
|
||||
@@ -168,14 +157,7 @@ export default defineComponent({
|
||||
) {
|
||||
const { year, month, date, hours, minutes, seconds, period } = newValue;
|
||||
|
||||
const asDate = new Date(
|
||||
year,
|
||||
month,
|
||||
date,
|
||||
period === 'am' ? hours : hours + 12,
|
||||
minutes,
|
||||
seconds
|
||||
);
|
||||
const asDate = new Date(year, month, date, period === 'am' ? hours : hours + 12, minutes, seconds);
|
||||
|
||||
emit('input', format(asDate, formatString.value));
|
||||
}
|
||||
|
||||
@@ -20,11 +20,7 @@
|
||||
'is-svg': file && file.type.includes('svg'),
|
||||
}"
|
||||
>
|
||||
<img
|
||||
v-if="imageThumbnail"
|
||||
:src="imageThumbnail"
|
||||
:alt="file.title"
|
||||
/>
|
||||
<img v-if="imageThumbnail" :src="imageThumbnail" :alt="file.title" />
|
||||
<span class="extension" v-else-if="fileExtension">
|
||||
{{ fileExtension }}
|
||||
</span>
|
||||
@@ -32,12 +28,7 @@
|
||||
</div>
|
||||
</template>
|
||||
<template #append>
|
||||
<v-icon
|
||||
class="deselect"
|
||||
name="close"
|
||||
v-if="file"
|
||||
@click.stop="$emit('input', null)"
|
||||
/>
|
||||
<v-icon class="deselect" name="close" v-if="file" @click.stop="$emit('input', null)" />
|
||||
<v-icon v-else name="attach_file" />
|
||||
</template>
|
||||
</v-input>
|
||||
@@ -95,11 +86,7 @@
|
||||
@input="setSelection"
|
||||
/>
|
||||
|
||||
<v-dialog
|
||||
:active="activeDialog === 'url'"
|
||||
@toggle="activeDialog = null"
|
||||
:persistent="urlLoading"
|
||||
>
|
||||
<v-dialog :active="activeDialog === 'url'" @toggle="activeDialog = null" :persistent="urlLoading">
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('import_from_url') }}</v-card-title>
|
||||
<v-card-text>
|
||||
@@ -109,11 +96,7 @@
|
||||
<v-button :disabled="urlLoading" @click="activeDialog = null" secondary>
|
||||
{{ $t('cancel') }}
|
||||
</v-button>
|
||||
<v-button
|
||||
:loading="urlLoading"
|
||||
@click="importFromURL"
|
||||
:disabled="isValidURL === false"
|
||||
>
|
||||
<v-button :loading="urlLoading" @click="importFromURL" :disabled="isValidURL === false">
|
||||
{{ $t('import') }}
|
||||
</v-button>
|
||||
</v-card-actions>
|
||||
@@ -169,17 +152,10 @@ export default defineComponent({
|
||||
if (file.value === null) return null;
|
||||
if (file.value.type.includes('svg')) return file.value.data.asset_url;
|
||||
if (file.value.type.includes('image') === false) return null;
|
||||
return file.value.data.thumbnails?.find((thumb) => thumb.key === 'directus-small-crop')
|
||||
?.url;
|
||||
return file.value.data.thumbnails?.find((thumb) => thumb.key === 'directus-small-crop')?.url;
|
||||
});
|
||||
|
||||
const {
|
||||
url,
|
||||
isValidURL,
|
||||
loading: urlLoading,
|
||||
error: urlError,
|
||||
importFromURL,
|
||||
} = useURLImport();
|
||||
const { url, isValidURL, loading: urlLoading, error: urlError, importFromURL } = useURLImport();
|
||||
|
||||
return {
|
||||
activeDialog,
|
||||
|
||||
@@ -8,21 +8,11 @@
|
||||
@focus="activate"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-icon
|
||||
v-if="value"
|
||||
@click="activate"
|
||||
:name="value"
|
||||
:class="{ active: value }"
|
||||
/>
|
||||
<v-icon v-if="value" @click="activate" :name="value" :class="{ active: value }" />
|
||||
</template>
|
||||
|
||||
<template #append>
|
||||
<v-icon
|
||||
@click="activate"
|
||||
name="expand_more"
|
||||
class="open-indicator"
|
||||
:class="{ open: active }"
|
||||
/>
|
||||
<v-icon @click="activate" name="expand_more" class="open-indicator" :class="{ open: active }" />
|
||||
</template>
|
||||
</v-input>
|
||||
</template>
|
||||
@@ -74,9 +64,7 @@ export default defineComponent({
|
||||
return icons.map((group) => {
|
||||
if (searchQuery.value.length === 0) return group;
|
||||
|
||||
const icons = group.icons.filter((icon) =>
|
||||
icon.includes(searchQuery.value.toLowerCase())
|
||||
);
|
||||
const icons = group.icons.filter((icon) => icon.includes(searchQuery.value.toLowerCase()));
|
||||
|
||||
return {
|
||||
...group,
|
||||
|
||||
@@ -6,11 +6,7 @@
|
||||
{{ $t('disabled') }}
|
||||
</v-notice>
|
||||
|
||||
<div
|
||||
class="image-preview"
|
||||
v-else-if="image"
|
||||
:class="{ 'is-svg': image.type.includes('svg') }"
|
||||
>
|
||||
<div class="image-preview" v-else-if="image" :class="{ 'is-svg': image.type.includes('svg') }">
|
||||
<img :src="src" alt="" role="presentation" />
|
||||
|
||||
<div class="shadow" />
|
||||
@@ -108,9 +104,7 @@ export default defineComponent({
|
||||
return image.value.data.full_url;
|
||||
}
|
||||
|
||||
const url = image.value.data.thumbnails.find(
|
||||
(thumb) => thumb.key === 'directus-large-crop'
|
||||
)?.url;
|
||||
const url = image.value.data.thumbnails.find((thumb) => thumb.key === 'directus-large-crop')?.url;
|
||||
|
||||
if (url) {
|
||||
return `${url}&cache-buster=${cacheBuster.value}`;
|
||||
@@ -162,16 +156,7 @@ export default defineComponent({
|
||||
try {
|
||||
const response = await api.get(`/${currentProjectKey}/files/${props.value}`, {
|
||||
params: {
|
||||
fields: [
|
||||
'id',
|
||||
'data',
|
||||
'title',
|
||||
'width',
|
||||
'height',
|
||||
'filesize',
|
||||
'type',
|
||||
'filename_download',
|
||||
],
|
||||
fields: ['id', 'data', 'title', 'width', 'height', 'filesize', 'type', 'filename_download'],
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
@@ -71,11 +71,7 @@
|
||||
@click="setCurrent(item)"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<render-template
|
||||
:collection="collection"
|
||||
:template="displayTemplate"
|
||||
:item="item"
|
||||
/>
|
||||
<render-template :collection="collection" :template="displayTemplate" :item="item" />
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
@@ -162,12 +158,7 @@ export default defineComponent({
|
||||
const { displayTemplate, onPreviewClick, requiredFields } = usePreview();
|
||||
const { totalCount, loading: itemsLoading, fetchItems, items } = useItems();
|
||||
|
||||
const {
|
||||
setCurrent,
|
||||
currentItem,
|
||||
loading: loadingCurrent,
|
||||
currentPrimaryKey,
|
||||
} = useCurrent();
|
||||
const { setCurrent, currentItem, loading: loadingCurrent, currentPrimaryKey } = useCurrent();
|
||||
|
||||
const { edits, stageEdits } = useEdits();
|
||||
|
||||
@@ -232,10 +223,7 @@ export default defineComponent({
|
||||
return props.value;
|
||||
}
|
||||
|
||||
if (
|
||||
typeof props.value === 'object' &&
|
||||
props.value.hasOwnProperty(relatedPrimaryKeyField.value.field)
|
||||
) {
|
||||
if (typeof props.value === 'object' && props.value.hasOwnProperty(relatedPrimaryKeyField.value.field)) {
|
||||
return props.value[relatedPrimaryKeyField.value.field];
|
||||
}
|
||||
|
||||
@@ -261,9 +249,7 @@ export default defineComponent({
|
||||
|
||||
try {
|
||||
const endpoint = relatedCollection.value.collection.startsWith('directus_')
|
||||
? `/${currentProjectKey}/${relatedCollection.value.collection.substring(
|
||||
9
|
||||
)}/${props.value}`
|
||||
? `/${currentProjectKey}/${relatedCollection.value.collection.substring(9)}/${props.value}`
|
||||
: `/${currentProjectKey}/items/${relatedCollection.value.collection}/${props.value}`;
|
||||
|
||||
const response = await api.get(endpoint, {
|
||||
@@ -356,9 +342,7 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
const { collection } = toRefs(relatedCollection.value);
|
||||
const { primaryKeyField: relatedPrimaryKeyField } = useCollection(
|
||||
collection as Ref<string>
|
||||
);
|
||||
const { primaryKeyField: relatedPrimaryKeyField } = useCollection(collection as Ref<string>);
|
||||
|
||||
return { relation, relatedCollection, relatedPrimaryKeyField };
|
||||
}
|
||||
@@ -409,10 +393,7 @@ export default defineComponent({
|
||||
const selection = computed<(number | string)[]>(() => {
|
||||
if (!props.value) return [];
|
||||
|
||||
if (
|
||||
typeof props.value === 'object' &&
|
||||
props.value.hasOwnProperty(relatedPrimaryKeyField.value.field)
|
||||
) {
|
||||
if (typeof props.value === 'object' && props.value.hasOwnProperty(relatedPrimaryKeyField.value.field)) {
|
||||
return [props.value[relatedPrimaryKeyField.value.field]];
|
||||
}
|
||||
|
||||
|
||||
@@ -27,12 +27,7 @@
|
||||
</template>
|
||||
|
||||
<template #item-append="{ item }" v-if="!disabled">
|
||||
<v-icon
|
||||
name="close"
|
||||
v-tooltip="$t('deselect')"
|
||||
class="deselect"
|
||||
@click.stop="deselect(item)"
|
||||
/>
|
||||
<v-icon name="close" v-tooltip="$t('deselect')" class="deselect" @click.stop="deselect(item)" />
|
||||
</template>
|
||||
</v-table>
|
||||
|
||||
@@ -151,9 +146,7 @@ export default defineComponent({
|
||||
|
||||
const { collection } = toRefs(relatedCollection.value);
|
||||
|
||||
const { primaryKeyField: relatedPrimaryKeyField } = useCollection(
|
||||
collection as Ref<string>
|
||||
);
|
||||
const { primaryKeyField: relatedPrimaryKeyField } = useCollection(collection as Ref<string>);
|
||||
|
||||
return { relation, relatedCollection, relatedPrimaryKeyField };
|
||||
}
|
||||
@@ -248,9 +241,7 @@ export default defineComponent({
|
||||
|
||||
const updatedItems = items.value
|
||||
.map((item: any) => {
|
||||
const changeForThisItem = changes.find(
|
||||
(change) => change[pkField] === item[pkField]
|
||||
);
|
||||
const changeForThisItem = changes.find((change) => change[pkField] === item[pkField]);
|
||||
|
||||
if (changeForThisItem) {
|
||||
return {
|
||||
@@ -274,9 +265,7 @@ export default defineComponent({
|
||||
const selectedPrimaryKeys = changes
|
||||
.filter((change) => typeof change === 'string' || typeof change === 'number')
|
||||
.filter((primaryKey) => {
|
||||
const isAlsoUpdate = updatedItems.some(
|
||||
(update) => update[pkField] === primaryKey
|
||||
);
|
||||
const isAlsoUpdate = updatedItems.some((update) => update[pkField] === primaryKey);
|
||||
|
||||
return isAlsoUpdate === false;
|
||||
});
|
||||
@@ -291,9 +280,9 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
const response = await api.get(
|
||||
`/${currentProjectKey}/items/${
|
||||
relatedCollection.value.collection
|
||||
}/${selectedPrimaryKeys.join(',')}`,
|
||||
`/${currentProjectKey}/items/${relatedCollection.value.collection}/${selectedPrimaryKeys.join(
|
||||
','
|
||||
)}`,
|
||||
{
|
||||
params: {
|
||||
fields: fields,
|
||||
@@ -326,10 +315,7 @@ export default defineComponent({
|
||||
tableHeaders.value = props.fields
|
||||
.split(',')
|
||||
.map((fieldKey) => {
|
||||
const field = fieldsStore.getField(
|
||||
relatedCollection.value.collection,
|
||||
fieldKey
|
||||
);
|
||||
const field = fieldsStore.getField(relatedCollection.value.collection, fieldKey);
|
||||
|
||||
if (!field) return null;
|
||||
|
||||
@@ -388,10 +374,7 @@ export default defineComponent({
|
||||
|
||||
// Make sure the edits have the primary key included, otherwise the api will create
|
||||
// the item as a new one instead of update the existing
|
||||
if (
|
||||
primaryKey &&
|
||||
editsAtStart.value.hasOwnProperty(relatedPrimaryKeyField.value.field) === false
|
||||
) {
|
||||
if (primaryKey && editsAtStart.value.hasOwnProperty(relatedPrimaryKeyField.value.field) === false) {
|
||||
editsAtStart.value = {
|
||||
...editsAtStart.value,
|
||||
[relatedPrimaryKeyField.value.field]: primaryKey,
|
||||
@@ -408,11 +391,7 @@ export default defineComponent({
|
||||
|
||||
if (props.value && Array.isArray(props.value)) {
|
||||
const newValue = props.value.map((existingChange) => {
|
||||
if (
|
||||
existingChange[pkField] &&
|
||||
edits[pkField] &&
|
||||
existingChange[pkField] === edits[pkField]
|
||||
) {
|
||||
if (existingChange[pkField] && edits[pkField] && existingChange[pkField] === edits[pkField]) {
|
||||
return edits;
|
||||
}
|
||||
|
||||
@@ -504,9 +483,7 @@ export default defineComponent({
|
||||
// If the item is selected in the current edits, it will only have staged the primary
|
||||
// key so the API is able to properly set it on first creation. In that case, we have
|
||||
// to filter out the primary key
|
||||
const itemWasNewlySelect = !!props.value.find(
|
||||
(stagedItem) => stagedItem === itemPrimaryKey
|
||||
);
|
||||
const itemWasNewlySelect = !!props.value.find((stagedItem) => stagedItem === itemPrimaryKey);
|
||||
|
||||
if (itemWasNewlySelect) {
|
||||
currentItems.value = currentItems.value.filter(
|
||||
@@ -520,8 +497,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
const itemHasEdits =
|
||||
props.value.find((stagedItem: any) => stagedItem[pkField] === itemPrimaryKey) !==
|
||||
undefined;
|
||||
props.value.find((stagedItem: any) => stagedItem[pkField] === itemPrimaryKey) !== undefined;
|
||||
|
||||
if (itemHasEdits) {
|
||||
return emit(
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
<template>
|
||||
<div class="form">
|
||||
<v-divider />
|
||||
<v-form
|
||||
:disabled="disabled"
|
||||
:fields="fields"
|
||||
:edits="value"
|
||||
primary-key="+"
|
||||
@input="$emit('input', $event)"
|
||||
/>
|
||||
<v-form :disabled="disabled" :fields="fields" :edits="value" primary-key="+" @input="$emit('input', $event)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
||||
@@ -3,12 +3,7 @@
|
||||
<v-icon v-if="disabled === false" name="drag_handle" class="drag-handle" />
|
||||
{{ displayValue ? displayValue : placeholder }}
|
||||
<span class="spacer" />
|
||||
<v-icon
|
||||
v-if="disabled === false"
|
||||
name="close"
|
||||
class="delete"
|
||||
@click.stop.prevent="$emit('delete')"
|
||||
/>
|
||||
<v-icon v-if="disabled === false" name="close" class="delete" @click.stop.prevent="$emit('delete')" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -45,9 +40,7 @@ export default defineComponent({
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const displayValue = computed(() =>
|
||||
props.value ? render(props.template, props.value) : null
|
||||
);
|
||||
const displayValue = computed(() => (props.value ? render(props.template, props.value) : null));
|
||||
|
||||
return { displayValue };
|
||||
},
|
||||
|
||||
@@ -32,11 +32,7 @@ export const basic = () =>
|
||||
default: boolean('Allow Custom Values', true, 'Options'),
|
||||
},
|
||||
placeholder: {
|
||||
default: text(
|
||||
'Placeholder',
|
||||
'Click tags below, or add a new one here...',
|
||||
'Options'
|
||||
),
|
||||
default: text('Placeholder', 'Click tags below, or add a new one here...', 'Options'),
|
||||
},
|
||||
lowercase: {
|
||||
default: boolean('Lowercase', false, 'Options'),
|
||||
@@ -98,11 +94,7 @@ export const withPresets = () =>
|
||||
default: boolean('Allow Custom Values', true, 'Options'),
|
||||
},
|
||||
placeholder: {
|
||||
default: text(
|
||||
'Placeholder',
|
||||
'Click tags below, or add a new one here...',
|
||||
'Options'
|
||||
),
|
||||
default: text('Placeholder', 'Click tags below, or add a new one here...', 'Options'),
|
||||
},
|
||||
lowercase: {
|
||||
default: boolean('Lowercase', false, 'Options'),
|
||||
|
||||
@@ -12,11 +12,7 @@
|
||||
#default="{ active, toggle }"
|
||||
>
|
||||
<div class="header" @click="toggle">
|
||||
<render-template
|
||||
:template="template"
|
||||
:collection="languagesCollection"
|
||||
:item="item"
|
||||
/>
|
||||
<render-template :template="template" :collection="languagesCollection" :item="item" />
|
||||
</div>
|
||||
<transition-expand>
|
||||
<div v-if="active">
|
||||
@@ -27,9 +23,7 @@
|
||||
:collection="relatedCollection.collection"
|
||||
:primary-key="existing[index][relatedPrimaryKeyField.field] || '+'"
|
||||
:edits="edits[index]"
|
||||
@input="
|
||||
emitValue($event, existing[index][relatedPrimaryKeyField.field])
|
||||
"
|
||||
@input="emitValue($event, existing[index][relatedPrimaryKeyField.field])"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
@@ -124,9 +118,7 @@ export default defineComponent({
|
||||
|
||||
const { collection } = toRefs(relatedCollection.value);
|
||||
|
||||
const { primaryKeyField: relatedPrimaryKeyField } = useCollection(
|
||||
collection as Ref<string>
|
||||
);
|
||||
const { primaryKeyField: relatedPrimaryKeyField } = useCollection(collection as Ref<string>);
|
||||
|
||||
return { relation, relatedCollection, relatedPrimaryKeyField };
|
||||
}
|
||||
@@ -155,15 +147,12 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
try {
|
||||
const response = await api.get(
|
||||
`/${currentProjectKey}/items/${props.languagesCollection}`,
|
||||
{
|
||||
params: {
|
||||
fields: fields,
|
||||
limit: -1,
|
||||
},
|
||||
}
|
||||
);
|
||||
const response = await api.get(`/${currentProjectKey}/items/${props.languagesCollection}`, {
|
||||
params: {
|
||||
fields: fields,
|
||||
limit: -1,
|
||||
},
|
||||
});
|
||||
|
||||
languages.value = response.data.data;
|
||||
} catch (err) {
|
||||
@@ -220,9 +209,7 @@ export default defineComponent({
|
||||
return languages.value.map((language: any) => {
|
||||
const existing =
|
||||
items.value.find(
|
||||
(item) =>
|
||||
item[props.languageField] ===
|
||||
language[languagesPrimaryKeyField.value.field]
|
||||
(item) => item[props.languageField] === language[languagesPrimaryKeyField.value.field]
|
||||
) || {};
|
||||
|
||||
return existing;
|
||||
@@ -235,9 +222,7 @@ export default defineComponent({
|
||||
return languages.value.map((language: any) => {
|
||||
const edits =
|
||||
(props.value || []).find(
|
||||
(edit) =>
|
||||
edit[props.languageField] ===
|
||||
language[languagesPrimaryKeyField.value.field]
|
||||
(edit) => edit[props.languageField] === language[languagesPrimaryKeyField.value.field]
|
||||
) || {};
|
||||
|
||||
edits[props.languageField] = language[languagesPrimaryKeyField.value.field];
|
||||
@@ -258,11 +243,7 @@ export default defineComponent({
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
currentEdits.some(
|
||||
(edit) => edit[props.languageField] === newEdit[props.languageField]
|
||||
)
|
||||
) {
|
||||
if (currentEdits.some((edit) => edit[props.languageField] === newEdit[props.languageField])) {
|
||||
emit(
|
||||
'input',
|
||||
currentEdits.map((edit) => {
|
||||
|
||||
@@ -65,11 +65,7 @@
|
||||
@click="setCurrent(item)"
|
||||
>
|
||||
<v-list-item-content>
|
||||
<render-template
|
||||
collection="directus_users"
|
||||
:template="displayTemplate"
|
||||
:item="item"
|
||||
/>
|
||||
<render-template collection="directus_users" :template="displayTemplate" :item="item" />
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</template>
|
||||
@@ -132,12 +128,7 @@ export default defineComponent({
|
||||
const { displayTemplate, onPreviewClick, requiredFields } = usePreview();
|
||||
const { totalCount, loading: usersLoading, fetchUsers, users } = useUsers();
|
||||
|
||||
const {
|
||||
setCurrent,
|
||||
currentUser,
|
||||
loading: loadingCurrent,
|
||||
currentPrimaryKey,
|
||||
} = useCurrent();
|
||||
const { setCurrent, currentUser, loading: loadingCurrent, currentPrimaryKey } = useCurrent();
|
||||
|
||||
const { edits, stageEdits } = useEdits();
|
||||
|
||||
@@ -174,11 +165,7 @@ export default defineComponent({
|
||||
(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 === 'number'
|
||||
) {
|
||||
if (newValue !== null && newValue !== currentUser.value?.id && typeof newValue === 'number') {
|
||||
fetchCurrent();
|
||||
}
|
||||
|
||||
|
||||
@@ -88,9 +88,7 @@ export async function setLanguage(lang: Language): Promise<boolean> {
|
||||
const dateTimeFormats = await import(`@/lang/${lang}/date-format.json`);
|
||||
i18n.setDateTimeFormat(lang, dateTimeFormats);
|
||||
} catch {
|
||||
console.log(
|
||||
`[setCurrentLanguage] ❌ Couldn't fetch date time formats for language "${lang}"`
|
||||
);
|
||||
console.log(`[setCurrentLanguage] ❌ Couldn't fetch date time formats for language "${lang}"`);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,13 +3,7 @@
|
||||
<portal to="layout-options">
|
||||
<div class="layout-option">
|
||||
<div class="option-label">{{ $t('layouts.cards.image_source') }}</div>
|
||||
<v-select
|
||||
v-model="imageSource"
|
||||
allow-null
|
||||
item-value="field"
|
||||
item-text="name"
|
||||
:items="fileFields"
|
||||
/>
|
||||
<v-select v-model="imageSource" allow-null item-value="field" item-text="name" :items="fileFields" />
|
||||
</div>
|
||||
|
||||
<div class="layout-option">
|
||||
@@ -61,12 +55,7 @@
|
||||
</portal>
|
||||
|
||||
<template v-if="loading || itemCount > 0">
|
||||
<cards-header
|
||||
:fields="availableFields"
|
||||
:size.sync="size"
|
||||
:selection.sync="_selection"
|
||||
:sort.sync="sort"
|
||||
/>
|
||||
<cards-header :fields="availableFields" :size.sync="size" :selection.sync="_selection" :sort.sync="sort" />
|
||||
|
||||
<div class="grid" :class="{ 'single-row': isSingleRow }">
|
||||
<template v-if="loading">
|
||||
@@ -91,11 +80,7 @@
|
||||
<render-template :collection="collection" :item="item" :template="title" />
|
||||
</template>
|
||||
<template #subtitle v-if="subtitle">
|
||||
<render-template
|
||||
:collection="collection"
|
||||
:item="item"
|
||||
:template="subtitle"
|
||||
/>
|
||||
<render-template :collection="collection" :item="item" :template="subtitle" />
|
||||
</template>
|
||||
</card>
|
||||
</div>
|
||||
@@ -114,22 +99,12 @@
|
||||
|
||||
<div v-if="loading === false && items.length >= 25" class="per-page">
|
||||
<span>{{ $t('per_page') }}</span>
|
||||
<v-select
|
||||
@input="limit = +$event"
|
||||
:value="`${limit}`"
|
||||
:items="['25', '50', '100', '250']"
|
||||
inline
|
||||
/>
|
||||
<v-select @input="limit = +$event" :value="`${limit}`" :items="['25', '50', '100', '250']" inline />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<v-info
|
||||
v-else-if="itemCount === 0 && activeFilterCount > 0"
|
||||
:title="$t('no_results')"
|
||||
icon="search"
|
||||
center
|
||||
>
|
||||
<v-info v-else-if="itemCount === 0 && activeFilterCount > 0" :title="$t('no_results')" icon="search" center>
|
||||
{{ $t('no_results_copy') }}
|
||||
|
||||
<template #append>
|
||||
@@ -277,8 +252,7 @@ export default defineComponent({
|
||||
const { width } = useElementSize(layoutElement);
|
||||
|
||||
const isSingleRow = computed(() => {
|
||||
const cardsWidth =
|
||||
items.value.length * (size.value * 40) + (items.value.length - 1) * 24;
|
||||
const cardsWidth = items.value.length * (size.value * 40) + (items.value.length - 1) * 24;
|
||||
return cardsWidth <= width.value;
|
||||
});
|
||||
|
||||
@@ -342,10 +316,7 @@ export default defineComponent({
|
||||
const icon = createViewOption('icon', 'box');
|
||||
const title = createViewOption<string>('title', null);
|
||||
const subtitle = createViewOption<string>('subtitle', null);
|
||||
const imageSource = createViewOption<string>(
|
||||
'imageSource',
|
||||
fileFields.value[0]?.field ?? null
|
||||
);
|
||||
const imageSource = createViewOption<string>('imageSource', fileFields.value[0]?.field ?? null);
|
||||
const imageFit = createViewOption<string>('imageFit', 'crop');
|
||||
|
||||
return { size, icon, imageSource, title, subtitle, imageFit };
|
||||
@@ -353,9 +324,7 @@ export default defineComponent({
|
||||
function createViewOption<T>(key: keyof ViewOptions, defaultValue: any) {
|
||||
return computed<T>({
|
||||
get() {
|
||||
return _viewOptions.value?.[key] !== undefined
|
||||
? _viewOptions.value?.[key]
|
||||
: defaultValue;
|
||||
return _viewOptions.value?.[key] !== undefined ? _viewOptions.value?.[key] : defaultValue;
|
||||
},
|
||||
set(newValue: T) {
|
||||
_viewOptions.value = {
|
||||
@@ -399,10 +368,7 @@ export default defineComponent({
|
||||
titleSubtitleFields.push(...getFieldsFromTemplate(subtitle.value));
|
||||
}
|
||||
|
||||
return [
|
||||
...fields,
|
||||
...adjustFieldsForDisplays(titleSubtitleFields, props.collection),
|
||||
];
|
||||
return [...fields, ...adjustFieldsForDisplays(titleSubtitleFields, props.collection)];
|
||||
});
|
||||
|
||||
return { sort, limit, page, fields };
|
||||
|
||||
@@ -16,13 +16,7 @@
|
||||
alt=""
|
||||
role="presentation"
|
||||
/>
|
||||
<img
|
||||
class="svg"
|
||||
v-else-if="svgSource"
|
||||
:src="svgSource"
|
||||
alt=""
|
||||
role="presentation"
|
||||
/>
|
||||
<img class="svg" v-else-if="svgSource" :src="svgSource" alt="" role="presentation" />
|
||||
<v-icon v-else large :name="icon" />
|
||||
</template>
|
||||
</template>
|
||||
@@ -130,9 +124,7 @@ export default defineComponent({
|
||||
const selectionIcon = computed(() => {
|
||||
if (!props.item) return 'radio_button_unchecked';
|
||||
|
||||
return props.value.includes(props.item[props.itemKey])
|
||||
? 'check_circle'
|
||||
: 'radio_button_unchecked';
|
||||
return props.value.includes(props.item[props.itemKey]) ? 'check_circle' : 'radio_button_unchecked';
|
||||
});
|
||||
|
||||
return { imageSource, svgSource, type, selectionIcon, toggleSelection, handleClick };
|
||||
|
||||
@@ -75,17 +75,13 @@ export default defineComponent({
|
||||
const _selection = useSync(props, 'selection', emit);
|
||||
const descending = computed(() => props.sort.startsWith('-'));
|
||||
|
||||
const sortKey = computed(() =>
|
||||
props.sort.startsWith('-') ? props.sort.substring(1) : props.sort
|
||||
);
|
||||
const sortKey = computed(() => (props.sort.startsWith('-') ? props.sort.substring(1) : props.sort));
|
||||
|
||||
const sortField = computed(() => {
|
||||
return props.fields.find((field) => field.field === sortKey.value);
|
||||
});
|
||||
|
||||
const fieldsWithoutFake = computed(() =>
|
||||
props.fields.filter((field) => field.field.startsWith('$') === false)
|
||||
);
|
||||
const fieldsWithoutFake = computed(() => props.fields.filter((field) => field.field.startsWith('$') === false));
|
||||
|
||||
return {
|
||||
toggleSize,
|
||||
|
||||
@@ -40,9 +40,7 @@
|
||||
</draggable>
|
||||
|
||||
<v-checkbox
|
||||
v-for="field in availableFields.filter(
|
||||
(field) => fields.includes(field.field) === false
|
||||
)"
|
||||
v-for="field in availableFields.filter((field) => fields.includes(field.field) === false)"
|
||||
v-model="fields"
|
||||
:key="field.field"
|
||||
:value="field.field"
|
||||
@@ -125,12 +123,7 @@
|
||||
</template>
|
||||
</v-table>
|
||||
|
||||
<v-info
|
||||
v-else-if="itemCount === 0 && activeFilterCount > 0"
|
||||
:title="$t('no_results')"
|
||||
icon="search"
|
||||
center
|
||||
>
|
||||
<v-info v-else-if="itemCount === 0 && activeFilterCount > 0" :title="$t('no_results')" icon="search" center>
|
||||
{{ $t('no_results_copy') }}
|
||||
|
||||
<template #append>
|
||||
@@ -150,15 +143,7 @@
|
||||
|
||||
<script lang="ts">
|
||||
import Vue from 'vue';
|
||||
import {
|
||||
defineComponent,
|
||||
PropType,
|
||||
ref,
|
||||
computed,
|
||||
inject,
|
||||
toRefs,
|
||||
Ref,
|
||||
} from '@vue/composition-api';
|
||||
import { defineComponent, PropType, ref, computed, inject, toRefs, Ref } from '@vue/composition-api';
|
||||
import useProjectsStore from '@/stores/projects';
|
||||
import { HeaderRaw, Item } from '@/components/v-table/types';
|
||||
import { Field } from '@/stores/fields/types';
|
||||
@@ -240,9 +225,7 @@ export default defineComponent({
|
||||
const _searchQuery = useSync(props, 'searchQuery', emit);
|
||||
|
||||
const { collection, searchQuery } = toRefs(props);
|
||||
const { info, primaryKeyField, fields: fieldsInCollection, sortField } = useCollection(
|
||||
collection
|
||||
);
|
||||
const { info, primaryKeyField, fields: fieldsInCollection, sortField } = useCollection(collection);
|
||||
|
||||
const availableFields = computed(() =>
|
||||
fieldsInCollection.value.filter(({ hidden_browse }) => hidden_browse === false)
|
||||
@@ -250,15 +233,7 @@ export default defineComponent({
|
||||
|
||||
const { sort, limit, page, fields, fieldsWithRelational } = useItemOptions();
|
||||
|
||||
const {
|
||||
items,
|
||||
loading,
|
||||
error,
|
||||
totalPages,
|
||||
itemCount,
|
||||
changeManualSort,
|
||||
getItems,
|
||||
} = useItems(collection, {
|
||||
const { items, loading, error, totalPages, itemCount, changeManualSort, getItems } = useItems(collection, {
|
||||
sort,
|
||||
limit,
|
||||
page,
|
||||
@@ -393,8 +368,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
const fields =
|
||||
_viewQuery.value?.fields ||
|
||||
availableFields.value.slice(0, 4).map(({ field }) => field);
|
||||
_viewQuery.value?.fields || availableFields.value.slice(0, 4).map(({ field }) => field);
|
||||
|
||||
return fields;
|
||||
},
|
||||
@@ -406,9 +380,7 @@ export default defineComponent({
|
||||
},
|
||||
});
|
||||
|
||||
const fieldsWithRelational = computed(() =>
|
||||
adjustFieldsForDisplays(fields.value, props.collection)
|
||||
);
|
||||
const fieldsWithRelational = computed(() => adjustFieldsForDisplays(fields.value, props.collection));
|
||||
|
||||
return { sort, limit, page, fields, fieldsWithRelational };
|
||||
}
|
||||
@@ -447,10 +419,7 @@ export default defineComponent({
|
||||
return activeFields.value.map((field) => ({
|
||||
text: field.name,
|
||||
value: field.field,
|
||||
width:
|
||||
localWidths.value[field.field] ||
|
||||
_viewOptions.value?.widths?.[field.field] ||
|
||||
null,
|
||||
width: localWidths.value[field.field] || _viewOptions.value?.widths?.[field.field] || null,
|
||||
field: {
|
||||
display: field.display,
|
||||
displayOptions: field.display_options,
|
||||
@@ -517,8 +486,7 @@ export default defineComponent({
|
||||
if (props.selectMode || _selection.value?.length > 0) {
|
||||
(table.value as any).onItemSelected({
|
||||
item,
|
||||
value:
|
||||
_selection.value?.includes(item[primaryKeyField.value.field]) === false,
|
||||
value: _selection.value?.includes(item[primaryKeyField.value.field]) === false,
|
||||
});
|
||||
} else {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
|
||||
@@ -25,10 +25,7 @@
|
||||
</drawer-detail>
|
||||
<portal-target name="drawer" />
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
|
||||
@@ -14,22 +14,14 @@
|
||||
<activity-navigation />
|
||||
</template>
|
||||
|
||||
<v-form
|
||||
collection="directus_activity"
|
||||
:loading="loading"
|
||||
:initial-values="item"
|
||||
:primary-key="primaryKey"
|
||||
/>
|
||||
<v-form collection="directus_activity" :loading="loading" :initial-values="item" :primary-key="primaryKey" />
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_activity_detail'))" />
|
||||
</drawer-detail>
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
|
||||
@@ -3,12 +3,7 @@
|
||||
<template v-if="customNavItems && customNavItems.length > 0">
|
||||
<div :key="group.name" v-for="(group, index) in customNavItems">
|
||||
<div class="group-name">{{ group.name }}</div>
|
||||
<v-list-item
|
||||
:exact="exact"
|
||||
v-for="navItem in group.items"
|
||||
:key="navItem.to"
|
||||
:to="navItem.to"
|
||||
>
|
||||
<v-list-item :exact="exact" v-for="navItem in group.items" :key="navItem.to" :to="navItem.to">
|
||||
<v-list-item-icon><v-icon :name="navItem.icon" /></v-list-item-icon>
|
||||
<v-list-item-content>{{ navItem.name }}</v-list-item-content>
|
||||
</v-list-item>
|
||||
@@ -16,13 +11,7 @@
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<v-list-item
|
||||
v-else
|
||||
:exact="exact"
|
||||
v-for="navItem in navItems"
|
||||
:key="navItem.to"
|
||||
:to="navItem.to"
|
||||
>
|
||||
<v-list-item v-else :exact="exact" v-for="navItem in navItems" :key="navItem.to" :to="navItem.to">
|
||||
<v-list-item-icon><v-icon :name="navItem.icon" /></v-list-item-icon>
|
||||
<v-list-item-content>{{ navItem.name }}</v-list-item-content>
|
||||
</v-list-item>
|
||||
@@ -61,9 +50,7 @@ export default defineComponent({
|
||||
|
||||
return collectionPresetsStore.state.collectionPresets
|
||||
.filter((preset) => {
|
||||
return (
|
||||
preset.title !== null && preset.collection.startsWith('directus_') === false
|
||||
);
|
||||
return preset.title !== null && preset.collection.startsWith('directus_') === false;
|
||||
})
|
||||
.map((preset) => {
|
||||
return {
|
||||
|
||||
@@ -308,9 +308,7 @@ export default defineComponent({
|
||||
const batchPrimaryKeys = selection.value;
|
||||
|
||||
try {
|
||||
await api.delete(
|
||||
`/${currentProjectKey}/items/${props.collection}/${batchPrimaryKeys}`
|
||||
);
|
||||
await api.delete(`/${currentProjectKey}/items/${props.collection}/${batchPrimaryKeys}`);
|
||||
|
||||
await layout.value?.refresh?.();
|
||||
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
<template>
|
||||
<collections-not-found v-if="error && error.code === 404" />
|
||||
<private-view v-else :title="title">
|
||||
<template
|
||||
#title
|
||||
v-if="isNew === false && isBatch === false && collectionInfo.display_template"
|
||||
>
|
||||
<template #title v-if="isNew === false && isBatch === false && collectionInfo.display_template">
|
||||
<v-skeleton-loader class="title-loader" type="text" v-if="loading" />
|
||||
<h1 class="type-title" v-else>
|
||||
<render-template
|
||||
@@ -16,14 +13,7 @@
|
||||
</template>
|
||||
|
||||
<template #title-outer:prepend>
|
||||
<v-button
|
||||
v-if="collectionInfo.single"
|
||||
class="header-icon"
|
||||
rounded
|
||||
icon
|
||||
secondary
|
||||
disabled
|
||||
>
|
||||
<v-button v-if="collectionInfo.single" class="header-icon" rounded icon secondary disabled>
|
||||
<v-icon :name="collectionInfo.icon" />
|
||||
</v-button>
|
||||
<v-button
|
||||
@@ -96,11 +86,7 @@
|
||||
<v-button @click="confirmSoftDelete = false" secondary>
|
||||
{{ $t('cancel') }}
|
||||
</v-button>
|
||||
<v-button
|
||||
@click="deleteAndQuit(true)"
|
||||
class="action-delete"
|
||||
:loading="softDeleting"
|
||||
>
|
||||
<v-button @click="deleteAndQuit(true)" class="action-delete" :loading="softDeleting">
|
||||
{{ $t('delete') }}
|
||||
</v-button>
|
||||
</v-card-actions>
|
||||
@@ -172,10 +158,7 @@
|
||||
:primary-key="primaryKey"
|
||||
/>
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
@@ -238,9 +221,7 @@ export default defineComponent({
|
||||
|
||||
const revisionsDrawerDetail = ref<Vue>(null);
|
||||
|
||||
const { info: collectionInfo, softDeleteStatus, primaryKeyField } = useCollection(
|
||||
collection
|
||||
);
|
||||
const { info: collectionInfo, softDeleteStatus, primaryKeyField } = useCollection(collection);
|
||||
|
||||
const {
|
||||
isNew,
|
||||
@@ -266,9 +247,7 @@ export default defineComponent({
|
||||
const confirmLeave = ref(false);
|
||||
const leaveTo = ref<string>(null);
|
||||
|
||||
const backLink = computed(
|
||||
() => `/${currentProjectKey.value}/collections/${collection.value}/`
|
||||
);
|
||||
const backLink = computed(() => `/${currentProjectKey.value}/collections/${collection.value}/`);
|
||||
|
||||
const templateValues = computed(() => {
|
||||
return {
|
||||
@@ -344,9 +323,7 @@ export default defineComponent({
|
||||
if (props.primaryKey === '+') {
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const newPrimaryKey = savedItem[primaryKeyField.value!.field];
|
||||
router.replace(
|
||||
`/${currentProjectKey.value}/collections/${props.collection}/${newPrimaryKey}`
|
||||
);
|
||||
router.replace(`/${currentProjectKey.value}/collections/${props.collection}/${newPrimaryKey}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -357,9 +334,7 @@ export default defineComponent({
|
||||
|
||||
async function saveAsCopyAndNavigate() {
|
||||
const newPrimaryKey = await saveAsCopy();
|
||||
router.push(
|
||||
`/${currentProjectKey.value}/collections/${props.collection}/${newPrimaryKey}`
|
||||
);
|
||||
router.push(`/${currentProjectKey.value}/collections/${props.collection}/${newPrimaryKey}`);
|
||||
}
|
||||
|
||||
async function deleteAndQuit(soft = false) {
|
||||
|
||||
@@ -10,12 +10,7 @@
|
||||
<collections-navigation />
|
||||
</template>
|
||||
|
||||
<v-table
|
||||
v-if="navItems.length > 0"
|
||||
:headers="tableHeaders"
|
||||
:items="navItems"
|
||||
@click:row="navigateToCollection"
|
||||
>
|
||||
<v-table v-if="navItems.length > 0" :headers="tableHeaders" :items="navItems" @click:row="navigateToCollection">
|
||||
<template #item.icon="{ item }">
|
||||
<v-icon class="icon" :name="item.icon" />
|
||||
</template>
|
||||
@@ -35,16 +30,10 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
import { i18n } from '@/lang/';
|
||||
import { ModuleDefineParam, ModuleContext, ModuleConfig } from './types';
|
||||
|
||||
export function defineModule(
|
||||
config: ModuleDefineParam | ((context: ModuleContext) => ModuleConfig)
|
||||
): ModuleConfig {
|
||||
export function defineModule(config: ModuleDefineParam | ((context: ModuleContext) => ModuleConfig)): ModuleConfig {
|
||||
let options: ModuleConfig;
|
||||
|
||||
if (typeof config === 'function') {
|
||||
|
||||
@@ -13,11 +13,7 @@
|
||||
</v-card-text>
|
||||
<v-card-actions>
|
||||
<v-button secondary @click="dialogActive = false">{{ $t('cancel') }}</v-button>
|
||||
<v-button
|
||||
:disabled="!newFolderName || newFolderName.length === 0"
|
||||
@click="addFolder"
|
||||
:loading="saving"
|
||||
>
|
||||
<v-button :disabled="!newFolderName || newFolderName.length === 0" @click="addFolder" :loading="saving">
|
||||
{{ $t('save') }}
|
||||
</v-button>
|
||||
</v-card-actions>
|
||||
|
||||
@@ -70,10 +70,7 @@
|
||||
<layout-drawer-detail @input="viewType = $event" :value="viewType" />
|
||||
<portal-target name="drawer" />
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
@@ -107,9 +104,7 @@ export default defineComponent({
|
||||
|
||||
const selection = ref<Item[]>([]);
|
||||
|
||||
const { viewType, viewOptions, viewQuery, filters, searchQuery } = useCollectionPreset(
|
||||
ref('directus_files')
|
||||
);
|
||||
const { viewType, viewOptions, viewQuery, filters, searchQuery } = useCollectionPreset(ref('directus_files'));
|
||||
const { addNewLink, batchLink } = useLinks();
|
||||
const { confirmDelete, deleting, batchDelete } = useBatchDelete();
|
||||
const { breadcrumb } = useBreadcrumb();
|
||||
|
||||
@@ -73,11 +73,9 @@ export default defineComponent({
|
||||
|
||||
const creationDate = ref<string>(null);
|
||||
|
||||
localizedFormat(new Date(props.uploaded_on), String(i18n.t('date-fns_datetime'))).then(
|
||||
(result) => {
|
||||
creationDate.value = result;
|
||||
}
|
||||
);
|
||||
localizedFormat(new Date(props.uploaded_on), String(i18n.t('date-fns_datetime'))).then((result) => {
|
||||
creationDate.value = result;
|
||||
});
|
||||
|
||||
return { readableMimeType, size, creationDate };
|
||||
},
|
||||
|
||||
@@ -13,13 +13,7 @@
|
||||
<template #actions>
|
||||
<v-dialog v-model="confirmDelete">
|
||||
<template #activator="{ on }">
|
||||
<v-button
|
||||
rounded
|
||||
icon
|
||||
class="action-delete"
|
||||
:disabled="item === null"
|
||||
@click="on"
|
||||
>
|
||||
<v-button rounded icon class="action-delete" :disabled="item === null" @click="on">
|
||||
<v-icon name="delete" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -38,23 +32,11 @@
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<v-button
|
||||
v-if="item && item.type.includes('image')"
|
||||
rounded
|
||||
icon
|
||||
@click="editActive = true"
|
||||
class="edit"
|
||||
>
|
||||
<v-button v-if="item && item.type.includes('image')" rounded icon @click="editActive = true" class="edit">
|
||||
<v-icon name="tune" />
|
||||
</v-button>
|
||||
|
||||
<v-button
|
||||
rounded
|
||||
icon
|
||||
:loading="saving"
|
||||
:disabled="hasEdits === false"
|
||||
@click="saveAndQuit"
|
||||
>
|
||||
<v-button rounded icon :loading="saving" :disabled="hasEdits === false" @click="saveAndQuit">
|
||||
<v-icon name="check" />
|
||||
|
||||
<template #append-outer>
|
||||
@@ -129,10 +111,7 @@
|
||||
:primary-key="primaryKey"
|
||||
/>
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
@@ -200,19 +179,10 @@ export default defineComponent({
|
||||
|
||||
const revisionsDrawerDetail = ref<Vue>(null);
|
||||
|
||||
const {
|
||||
isNew,
|
||||
edits,
|
||||
item,
|
||||
saving,
|
||||
loading,
|
||||
error,
|
||||
save,
|
||||
remove,
|
||||
deleting,
|
||||
saveAsCopy,
|
||||
isBatch,
|
||||
} = useItem(ref('directus_files'), primaryKey);
|
||||
const { isNew, edits, item, saving, loading, error, save, remove, deleting, saveAsCopy, isBatch } = useItem(
|
||||
ref('directus_files'),
|
||||
primaryKey
|
||||
);
|
||||
|
||||
const hasEdits = computed<boolean>(() => Object.keys(edits.value).length > 0);
|
||||
const confirmDelete = ref(false);
|
||||
|
||||
@@ -5,13 +5,6 @@ import ActivityModule from './activity/';
|
||||
import DocsModule from './docs/';
|
||||
import SettingsModule from './settings/';
|
||||
|
||||
export const modules = [
|
||||
ActivityModule,
|
||||
CollectionsModule,
|
||||
UsersModule,
|
||||
FilesModule,
|
||||
DocsModule,
|
||||
SettingsModule,
|
||||
];
|
||||
export const modules = [ActivityModule, CollectionsModule, UsersModule, FilesModule, DocsModule, SettingsModule];
|
||||
|
||||
export default modules;
|
||||
|
||||
@@ -9,15 +9,8 @@ const moduleRoutes = modules
|
||||
|
||||
replaceRoutes((routes) => insertBeforeProjectWildcard(routes, moduleRoutes));
|
||||
|
||||
export function insertBeforeProjectWildcard(
|
||||
currentRoutes: RouteConfig[],
|
||||
routesToBeAdded: RouteConfig[]
|
||||
) {
|
||||
export function insertBeforeProjectWildcard(currentRoutes: RouteConfig[], routesToBeAdded: RouteConfig[]) {
|
||||
// Find the index of the /:project/* route, so we can insert the module routes right above that
|
||||
const wildcardIndex = currentRoutes.findIndex((route) => route.path === '/:project/*');
|
||||
return [
|
||||
...currentRoutes.slice(0, wildcardIndex),
|
||||
...routesToBeAdded,
|
||||
...currentRoutes.slice(wildcardIndex),
|
||||
];
|
||||
return [...currentRoutes.slice(0, wildcardIndex), ...routesToBeAdded, ...currentRoutes.slice(wildcardIndex)];
|
||||
}
|
||||
|
||||
@@ -17,13 +17,7 @@
|
||||
</template>
|
||||
|
||||
<div class="padding-box">
|
||||
<v-info
|
||||
type="warning"
|
||||
icon="box"
|
||||
:title="$t('no_collections')"
|
||||
v-if="items.length === 0"
|
||||
center
|
||||
>
|
||||
<v-info type="warning" icon="box" :title="$t('no_collections')" v-if="items.length === 0" center>
|
||||
{{ $t('no_collections_copy_admin') }}
|
||||
|
||||
<template #append>
|
||||
@@ -46,9 +40,7 @@
|
||||
:class="{
|
||||
hidden: item.hidden,
|
||||
system: item.collection.startsWith('directus_'),
|
||||
unmanaged:
|
||||
item.managed === false &&
|
||||
item.collection.startsWith('directus_') === false,
|
||||
unmanaged: item.managed === false && item.collection.startsWith('directus_') === false,
|
||||
}"
|
||||
:name="item.icon"
|
||||
/>
|
||||
@@ -60,9 +52,7 @@
|
||||
:class="{
|
||||
hidden: item.hidden,
|
||||
system: item.collection.startsWith('directus_'),
|
||||
unmanaged:
|
||||
item.managed === false &&
|
||||
item.collection.startsWith('directus_') === false,
|
||||
unmanaged: item.managed === false && item.collection.startsWith('directus_') === false,
|
||||
}"
|
||||
>
|
||||
{{ item.name }}
|
||||
@@ -85,17 +75,11 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_settings_datamodel_collections'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_settings_datamodel_collections'))" />
|
||||
</drawer-detail>
|
||||
<collections-filter v-model="activeTypes" />
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
@@ -188,9 +172,7 @@ export default defineComponent({
|
||||
const system = computed(() => {
|
||||
return sortBy(
|
||||
collectionsStore.state.collections
|
||||
.filter(
|
||||
(collection) => collection.collection.startsWith('directus_') === true
|
||||
)
|
||||
.filter((collection) => collection.collection.startsWith('directus_') === true)
|
||||
.map((collection) => ({ ...collection, icon: 'settings' })),
|
||||
'collection'
|
||||
);
|
||||
@@ -199,9 +181,7 @@ export default defineComponent({
|
||||
const unmanaged = computed(() => {
|
||||
return sortBy(
|
||||
collectionsStore.state.collections
|
||||
.filter(
|
||||
(collection) => collection.collection.startsWith('directus_') === false
|
||||
)
|
||||
.filter((collection) => collection.collection.startsWith('directus_') === false)
|
||||
.filter((collection) => collection.managed === false)
|
||||
.map((collection) => ({ ...collection, icon: 'block' })),
|
||||
'collection'
|
||||
|
||||
@@ -1,8 +1,6 @@
|
||||
<template>
|
||||
<v-button
|
||||
v-if="
|
||||
collection.managed === false && collection.collection.startsWith('directus_') === false
|
||||
"
|
||||
v-if="collection.managed === false && collection.collection.startsWith('directus_') === false"
|
||||
x-small
|
||||
outlined
|
||||
class="manage"
|
||||
|
||||
@@ -86,11 +86,7 @@
|
||||
{{ $t('cancel') }}
|
||||
</v-button>
|
||||
<div class="spacer" />
|
||||
<v-button
|
||||
secondary
|
||||
@click="currentTab = ['collection']"
|
||||
:disabled="currentTab[0] === 'collection'"
|
||||
>
|
||||
<v-button secondary @click="currentTab = ['collection']" :disabled="currentTab[0] === 'collection'">
|
||||
{{ $t('previous') }}
|
||||
</v-button>
|
||||
<v-button
|
||||
|
||||
@@ -2,13 +2,7 @@
|
||||
<div :class="hidden ? 'half' : field.width">
|
||||
<v-menu attached close-on-content-click>
|
||||
<template #activator="{ toggle, active }">
|
||||
<v-input
|
||||
class="field"
|
||||
:class="{ hidden, active }"
|
||||
readonly
|
||||
@click="toggle"
|
||||
:value="field.name"
|
||||
>
|
||||
<v-input class="field" :class="{ hidden, active }" readonly @click="toggle" :value="field.name">
|
||||
<template #prepend>
|
||||
<v-icon class="drag-handle" name="drag_indicator" @click.stop />
|
||||
</template>
|
||||
@@ -123,14 +117,7 @@ export default defineComponent({
|
||||
const collectionsStore = useCollectionsStore();
|
||||
|
||||
const { deleteActive, deleting, deleteField } = useDeleteField();
|
||||
const {
|
||||
duplicateActive,
|
||||
duplicateName,
|
||||
collections,
|
||||
duplicateTo,
|
||||
saveDuplicate,
|
||||
duplicating,
|
||||
} = useDuplicate();
|
||||
const { duplicateActive, duplicateName, collections, duplicateTo, saveDuplicate, duplicating } = useDuplicate();
|
||||
|
||||
return {
|
||||
editActive,
|
||||
|
||||
@@ -2,16 +2,10 @@
|
||||
<div>
|
||||
<h2 class="type-title" v-if="isNew">{{ $t('display_setup_title') }}</h2>
|
||||
|
||||
<v-fancy-select
|
||||
:items="items"
|
||||
:value="value.display"
|
||||
@input="emitValue('display', $event)"
|
||||
/>
|
||||
<v-fancy-select :items="items" :value="value.display" @input="emitValue('display', $event)" />
|
||||
|
||||
<v-form
|
||||
v-if="
|
||||
selectedDisplay && selectedDisplay.options && Array.isArray(selectedDisplay.options)
|
||||
"
|
||||
v-if="selectedDisplay && selectedDisplay.options && Array.isArray(selectedDisplay.options)"
|
||||
:fields="selectedDisplay.options"
|
||||
primary-key="+"
|
||||
:edits="value.options"
|
||||
|
||||
@@ -2,18 +2,10 @@
|
||||
<div>
|
||||
<h2 class="type-title" v-if="isNew">{{ $t('relationship_setup_title') }}</h2>
|
||||
|
||||
<v-fancy-select
|
||||
:items="items"
|
||||
:value="value.interface"
|
||||
@input="emitValue('interface', $event)"
|
||||
/>
|
||||
<v-fancy-select :items="items" :value="value.interface" @input="emitValue('interface', $event)" />
|
||||
|
||||
<v-form
|
||||
v-if="
|
||||
selectedInterface &&
|
||||
selectedInterface.options &&
|
||||
Array.isArray(selectedInterface.options)
|
||||
"
|
||||
v-if="selectedInterface && selectedInterface.options && Array.isArray(selectedInterface.options)"
|
||||
:fields="selectedInterface.options"
|
||||
primary-key="+"
|
||||
:edits="value.options"
|
||||
|
||||
@@ -13,18 +13,10 @@
|
||||
<v-select :items="collectionItems" v-model="relatedCollection" />
|
||||
</div>
|
||||
<v-input disabled :value="field.field" />
|
||||
<v-select
|
||||
:disabled="!junctionCollection"
|
||||
:items="junctionFields"
|
||||
v-model="junctionFieldCurrent"
|
||||
/>
|
||||
<v-select :disabled="!junctionCollection" :items="junctionFields" v-model="junctionFieldCurrent" />
|
||||
<div class="spacer" />
|
||||
<div class="spacer" />
|
||||
<v-select
|
||||
:disabled="!junctionCollection"
|
||||
:items="junctionFields"
|
||||
v-model="junctionFieldRelated"
|
||||
/>
|
||||
<v-select :disabled="!junctionCollection" :items="junctionFields" v-model="junctionFieldRelated" />
|
||||
<v-input disabled value="id" />
|
||||
<v-icon name="arrow_forward" />
|
||||
<v-icon name="arrow_backward" />
|
||||
@@ -124,12 +116,10 @@ export default defineComponent({
|
||||
const junctionFields = computed(() => {
|
||||
if (!junctionCollection.value) return [];
|
||||
|
||||
return fieldsStore
|
||||
.getFieldsForCollection(junctionCollection.value)
|
||||
.map((field: Field) => ({
|
||||
text: field.name,
|
||||
value: field.field,
|
||||
}));
|
||||
return fieldsStore.getFieldsForCollection(junctionCollection.value).map((field: Field) => ({
|
||||
text: field.name,
|
||||
value: field.field,
|
||||
}));
|
||||
});
|
||||
|
||||
const relatedCollection = computed({
|
||||
|
||||
@@ -93,10 +93,7 @@ export default defineComponent({
|
||||
|
||||
const existingRelation = computed(() => {
|
||||
return props.existingRelations.find((relation) => {
|
||||
return (
|
||||
relation.field_many === props.field.field &&
|
||||
relation.collection_many === props.field.collection
|
||||
);
|
||||
return relation.field_many === props.field.field && relation.collection_many === props.field.collection;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -86,10 +86,7 @@ export default defineComponent({
|
||||
|
||||
const existingRelation = computed(() => {
|
||||
return props.existingRelations.find((relation) => {
|
||||
return (
|
||||
relation.field_one === props.field.field &&
|
||||
relation.collection_one === props.field.collection
|
||||
);
|
||||
return relation.field_one === props.field.field && relation.collection_one === props.field.collection;
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -54,18 +54,13 @@ export default defineComponent({
|
||||
const _currentTab = useSync(props, 'currentTab', emit);
|
||||
|
||||
const { field, localType } = toRefs(props);
|
||||
const {
|
||||
fieldComplete,
|
||||
relationComplete,
|
||||
interfaceComplete,
|
||||
displayComplete,
|
||||
advancedComplete,
|
||||
} = useValidation(field, localType);
|
||||
|
||||
const currentTabIndex = computed(() =>
|
||||
props.tabs.findIndex((tab) => tab.value === props.currentTab[0])
|
||||
const { fieldComplete, relationComplete, interfaceComplete, displayComplete, advancedComplete } = useValidation(
|
||||
field,
|
||||
localType
|
||||
);
|
||||
|
||||
const currentTabIndex = computed(() => props.tabs.findIndex((tab) => tab.value === props.currentTab[0]));
|
||||
|
||||
const previousDisabled = computed(() => {
|
||||
return currentTabIndex.value === 0;
|
||||
});
|
||||
|
||||
@@ -1,11 +1,6 @@
|
||||
<template>
|
||||
<v-tabs vertical v-model="_currentTab">
|
||||
<v-tab
|
||||
v-for="tab in tabs"
|
||||
:key="tab.value"
|
||||
:value="tab.value"
|
||||
:disabled="tabEnabled(tab) === false"
|
||||
>
|
||||
<v-tab v-for="tab in tabs" :key="tab.value" :value="tab.value" :disabled="tabEnabled(tab) === false">
|
||||
{{ tab.text }}
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
@@ -45,12 +40,7 @@ export default defineComponent({
|
||||
const _currentTab = useSync(props, 'currentTab', emit);
|
||||
|
||||
const { field, localType } = toRefs(props);
|
||||
const {
|
||||
fieldComplete,
|
||||
relationComplete,
|
||||
interfaceComplete,
|
||||
displayComplete,
|
||||
} = useValidation(field, localType);
|
||||
const { fieldComplete, relationComplete, interfaceComplete, displayComplete } = useValidation(field, localType);
|
||||
|
||||
const hasRelationshipTab = computed(() => {
|
||||
const relationshipTab = props.tabs.find((tab) => tab.value === 'relationship');
|
||||
@@ -69,9 +59,7 @@ export default defineComponent({
|
||||
case 'relationship':
|
||||
return fieldComplete.value === true;
|
||||
case 'interface':
|
||||
return hasRelationshipTab.value
|
||||
? relationComplete.value === true
|
||||
: fieldComplete.value === true;
|
||||
return hasRelationshipTab.value ? relationComplete.value === true : fieldComplete.value === true;
|
||||
case 'display':
|
||||
return interfaceComplete.value === true;
|
||||
case 'advanced':
|
||||
|
||||
@@ -21,14 +21,7 @@
|
||||
/>
|
||||
|
||||
<template #footer>
|
||||
<v-button
|
||||
class="add-field"
|
||||
align="left"
|
||||
dashed
|
||||
outlined
|
||||
large
|
||||
@click="openFieldSetup()"
|
||||
>
|
||||
<v-button class="add-field" align="left" dashed outlined large @click="openFieldSetup()">
|
||||
<v-icon name="add" />
|
||||
|
||||
{{ $t('add_field') }}
|
||||
@@ -57,14 +50,7 @@
|
||||
/>
|
||||
|
||||
<template #footer>
|
||||
<v-button
|
||||
class="add-field"
|
||||
align="left"
|
||||
dashed
|
||||
outlined
|
||||
large
|
||||
@click="openFieldSetup()"
|
||||
>
|
||||
<v-button class="add-field" align="left" dashed outlined large @click="openFieldSetup()">
|
||||
<v-icon name="add" />
|
||||
|
||||
{{ $t('add_field') }}
|
||||
@@ -156,8 +142,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
function toggleVisibility(field: Field, location: 'visible' | 'hidden') {
|
||||
const fields =
|
||||
location === 'hidden' ? sortedVisibleFields.value : sortedHiddenFields.value;
|
||||
const fields = location === 'hidden' ? sortedVisibleFields.value : sortedHiddenFields.value;
|
||||
|
||||
handleChange(
|
||||
{ added: { element: field, newIndex: fields.length } },
|
||||
@@ -165,21 +150,16 @@ export default defineComponent({
|
||||
);
|
||||
}
|
||||
|
||||
function addToGroup(
|
||||
event: Required<DraggableEvent>['added'],
|
||||
location: 'visible' | 'hidden'
|
||||
) {
|
||||
function addToGroup(event: Required<DraggableEvent>['added'], location: 'visible' | 'hidden') {
|
||||
/** @NOTE Adding to one group also means removing from the other */
|
||||
|
||||
const { element, newIndex } = event;
|
||||
|
||||
const fieldsInGroup =
|
||||
location === 'visible' ? sortedVisibleFields.value : sortedHiddenFields.value;
|
||||
const fieldsInGroup = location === 'visible' ? sortedVisibleFields.value : sortedHiddenFields.value;
|
||||
|
||||
const updates: Partial<Field>[] = fieldsInGroup.slice(newIndex).map((field) => {
|
||||
const sortValue =
|
||||
field.sort ||
|
||||
fieldsInGroup.findIndex((existingField) => existingField.field === field.field);
|
||||
field.sort || fieldsInGroup.findIndex((existingField) => existingField.field === field.field);
|
||||
|
||||
return {
|
||||
field: field.field,
|
||||
@@ -209,25 +189,19 @@ export default defineComponent({
|
||||
fieldsStore.updateFields(element.collection, updates);
|
||||
}
|
||||
|
||||
function sortInGroup(
|
||||
event: Required<DraggableEvent>['moved'],
|
||||
location: 'visible' | 'hidden'
|
||||
) {
|
||||
function sortInGroup(event: Required<DraggableEvent>['moved'], location: 'visible' | 'hidden') {
|
||||
const { element, newIndex, oldIndex } = event;
|
||||
const move = newIndex > oldIndex ? 'down' : 'up';
|
||||
|
||||
const selectionRange =
|
||||
move === 'down' ? [oldIndex + 1, newIndex + 1] : [newIndex, oldIndex];
|
||||
const selectionRange = move === 'down' ? [oldIndex + 1, newIndex + 1] : [newIndex, oldIndex];
|
||||
|
||||
const fields =
|
||||
location === 'visible' ? sortedVisibleFields.value : sortedHiddenFields.value;
|
||||
const fields = location === 'visible' ? sortedVisibleFields.value : sortedHiddenFields.value;
|
||||
|
||||
const updates: Partial<Field>[] = fields.slice(...selectionRange).map((field) => {
|
||||
// If field.sort isn't set yet, base it on the index of the array. That way, the
|
||||
// new sort value will match what's visible on the screen
|
||||
const sortValue =
|
||||
field.sort ||
|
||||
fields.findIndex((existingField) => existingField.field === field.field);
|
||||
field.sort || fields.findIndex((existingField) => existingField.field === field.field);
|
||||
|
||||
return {
|
||||
field: field.field,
|
||||
|
||||
@@ -9,13 +9,7 @@
|
||||
<template #actions>
|
||||
<v-dialog v-model="confirmDelete">
|
||||
<template #activator="{ on }">
|
||||
<v-button
|
||||
rounded
|
||||
icon
|
||||
class="action-delete"
|
||||
:disabled="item === null"
|
||||
@click="on"
|
||||
>
|
||||
<v-button rounded icon class="action-delete" :disabled="item === null" @click="on">
|
||||
<v-icon name="delete" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -34,13 +28,7 @@
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<v-button
|
||||
rounded
|
||||
icon
|
||||
:loading="saving"
|
||||
:disabled="hasEdits === false"
|
||||
@click="saveAndQuit"
|
||||
>
|
||||
<v-button rounded icon :loading="saving" :disabled="hasEdits === false" @click="saveAndQuit">
|
||||
<v-icon name="check" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -70,16 +58,10 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_settings_datamodel_fields'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_settings_datamodel_fields'))" />
|
||||
</drawer-detail>
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
@@ -111,19 +93,10 @@ export default defineComponent({
|
||||
const { currentProjectKey } = toRefs(projectsStore.state);
|
||||
const collectionsStore = useCollectionsStore();
|
||||
|
||||
const {
|
||||
isNew,
|
||||
edits,
|
||||
item,
|
||||
saving,
|
||||
loading,
|
||||
error,
|
||||
save,
|
||||
remove,
|
||||
deleting,
|
||||
saveAsCopy,
|
||||
isBatch,
|
||||
} = useItem(ref('directus_collections'), collection);
|
||||
const { isNew, edits, item, saving, loading, error, save, remove, deleting, saveAsCopy, isBatch } = useItem(
|
||||
ref('directus_collections'),
|
||||
collection
|
||||
);
|
||||
|
||||
const hasEdits = computed<boolean>(() => Object.keys(edits.value).length > 0);
|
||||
|
||||
|
||||
@@ -17,12 +17,7 @@
|
||||
</template>
|
||||
|
||||
<div class="settings">
|
||||
<v-form
|
||||
:initial-values="initialValues"
|
||||
v-model="edits"
|
||||
:fields="fields"
|
||||
:primary-key="1"
|
||||
/>
|
||||
<v-form :initial-values="initialValues" v-model="edits" :fields="fields" :primary-key="1" />
|
||||
</div>
|
||||
|
||||
<template #drawer>
|
||||
@@ -53,9 +48,7 @@ export default defineComponent({
|
||||
|
||||
const edits = ref<{ [key: string]: any }>(null);
|
||||
|
||||
const noEdits = computed<boolean>(
|
||||
() => edits.value === null || Object.keys(edits.value).length === 0
|
||||
);
|
||||
const noEdits = computed<boolean>(() => edits.value === null || Object.keys(edits.value).length === 0);
|
||||
|
||||
const saving = ref(false);
|
||||
|
||||
|
||||
@@ -21,11 +21,7 @@
|
||||
<v-button @click="confirmDelete = false" secondary>
|
||||
{{ $t('cancel') }}
|
||||
</v-button>
|
||||
<v-button
|
||||
@click="deleteSelection"
|
||||
class="action-delete"
|
||||
:loading="deleting"
|
||||
>
|
||||
<v-button @click="deleteSelection" class="action-delete" :loading="deleting">
|
||||
{{ $t('delete') }}
|
||||
</v-button>
|
||||
</v-card-actions>
|
||||
@@ -42,13 +38,7 @@
|
||||
</template>
|
||||
|
||||
<div class="presets-browse">
|
||||
<v-info
|
||||
center
|
||||
type="warning"
|
||||
v-if="presets.length === 0"
|
||||
:title="$t('no_presets')"
|
||||
icon="bookmark"
|
||||
>
|
||||
<v-info center type="warning" v-if="presets.length === 0" :title="$t('no_presets')" icon="bookmark">
|
||||
{{ $t('no_presets_copy') }}
|
||||
|
||||
<template #append>
|
||||
@@ -88,16 +78,10 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_settings_presets_browse'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_settings_presets_browse'))" />
|
||||
</drawer-detail>
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
|
||||
@@ -13,13 +13,7 @@
|
||||
<template #actions>
|
||||
<v-dialog v-model="confirmDelete">
|
||||
<template #activator="{ on }">
|
||||
<v-button
|
||||
rounded
|
||||
icon
|
||||
class="action-delete"
|
||||
:disabled="preset === null || id === '+'"
|
||||
@click="on"
|
||||
>
|
||||
<v-button rounded icon class="action-delete" :disabled="preset === null || id === '+'" @click="on">
|
||||
<v-icon name="delete" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -68,19 +62,13 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_settings_presets_detail'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_settings_presets_detail'))" />
|
||||
</drawer-detail>
|
||||
<div class="layout-drawer">
|
||||
<portal-target name="drawer" />
|
||||
</div>
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
@@ -146,9 +134,7 @@ export default defineComponent({
|
||||
const { save, saving } = useSave();
|
||||
const { deleting, deleteAndQuit, confirmDelete } = useDelete();
|
||||
|
||||
const loading = computed(
|
||||
() => usersLoading.value || presetLoading.value || rolesLoading.value
|
||||
);
|
||||
const loading = computed(() => usersLoading.value || presetLoading.value || rolesLoading.value);
|
||||
|
||||
return {
|
||||
backLink,
|
||||
@@ -202,10 +188,7 @@ export default defineComponent({
|
||||
if (isNew.value === true) {
|
||||
await api.post(`/${currentProjectKey}/collection_presets`, editsParsed);
|
||||
} else {
|
||||
await api.patch(
|
||||
`/${currentProjectKey}/collection_presets/${props.id}`,
|
||||
editsParsed
|
||||
);
|
||||
await api.patch(`/${currentProjectKey}/collection_presets/${props.id}`, editsParsed);
|
||||
}
|
||||
|
||||
await collectionPresetsStore.hydrate();
|
||||
@@ -334,9 +317,7 @@ export default defineComponent({
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await api.get(
|
||||
`/${currentProjectKey}/collection_presets/${props.id}`
|
||||
);
|
||||
const response = await api.get(`/${currentProjectKey}/collection_presets/${props.id}`);
|
||||
|
||||
preset.value = response.data.data;
|
||||
} catch (err) {
|
||||
@@ -442,8 +423,7 @@ export default defineComponent({
|
||||
interface: 'dropdown',
|
||||
options: {
|
||||
choices: collectionsStore.state.collections.reduce(
|
||||
(string, collection) =>
|
||||
(string += `${collection.collection} :: ${collection.name}\n`),
|
||||
(string, collection) => (string += `${collection.collection} :: ${collection.name}\n`),
|
||||
''
|
||||
),
|
||||
},
|
||||
@@ -463,10 +443,7 @@ export default defineComponent({
|
||||
name: i18n.t('layout'),
|
||||
interface: 'dropdown',
|
||||
options: {
|
||||
choices: layouts.reduce(
|
||||
(string, layout) => (string += `${layout.id}::${layout.name}\n`),
|
||||
''
|
||||
),
|
||||
choices: layouts.reduce((string, layout) => (string += `${layout.id}::${layout.name}\n`), ''),
|
||||
},
|
||||
width: 'half',
|
||||
},
|
||||
|
||||
@@ -9,13 +9,7 @@
|
||||
<template #actions>
|
||||
<v-dialog v-model="confirmDelete">
|
||||
<template #activator="{ on }">
|
||||
<v-button
|
||||
rounded
|
||||
icon
|
||||
class="action-delete"
|
||||
v-if="selection.length > 0"
|
||||
@click="on"
|
||||
>
|
||||
<v-button rounded icon class="action-delete" v-if="selection.length > 0" @click="on">
|
||||
<v-icon name="delete" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -59,17 +53,11 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_settings_roles_browse'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_settings_roles_browse'))" />
|
||||
</drawer-detail>
|
||||
<portal-target name="drawer" />
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
|
||||
@@ -15,9 +15,7 @@
|
||||
:value="field.field"
|
||||
:key="field.field"
|
||||
:indeterminate="readIndeterminate.includes(field.field)"
|
||||
@update:indeterminate="
|
||||
readIndeterminate = readIndeterminate.filter((f) => f !== field.field)
|
||||
"
|
||||
@update:indeterminate="readIndeterminate = readIndeterminate.filter((f) => f !== field.field)"
|
||||
:label="field.name"
|
||||
/>
|
||||
</div>
|
||||
@@ -109,9 +107,7 @@ export default defineComponent({
|
||||
if (newVal !== true) return;
|
||||
|
||||
if (props.combined === true) {
|
||||
readableFields.value = invertBlacklist(
|
||||
intersection(...(props.readBlacklist as string[][]))
|
||||
);
|
||||
readableFields.value = invertBlacklist(intersection(...(props.readBlacklist as string[][])));
|
||||
|
||||
readIndeterminate.value = [...new Set(props.readBlacklist.flat())].filter((k) =>
|
||||
readableFields.value.includes(k)
|
||||
@@ -121,9 +117,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
if (props.combined === true) {
|
||||
writableFields.value = invertBlacklist(
|
||||
intersection(...(props.writeBlacklist as string[][]))
|
||||
);
|
||||
writableFields.value = invertBlacklist(intersection(...(props.writeBlacklist as string[][])));
|
||||
|
||||
writeIndeterminate.value = [...new Set(props.writeBlacklist.flat())].filter((k) =>
|
||||
writableFields.value.includes(k)
|
||||
@@ -154,12 +148,8 @@ export default defineComponent({
|
||||
collection: props.collection,
|
||||
status: props.status,
|
||||
role: props.role,
|
||||
read_field_blacklist: fieldKeys.value.filter(
|
||||
(key) => readableFields.value.includes(key) === false
|
||||
),
|
||||
write_field_blacklist: fieldKeys.value.filter(
|
||||
(key) => writableFields.value.includes(key) === false
|
||||
),
|
||||
read_field_blacklist: fieldKeys.value.filter((key) => readableFields.value.includes(key) === false),
|
||||
write_field_blacklist: fieldKeys.value.filter((key) => writableFields.value.includes(key) === false),
|
||||
};
|
||||
|
||||
if (props.permissionId) {
|
||||
|
||||
@@ -63,10 +63,7 @@
|
||||
/>
|
||||
<div class="spacer" v-else>--</div>
|
||||
|
||||
<v-icon
|
||||
@click="detailsOpen = !detailsOpen"
|
||||
:name="detailsOpen ? 'expand_less' : 'expand_more'"
|
||||
/>
|
||||
<v-icon @click="detailsOpen = !detailsOpen" :name="detailsOpen ? 'expand_less' : 'expand_more'" />
|
||||
</div>
|
||||
|
||||
<div class="details" v-if="detailsOpen">
|
||||
@@ -270,13 +267,9 @@ export default defineComponent({
|
||||
|
||||
if (statusField.value && statuses.value) {
|
||||
const statusPermissions = statuses.value.map((status) => {
|
||||
const existing = props.savedPermissions.find(
|
||||
(permission) => permission.status === status.value
|
||||
);
|
||||
const existing = props.savedPermissions.find((permission) => permission.status === status.value);
|
||||
|
||||
return (
|
||||
existing || getDefaultPermission(props.collection, props.role, status.value)
|
||||
);
|
||||
return existing || getDefaultPermission(props.collection, props.role, status.value);
|
||||
});
|
||||
|
||||
return [...statusPermissions, createPermission];
|
||||
@@ -316,9 +309,7 @@ export default defineComponent({
|
||||
if (statusField.value) {
|
||||
let value = permissions.value[0][type];
|
||||
|
||||
for (const permission of permissions.value.filter(
|
||||
({ status }) => status !== '$create'
|
||||
)) {
|
||||
for (const permission of permissions.value.filter(({ status }) => status !== '$create')) {
|
||||
if (value !== permission[type]) {
|
||||
value = 'indeterminate';
|
||||
break;
|
||||
@@ -327,9 +318,7 @@ export default defineComponent({
|
||||
|
||||
return value;
|
||||
} else {
|
||||
const permission = permissions.value.find(
|
||||
(permission) => permission.status === null
|
||||
);
|
||||
const permission = permissions.value.find((permission) => permission.status === null);
|
||||
|
||||
return permission?.[type];
|
||||
}
|
||||
|
||||
@@ -13,9 +13,7 @@
|
||||
:value="status.value"
|
||||
:key="status.value"
|
||||
:indeterminate="indeterminate.includes(status.value)"
|
||||
@update:indeterminate="
|
||||
indeterminate = indeterminate.filter((s) => s !== status.value)
|
||||
"
|
||||
@update:indeterminate="indeterminate = indeterminate.filter((s) => s !== status.value)"
|
||||
:label="status.name"
|
||||
/>
|
||||
</div>
|
||||
@@ -88,9 +86,7 @@ export default defineComponent({
|
||||
if (newVal !== true) return;
|
||||
|
||||
if (props.combined === true) {
|
||||
allowedStatuses.value = invertBlacklist(
|
||||
intersection(...(props.statusBlacklist as string[][]))
|
||||
);
|
||||
allowedStatuses.value = invertBlacklist(intersection(...(props.statusBlacklist as string[][])));
|
||||
|
||||
allowedStatuses.value = [...new Set(props.statusBlacklist.flat())].filter((k) =>
|
||||
allowedStatuses.value.includes(k)
|
||||
@@ -118,9 +114,7 @@ export default defineComponent({
|
||||
collection: props.collection,
|
||||
status: props.status,
|
||||
role: props.role,
|
||||
status_blacklist: statusKeys.value.filter(
|
||||
(key) => allowedStatuses.value.includes(key) === false
|
||||
),
|
||||
status_blacklist: statusKeys.value.filter((key) => allowedStatuses.value.includes(key) === false),
|
||||
};
|
||||
|
||||
if (props.permissionId) {
|
||||
|
||||
@@ -1,11 +1,5 @@
|
||||
<template>
|
||||
<v-menu
|
||||
show-arrow
|
||||
placement="left-start"
|
||||
class="permissions-toggle"
|
||||
close-on-content-click
|
||||
:disabled="saving"
|
||||
>
|
||||
<v-menu show-arrow placement="left-start" class="permissions-toggle" close-on-content-click :disabled="saving">
|
||||
<template #activator="{ toggle }">
|
||||
<span>
|
||||
<v-progress-circular class="spinner" indeterminate small v-if="saving" />
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
<template>
|
||||
<private-view :title="$t('editing', { collection: $t('roles') })">
|
||||
<template #title-outer:prepend>
|
||||
<v-button
|
||||
class="header-icon"
|
||||
rounded
|
||||
icon
|
||||
exact
|
||||
:to="`/${currentProjectKey}/settings/roles/`"
|
||||
>
|
||||
<v-button class="header-icon" rounded icon exact :to="`/${currentProjectKey}/settings/roles/`">
|
||||
<v-icon name="arrow_back" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -15,13 +9,7 @@
|
||||
<template #actions>
|
||||
<v-dialog v-model="confirmDelete">
|
||||
<template #activator="{ on }">
|
||||
<v-button
|
||||
rounded
|
||||
icon
|
||||
class="action-delete"
|
||||
:disabled="item === null"
|
||||
@click="on"
|
||||
>
|
||||
<v-button rounded icon class="action-delete" :disabled="item === null" @click="on">
|
||||
<v-icon name="delete" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -40,13 +28,7 @@
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<v-button
|
||||
rounded
|
||||
icon
|
||||
:loading="saving"
|
||||
:disabled="hasEdits === false"
|
||||
@click="saveAndQuit"
|
||||
>
|
||||
<v-button rounded icon :loading="saving" :disabled="hasEdits === false" @click="saveAndQuit">
|
||||
<v-icon name="check" />
|
||||
|
||||
<template #append-outer>
|
||||
@@ -84,21 +66,11 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_settings_roles_detail'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_settings_roles_detail'))" />
|
||||
</drawer-detail>
|
||||
<revisions-drawer-detail
|
||||
v-if="isNew === false"
|
||||
collection="directus_roles"
|
||||
:primary-key="primaryKey"
|
||||
/>
|
||||
<revisions-drawer-detail v-if="isNew === false" collection="directus_roles" :primary-key="primaryKey" />
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
@@ -136,19 +108,10 @@ export default defineComponent({
|
||||
const { currentProjectKey } = toRefs(projectsStore.state);
|
||||
const { primaryKey } = toRefs(props);
|
||||
|
||||
const {
|
||||
isNew,
|
||||
edits,
|
||||
item,
|
||||
saving,
|
||||
loading,
|
||||
error,
|
||||
save,
|
||||
remove,
|
||||
deleting,
|
||||
saveAsCopy,
|
||||
isBatch,
|
||||
} = useItem(ref('directus_roles'), primaryKey);
|
||||
const { isNew, edits, item, saving, loading, error, save, remove, deleting, saveAsCopy, isBatch } = useItem(
|
||||
ref('directus_roles'),
|
||||
primaryKey
|
||||
);
|
||||
|
||||
const hasEdits = computed<boolean>(() => Object.keys(edits.value).length > 0);
|
||||
|
||||
|
||||
@@ -9,13 +9,7 @@
|
||||
<template #actions>
|
||||
<v-dialog v-model="confirmDelete">
|
||||
<template #activator="{ on }">
|
||||
<v-button
|
||||
rounded
|
||||
icon
|
||||
class="action-delete"
|
||||
v-if="selection.length > 0"
|
||||
@click="on"
|
||||
>
|
||||
<v-button rounded icon class="action-delete" v-if="selection.length > 0" @click="on">
|
||||
<v-icon name="delete" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -59,17 +53,11 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_settings_webhooks_browse'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_settings_webhooks_browse'))" />
|
||||
</drawer-detail>
|
||||
<portal-target name="drawer" />
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
|
||||
@@ -1,13 +1,7 @@
|
||||
<template>
|
||||
<private-view :title="$t('editing', { collection: $t('webhooks') })">
|
||||
<template #title-outer:prepend>
|
||||
<v-button
|
||||
class="header-icon"
|
||||
rounded
|
||||
icon
|
||||
exact
|
||||
:to="`/${currentProjectKey}/settings/webhooks/`"
|
||||
>
|
||||
<v-button class="header-icon" rounded icon exact :to="`/${currentProjectKey}/settings/webhooks/`">
|
||||
<v-icon name="arrow_back" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -15,13 +9,7 @@
|
||||
<template #actions>
|
||||
<v-dialog v-model="confirmDelete">
|
||||
<template #activator="{ on }">
|
||||
<v-button
|
||||
rounded
|
||||
icon
|
||||
class="action-delete"
|
||||
:disabled="item === null"
|
||||
@click="on"
|
||||
>
|
||||
<v-button rounded icon class="action-delete" :disabled="item === null" @click="on">
|
||||
<v-icon name="delete" />
|
||||
</v-button>
|
||||
</template>
|
||||
@@ -40,13 +28,7 @@
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<v-button
|
||||
rounded
|
||||
icon
|
||||
:loading="saving"
|
||||
:disabled="hasEdits === false"
|
||||
@click="saveAndQuit"
|
||||
>
|
||||
<v-button rounded icon :loading="saving" :disabled="hasEdits === false" @click="saveAndQuit">
|
||||
<v-icon name="check" />
|
||||
|
||||
<template #append-outer>
|
||||
@@ -75,21 +57,11 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_settings_webhooks_detail'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_settings_webhooks_detail'))" />
|
||||
</drawer-detail>
|
||||
<revisions-drawer-detail
|
||||
v-if="isNew === false"
|
||||
collection="directus_webhooks"
|
||||
:primary-key="primaryKey"
|
||||
/>
|
||||
<revisions-drawer-detail v-if="isNew === false" collection="directus_webhooks" :primary-key="primaryKey" />
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div
|
||||
class="format-markdown"
|
||||
v-html="marked($t('page_help_collections_overview'))"
|
||||
/>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
@@ -123,19 +95,10 @@ export default defineComponent({
|
||||
const { currentProjectKey } = toRefs(projectsStore.state);
|
||||
const { primaryKey } = toRefs(props);
|
||||
|
||||
const {
|
||||
isNew,
|
||||
edits,
|
||||
item,
|
||||
saving,
|
||||
loading,
|
||||
error,
|
||||
save,
|
||||
remove,
|
||||
deleting,
|
||||
saveAsCopy,
|
||||
isBatch,
|
||||
} = useItem(ref('directus_webhooks'), primaryKey);
|
||||
const { isNew, edits, item, saving, loading, error, save, remove, deleting, saveAsCopy, isBatch } = useItem(
|
||||
ref('directus_webhooks'),
|
||||
primaryKey
|
||||
);
|
||||
|
||||
const hasEdits = computed<boolean>(() => Object.keys(edits.value).length > 0);
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user