mirror of
https://github.com/directus/directus.git
synced 2026-02-13 14:54:58 -05:00
Update spec service to use m2a
This commit is contained in:
@@ -1,19 +1,34 @@
|
||||
<template>
|
||||
<v-list large>
|
||||
<template v-if="customNavItems && customNavItems.length > 0">
|
||||
<v-detail
|
||||
:active="group.accordion === 'always_open' || undefined"
|
||||
:disabled="group.accordion === 'always_open'"
|
||||
:start-open="group.accordion === 'start_open'"
|
||||
:label="group.name"
|
||||
:key="group.name"
|
||||
v-for="group in customNavItems"
|
||||
>
|
||||
<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>
|
||||
</v-detail>
|
||||
<template v-for="(group, index) in customNavItems">
|
||||
<template
|
||||
v-if="
|
||||
(group.name === undefined || group.name === null) &&
|
||||
group.accordion === 'always_open' &&
|
||||
index === 0
|
||||
"
|
||||
>
|
||||
<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>
|
||||
</template>
|
||||
<template v-else>
|
||||
<v-detail
|
||||
:active="group.accordion === 'always_open' || undefined"
|
||||
:disabled="group.accordion === 'always_open'"
|
||||
:start-open="group.accordion === 'start_open'"
|
||||
:label="group.name || null"
|
||||
:key="group.name"
|
||||
>
|
||||
<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>
|
||||
</v-detail>
|
||||
</template>
|
||||
</template>
|
||||
</template>
|
||||
|
||||
<v-list-item v-else :exact="exact" v-for="navItem in navItems" :key="navItem.to" :to="navItem.to">
|
||||
|
||||
@@ -1,21 +1,16 @@
|
||||
<template>
|
||||
<v-divider v-if="section.divider" />
|
||||
<v-list-group v-else-if="section.children" :dense="dense">
|
||||
<v-list-group v-else-if="section.children" :dense="dense" :multiple="false" :value="section.to">
|
||||
<template #activator>
|
||||
<v-list-item-icon v-if="section.icon !== undefined"><v-icon :name="section.icon" /></v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-text>{{ section.name }}</v-list-item-text>
|
||||
</v-list-item-content>
|
||||
</template>
|
||||
<navigation-list-item
|
||||
v-for="(childSection, index) in section.children"
|
||||
:key="index"
|
||||
:section="childSection"
|
||||
dense
|
||||
/>
|
||||
<navigation-list-item v-for="(child, index) in section.children" :key="index" :section="child" dense />
|
||||
</v-list-group>
|
||||
|
||||
<v-list-item v-else :to="`/docs${section.to}`" :dense="dense">
|
||||
<v-list-item v-else :to="`/docs${section.to}`" :dense="dense" :value="section.to">
|
||||
<v-list-item-icon v-if="section.icon !== undefined"><v-icon :name="section.icon" /></v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-text>{{ section.name }}</v-list-item-text>
|
||||
@@ -24,7 +19,7 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from '@vue/composition-api';
|
||||
import { defineComponent, PropType, computed } from '@vue/composition-api';
|
||||
import { Link, Group } from '@directus/docs';
|
||||
|
||||
export default defineComponent({
|
||||
|
||||
@@ -1,18 +1,65 @@
|
||||
<template>
|
||||
<v-list large>
|
||||
<v-list large :multiple="false" v-model="selection" :mandatory="false">
|
||||
<navigation-item v-for="item in navSections" :key="item.name" :section="item" />
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType, computed } from '@vue/composition-api';
|
||||
import { defineComponent, PropType, computed, watch, ref } from '@vue/composition-api';
|
||||
import NavigationItem from './navigation-item.vue';
|
||||
import { nav } from '@directus/docs';
|
||||
|
||||
function spreadPath(path: string) {
|
||||
const sections = path.substr(1).split('/');
|
||||
if (sections.length === 0) return [];
|
||||
|
||||
const paths: string[] = ['/' + sections[0]];
|
||||
|
||||
for (let i = 1; i < sections.length; i++) {
|
||||
paths.push(paths[i - 1] + '/' + sections[i]);
|
||||
}
|
||||
return paths;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
components: { NavigationItem },
|
||||
setup() {
|
||||
return { navSections: nav.app };
|
||||
props: {
|
||||
path: {
|
||||
type: String,
|
||||
default: '/docs',
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const _selection = ref<string[] | null>(null);
|
||||
|
||||
watch(
|
||||
() => props.path,
|
||||
(newPath) => {
|
||||
if (newPath === null) return;
|
||||
_selection.value = spreadPath(newPath.replace('/docs', ''));
|
||||
}
|
||||
);
|
||||
|
||||
const selection = computed({
|
||||
get() {
|
||||
if (_selection.value === null && props.path !== null)
|
||||
_selection.value = spreadPath(props.path.replace('/docs', ''));
|
||||
return _selection.value || [];
|
||||
},
|
||||
set(newSelection: string[]) {
|
||||
if (newSelection.length === 0) {
|
||||
_selection.value = [];
|
||||
} else {
|
||||
if (_selection.value && _selection.value.includes(newSelection[0])) {
|
||||
_selection.value = _selection.value.filter((s) => s !== newSelection[0]);
|
||||
} else {
|
||||
_selection.value = spreadPath(newSelection[0]);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
return { navSections: nav.app, selection };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -31,19 +31,19 @@ export default defineModule(({ i18n }) => {
|
||||
for (const doc of directory.children) {
|
||||
if (doc.type === 'file') {
|
||||
routes.push({
|
||||
path: '/' + doc.path.replace('.md', ''),
|
||||
path: '/' + doc.path.replace('.md', '').replaceAll('\\', '/'),
|
||||
component: StaticDocs,
|
||||
});
|
||||
} else if (doc.type === 'directory') {
|
||||
routes.push({
|
||||
path: '/' + doc.path,
|
||||
redirect: '/' + doc.children![0].path.replace('.md', ''),
|
||||
});
|
||||
if (doc.path && doc.children && doc.children.length > 0)
|
||||
routes.push({
|
||||
path: '/' + doc.path.replaceAll('\\', '/'),
|
||||
redirect: '/' + doc.children![0].path.replace('.md', '').replaceAll('\\', '/'),
|
||||
});
|
||||
|
||||
routes.push(...parseRoutes(doc));
|
||||
}
|
||||
}
|
||||
|
||||
return routes;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<private-view :title="$t('page_not_found')">
|
||||
<template #navigation>
|
||||
<docs-navigation />
|
||||
<docs-navigation :path="path" />
|
||||
</template>
|
||||
|
||||
<div class="not-found">
|
||||
@@ -13,12 +13,25 @@
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from '@vue/composition-api';
|
||||
import { defineComponent, ref } from '@vue/composition-api';
|
||||
import DocsNavigation from '../components/navigation.vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NotFound',
|
||||
components: { DocsNavigation },
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
next((vm: any) => {
|
||||
vm.path = to.path;
|
||||
});
|
||||
},
|
||||
async beforeRouteUpdate(to, from, next) {
|
||||
this.path = to.path;
|
||||
next();
|
||||
},
|
||||
setup() {
|
||||
const path = ref<string | null>(null);
|
||||
return { path };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
</template>
|
||||
|
||||
<template #navigation>
|
||||
<docs-navigation />
|
||||
<docs-navigation :path="path" />
|
||||
</template>
|
||||
|
||||
<div class="docs-content selectable">
|
||||
@@ -55,16 +55,18 @@ export default defineComponent({
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
const md = await getMarkdownForPath(to.path);
|
||||
|
||||
next((vm) => {
|
||||
(vm as any).markdown = md;
|
||||
next((vm: any) => {
|
||||
vm.markdown = md;
|
||||
vm.path = to.path;
|
||||
});
|
||||
},
|
||||
async beforeRouteUpdate(to, from, next) {
|
||||
this.markdown = await getMarkdownForPath(to.path);
|
||||
|
||||
this.path = to.path;
|
||||
next();
|
||||
},
|
||||
setup() {
|
||||
const path = ref<string | null>(null);
|
||||
const markdown = ref('');
|
||||
const view = ref<Vue>();
|
||||
|
||||
@@ -83,7 +85,7 @@ export default defineComponent({
|
||||
view.value?.$data.contentEl?.scrollTo({ top: 0 });
|
||||
});
|
||||
|
||||
return { markdown, title, markdownWithoutTitle, view, marked };
|
||||
return { markdown, title, markdownWithoutTitle, view, marked, path };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -41,11 +41,25 @@
|
||||
<dd>{{ file.checksum }}</dd>
|
||||
</div>
|
||||
|
||||
<div v-if="user">
|
||||
<div v-if="user_created">
|
||||
<dt>{{ $t('owner') }}</dt>
|
||||
<dd>
|
||||
<user-popover :user="user.id">
|
||||
<router-link :to="user.link">{{ user.name }}</router-link>
|
||||
<user-popover :user="user_created.id">
|
||||
<router-link :to="user_created.link">{{ user_created.name }}</router-link>
|
||||
</user-popover>
|
||||
</dd>
|
||||
</div>
|
||||
|
||||
<div v-if="modificationDate">
|
||||
<dt>{{ $t('modified') }}</dt>
|
||||
<dd>{{ modificationDate }}</dd>
|
||||
</div>
|
||||
|
||||
<div v-if="user_modified">
|
||||
<dt>{{ $t('edited_by') }}</dt>
|
||||
<dd>
|
||||
<user-popover :user="user_modified.id">
|
||||
<router-link :to="user_modified.link">{{ user_modified.name }}</router-link>
|
||||
</user-popover>
|
||||
</dd>
|
||||
</div>
|
||||
@@ -123,14 +137,15 @@ export default defineComponent({
|
||||
return bytes(props.file.filesize, { decimalPlaces: 2, unitSeparator: ' ' }); // { locale: i18n.locale.split('-')[0] }
|
||||
});
|
||||
|
||||
const { creationDate } = useCreationDate();
|
||||
const { user } = useUser();
|
||||
const { creationDate, modificationDate } = useDates();
|
||||
const { userCreated, userModified } = useUser();
|
||||
const { folder } = useFolder();
|
||||
|
||||
return { readableMimeType, size, creationDate, user, folder, marked };
|
||||
return { readableMimeType, size, creationDate, modificationDate, userCreated, userModified, folder, marked };
|
||||
|
||||
function useCreationDate() {
|
||||
function useDates() {
|
||||
const creationDate = ref<string | null>(null);
|
||||
const modificationDate = ref<string | null>(null);
|
||||
|
||||
watch(
|
||||
() => props.file,
|
||||
@@ -141,11 +156,18 @@ export default defineComponent({
|
||||
new Date(props.file.uploaded_on),
|
||||
String(i18n.t('date-fns_date_short'))
|
||||
);
|
||||
|
||||
if (props.file.modified_on) {
|
||||
modificationDate.value = await localizedFormat(
|
||||
new Date(props.file.modified_on),
|
||||
String(i18n.t('date-fns_date_short'))
|
||||
);
|
||||
}
|
||||
},
|
||||
{ immediate: true }
|
||||
);
|
||||
|
||||
return { creationDate };
|
||||
return { creationDate, modificationDate };
|
||||
}
|
||||
|
||||
function useUser() {
|
||||
@@ -156,11 +178,12 @@ export default defineComponent({
|
||||
};
|
||||
|
||||
const loading = ref(false);
|
||||
const user = ref<User | null>(null);
|
||||
const userCreated = ref<User | null>(null);
|
||||
const userModified = ref<User | null>(null);
|
||||
|
||||
watch(() => props.file, fetchUser, { immediate: true });
|
||||
|
||||
return { user };
|
||||
return { userCreated, userModified };
|
||||
|
||||
async function fetchUser() {
|
||||
if (!props.file) return null;
|
||||
@@ -177,11 +200,27 @@ export default defineComponent({
|
||||
|
||||
const { id, first_name, last_name, role } = response.data.data;
|
||||
|
||||
user.value = {
|
||||
userCreated.value = {
|
||||
id: props.file.uploaded_by,
|
||||
name: first_name + ' ' + last_name,
|
||||
link: `/users/${id}`,
|
||||
};
|
||||
|
||||
if (props.file.modified_by) {
|
||||
const response = await api.get(`/users/${props.file.modified_by}`, {
|
||||
params: {
|
||||
fields: ['id', 'first_name', 'last_name', 'role'],
|
||||
},
|
||||
});
|
||||
|
||||
const { id, first_name, last_name, role } = response.data.data;
|
||||
|
||||
userModified.value = {
|
||||
id: props.file.modified_by,
|
||||
name: first_name + ' ' + last_name,
|
||||
link: `/users/${id}`,
|
||||
};
|
||||
}
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
|
||||
@@ -274,6 +274,8 @@ export default defineComponent({
|
||||
'checksum',
|
||||
'uploaded_by',
|
||||
'uploaded_on',
|
||||
'modified_by',
|
||||
'modified_on',
|
||||
'duration',
|
||||
'folder',
|
||||
'charset',
|
||||
@@ -287,9 +289,9 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
const to = computed(() => {
|
||||
if(item.value && item.value?.folder) return `/files?folder=${item.value.folder}`
|
||||
else return '/files'
|
||||
})
|
||||
if (item.value && item.value?.folder) return `/files?folder=${item.value.folder}`;
|
||||
else return '/files';
|
||||
});
|
||||
|
||||
const { formFields } = useFormFields(fieldsFiltered);
|
||||
|
||||
@@ -332,7 +334,7 @@ export default defineComponent({
|
||||
selectedFolder,
|
||||
fileSrc,
|
||||
form,
|
||||
to
|
||||
to,
|
||||
};
|
||||
|
||||
function changeCacheBuster() {
|
||||
|
||||
@@ -178,6 +178,7 @@ export default defineComponent({
|
||||
interface: 'one-to-many',
|
||||
},
|
||||
});
|
||||
state.relations[0].one_field = state.relations[0].one_collection;
|
||||
} else {
|
||||
state.newFields = state.newFields.filter((field: any) => field.$type !== 'corresponding');
|
||||
}
|
||||
|
||||
@@ -26,19 +26,25 @@
|
||||
<v-tabs-items v-model="currentTab">
|
||||
<v-tab-item value="collection">
|
||||
<h2 class="type-title">{{ $t('creating_collection_info') }}</h2>
|
||||
<div class="type-label">
|
||||
{{ $t('name') }}
|
||||
<v-icon class="required" v-tooltip="$t('required')" name="star" sup />
|
||||
</div>
|
||||
<v-input
|
||||
autofocus
|
||||
class="monospace"
|
||||
v-model="collectionName"
|
||||
db-safe
|
||||
:placeholder="$t('a_unique_table_name')"
|
||||
/>
|
||||
<v-divider />
|
||||
<div class="grid">
|
||||
<div>
|
||||
<div class="type-label">
|
||||
{{ $t('name') }}
|
||||
<v-icon class="required" v-tooltip="$t('required')" name="star" sup />
|
||||
</div>
|
||||
<v-input
|
||||
autofocus
|
||||
class="monospace"
|
||||
v-model="collectionName"
|
||||
db-safe
|
||||
:placeholder="$t('a_unique_table_name')"
|
||||
/>
|
||||
</div>
|
||||
<div>
|
||||
<div class="type-label">{{ $t('singleton') }}</div>
|
||||
<v-checkbox block :label="$t('singleton_label')" v-model="singleton" />
|
||||
</div>
|
||||
<v-divider class="full" />
|
||||
<div>
|
||||
<div class="type-label">{{ $t('primary_key_field') }}</div>
|
||||
<v-input
|
||||
@@ -73,9 +79,14 @@
|
||||
<v-tab-item value="system">
|
||||
<h2 class="type-title">{{ $t('creating_collection_system') }}</h2>
|
||||
<div class="grid system">
|
||||
<div class="field" v-for="(info, field) in systemFields" :key="field">
|
||||
<div v-for="(info, field) in systemFields" :key="field">
|
||||
<div class="type-label">{{ $t(info.label) }}</div>
|
||||
<v-input v-model="info.name" class="monospace" :class="{active: info.enabled}" @click.native="info.enabled = true">
|
||||
<v-input
|
||||
v-model="info.name"
|
||||
class="monospace"
|
||||
:class="{ active: info.enabled }"
|
||||
@click.native="info.enabled = true"
|
||||
>
|
||||
<template #prepend>
|
||||
<v-checkbox v-model="info.enabled" />
|
||||
</template>
|
||||
@@ -124,6 +135,7 @@ export default defineComponent({
|
||||
const currentTab = ref(['collection']);
|
||||
|
||||
const collectionName = ref(null);
|
||||
const singleton = ref(false);
|
||||
const primaryKeyFieldName = ref('id');
|
||||
const primaryKeyFieldType = ref<'auto_int' | 'uuid' | 'manual'>('auto_int');
|
||||
|
||||
@@ -184,6 +196,7 @@ export default defineComponent({
|
||||
collectionName,
|
||||
saveError,
|
||||
saving,
|
||||
singleton,
|
||||
};
|
||||
|
||||
async function save() {
|
||||
@@ -198,6 +211,7 @@ export default defineComponent({
|
||||
archive_field: archiveField.value,
|
||||
archive_value: archiveValue.value,
|
||||
unarchive_value: unarchiveValue.value,
|
||||
singleton: singleton.value,
|
||||
},
|
||||
});
|
||||
|
||||
@@ -412,22 +426,14 @@ export default defineComponent({
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
@import '@/styles/mixins/form-grid';
|
||||
|
||||
.type-title {
|
||||
margin-bottom: 48px;
|
||||
}
|
||||
|
||||
.type-label {
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.v-divider {
|
||||
margin: 48px 0;
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-gap: 48px 36px;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
@include form-grid;
|
||||
}
|
||||
|
||||
.system {
|
||||
|
||||
Reference in New Issue
Block a user