mirror of
https://github.com/directus/directus.git
synced 2026-01-29 00:27:59 -05:00
Merge branch 'main' into feature-redis-cache
This commit is contained in:
@@ -79,7 +79,9 @@ router.patch(
|
||||
return res.json({ data: item || null });
|
||||
}
|
||||
|
||||
throw new RouteNotFoundException(req.path);
|
||||
const primaryKeys = await service.update(req.body);
|
||||
const result = await service.readByKey(primaryKeys, req.sanitizedQuery);
|
||||
return res.json({ data: result || null });
|
||||
})
|
||||
);
|
||||
|
||||
@@ -96,7 +98,6 @@ router.patch(
|
||||
const primaryKey = req.params.pk.includes(',') ? req.params.pk.split(',') : req.params.pk;
|
||||
|
||||
const updatedPrimaryKey = await service.update(req.body, primaryKey as any);
|
||||
|
||||
const result = await service.readByKey(updatedPrimaryKey, req.sanitizedQuery);
|
||||
|
||||
res.json({ data: result || null });
|
||||
|
||||
@@ -22,6 +22,9 @@ tables:
|
||||
display_template:
|
||||
type: string
|
||||
length: 255
|
||||
sort_field:
|
||||
type: string
|
||||
length: 64
|
||||
|
||||
directus_roles:
|
||||
id:
|
||||
@@ -84,6 +87,8 @@ tables:
|
||||
type: text
|
||||
tags:
|
||||
type: json
|
||||
avatar:
|
||||
type: uuid
|
||||
timezone:
|
||||
type: string
|
||||
length: 255
|
||||
@@ -115,8 +120,6 @@ tables:
|
||||
length: 255
|
||||
last_login:
|
||||
type: timestamp
|
||||
avatar:
|
||||
type: uuid
|
||||
last_page:
|
||||
type: string
|
||||
length: 255
|
||||
@@ -628,6 +631,8 @@ rows:
|
||||
- collection: directus_roles
|
||||
field: name
|
||||
interface: text-input
|
||||
options:
|
||||
placeholder: The unique name for this role...
|
||||
locked: true
|
||||
sort: 1
|
||||
width: half
|
||||
|
||||
16
app/src/components/v-icon/custom-icons/directus.vue
Normal file
16
app/src/components/v-icon/custom-icons/directus.vue
Normal file
@@ -0,0 +1,16 @@
|
||||
<template functional>
|
||||
<svg
|
||||
viewBox="0 0 24 24"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
fill-rule="evenodd"
|
||||
clip-rule="evenodd"
|
||||
stroke-linejoin="round"
|
||||
stroke-miterlimit="2"
|
||||
>
|
||||
<path fill-rule="evenodd" clip-rule="evenodd" d="M19.2 14.15a1.8 1.8 0 01-.35-.12c-.1-.05-.14-.18-.13-.3.02-.41-.01-.78.03-1.2.18-1.85 1.38-1.26 2.46-1.57.58-.16 1.17-.47 1.42-1.06.07-.16.02-.35-.1-.48a13.66 13.66 0 00-2.27-1.98 14.25 14.25 0 00-9.85-2.31.2.2 0 00-.15.32A5.17 5.17 0 0011.93 7c.1.06.06.2-.06.18-.3-.06-.68-.18-1.06-.4a.43.43 0 00-.38-.05l-.44.18a.2.2 0 00-.05.34 5.32 5.32 0 006.14.42c.1-.06.25.07.22.18-.07.21-.15.52-.23.95-.48 2.37-1.87 2.18-3.58 1.59-3.36-1.19-5.3-.22-7-2.1-.19-.21-.5-.29-.7-.09a1.55 1.55 0 00.1 2.29c.15.12.36.07.5-.06.07-.06.13-.1.21-.14.1-.04.16.11.07.18-.4.33-.51.7-.76 1.48-.38 1.16-.22 2.36-1.98 2.67-.93.04-.91.66-1.25 1.58A5.2 5.2 0 01.3 18.27c-.4.41-.44 1.18.14 1.23.18 0 .36-.03.55-.1.99-.4 1.75-1.65 2.47-2.46.8-.9 2.72-.51 4.17-1.4.82-.48 1.3-1.1 1.08-2.07-.02-.12.12-.2.18-.09.1.2.18.41.23.63.05.22.25.39.47.4 1.36.1 3.02 1.3 4.63 1.88.32.11.56-.26.43-.57-.1-.24-.18-.48-.23-.7-.02-.13.16-.16.22-.05a3.5 3.5 0 002.88 1.88c.46.03.97-.02 1.5-.18.63-.18 1.22-.42 1.91-.3.52.1 1 .36 1.3.79.36.5 1.04.7 1.54.38.28-.19.29-.58.13-.87-1.14-2.08-3.61-2.25-4.7-2.52z"/>
|
||||
</svg>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
export default {};
|
||||
</script>
|
||||
@@ -15,6 +15,7 @@
|
||||
import { defineComponent, computed } from '@vue/composition-api';
|
||||
import useSizeClass, { sizeProps } from '@/composables/size-class';
|
||||
|
||||
import CustomIconDirectus from './custom-icons/directus.vue';
|
||||
import CustomIconBox from './custom-icons/box.vue';
|
||||
import CustomIconCommitNode from './custom-icons/commit_node.vue';
|
||||
import CustomIconGrid1 from './custom-icons/grid_1.vue';
|
||||
@@ -31,6 +32,7 @@ import CustomIconFlipVertical from './custom-icons/flip_vertical.vue';
|
||||
import CustomIconFolderMove from './custom-icons/folder_move.vue';
|
||||
|
||||
const customIcons: string[] = [
|
||||
'directus',
|
||||
'box',
|
||||
'commit_node',
|
||||
'grid_1',
|
||||
@@ -49,6 +51,7 @@ const customIcons: string[] = [
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
CustomIconDirectus,
|
||||
CustomIconBox,
|
||||
CustomIconCommitNode,
|
||||
CustomIconGrid1,
|
||||
|
||||
@@ -120,10 +120,14 @@ body {
|
||||
@keyframes indeterminate {
|
||||
0% {
|
||||
transform: scaleX(0);
|
||||
}
|
||||
|
||||
10% {
|
||||
transform: scaleX(0);
|
||||
animation-timing-function: cubic-bezier(0.1, 0.6, 0.9, 0.5);
|
||||
}
|
||||
|
||||
50% {
|
||||
60% {
|
||||
transform: scaleX(1) translateX(25%);
|
||||
animation-timing-function: cubic-bezier(0.4, 0.1, 0.2, 0.9);
|
||||
}
|
||||
|
||||
@@ -33,7 +33,7 @@ export function useCollection(collectionKey: string | Ref<string>) {
|
||||
});
|
||||
|
||||
const sortField = computed(() => {
|
||||
return fields.value?.find((field) => field.meta?.special === 'sort') || null;
|
||||
return info.value?.meta?.sort_field || null;
|
||||
});
|
||||
|
||||
type Status = {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
useSettingsStore,
|
||||
useLatencyStore,
|
||||
useRelationsStore,
|
||||
usePermissionsStore,
|
||||
} from '@/stores';
|
||||
|
||||
import { setLanguage, Language } from '@/lang';
|
||||
@@ -30,6 +31,7 @@ export function useStores(
|
||||
useSettingsStore,
|
||||
useLatencyStore,
|
||||
useRelationsStore,
|
||||
usePermissionsStore,
|
||||
]
|
||||
) {
|
||||
return stores.map((useStore) => useStore()) as GenericStore[];
|
||||
|
||||
@@ -13,6 +13,7 @@ import InterfaceIcon from './icon';
|
||||
import InterfaceImage from './image';
|
||||
import InterfaceManyToMany from './many-to-many';
|
||||
import InterfaceManyToOne from './many-to-one';
|
||||
import InterfaceMarkdown from './markdown';
|
||||
import InterfaceNotice from './notice';
|
||||
import InterfaceNumeric from './numeric/';
|
||||
import InterfaceOneToMany from './one-to-many';
|
||||
@@ -45,6 +46,7 @@ export const interfaces = [
|
||||
InterfaceImage,
|
||||
InterfaceManyToMany,
|
||||
InterfaceManyToOne,
|
||||
InterfaceMarkdown,
|
||||
InterfaceNotice,
|
||||
InterfaceNumeric,
|
||||
InterfaceOneToMany,
|
||||
|
||||
132
app/src/interfaces/markdown/demo.md
Normal file
132
app/src/interfaces/markdown/demo.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# h1 Heading
|
||||
## h2 Heading
|
||||
### h3 Heading
|
||||
#### h4 Heading
|
||||
##### h5 Heading
|
||||
###### h6 Heading
|
||||
|
||||
|
||||
## Horizontal Rules
|
||||
|
||||
___
|
||||
|
||||
---
|
||||
|
||||
***
|
||||
|
||||
|
||||
## Emphasis
|
||||
|
||||
**This is bold text**
|
||||
|
||||
__This is bold text__
|
||||
|
||||
*This is italic text*
|
||||
|
||||
_This is italic text_
|
||||
|
||||
~~Strikethrough~~
|
||||
|
||||
|
||||
## Blockquotes
|
||||
|
||||
|
||||
> Blockquotes can also be nested...
|
||||
>> ...by using additional greater-than signs right next to each other...
|
||||
> > > ...or with spaces between arrows.
|
||||
|
||||
|
||||
## Lists
|
||||
|
||||
Unordered
|
||||
|
||||
+ Create a list by starting a line with `+`, `-`, or `*`
|
||||
+ Sub-lists are made by indenting 2 spaces:
|
||||
- Marker character change forces new list start:
|
||||
* Ac tristique libero volutpat at
|
||||
+ Facilisis in pretium nisl aliquet
|
||||
- Nulla volutpat aliquam velit
|
||||
+ Very easy!
|
||||
|
||||
Ordered
|
||||
|
||||
1. Lorem ipsum dolor sit amet
|
||||
2. Consectetur adipiscing elit
|
||||
3. Integer molestie lorem at massa
|
||||
|
||||
|
||||
1. You can use sequential numbers...
|
||||
1. ...or keep all the numbers as `1.`
|
||||
|
||||
Start numbering with offset:
|
||||
|
||||
57. foo
|
||||
1. bar
|
||||
|
||||
|
||||
## Code
|
||||
|
||||
Inline `code`
|
||||
|
||||
Indented code
|
||||
|
||||
// Some comments
|
||||
line 1 of code
|
||||
line 2 of code
|
||||
line 3 of code
|
||||
|
||||
|
||||
Block code "fences"
|
||||
|
||||
```
|
||||
Sample text here...
|
||||
```
|
||||
|
||||
Syntax highlighting
|
||||
|
||||
``` js
|
||||
var foo = function (bar) {
|
||||
return bar++;
|
||||
};
|
||||
|
||||
console.log(foo(5));
|
||||
```
|
||||
|
||||
## Tables
|
||||
|
||||
| Option | Description |
|
||||
| ------ | ----------- |
|
||||
| data | path to data files to supply the data that will be passed into templates. |
|
||||
| engine | engine to be used for processing templates. Handlebars is the default. |
|
||||
| ext | extension to be used for dest files. |
|
||||
|
||||
Right aligned columns
|
||||
|
||||
| Option | Description |
|
||||
| ------:| -----------:|
|
||||
| data | path to data files to supply the data that will be passed into templates. |
|
||||
| engine | engine to be used for processing templates. Handlebars is the default. |
|
||||
| ext | extension to be used for dest files. |
|
||||
|
||||
|
||||
## Links
|
||||
|
||||
[link text](http://dev.nodeca.com)
|
||||
|
||||
[link with title](http://nodeca.github.io/pica/demo/ "title text!")
|
||||
|
||||
Autoconverted link https://github.com/nodeca/pica (enable linkify to see)
|
||||
|
||||
|
||||
## Images
|
||||
|
||||

|
||||

|
||||
|
||||
Like links, Images also have a footnote style syntax
|
||||
|
||||
![Alt text][id]
|
||||
|
||||
With a reference later in the document defining the URL location:
|
||||
|
||||
[id]: https://octodex.github.com/images/dojocat.jpg "The Dojocat"
|
||||
30
app/src/interfaces/markdown/index.ts
Normal file
30
app/src/interfaces/markdown/index.ts
Normal file
@@ -0,0 +1,30 @@
|
||||
import InterfaceMarkdown from './markdown.vue';
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
|
||||
export default defineInterface(({ i18n }) => ({
|
||||
id: 'markdown',
|
||||
name: i18n.t('markdown'),
|
||||
icon: 'text_fields',
|
||||
component: InterfaceMarkdown,
|
||||
types: ['text'],
|
||||
options: [
|
||||
{
|
||||
field: 'placeholder',
|
||||
name: i18n.t('placeholder'),
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'text-input',
|
||||
},
|
||||
},
|
||||
{
|
||||
field: 'tabbed',
|
||||
name: i18n.t('tabbed'),
|
||||
type: 'boolean',
|
||||
meta: {
|
||||
width: 'half',
|
||||
interface: 'toggle',
|
||||
},
|
||||
},
|
||||
],
|
||||
}));
|
||||
51
app/src/interfaces/markdown/markdown.story.ts
Normal file
51
app/src/interfaces/markdown/markdown.story.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { withKnobs, boolean, text, optionsKnob } from '@storybook/addon-knobs';
|
||||
import { action } from '@storybook/addon-actions';
|
||||
import Vue from 'vue';
|
||||
import InterfaceMarkdown from './markdown.vue';
|
||||
import markdown from './readme.md';
|
||||
import withPadding from '../../../.storybook/decorators/with-padding';
|
||||
import { defineComponent, ref } from '@vue/composition-api';
|
||||
import RawValue from '../../../.storybook/raw-value.vue';
|
||||
import i18n from '@/lang';
|
||||
|
||||
Vue.component('interface-markdown', InterfaceMarkdown);
|
||||
|
||||
export default {
|
||||
title: 'Interfaces / Markdown',
|
||||
decorators: [withKnobs, withPadding],
|
||||
parameters: {
|
||||
notes: markdown,
|
||||
},
|
||||
};
|
||||
|
||||
export const basic = () =>
|
||||
defineComponent({
|
||||
components: { RawValue },
|
||||
i18n,
|
||||
props: {
|
||||
disabled: {
|
||||
default: boolean('Disabled', false, 'Options'),
|
||||
},
|
||||
placeholder: {
|
||||
default: text('Placeholder', 'Enter a value...', 'Options'),
|
||||
},
|
||||
tabbed: {
|
||||
default: boolean('Tabbed', false, 'Options'),
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
const value = ref('');
|
||||
const onInput = action('input');
|
||||
return { onInput, value };
|
||||
},
|
||||
template: `
|
||||
<div>
|
||||
<interface-markdown
|
||||
v-model="value"
|
||||
v-bind="{ placeholder, tabbed, disabled }"
|
||||
@input="onInput"
|
||||
/>
|
||||
<raw-value>{{ value }}</raw-value>
|
||||
</div>
|
||||
`,
|
||||
});
|
||||
24
app/src/interfaces/markdown/markdown.test.ts
Normal file
24
app/src/interfaces/markdown/markdown.test.ts
Normal file
@@ -0,0 +1,24 @@
|
||||
import VueCompositionAPI from '@vue/composition-api';
|
||||
import { shallowMount, createLocalVue } from '@vue/test-utils';
|
||||
import InterfaceMarkdown from './markdown.vue';
|
||||
|
||||
import VTextarea from '@/components/v-textarea';
|
||||
|
||||
const localVue = createLocalVue();
|
||||
localVue.use(VueCompositionAPI);
|
||||
localVue.component('v-textarea', VTextarea);
|
||||
|
||||
describe('Interfaces / Markdown', () => {
|
||||
it('Renders a v-markdown', () => {
|
||||
const component = shallowMount(InterfaceMarkdown, {
|
||||
localVue,
|
||||
propsData: {
|
||||
placeholder: 'Enter value...',
|
||||
},
|
||||
listeners: {
|
||||
input: () => {},
|
||||
},
|
||||
});
|
||||
expect(component.find(VTextarea).exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
340
app/src/interfaces/markdown/markdown.vue
Normal file
340
app/src/interfaces/markdown/markdown.vue
Normal file
@@ -0,0 +1,340 @@
|
||||
<template>
|
||||
<div class="interface-markdown" :class="{ tabbed }">
|
||||
<div v-if="tabbed" class="toolbar">
|
||||
<v-tabs v-model="currentTab">
|
||||
<v-tab>
|
||||
<v-icon name="code" left />
|
||||
{{ $t('edit') }}
|
||||
</v-tab>
|
||||
<v-tab>
|
||||
<v-icon name="visibility" left />
|
||||
{{ $t('preview') }}
|
||||
</v-tab>
|
||||
</v-tabs>
|
||||
</div>
|
||||
<v-textarea
|
||||
v-show="showEdit"
|
||||
:placeholder="placeholder"
|
||||
:value="value"
|
||||
:disabled="disabled"
|
||||
@input="$listeners.input"
|
||||
/>
|
||||
<div v-show="showPreview" class="preview-container">
|
||||
<div class="preview" v-html="html"></div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import marked from 'marked';
|
||||
import { defineComponent, computed, ref } from '@vue/composition-api';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
disabled: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
placeholder: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
tabbed: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const currentTab = ref([0]);
|
||||
|
||||
const html = computed(() => (props.value ? marked(props.value) : ''));
|
||||
const showEdit = computed(() => !props.tabbed || currentTab.value[0] === 0);
|
||||
const showPreview = computed(() => !props.tabbed || currentTab.value[0] !== 0);
|
||||
|
||||
return { html, currentTab, showEdit, showPreview };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.interface-markdown {
|
||||
--v-textarea-min-height: var(--input-height-tall);
|
||||
--v-textarea-max-height: 400px;
|
||||
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.toolbar {
|
||||
width: 100%;
|
||||
border: var(--border-width) solid var(--border-normal);
|
||||
}
|
||||
|
||||
.v-textarea {
|
||||
height: unset;
|
||||
border-radius: var(--border-radius) 0 0 var(--border-radius);
|
||||
}
|
||||
|
||||
.preview-container {
|
||||
min-height: var(--v-textarea-min-height);
|
||||
max-height: var(--v-textarea-max-height);
|
||||
padding: var(--input-padding);
|
||||
overflow-y: auto;
|
||||
border: var(--border-width) solid var(--border-normal);
|
||||
border-radius: 0 var(--border-radius) var(--border-radius) 0;
|
||||
}
|
||||
|
||||
.v-textarea,
|
||||
.preview-container {
|
||||
flex-basis: 100px;
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
&:not(.tabbed) .preview-container {
|
||||
border-left: none;
|
||||
}
|
||||
|
||||
&.tabbed .v-textarea {
|
||||
border-top: none;
|
||||
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
||||
}
|
||||
|
||||
&.tabbed .preview-container {
|
||||
border-top: none;
|
||||
border-radius: 0 0 var(--border-radius) var(--border-radius);
|
||||
}
|
||||
|
||||
::v-deep {
|
||||
.preview {
|
||||
font-weight: 400;
|
||||
font-size: 14px;
|
||||
line-height: 1.6;
|
||||
& > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
& > *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
position: relative;
|
||||
margin: 20px 0 10px;
|
||||
padding: 0;
|
||||
font-weight: 600;
|
||||
cursor: text;
|
||||
}
|
||||
pre {
|
||||
padding: 6px 10px;
|
||||
overflow: auto;
|
||||
font-size: 13px;
|
||||
line-height: 19px;
|
||||
background-color: var(--background-page);
|
||||
border: 1px solid var(--background-normal);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
code,
|
||||
tt {
|
||||
margin: 0 2px;
|
||||
padding: 0 5px;
|
||||
white-space: nowrap;
|
||||
background-color: var(--background-page);
|
||||
border: 1px solid var(--background-normal);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
pre code {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
white-space: pre;
|
||||
background: transparent;
|
||||
border: none;
|
||||
}
|
||||
pre code,
|
||||
pre tt {
|
||||
background-color: transparent;
|
||||
border: none;
|
||||
}
|
||||
h1 tt,
|
||||
h1 code {
|
||||
font-size: inherit;
|
||||
}
|
||||
h2 tt,
|
||||
h2 code {
|
||||
font-size: inherit;
|
||||
}
|
||||
h3 tt,
|
||||
h3 code {
|
||||
font-size: inherit;
|
||||
}
|
||||
h4 tt,
|
||||
h4 code {
|
||||
font-size: inherit;
|
||||
}
|
||||
h5 tt,
|
||||
h5 code {
|
||||
font-size: inherit;
|
||||
}
|
||||
h6 tt,
|
||||
h6 code {
|
||||
font-size: inherit;
|
||||
}
|
||||
h1 {
|
||||
font-size: 28px;
|
||||
}
|
||||
h2 {
|
||||
font-size: 24px;
|
||||
}
|
||||
h3 {
|
||||
font-size: 18px;
|
||||
}
|
||||
h4 {
|
||||
font-size: 16px;
|
||||
}
|
||||
h5 {
|
||||
font-size: 14px;
|
||||
}
|
||||
h6 {
|
||||
color: var(--foreground-normal);
|
||||
font-size: 14px;
|
||||
}
|
||||
p,
|
||||
blockquote,
|
||||
ul,
|
||||
ol,
|
||||
dl,
|
||||
li,
|
||||
table,
|
||||
pre {
|
||||
margin: 15px 0;
|
||||
}
|
||||
& > h2:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
& > h1:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
& > h1:first-child + h2 {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
& > h3:first-child,
|
||||
& > h4:first-child,
|
||||
& > h5:first-child,
|
||||
& > h6:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
a:first-child h1,
|
||||
a:first-child h2,
|
||||
a:first-child h3,
|
||||
a:first-child h4,
|
||||
a:first-child h5,
|
||||
a:first-child h6 {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
h1 p,
|
||||
h2 p,
|
||||
h3 p,
|
||||
h4 p,
|
||||
h5 p,
|
||||
h6 p {
|
||||
margin-top: 0;
|
||||
}
|
||||
li p.first {
|
||||
display: inline-block;
|
||||
}
|
||||
ul,
|
||||
ol {
|
||||
padding-left: 30px;
|
||||
li {
|
||||
margin: 0;
|
||||
}
|
||||
}
|
||||
ul :first-child,
|
||||
ol :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
ul :last-child,
|
||||
ol :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
blockquote {
|
||||
padding: 0 15px;
|
||||
color: var(--foreground-normal);
|
||||
border-left: 4px solid var(--background-normal);
|
||||
}
|
||||
blockquote > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
blockquote > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
table {
|
||||
padding: 0;
|
||||
border-collapse: collapse;
|
||||
border-spacing: 0;
|
||||
}
|
||||
table tr {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
background-color: white;
|
||||
border-top: 1px solid var(--background-normal);
|
||||
}
|
||||
table tr:nth-child(2n) {
|
||||
background-color: var(--background-page);
|
||||
}
|
||||
table tr th {
|
||||
margin: 0;
|
||||
padding: 6px 13px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
border: 1px solid var(--background-normal);
|
||||
}
|
||||
table tr td {
|
||||
margin: 0;
|
||||
padding: 6px 13px;
|
||||
text-align: left;
|
||||
border: 1px solid var(--background-normal);
|
||||
}
|
||||
table tr th :first-child,
|
||||
table tr td :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
table tr th :last-child,
|
||||
table tr td :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
img {
|
||||
max-width: 100%;
|
||||
}
|
||||
.highlight pre {
|
||||
padding: 6px 10px;
|
||||
overflow: auto;
|
||||
font-size: 13px;
|
||||
line-height: 19px;
|
||||
background-color: var(--background-page);
|
||||
border: 1px solid var(--background-normal);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
hr {
|
||||
margin: 20px auto;
|
||||
border: none;
|
||||
border-top: 1px solid var(--background-normal);
|
||||
}
|
||||
b,
|
||||
strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
9
app/src/interfaces/markdown/readme.md
Normal file
9
app/src/interfaces/markdown/readme.md
Normal file
@@ -0,0 +1,9 @@
|
||||
# Markdown
|
||||
|
||||
## Options
|
||||
|
||||
| Option | Description | Default |
|
||||
| ------------- | ------------------------------------------------------------------- | ------------ |
|
||||
| `placeholder` | Text to show when no input is entered | `null` |
|
||||
| `tabbed` | If the view should be tabbed | `false` |
|
||||
| `disabled` | Disables the input | `false` |
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
"nested_files_folders_will_be_moved": "Nested files and folders will be moved one level up.",
|
||||
|
||||
"markdown": "Markdown",
|
||||
"tabbed": "Tabbed",
|
||||
|
||||
"revision_post_update": "Here is what this item looked like after the update...",
|
||||
"changes_made": "These are the specific changes that were made...",
|
||||
"no_relational_data": "Keep in mind that this does not include relational data.",
|
||||
@@ -455,8 +458,8 @@
|
||||
|
||||
"presets": "Presets",
|
||||
|
||||
"unexpected_error": "An unexpected error occured",
|
||||
"unexpected_error_copy": "Something went wrong.. Please try again later.",
|
||||
"unexpected_error": "Unexpected Error",
|
||||
"unexpected_error_copy": "An unexpected error has occured. Please try again later.",
|
||||
"copy_details": "Copy Details",
|
||||
|
||||
"no_app_access": "No App Access",
|
||||
@@ -760,19 +763,19 @@
|
||||
"keep_editing": "Keep Editing",
|
||||
|
||||
"page_help_collections_overview": "**Collections Overview** — Lists of all collections you have access to.",
|
||||
"page_help_collections_browse": "**Browse Items** — Lists all {collection} items you have access to. Customize layout, filters, and sorting to tailor your view, and even save bookmarks of these different configurations for quick access.<br><br><a href='https://docs.directus.io/guides/user-guide.html#items' target='_blank'>Learn More</a>",
|
||||
"page_help_collections_browse": "**Browse Items** — Lists all {collection} items you have access to. Customize layout, filters, and sorting to tailor your view, and even save bookmarks of these different configurations for quick access.",
|
||||
"page_help_collections_detail": "**Item Detail** — A form for viewing and managing this item. This sidebar also contains a full history of revisions, and embedded comments.",
|
||||
"page_help_activity_browse": "**Browse Activity** — A comprehensive listing of all your user's system and content activity.",
|
||||
"page_help_activity_detail": "**Activity Detail** — Shows accountability info, revision data, and the update message for this activity record.",
|
||||
"page_help_files_browse": "**File Library** — Lists all file assets uploaded to this project. Customize layout, filters, and sorting to tailor your view, and even save bookmarks of these different configurations for quick access.",
|
||||
"page_help_files_detail": "**File Detail** — A form for managing file metadata, editing the original asset, and updating access settings.",
|
||||
"page_help_settings_project": "**Project Settings** — Your project's global configuration options.<br><br><a href='https://docs.directus.io/guides/admin-guide.html#global-settings' target='_blank'>Learn More</a>",
|
||||
"page_help_settings_project": "**Project Settings** — Your project's global configuration options.",
|
||||
"page_help_settings_datamodel_collections": "**Data Model: Collections** — Lists all collections available. This includes visible, hidden, and system collections, as well as unmanaged database tables that can be added.",
|
||||
"page_help_settings_datamodel_fields": "**Data Model: Collection** — A form for managing this collection and its fields.",
|
||||
"page_help_settings_roles_browse": "**Browse Roles** — Lists the Admin, Public and custom User Roles.",
|
||||
"page_help_settings_roles_detail": "**Role Detail** — Manage a role's permissions and other settings.",
|
||||
"page_help_settings_presets_browse": "**Browse Presets** — Lists all presets in the project, including: user, role, and global bookmarks, as well as default views.",
|
||||
"page_help_settings_presets_detail": "**Preset Detail** — A form for managing bookmarks and default collection presets.<br><br>To create a default preset, choose a role... TK TK",
|
||||
"page_help_settings_presets_detail": "**Preset Detail** — A form for managing bookmarks and default collection presets.",
|
||||
"page_help_settings_webhooks_browse": "**Browse Webhooks** — Lists all webhooks within the project.",
|
||||
"page_help_settings_webhooks_detail": "**Webhook Detail** — A form for creating and managing project webhooks.",
|
||||
"page_help_users_browse": "**User Directory** — Lists all system users within this project.",
|
||||
@@ -912,7 +915,7 @@
|
||||
"connection": "Connection",
|
||||
"contains": "Contains",
|
||||
"continue": "Continue",
|
||||
"continue_as": "<b>{name}</b> is already authenticated for this project. If you recognize this account, please press continue.",
|
||||
"continue_as": "<b>{name}</b> is already authenticated. If you recognize this account, press continue.",
|
||||
"creating_item": "Creating Item",
|
||||
"creating_item_page_title": "Creating Item: {collection}",
|
||||
"creating_role": "Creating Role",
|
||||
@@ -964,6 +967,12 @@
|
||||
"dialog_beginning": "Beginning of dialog window.",
|
||||
"display_name": "Display Name",
|
||||
"directus_version": "Directus Version",
|
||||
"server_stack": "Server Stack",
|
||||
"operating_system": "Operating System",
|
||||
"installed_on": "Installed On",
|
||||
"database_client": "Database Client",
|
||||
"database_host": "Database Host",
|
||||
"database_port": "Database Port",
|
||||
"done": "Done",
|
||||
"dont_manage": "Don't Manage",
|
||||
"dont_manage_copy": "Privileges, preferences, and settings for this collection will be permanently removed from the system! Are you sure?",
|
||||
@@ -1102,6 +1111,7 @@
|
||||
"no_items_selected": "No items selected",
|
||||
"no_related_entries": "Has no related entries",
|
||||
"not_authenticated": "Not Authenticated",
|
||||
"authenticated": "Authenticated",
|
||||
"not_between": "Not between",
|
||||
"not_contains": "Doesn't contain",
|
||||
"not_empty": "Is not empty",
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
:server-sort="itemCount === limit || totalPages > 1"
|
||||
:item-key="primaryKeyField.field"
|
||||
:show-manual-sort="_filters && _filters.length === 0 && sortField !== null"
|
||||
:manual-sort-key="sortField && sortField.field"
|
||||
:manual-sort-key="sortField"
|
||||
selection-use-keys
|
||||
@click:row="onRowClick"
|
||||
@update:sort="onSortChange"
|
||||
@@ -343,7 +343,7 @@ export default defineComponent({
|
||||
_viewQuery.value?.fields ||
|
||||
availableFields.value
|
||||
.filter((field: Field) => {
|
||||
return field.schema?.is_primary_key === false && field.meta.special !== 'sort';
|
||||
return field.schema?.is_primary_key === false;
|
||||
})
|
||||
.slice(0, 4)
|
||||
.map(({ field }) => field);
|
||||
|
||||
@@ -34,13 +34,10 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_activity_browse'))" />
|
||||
<div class="page-description" v-html="marked($t('page_help_activity_browse'))" />
|
||||
</drawer-detail>
|
||||
<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_activity_browse'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
@@ -138,13 +138,8 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
Page Info Here...
|
||||
</drawer-detail>
|
||||
<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"
|
||||
class="page-description"
|
||||
v-html="
|
||||
marked(
|
||||
$t('page_help_collections_browse', {
|
||||
@@ -154,6 +149,8 @@
|
||||
"
|
||||
/>
|
||||
</drawer-detail>
|
||||
<layout-drawer-detail @input="viewType = $event" :value="viewType" />
|
||||
<portal-target name="drawer" />
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_detail'))" />
|
||||
<div class="page-description" v-html="marked($t('page_help_collections_detail'))" />
|
||||
</drawer-detail>
|
||||
<revisions-drawer-detail
|
||||
v-if="collectionInfo.meta.singleton === false && isBatch === false && isNew === false"
|
||||
@@ -166,9 +166,6 @@
|
||||
:collection="collection"
|
||||
:primary-key="primaryKey"
|
||||
/>
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div class="format-markdown" v-html="marked($t('page_help_collections_detail'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
@@ -30,10 +30,7 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<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="page-description" v-html="marked($t('page_help_collections_overview'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
|
||||
@@ -128,13 +128,10 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_files_browse'))" />
|
||||
<div class="page-description" v-html="marked($t('page_help_files_browse'))" />
|
||||
</drawer-detail>
|
||||
<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_files_browse'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
</div>
|
||||
|
||||
<div v-if="user">
|
||||
<dt>{{ $t('uploaded_by') }}</dt>
|
||||
<dt>{{ $t('owner') }}</dt>
|
||||
<dd>
|
||||
<user-popover :user="user.id">
|
||||
<router-link :to="user.link">{{ user.name }}</router-link>
|
||||
@@ -86,6 +86,11 @@
|
||||
</div>
|
||||
</template>
|
||||
</dl>
|
||||
|
||||
<v-divider />
|
||||
|
||||
<div class="page-description" v-html="marked($t('page_help_files_detail'))" />
|
||||
|
||||
</drawer-detail>
|
||||
</template>
|
||||
|
||||
@@ -94,6 +99,7 @@ import { defineComponent, computed, ref, watch } from '@vue/composition-api';
|
||||
import readableMimeType from '@/utils/readable-mime-type';
|
||||
import bytes from 'bytes';
|
||||
import i18n from '@/lang';
|
||||
import marked from 'marked';
|
||||
import localizedFormat from '@/utils/localized-format';
|
||||
import api from '@/api';
|
||||
|
||||
@@ -122,7 +128,7 @@ export default defineComponent({
|
||||
const { user } = useUser();
|
||||
const { folder } = useFolder();
|
||||
|
||||
return { readableMimeType, size, creationDate, user, folder };
|
||||
return { readableMimeType, size, creationDate, user, folder, marked };
|
||||
|
||||
function useCreationDate() {
|
||||
const creationDate = ref<string | null>(null);
|
||||
|
||||
@@ -163,9 +163,6 @@
|
||||
collection="directus_files"
|
||||
:primary-key="primaryKey"
|
||||
/>
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div class="format-markdown" v-html="marked($t('page_help_files_detail'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
@@ -186,7 +183,6 @@ import FileLightbox from '@/views/private/components/file-lightbox';
|
||||
import { useFieldsStore } from '@/stores/';
|
||||
import { Field } from '@/types';
|
||||
import FileInfoDrawerDetail from './components/file-info-drawer-detail.vue';
|
||||
import marked from 'marked';
|
||||
import useFormFields from '@/composables/use-form-fields';
|
||||
import FolderPicker from '../../components/folder-picker';
|
||||
import api from '@/api';
|
||||
@@ -315,7 +311,6 @@ export default defineComponent({
|
||||
previewActive,
|
||||
revisionsDrawerDetail,
|
||||
formFields,
|
||||
marked,
|
||||
confirmLeave,
|
||||
leaveTo,
|
||||
discardAndLeave,
|
||||
|
||||
@@ -15,12 +15,21 @@
|
||||
<v-list-item-title>{{ item.name }}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item href="https://github.com/directus/directus/releases" class="version">
|
||||
<v-list-item-icon><v-icon name="directus" /></v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
<v-list-item-title class="version">Directus {{ version }}</v-list-item-title>
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, toRefs } from '@vue/composition-api';
|
||||
import { i18n } from '@/lang';
|
||||
import { version } from '../../../../../package.json';
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
@@ -65,7 +74,30 @@ export default defineComponent({
|
||||
},
|
||||
];
|
||||
|
||||
return { navItems, externalItems };
|
||||
return { version, navItems, externalItems };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
|
||||
.version {
|
||||
.v-icon {
|
||||
color: var(--foreground-subdued);
|
||||
transition: color var(--fast) var(--transition);
|
||||
}
|
||||
::v-deep .type-text {
|
||||
color: var(--foreground-subdued);
|
||||
transition: color var(--fast) var(--transition);
|
||||
}
|
||||
&:hover {
|
||||
.v-icon {
|
||||
color: var(--foreground-normal);
|
||||
}
|
||||
::v-deep .type-text {
|
||||
color: var(--foreground-normal);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
@@ -77,12 +77,9 @@
|
||||
|
||||
<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="page-description" 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_settings_datamodel_collections'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
@@ -75,10 +75,7 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<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_settings_datamodel_fields'))" />
|
||||
<div class="page-description" v-html="marked($t('page_help_settings_datamodel_fields'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
|
||||
@@ -64,15 +64,15 @@
|
||||
<v-tab-item value="system">
|
||||
<h2 class="type-title">{{ $t('creating_collection_system') }}</h2>
|
||||
<div class="grid system">
|
||||
<div class="field" v-for="field in systemFields" :key="field.id">
|
||||
<div class="type-label">{{ $t(field.label) }}</div>
|
||||
<v-input v-model="field.name" class="monospace">
|
||||
<div class="field" v-for="(info, field) in systemFields" :key="field">
|
||||
<div class="type-label">{{ $t(info.label) }}</div>
|
||||
<v-input v-model="info.name" class="monospace">
|
||||
<template #prepend>
|
||||
<v-checkbox v-model="field.enabled" />
|
||||
<v-checkbox v-model="info.enabled" />
|
||||
</template>
|
||||
|
||||
<template #append>
|
||||
<v-icon :name="field.icon" />
|
||||
<v-icon :name="info.icon" />
|
||||
</template>
|
||||
</v-input>
|
||||
</div>
|
||||
@@ -108,7 +108,7 @@ import notify from '@/utils/notify';
|
||||
import router from '@/router';
|
||||
|
||||
export default defineComponent({
|
||||
setup(props) {
|
||||
setup() {
|
||||
const collectionsStore = useCollectionsStore();
|
||||
const fieldsStore = useFieldsStore();
|
||||
|
||||
@@ -118,51 +118,51 @@ export default defineComponent({
|
||||
const primaryKeyFieldName = ref('id');
|
||||
const primaryKeyFieldType = ref<'auto_int' | 'uuid' | 'manual'>('auto_int');
|
||||
|
||||
const systemFields = reactive([
|
||||
{
|
||||
id: 'status',
|
||||
const sortField = ref<string>();
|
||||
|
||||
const systemFields = reactive({
|
||||
status: {
|
||||
enabled: false,
|
||||
name: 'status',
|
||||
label: 'status',
|
||||
icon: 'flag',
|
||||
},
|
||||
{
|
||||
id: 'sort',
|
||||
sort: {
|
||||
enabled: false,
|
||||
name: 'sort',
|
||||
label: 'sort',
|
||||
icon: 'low_priority',
|
||||
},
|
||||
/** @TODO re-enable these when the api supports the special types for created/modified by/on */
|
||||
// {
|
||||
// id: 'owner',
|
||||
// enabled: false,
|
||||
// name: 'created_by',
|
||||
// label: 'created_by_owner',
|
||||
// icon: 'account_circle',
|
||||
// },
|
||||
// {
|
||||
// id: 'created_on',
|
||||
// enabled: false,
|
||||
// name: 'created_on',
|
||||
// label: 'created_on',
|
||||
// icon: 'access_time',
|
||||
// },
|
||||
// {
|
||||
// id: 'modified_by',
|
||||
// enabled: false,
|
||||
// name: 'modified_by',
|
||||
// label: 'modified_by',
|
||||
// icon: 'account_circle',
|
||||
// },
|
||||
// {
|
||||
// id: 'modified_on',
|
||||
// enabled: false,
|
||||
// name: 'modified_on',
|
||||
// label: 'modified_on',
|
||||
// icon: 'access_time',
|
||||
// },
|
||||
]);
|
||||
});
|
||||
|
||||
/** @TODO re-enable these when the api supports the special types for created/modified by/on */
|
||||
// {
|
||||
// id: 'owner',
|
||||
// enabled: false,
|
||||
// name: 'created_by',
|
||||
// label: 'created_by_owner',
|
||||
// icon: 'account_circle',
|
||||
// },
|
||||
// {
|
||||
// id: 'created_on',
|
||||
// enabled: false,
|
||||
// name: 'created_on',
|
||||
// label: 'created_on',
|
||||
// icon: 'access_time',
|
||||
// },
|
||||
// {
|
||||
// id: 'modified_by',
|
||||
// enabled: false,
|
||||
// name: 'modified_by',
|
||||
// label: 'modified_by',
|
||||
// icon: 'account_circle',
|
||||
// },
|
||||
// {
|
||||
// id: 'modified_on',
|
||||
// enabled: false,
|
||||
// name: 'modified_on',
|
||||
// label: 'modified_on',
|
||||
// icon: 'access_time',
|
||||
|
||||
const saving = ref(false);
|
||||
const saveError = ref(null);
|
||||
@@ -185,6 +185,7 @@ export default defineComponent({
|
||||
await api.post(`/collections`, {
|
||||
collection: collectionName.value,
|
||||
fields: [getPrimaryKeyField(), ...getSystemFields()],
|
||||
sort_field: sortField.value,
|
||||
});
|
||||
|
||||
await collectionsStore.hydrate();
|
||||
@@ -259,9 +260,10 @@ export default defineComponent({
|
||||
function getSystemFields() {
|
||||
const fields: DeepPartial<Field>[] = [];
|
||||
|
||||
if (systemFields[0].enabled === true) {
|
||||
// Status
|
||||
if (systemFields.status.enabled === true) {
|
||||
fields.push({
|
||||
field: systemFields[0].name,
|
||||
field: systemFields.status.name,
|
||||
type: 'string',
|
||||
meta: {
|
||||
width: 'full',
|
||||
@@ -294,18 +296,19 @@ export default defineComponent({
|
||||
});
|
||||
}
|
||||
|
||||
if (systemFields[1].enabled === true) {
|
||||
// Sort
|
||||
if (systemFields.sort.enabled === true) {
|
||||
fields.push({
|
||||
field: systemFields[1].name,
|
||||
field: systemFields.sort.name,
|
||||
type: 'integer',
|
||||
meta: {
|
||||
interface: 'sort',
|
||||
hidden: true,
|
||||
width: 'full',
|
||||
special: 'sort',
|
||||
},
|
||||
schema: {},
|
||||
});
|
||||
|
||||
sortField.value = systemFields.sort.name;
|
||||
}
|
||||
|
||||
// if (systemFields[2].enabled === true) {
|
||||
|
||||
@@ -86,9 +86,6 @@
|
||||
|
||||
<template #drawer>
|
||||
<presets-info-drawer-detail />
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div class="format-markdown" v-html="marked($t('page_help_settings_presets_browse'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
@@ -105,7 +102,6 @@ import layouts from '@/layouts';
|
||||
import { TranslateResult } from 'vue-i18n';
|
||||
import router from '@/router';
|
||||
import ValueNull from '@/views/private/components/value-null';
|
||||
import marked from 'marked';
|
||||
import PresetsInfoDrawerDetail from './components/presets-info-drawer-detail.vue';
|
||||
|
||||
type PresetRaw = {
|
||||
@@ -152,7 +148,6 @@ export default defineComponent({
|
||||
confirmDelete,
|
||||
deleting,
|
||||
deleteSelection,
|
||||
marked,
|
||||
};
|
||||
|
||||
function useLinks() {
|
||||
|
||||
@@ -10,12 +10,18 @@
|
||||
<dd>{{ presetsCount }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
<v-divider />
|
||||
|
||||
<div class="page-description" v-html="marked($t('page_help_settings_presets_browse'))" />
|
||||
|
||||
</drawer-detail>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref } from '@vue/composition-api';
|
||||
import api from '@/api';
|
||||
import marked from 'marked';
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
@@ -26,7 +32,7 @@ export default defineComponent({
|
||||
|
||||
fetchCounts();
|
||||
|
||||
return { bookmarksCount, presetsCount };
|
||||
return { bookmarksCount, presetsCount, marked };
|
||||
|
||||
async function fetchCounts() {
|
||||
loading.value = true;
|
||||
@@ -51,3 +57,9 @@ export default defineComponent({
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.v-divider {
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -77,16 +77,12 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<span class="subdued">{{ $t('no_additional_info') }}</span>
|
||||
<div class="page-description" 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_settings_presets_detail'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
@@ -1,13 +1,47 @@
|
||||
<template>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<dl v-if="project">
|
||||
<!-- @todo -->
|
||||
<div>
|
||||
<dt>{{ $t('directus_version') }}</dt>
|
||||
<dd>{{ version }}</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>{{ $t('installed_on') }}</dt>
|
||||
<dd>August 15, 2020</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>{{ $t('operating_system') }}</dt>
|
||||
<dd>Ubuntu 8.0</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>{{ $t('server_stack') }}</dt>
|
||||
<dd>Node.js 10.2</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>{{ $t('database_client') }}</dt>
|
||||
<dd>MySQL 5.7</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>{{ $t('database_host') }}</dt>
|
||||
<dd>Localhost</dd>
|
||||
</div>
|
||||
<div>
|
||||
<dt>{{ $t('database_port') }}</dt>
|
||||
<dd>3306</dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
<v-divider />
|
||||
|
||||
<div class="page-description" v-html="marked($t('page_help_settings_project'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from '@vue/composition-api';
|
||||
import i18n from '@/lang';
|
||||
import marked from 'marked';
|
||||
import { version } from '../../../../../../package.json';
|
||||
|
||||
import bytes from 'bytes';
|
||||
|
||||
@@ -18,7 +52,13 @@ import bytes from 'bytes';
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
return { project: {}, bytes };
|
||||
return { version, project: {}, bytes, marked };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.v-divider {
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -23,9 +23,6 @@
|
||||
|
||||
<template #drawer>
|
||||
<project-info-drawer-detail />
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div class="format-markdown" v-html="marked($t('page_help_settings_project'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
@@ -35,7 +32,6 @@ import { defineComponent, ref, computed } from '@vue/composition-api';
|
||||
import SettingsNavigation from '../../components/navigation/';
|
||||
import useCollection from '@/composables/use-collection';
|
||||
import { useSettingsStore } from '@/stores';
|
||||
import marked from 'marked';
|
||||
import ProjectInfoDrawerDetail from './components/project-info-drawer-detail.vue';
|
||||
import { clone } from 'lodash';
|
||||
|
||||
@@ -54,7 +50,7 @@ export default defineComponent({
|
||||
|
||||
const saving = ref(false);
|
||||
|
||||
return { fields, initialValues, edits, noEdits, saving, save, marked };
|
||||
return { fields, initialValues, edits, noEdits, saving, save };
|
||||
|
||||
async function save() {
|
||||
if (edits.value === null) return;
|
||||
|
||||
@@ -20,11 +20,7 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<span class="subdued">{{ $t('no_additional_info') }}</span>
|
||||
</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="page-description" v-html="marked($t('page_help_settings_roles_browse'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
|
||||
@@ -159,11 +155,6 @@ export default defineComponent({
|
||||
--v-button-background-color-disabled: var(--warning-25);
|
||||
}
|
||||
|
||||
.subdued {
|
||||
color: var(--foreground-subdued);
|
||||
font-style: italic;
|
||||
}
|
||||
|
||||
.roles {
|
||||
padding: var(--content-padding);
|
||||
padding-bottom: var(--content-padding-bottom);
|
||||
|
||||
@@ -6,11 +6,16 @@
|
||||
<dd>{{ role.id }}</dd>
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
<v-divider />
|
||||
|
||||
<div class="page-description" v-html="marked($t('page_help_settings_roles_detail'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from '@vue/composition-api';
|
||||
import marked from 'marked';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -23,5 +28,14 @@ export default defineComponent({
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
setup() {
|
||||
return { marked };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.v-divider {
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -91,9 +91,6 @@
|
||||
<template #drawer>
|
||||
<role-info-drawer-detail :is-new="isNew" :role="item" />
|
||||
<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'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
@@ -106,7 +103,6 @@ import router from '@/router';
|
||||
import RevisionsDrawerDetail from '@/views/private/components/revisions-drawer-detail';
|
||||
import useItem from '@/composables/use-item';
|
||||
import SaveOptions from '@/views/private/components/save-options';
|
||||
import marked from 'marked';
|
||||
import { useUserStore } from '@/stores/';
|
||||
import RoleInfoDrawerDetail from './components/role-info-drawer-detail';
|
||||
|
||||
@@ -153,7 +149,6 @@ export default defineComponent({
|
||||
saveAndAddNew,
|
||||
saveAsCopyAndNavigate,
|
||||
isBatch,
|
||||
marked,
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -61,13 +61,10 @@
|
||||
|
||||
<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="page-description" v-html="marked($t('page_help_settings_webhooks_browse'))" />
|
||||
</drawer-detail>
|
||||
<layout-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_settings_webhooks_browse'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
@@ -59,12 +59,9 @@
|
||||
|
||||
<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="page-description" v-html="marked($t('page_help_settings_webhooks_detail'))" />
|
||||
</drawer-detail>
|
||||
<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_settings_webhooks_detail'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
@@ -93,13 +93,10 @@
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div class="format-markdown" v-html="marked($t('page_help_users_browse'))" />
|
||||
<div class="page-description" v-html="marked($t('page_help_users_browse'))" />
|
||||
</drawer-detail>
|
||||
<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_users_browse'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
@@ -29,14 +29,15 @@
|
||||
</div>
|
||||
</dl>
|
||||
|
||||
<template v-else>
|
||||
--
|
||||
</template>
|
||||
<v-divider />
|
||||
|
||||
<div class="page-description" v-html="marked($t('page_help_users_detail'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from '@vue/composition-api';
|
||||
import marked from 'marked';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
@@ -49,5 +50,14 @@ export default defineComponent({
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
return { marked };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.v-divider {
|
||||
margin: 20px 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -121,9 +121,6 @@
|
||||
collection="directus_users"
|
||||
:primary-key="primaryKey"
|
||||
/>
|
||||
<drawer-detail icon="help_outline" :title="$t('help_and_docs')">
|
||||
<div class="format-markdown" v-html="marked($t('page_help_users_detail'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
@@ -138,7 +135,6 @@ import RevisionsDrawerDetail from '@/views/private/components/revisions-drawer-d
|
||||
import CommentsDrawerDetail from '@/views/private/components/comments-drawer-detail';
|
||||
import useItem from '@/composables/use-item';
|
||||
import SaveOptions from '@/views/private/components/save-options';
|
||||
import marked from 'marked';
|
||||
import api from '@/api';
|
||||
import { useFieldsStore } from '@/stores/';
|
||||
import useFormFields from '@/composables/use-form-fields';
|
||||
@@ -258,7 +254,6 @@ export default defineComponent({
|
||||
saveAsCopyAndNavigate,
|
||||
isBatch,
|
||||
revisionsDrawerDetail,
|
||||
marked,
|
||||
previewLoading,
|
||||
avatarSrc,
|
||||
roleName,
|
||||
|
||||
@@ -66,7 +66,7 @@ export default defineComponent({
|
||||
::v-deep {
|
||||
// In the translated string for continue as, there's a B element to emphasize the users name
|
||||
b {
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,11 @@
|
||||
|
||||
<login-form v-else :sso-error="ssoErrorCode" />
|
||||
|
||||
<template #notice>
|
||||
<template v-if="authenticated" #notice>
|
||||
<v-icon name="lock_open" left />
|
||||
{{ $t('authenticated') }}
|
||||
</template>
|
||||
<template v-else #notice>
|
||||
<v-icon name="lock_outlined" left />
|
||||
{{ $t('not_authenticated') }}
|
||||
</template>
|
||||
|
||||
@@ -3,6 +3,7 @@ export * from './collections';
|
||||
export * from './fields';
|
||||
export * from './latency';
|
||||
export * from './notifications';
|
||||
export * from './permissions';
|
||||
export * from './presets';
|
||||
export * from './relations';
|
||||
export * from './requests';
|
||||
|
||||
18
app/src/stores/permissions.ts
Normal file
18
app/src/stores/permissions.ts
Normal file
@@ -0,0 +1,18 @@
|
||||
import { createStore } from 'pinia';
|
||||
import api from '@/api';
|
||||
|
||||
export const usePermissionsStore = createStore({
|
||||
id: 'permissionsStore',
|
||||
state: () => ({
|
||||
permissions: [],
|
||||
}),
|
||||
actions: {
|
||||
async hydrate() {
|
||||
const response = await api.get('/permissions/me');
|
||||
this.state.permissions = response.data.data;
|
||||
},
|
||||
dehydrate() {
|
||||
this.reset();
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -111,7 +111,7 @@ strong {
|
||||
|
||||
dl > div {
|
||||
display: flex;
|
||||
margin-bottom: 12px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
dt,
|
||||
|
||||
@@ -14,6 +14,7 @@ export interface CollectionRaw {
|
||||
icon: string | null;
|
||||
translation: Translation[] | null;
|
||||
display_template: string | null;
|
||||
sort_field: string | null;
|
||||
} | null;
|
||||
schema: Record<string, any>;
|
||||
}
|
||||
|
||||
@@ -151,7 +151,10 @@ body {
|
||||
.content {
|
||||
padding: 16px;
|
||||
::v-deep {
|
||||
.format-markdown {
|
||||
.page-description {
|
||||
color: var(--foreground-subdued);
|
||||
margin-bottom: 8px;
|
||||
|
||||
a {
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
@@ -1,7 +1,16 @@
|
||||
<template>
|
||||
<div class="file-preview" v-if="type">
|
||||
<div v-if="type === 'image'" class="image" :class="{ svg: isSVG, 'max-size': inModal === false }" @click="$emit('click')">
|
||||
<img :src="src" :width="width" :height="height" :alt="title" />
|
||||
<img
|
||||
:src="src"
|
||||
:width="width"
|
||||
:height="height"
|
||||
:style="{
|
||||
'maxWidth': width ? width + 'px' : '100%',
|
||||
'maxHeight': height ? height + 'px' : '100%'
|
||||
}"
|
||||
:alt="title"
|
||||
/>
|
||||
<v-icon v-if="inModal === false" name="fullscreen" />
|
||||
</div>
|
||||
|
||||
@@ -101,6 +110,7 @@ audio {
|
||||
max-height: inherit;
|
||||
z-index: 1;
|
||||
display: block;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.v-icon {
|
||||
|
||||
@@ -119,11 +119,14 @@ export default defineComponent({
|
||||
}
|
||||
}
|
||||
|
||||
.fade-enter-active,
|
||||
.fade-leave-active {
|
||||
.fade-enter-active {
|
||||
transition: opacity var(--slow) var(--transition);
|
||||
}
|
||||
|
||||
.fade-leave-active {
|
||||
transition: opacity var(--medium) var(--transition);
|
||||
}
|
||||
|
||||
.fade-enter,
|
||||
.fade-leave-to {
|
||||
opacity: 0;
|
||||
|
||||
@@ -108,7 +108,7 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
.title {
|
||||
font-weight: 500;
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
&::after {
|
||||
|
||||
Reference in New Issue
Block a user