Update spec service to use m2a

This commit is contained in:
rijkvanzanten
2020-10-12 14:16:54 -04:00
115 changed files with 5619 additions and 2359 deletions

View File

@@ -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">

View File

@@ -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({

View File

@@ -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>

View File

@@ -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;
}
});

View File

@@ -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>

View File

@@ -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>

View File

@@ -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;
}

View File

@@ -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() {

View File

@@ -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');
}

View File

@@ -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 {