mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
Merge branch 'main' into add-modified_on
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -7,7 +7,4 @@ npm-debug.log
|
||||
lerna-debug.log
|
||||
.nova
|
||||
*.code-workspace
|
||||
api/package-lock.json
|
||||
app/package-lock.json
|
||||
packages/**/package-lock.json
|
||||
dist
|
||||
|
||||
8021
api/package-lock.json
generated
Normal file
8021
api/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "directus",
|
||||
"version": "9.0.0-beta.9",
|
||||
"version": "9.0.0-beta.10",
|
||||
"license": "GPL-3.0-only",
|
||||
"homepage": "https://github.com/directus/next#readme",
|
||||
"description": "Directus is a real-time API and App dashboard for managing SQL database content.",
|
||||
@@ -66,7 +66,7 @@
|
||||
"dependencies": {
|
||||
"@directus/app": "file:../app",
|
||||
"@directus/format-title": "^3.2.0",
|
||||
"@directus/specs": "^9.0.0-beta.8",
|
||||
"@directus/specs": "file:../packages/spec",
|
||||
"@slynova/flydrive": "^1.0.2",
|
||||
"@slynova/flydrive-gcs": "^1.0.2",
|
||||
"@slynova/flydrive-s3": "^1.0.2",
|
||||
@@ -127,7 +127,7 @@
|
||||
"mssql": "^6.2.0",
|
||||
"mysql": "^2.18.1",
|
||||
"oracledb": "^5.0.0",
|
||||
"pg": "^8.3.3",
|
||||
"pg": "^8.4.0",
|
||||
"sqlite3": "^5.0.0"
|
||||
},
|
||||
"gitHead": "4476da28dbbc2824e680137aa28b2b91b5afabec",
|
||||
|
||||
@@ -13,14 +13,20 @@ type RunASTOptions = {
|
||||
child?: boolean;
|
||||
};
|
||||
|
||||
export default async function runAST(originalAST: AST, options?: RunASTOptions): Promise<null | Item | Item[]> {
|
||||
export default async function runAST(
|
||||
originalAST: AST,
|
||||
options?: RunASTOptions
|
||||
): Promise<null | Item | Item[]> {
|
||||
const ast = cloneDeep(originalAST);
|
||||
|
||||
const query = options?.query || ast.query;
|
||||
const knex = options?.knex || database;
|
||||
|
||||
// Retrieve the database columns to select in the current AST
|
||||
const { columnsToSelect, primaryKeyField, nestedCollectionASTs } = await parseCurrentLevel(ast, knex);
|
||||
const { columnsToSelect, primaryKeyField, nestedCollectionASTs } = await parseCurrentLevel(
|
||||
ast,
|
||||
knex
|
||||
);
|
||||
|
||||
// The actual knex query builder instance. This is a promise that resolves with the raw items from the db
|
||||
const dbQuery = await getDBQuery(knex, ast.name, columnsToSelect, query, primaryKeyField);
|
||||
@@ -63,7 +69,7 @@ export default async function runAST(originalAST: AST, options?: RunASTOptions):
|
||||
// and nesting is done, we parse through the output structure, and filter out all non-requested
|
||||
// fields
|
||||
if (options?.child !== true) {
|
||||
items = removeTemporaryFields(items, originalAST);
|
||||
items = removeTemporaryFields(items, originalAST, primaryKeyField);
|
||||
}
|
||||
|
||||
return items;
|
||||
@@ -109,7 +115,13 @@ async function parseCurrentLevel(ast: AST, knex: Knex) {
|
||||
return { columnsToSelect, nestedCollectionASTs, primaryKeyField };
|
||||
}
|
||||
|
||||
async function getDBQuery(knex: Knex, table: string, columns: string[], query: Query, primaryKeyField: string): Promise<QueryBuilder> {
|
||||
async function getDBQuery(
|
||||
knex: Knex,
|
||||
table: string,
|
||||
columns: string[],
|
||||
query: Query,
|
||||
primaryKeyField: string
|
||||
): Promise<QueryBuilder> {
|
||||
let dbQuery = knex.select(columns.map((column) => `${table}.${column}`)).from(table);
|
||||
|
||||
const queryCopy = clone(query);
|
||||
@@ -127,7 +139,10 @@ async function getDBQuery(knex: Knex, table: string, columns: string[], query: Q
|
||||
return dbQuery;
|
||||
}
|
||||
|
||||
function applyParentFilters(nestedCollectionASTs: NestedCollectionAST[], parentItem: Item | Item[]) {
|
||||
function applyParentFilters(
|
||||
nestedCollectionASTs: NestedCollectionAST[],
|
||||
parentItem: Item | Item[]
|
||||
) {
|
||||
const parentItems = Array.isArray(parentItem) ? parentItem : [parentItem];
|
||||
|
||||
for (const nestedAST of nestedCollectionASTs) {
|
||||
@@ -139,15 +154,15 @@ function applyParentFilters(nestedCollectionASTs: NestedCollectionAST[], parentI
|
||||
filter: {
|
||||
...(nestedAST.query.filter || {}),
|
||||
[nestedAST.relation.one_primary]: {
|
||||
_in: uniq(parentItems.map((res) => res[nestedAST.relation.many_field])).filter(
|
||||
(id) => id
|
||||
),
|
||||
}
|
||||
}
|
||||
}
|
||||
_in: uniq(
|
||||
parentItems.map((res) => res[nestedAST.relation.many_field])
|
||||
).filter((id) => id),
|
||||
},
|
||||
},
|
||||
};
|
||||
} else {
|
||||
const relatedM2OisFetched = !!nestedAST.children.find((child) => {
|
||||
return child.type === 'field' && child.name === nestedAST.relation.many_field
|
||||
return child.type === 'field' && child.name === nestedAST.relation.many_field;
|
||||
});
|
||||
|
||||
if (relatedM2OisFetched === false) {
|
||||
@@ -159,24 +174,33 @@ function applyParentFilters(nestedCollectionASTs: NestedCollectionAST[], parentI
|
||||
filter: {
|
||||
...(nestedAST.query.filter || {}),
|
||||
[nestedAST.relation.many_field]: {
|
||||
_in: uniq(parentItems.map((res) => res[nestedAST.parentKey])).filter((id) => id),
|
||||
}
|
||||
}
|
||||
}
|
||||
_in: uniq(parentItems.map((res) => res[nestedAST.parentKey])).filter(
|
||||
(id) => id
|
||||
),
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return nestedCollectionASTs;
|
||||
}
|
||||
|
||||
function mergeWithParentItems(nestedItem: Item | Item[], parentItem: Item | Item[], nestedAST: NestedCollectionAST, o2mLimit?: number | null) {
|
||||
function mergeWithParentItems(
|
||||
nestedItem: Item | Item[],
|
||||
parentItem: Item | Item[],
|
||||
nestedAST: NestedCollectionAST,
|
||||
o2mLimit?: number | null
|
||||
) {
|
||||
const nestedItems = Array.isArray(nestedItem) ? nestedItem : [nestedItem];
|
||||
const parentItems = clone(Array.isArray(parentItem) ? parentItem : [parentItem]);
|
||||
|
||||
if (isM2O(nestedAST)) {
|
||||
for (const parentItem of parentItems) {
|
||||
const itemChild = nestedItems.find((nestedItem) => {
|
||||
return nestedItem[nestedAST.relation.one_primary] === parentItem[nestedAST.fieldKey];
|
||||
return (
|
||||
nestedItem[nestedAST.relation.one_primary] === parentItem[nestedAST.fieldKey]
|
||||
);
|
||||
});
|
||||
|
||||
parentItem[nestedAST.fieldKey] = itemChild || null;
|
||||
@@ -188,8 +212,10 @@ function mergeWithParentItems(nestedItem: Item | Item[], parentItem: Item | Item
|
||||
if (Array.isArray(nestedItem[nestedAST.relation.many_field])) return true;
|
||||
|
||||
return (
|
||||
nestedItem[nestedAST.relation.many_field] === parentItem[nestedAST.relation.one_primary] ||
|
||||
nestedItem[nestedAST.relation.many_field]?.[nestedAST.relation.many_primary] === parentItem[nestedAST.relation.one_primary]
|
||||
nestedItem[nestedAST.relation.many_field] ===
|
||||
parentItem[nestedAST.relation.one_primary] ||
|
||||
nestedItem[nestedAST.relation.many_field]?.[nestedAST.relation.many_primary] ===
|
||||
parentItem[nestedAST.relation.one_primary]
|
||||
);
|
||||
});
|
||||
|
||||
@@ -206,21 +232,34 @@ function mergeWithParentItems(nestedItem: Item | Item[], parentItem: Item | Item
|
||||
return Array.isArray(parentItem) ? parentItems : parentItems[0];
|
||||
}
|
||||
|
||||
function removeTemporaryFields(rawItem: Item | Item[], ast: AST | NestedCollectionAST): Item | Item[] {
|
||||
function removeTemporaryFields(
|
||||
rawItem: Item | Item[],
|
||||
ast: AST | NestedCollectionAST,
|
||||
primaryKeyField: string
|
||||
): Item | Item[] {
|
||||
const rawItems: Item[] = Array.isArray(rawItem) ? rawItem : [rawItem];
|
||||
|
||||
const items: Item[] = [];
|
||||
|
||||
const fields = ast.children.filter((child) => child.type === 'field').map((child) => child.name);
|
||||
const nestedCollections = ast.children.filter((child) => child.type === 'collection') as NestedCollectionAST[];
|
||||
const fields = ast.children
|
||||
.filter((child) => child.type === 'field')
|
||||
.map((child) => child.name);
|
||||
const nestedCollections = ast.children.filter(
|
||||
(child) => child.type === 'collection'
|
||||
) as NestedCollectionAST[];
|
||||
|
||||
for (const rawItem of rawItems) {
|
||||
if (rawItem === null) return rawItem;
|
||||
const item = fields.includes('*') ? rawItem : pick(rawItem, fields);
|
||||
|
||||
const item = fields.length > 0 ? pick(rawItem, fields) : rawItem[primaryKeyField];
|
||||
|
||||
for (const nestedCollection of nestedCollections) {
|
||||
if (item[nestedCollection.fieldKey] !== null) {
|
||||
item[nestedCollection.fieldKey] = removeTemporaryFields(rawItem[nestedCollection.fieldKey], nestedCollection);
|
||||
item[nestedCollection.fieldKey] = removeTemporaryFields(
|
||||
rawItem[nestedCollection.fieldKey],
|
||||
nestedCollection,
|
||||
nestedCollection.relatedKey
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -11,28 +11,42 @@ defaults:
|
||||
|
||||
data:
|
||||
- collection: directus_activity
|
||||
note: Accountability logs for all events
|
||||
- collection: directus_collections
|
||||
icon: list_alt
|
||||
note: Additional collection configuration and metadata
|
||||
- collection: directus_fields
|
||||
icon: input
|
||||
note: Additional field configuration and metadata
|
||||
- collection: directus_files
|
||||
icon: folder
|
||||
note: Metadata for all managed file assets
|
||||
- collection: directus_folders
|
||||
note: Provides virtual directories for files
|
||||
- collection: directus_permissions
|
||||
icon: admin_panel_settings
|
||||
note: Access permissions for each role
|
||||
- collection: directus_presets
|
||||
icon: bookmark_border
|
||||
note: Presets for collection defaults and bookmarks
|
||||
- collection: directus_relations
|
||||
icon: merge_type
|
||||
note: Relationship configuration and metadata
|
||||
- collection: directus_revisions
|
||||
note: Data snapshots for all activity
|
||||
- collection: directus_roles
|
||||
icon: supervised_user_circle
|
||||
note: Permission groups for system users
|
||||
- collection: directus_sessions
|
||||
note: User session information
|
||||
- collection: directus_settings
|
||||
singleton: true
|
||||
note: Project configuration options
|
||||
- collection: directus_users
|
||||
archive_field: status
|
||||
archive_value: archived
|
||||
unarchive_value: draft
|
||||
icon: people_alt
|
||||
note: System users for the platform
|
||||
- collection: directus_webhooks
|
||||
note: Configuration for event-based HTTP requests
|
||||
|
||||
@@ -32,6 +32,11 @@ data:
|
||||
many_primary: id
|
||||
one_collection: directus_users
|
||||
one_primary: id
|
||||
- many_collection: directus_presets
|
||||
many_field: role
|
||||
many_primary: id
|
||||
one_collection: directus_roles
|
||||
one_primary: id
|
||||
- many_collection: directus_folders
|
||||
many_field: parent
|
||||
many_primary: id
|
||||
|
||||
@@ -33,6 +33,7 @@ fields:
|
||||
special: json
|
||||
sort: 3
|
||||
width: full
|
||||
display: tags
|
||||
- collection: directus_files
|
||||
field: location
|
||||
interface: text-input
|
||||
@@ -104,4 +105,10 @@ fields:
|
||||
locked: true
|
||||
special: date-updated
|
||||
width: half
|
||||
display: datetime
|
||||
display: datetime
|
||||
- collection: directus_files
|
||||
field: created_on
|
||||
display: datetime
|
||||
- collection: directus_files
|
||||
field: created_by
|
||||
display: user
|
||||
@@ -20,7 +20,7 @@ import logger from '../logger';
|
||||
import { PayloadService } from './payload';
|
||||
import { AuthorizationService } from './authorization';
|
||||
|
||||
import { pick, clone } from 'lodash';
|
||||
import { pick, clone, cloneDeep } from 'lodash';
|
||||
import getDefaultValue from '../utils/get-default-value';
|
||||
import { InvalidPayloadException } from '../exceptions';
|
||||
|
||||
@@ -29,6 +29,7 @@ export class ItemsService implements AbstractService {
|
||||
knex: Knex;
|
||||
accountability: Accountability | null;
|
||||
eventScope: string;
|
||||
schemaInspector: ReturnType<typeof SchemaInspector>;
|
||||
|
||||
constructor(collection: string, options?: AbstractServiceOptions) {
|
||||
this.collection = collection;
|
||||
@@ -38,15 +39,16 @@ export class ItemsService implements AbstractService {
|
||||
? this.collection.substring(9)
|
||||
: 'items';
|
||||
|
||||
this.schemaInspector = SchemaInspector(this.knex);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
async create(data: Partial<Item>[]): Promise<PrimaryKey[]>;
|
||||
async create(data: Partial<Item>): Promise<PrimaryKey>;
|
||||
async create(data: Partial<Item> | Partial<Item>[]): Promise<PrimaryKey | PrimaryKey[]> {
|
||||
const schemaInspector = SchemaInspector(this.knex);
|
||||
const primaryKeyField = await schemaInspector.primary(this.collection);
|
||||
const columns = await schemaInspector.columns(this.collection);
|
||||
const primaryKeyField = await this.schemaInspector.primary(this.collection);
|
||||
const columns = await this.schemaInspector.columns(this.collection);
|
||||
|
||||
let payloads = clone(Array.isArray(data) ? data : [data]);
|
||||
|
||||
@@ -220,8 +222,7 @@ export class ItemsService implements AbstractService {
|
||||
action: PermissionsAction = 'read'
|
||||
): Promise<null | Item | Item[]> {
|
||||
query = clone(query);
|
||||
const schemaInspector = SchemaInspector(this.knex);
|
||||
const primaryKeyField = await schemaInspector.primary(this.collection);
|
||||
const primaryKeyField = await this.schemaInspector.primary(this.collection);
|
||||
const keys = Array.isArray(key) ? key : [key];
|
||||
|
||||
if (keys.length === 1) {
|
||||
@@ -263,9 +264,8 @@ export class ItemsService implements AbstractService {
|
||||
data: Partial<Item> | Partial<Item>[],
|
||||
key?: PrimaryKey | PrimaryKey[]
|
||||
): Promise<PrimaryKey | PrimaryKey[]> {
|
||||
const schemaInspector = SchemaInspector(this.knex);
|
||||
const primaryKeyField = await schemaInspector.primary(this.collection);
|
||||
const columns = await schemaInspector.columns(this.collection);
|
||||
const primaryKeyField = await this.schemaInspector.primary(this.collection);
|
||||
const columns = await this.schemaInspector.columns(this.collection);
|
||||
|
||||
// Updating one or more items to the same payload
|
||||
if (data && key) {
|
||||
@@ -421,12 +421,58 @@ export class ItemsService implements AbstractService {
|
||||
return keys;
|
||||
}
|
||||
|
||||
async updateByQuery(data: Partial<Item>, query: Query): Promise<PrimaryKey[]> {
|
||||
const primaryKeyField = await this.schemaInspector.primary(this.collection);
|
||||
const readQuery = cloneDeep(query);
|
||||
readQuery.fields = [primaryKeyField];
|
||||
|
||||
// Not authenticated:
|
||||
const itemsService = new ItemsService(this.collection);
|
||||
|
||||
let itemsToUpdate = await itemsService.readByQuery(readQuery);
|
||||
itemsToUpdate = Array.isArray(itemsToUpdate) ? itemsToUpdate : [itemsToUpdate];
|
||||
|
||||
const keys: PrimaryKey[] = itemsToUpdate.map(
|
||||
(item: Partial<Item>) => item[primaryKeyField]
|
||||
);
|
||||
|
||||
return await this.update(data, keys);
|
||||
}
|
||||
|
||||
upsert(data: Partial<Item>): Promise<PrimaryKey>;
|
||||
upsert(data: Partial<Item>[]): Promise<PrimaryKey[]>;
|
||||
async upsert(data: Partial<Item> | Partial<Item>[]): Promise<PrimaryKey | PrimaryKey[]> {
|
||||
const primaryKeyField = await this.schemaInspector.primary(this.collection);
|
||||
const payloads = Array.isArray(data) ? data : [data];
|
||||
const primaryKeys: PrimaryKey[] = [];
|
||||
|
||||
for (const payload of payloads) {
|
||||
const primaryKey = payload[primaryKeyField];
|
||||
const exists =
|
||||
primaryKey &&
|
||||
!!(await this.knex
|
||||
.select(primaryKeyField)
|
||||
.from(this.collection)
|
||||
.where({ [primaryKeyField]: primaryKey })
|
||||
.first());
|
||||
|
||||
if (exists) {
|
||||
const keys = await this.update([payload]);
|
||||
primaryKeys.push(...keys);
|
||||
} else {
|
||||
const key = await this.create(payload);
|
||||
primaryKeys.push(key);
|
||||
}
|
||||
}
|
||||
|
||||
return Array.isArray(data) ? primaryKeys : primaryKeys[0];
|
||||
}
|
||||
|
||||
delete(key: PrimaryKey): Promise<PrimaryKey>;
|
||||
delete(keys: PrimaryKey[]): Promise<PrimaryKey[]>;
|
||||
async delete(key: PrimaryKey | PrimaryKey[]): Promise<PrimaryKey | PrimaryKey[]> {
|
||||
const keys = (Array.isArray(key) ? key : [key]) as PrimaryKey[];
|
||||
const schemaInspector = SchemaInspector(this.knex);
|
||||
const primaryKeyField = await schemaInspector.primary(this.collection);
|
||||
const primaryKeyField = await this.schemaInspector.primary(this.collection);
|
||||
|
||||
if (this.accountability && this.accountability.admin !== true) {
|
||||
const authorizationService = new AuthorizationService({
|
||||
@@ -480,15 +526,31 @@ export class ItemsService implements AbstractService {
|
||||
return key;
|
||||
}
|
||||
|
||||
async deleteByQuery(query: Query): Promise<PrimaryKey[]> {
|
||||
const primaryKeyField = await this.schemaInspector.primary(this.collection);
|
||||
const readQuery = cloneDeep(query);
|
||||
readQuery.fields = [primaryKeyField];
|
||||
|
||||
// Not authenticated:
|
||||
const itemsService = new ItemsService(this.collection);
|
||||
|
||||
let itemsToDelete = await itemsService.readByQuery(readQuery);
|
||||
itemsToDelete = Array.isArray(itemsToDelete) ? itemsToDelete : [itemsToDelete];
|
||||
|
||||
const keys: PrimaryKey[] = itemsToDelete.map(
|
||||
(item: Partial<Item>) => item[primaryKeyField]
|
||||
);
|
||||
return await this.delete(keys);
|
||||
}
|
||||
|
||||
async readSingleton(query: Query) {
|
||||
query = clone(query);
|
||||
const schemaInspector = SchemaInspector(this.knex);
|
||||
query.single = true;
|
||||
|
||||
const record = (await this.readByQuery(query)) as Item;
|
||||
|
||||
if (!record) {
|
||||
const columns = await schemaInspector.columnInfo(this.collection);
|
||||
const columns = await this.schemaInspector.columnInfo(this.collection);
|
||||
const defaults: Record<string, any> = {};
|
||||
|
||||
for (const column of columns) {
|
||||
@@ -502,8 +564,7 @@ export class ItemsService implements AbstractService {
|
||||
}
|
||||
|
||||
async upsertSingleton(data: Partial<Item>) {
|
||||
const schemaInspector = SchemaInspector(this.knex);
|
||||
const primaryKeyField = await schemaInspector.primary(this.collection);
|
||||
const primaryKeyField = await this.schemaInspector.primary(this.collection);
|
||||
|
||||
const record = await this.knex
|
||||
.select(primaryKeyField)
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
import argon2 from 'argon2';
|
||||
import { v4 as uuidv4 } from 'uuid';
|
||||
import database from '../database';
|
||||
import { clone, isObject } from 'lodash';
|
||||
import { clone, isObject, cloneDeep } from 'lodash';
|
||||
import { Relation, Item, AbstractServiceOptions, Accountability, PrimaryKey } from '../types';
|
||||
import { ItemsService } from './items';
|
||||
import { URL } from 'url';
|
||||
@@ -15,6 +15,7 @@ import env from '../env';
|
||||
import SchemaInspector from 'knex-schema-inspector';
|
||||
import getLocalType from '../utils/get-local-type';
|
||||
import { format, formatISO } from 'date-fns';
|
||||
import { ForbiddenException } from '../exceptions';
|
||||
|
||||
type Action = 'create' | 'read' | 'update';
|
||||
|
||||
@@ -313,11 +314,7 @@ export class PayloadService {
|
||||
const exists = hasPrimaryKey && !!(await itemsService.readByKey(relatedPrimaryKey));
|
||||
|
||||
if (exists) {
|
||||
if (relatedRecord.hasOwnProperty('$delete') && relatedRecord.$delete) {
|
||||
await itemsService.delete(relatedPrimaryKey);
|
||||
} else {
|
||||
await itemsService.update(relatedRecord, relatedPrimaryKey);
|
||||
}
|
||||
await itemsService.update(relatedRecord, relatedPrimaryKey);
|
||||
} else {
|
||||
relatedPrimaryKey = await itemsService.create(relatedRecord);
|
||||
}
|
||||
@@ -353,48 +350,52 @@ export class PayloadService {
|
||||
});
|
||||
|
||||
for (const relation of relationsToProcess) {
|
||||
const relatedRecords: Partial<Item>[] = payload[relation.one_field].map(
|
||||
(record: string | number | Partial<Item>) => {
|
||||
if (typeof record === 'string' || typeof record === 'number') {
|
||||
record = {
|
||||
[relation.many_primary]: record,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
...record,
|
||||
[relation.many_field]: parent || payload[relation.one_primary],
|
||||
};
|
||||
}
|
||||
);
|
||||
|
||||
const itemsService = new ItemsService(relation.many_collection, {
|
||||
accountability: this.accountability,
|
||||
knex: this.knex,
|
||||
});
|
||||
|
||||
const toBeCreated = relatedRecords.filter(
|
||||
(record) => record.hasOwnProperty(relation.many_primary) === false
|
||||
const relatedRecords: Partial<Item>[] = [];
|
||||
|
||||
for (const relatedRecord of payload[relation.one_field]) {
|
||||
let record = cloneDeep(relatedRecord);
|
||||
|
||||
if (typeof relatedRecord === 'string' || typeof relatedRecord === 'number') {
|
||||
const exists = !!(await this.knex
|
||||
.select(relation.many_primary)
|
||||
.from(relation.many_collection)
|
||||
.where({ [relation.many_primary]: record })
|
||||
.first());
|
||||
|
||||
if (exists === false)
|
||||
throw new ForbiddenException(undefined, {
|
||||
item: record,
|
||||
collection: relation.many_collection,
|
||||
});
|
||||
|
||||
record = {
|
||||
[relation.many_primary]: relatedRecord,
|
||||
};
|
||||
}
|
||||
|
||||
relatedRecords.push({
|
||||
...record,
|
||||
[relation.many_field]: parent || payload[relation.one_primary],
|
||||
});
|
||||
}
|
||||
|
||||
const primaryKeys = await itemsService.upsert(relatedRecords);
|
||||
|
||||
await itemsService.updateByQuery(
|
||||
{ [relation.many_field]: null },
|
||||
{
|
||||
filter: {
|
||||
[relation.many_primary]: {
|
||||
_nin: primaryKeys,
|
||||
},
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
const toBeUpdated = relatedRecords.filter(
|
||||
(record) =>
|
||||
record.hasOwnProperty(relation.many_primary) === true &&
|
||||
record.hasOwnProperty('$delete') === false
|
||||
);
|
||||
|
||||
const toBeDeleted = relatedRecords
|
||||
.filter(
|
||||
(record) =>
|
||||
record.hasOwnProperty(relation.many_primary) === true &&
|
||||
record.hasOwnProperty('$delete') &&
|
||||
record.$delete === true
|
||||
)
|
||||
.map((record) => record[relation.many_primary]);
|
||||
|
||||
await itemsService.create(toBeCreated);
|
||||
await itemsService.update(toBeUpdated);
|
||||
await itemsService.delete(toBeDeleted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ export type NestedCollectionAST = {
|
||||
fieldKey: string;
|
||||
relation: Relation;
|
||||
parentKey: string;
|
||||
relatedKey: string;
|
||||
};
|
||||
|
||||
export type FieldAST = {
|
||||
|
||||
@@ -62,16 +62,84 @@ export default async function getASTFromQuery(
|
||||
delete query.fields;
|
||||
delete query.deep;
|
||||
|
||||
ast.children = (await parseFields(collection, fields, deep)).filter(filterEmptyChildCollections);
|
||||
ast.children = await parseFields(collection, fields, deep);
|
||||
|
||||
return ast;
|
||||
|
||||
function convertWildcards(parentCollection: string, fields: string[]) {
|
||||
async function parseFields(
|
||||
parentCollection: string,
|
||||
fields: string[],
|
||||
deep?: Record<string, Query>
|
||||
) {
|
||||
fields = await convertWildcards(parentCollection, fields);
|
||||
|
||||
if (!fields) return [];
|
||||
|
||||
const children: (NestedCollectionAST | FieldAST)[] = [];
|
||||
|
||||
const relationalStructure: Record<string, string[]> = {};
|
||||
|
||||
for (const field of fields) {
|
||||
const isRelational =
|
||||
field.includes('.') ||
|
||||
!!relations.find(
|
||||
(relation) =>
|
||||
(relation.many_collection === parentCollection &&
|
||||
relation.many_field === field) ||
|
||||
(relation.one_collection === parentCollection &&
|
||||
relation.one_field === field)
|
||||
);
|
||||
|
||||
if (isRelational) {
|
||||
// field is relational
|
||||
const parts = field.split('.');
|
||||
|
||||
if (relationalStructure.hasOwnProperty(parts[0]) === false) {
|
||||
relationalStructure[parts[0]] = [];
|
||||
}
|
||||
|
||||
if (parts.length > 1) {
|
||||
relationalStructure[parts[0]].push(parts.slice(1).join('.'));
|
||||
}
|
||||
} else {
|
||||
children.push({ type: 'field', name: field });
|
||||
}
|
||||
}
|
||||
|
||||
for (const [relationalField, nestedFields] of Object.entries(relationalStructure)) {
|
||||
const relatedCollection = getRelatedCollection(parentCollection, relationalField);
|
||||
|
||||
if (!relatedCollection) continue;
|
||||
|
||||
const relation = getRelation(parentCollection, relationalField);
|
||||
|
||||
if (!relation) continue;
|
||||
|
||||
const child: NestedCollectionAST = {
|
||||
type: 'collection',
|
||||
name: relatedCollection,
|
||||
fieldKey: relationalField,
|
||||
parentKey: await schemaInspector.primary(parentCollection),
|
||||
relatedKey: await schemaInspector.primary(relatedCollection),
|
||||
relation: relation,
|
||||
query: deep?.[relationalField] || {},
|
||||
children: await parseFields(relatedCollection, nestedFields),
|
||||
};
|
||||
|
||||
children.push(child);
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
async function convertWildcards(parentCollection: string, fields: string[]) {
|
||||
const fieldsInCollection = await getFieldsInCollection(parentCollection);
|
||||
|
||||
const allowedFields = permissions
|
||||
? permissions
|
||||
.find((permission) => parentCollection === permission.collection)
|
||||
?.fields?.split(',')
|
||||
: ['*'];
|
||||
: fieldsInCollection;
|
||||
|
||||
if (!allowedFields || allowedFields.length === 0) return [];
|
||||
|
||||
@@ -81,8 +149,13 @@ export default async function getASTFromQuery(
|
||||
if (fieldKey.includes('*') === false) continue;
|
||||
|
||||
if (fieldKey === '*') {
|
||||
if (allowedFields.includes('*')) continue;
|
||||
fields.splice(index, 1, ...allowedFields);
|
||||
// Set to all fields in collection
|
||||
if (allowedFields.includes('*')) {
|
||||
fields.splice(index, 1, ...fieldsInCollection);
|
||||
} else {
|
||||
// Set to all allowed fields
|
||||
fields.splice(index, 1, ...allowedFields);
|
||||
}
|
||||
}
|
||||
|
||||
// Swap *.* case for *,<relational-field>.*,<another-relational>.*
|
||||
@@ -122,57 +195,6 @@ export default async function getASTFromQuery(
|
||||
return fields;
|
||||
}
|
||||
|
||||
async function parseFields(parentCollection: string, fields: string[], deep?: Record<string, Query>) {
|
||||
fields = convertWildcards(parentCollection, fields);
|
||||
|
||||
if (!fields) return [];
|
||||
|
||||
const children: (NestedCollectionAST | FieldAST)[] = [];
|
||||
|
||||
const relationalStructure: Record<string, string[]> = {};
|
||||
|
||||
for (const field of fields) {
|
||||
if (field.includes('.') === false) {
|
||||
children.push({ type: 'field', name: field });
|
||||
} else {
|
||||
// field is relational
|
||||
const parts = field.split('.');
|
||||
|
||||
if (relationalStructure.hasOwnProperty(parts[0]) === false) {
|
||||
relationalStructure[parts[0]] = [];
|
||||
}
|
||||
|
||||
relationalStructure[parts[0]].push(parts.slice(1).join('.'));
|
||||
}
|
||||
}
|
||||
|
||||
for (const [relationalField, nestedFields] of Object.entries(relationalStructure)) {
|
||||
const relatedCollection = getRelatedCollection(parentCollection, relationalField);
|
||||
|
||||
if (!relatedCollection) continue;
|
||||
|
||||
const relation = getRelation(parentCollection, relationalField);
|
||||
|
||||
if (!relation) continue;
|
||||
|
||||
const child: NestedCollectionAST = {
|
||||
type: 'collection',
|
||||
name: relatedCollection,
|
||||
fieldKey: relationalField,
|
||||
parentKey: await schemaInspector.primary(parentCollection),
|
||||
relation: relation,
|
||||
query: deep?.[relationalField] || {},
|
||||
children: (await parseFields(relatedCollection, nestedFields)).filter(
|
||||
filterEmptyChildCollections
|
||||
),
|
||||
};
|
||||
|
||||
children.push(child);
|
||||
}
|
||||
|
||||
return children;
|
||||
}
|
||||
|
||||
function getRelation(collection: string, field: string) {
|
||||
const relation = relations.find((relation) => {
|
||||
return (
|
||||
@@ -198,8 +220,19 @@ export default async function getASTFromQuery(
|
||||
}
|
||||
}
|
||||
|
||||
function filterEmptyChildCollections(childAST: FieldAST | NestedCollectionAST) {
|
||||
if (childAST.type === 'collection' && childAST.children.length === 0) return false;
|
||||
return true;
|
||||
async function getFieldsInCollection(collection: string) {
|
||||
const columns = (await schemaInspector.columns(collection)).map((column) => column.column);
|
||||
const fields = (
|
||||
await database.select('field').from('directus_fields').where({ collection })
|
||||
).map((field) => field.field);
|
||||
|
||||
const fieldsInCollection = [
|
||||
...columns,
|
||||
...fields.filter((field) => {
|
||||
return columns.includes(field) === false;
|
||||
}),
|
||||
];
|
||||
|
||||
return fieldsInCollection;
|
||||
}
|
||||
}
|
||||
|
||||
17245
app/package-lock.json
generated
Normal file
17245
app/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@directus/app",
|
||||
"version": "9.0.0-beta.9",
|
||||
"version": "9.0.0-beta.10",
|
||||
"private": false,
|
||||
"description": "Directus is an Open-Source Headless CMS & API for Managing Custom Databases",
|
||||
"author": "Rijk van Zanten <rijk@rngr.org>",
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 64 64">
|
||||
<g fill="none" fill-rule="evenodd">
|
||||
<path fill="#ECEFF1" d="M0 0h64v64H0z"/>
|
||||
<path d="M32 12a20 20 0 100 40 20 20 0 000-40zm-9.86 32.56C23 42.76 28.24 41 32 41s9.02 1.76 9.86 3.56a15.8 15.8 0 01-19.72 0zm22.58-2.9C41.86 38.18 34.92 37 32 37s-9.86 1.18-12.72 4.66A16.02 16.02 0 1148 32a15.9 15.9 0 01-3.28 9.66zM32 20c-3.88 0-7 3.12-7 7s3.12 7 7 7 7-3.12 7-7-3.12-7-7-7zm0 10a3 3 0 110-6 3 3 0 010 6z" fill="#B0BEC5"/>
|
||||
<path d="M32 12a20 20 0 100 40 20 20 0 000-40zm-9.86 32.56C23 42.76 28.24 41 32 41s9.02 1.76 9.86 3.56a15.8 15.8 0 01-19.72 0zm22.58-2.9C41.86 38.18 34.92 37 32 37s-9.86 1.18-12.72 4.66A16.02 16.02 0 1148 32a15.9 15.9 0 01-3.28 9.66zM32 20c-3.88 0-7 3.12-7 7s3.12 7 7 7 7-3.12 7-7-3.12-7-7-7zm0 10a3 3 0 110-6 3 3 0 010 6z" fill="#B0BEC5"/>
|
||||
</g>
|
||||
</svg>
|
||||
|
||||
|
Before Width: | Height: | Size: 539 B After Width: | Height: | Size: 496 B |
@@ -2,7 +2,7 @@ import capitalizeFirst from '@/utils/capitalize-first';
|
||||
|
||||
interface HTMLExpandElement extends HTMLElement {
|
||||
_parent?: (Node & ParentNode & HTMLElement) | null;
|
||||
_initialStyle: {
|
||||
_initialStyle?: {
|
||||
transition: string;
|
||||
visibility: string;
|
||||
overflow: string;
|
||||
@@ -28,6 +28,7 @@ export default function (expandedParentClass = '', xAxis = false) {
|
||||
|
||||
enter(el: HTMLExpandElement) {
|
||||
const initialStyle = el._initialStyle;
|
||||
if (!initialStyle) return;
|
||||
const offset = `${el[offsetProperty]}px`;
|
||||
|
||||
el.style.setProperty('transition', 'none', 'important');
|
||||
@@ -82,6 +83,7 @@ export default function (expandedParentClass = '', xAxis = false) {
|
||||
}
|
||||
|
||||
function resetStyles(el: HTMLExpandElement) {
|
||||
if (!el._initialStyle) return;
|
||||
const size = el._initialStyle[sizeProperty];
|
||||
el.style.overflow = el._initialStyle.overflow;
|
||||
if (size != null) el.style[sizeProperty] = size;
|
||||
|
||||
@@ -83,9 +83,14 @@ function mapKeys(key: string) {
|
||||
|
||||
function callHandlers(event: KeyboardEvent) {
|
||||
Object.entries(handlers).forEach(([key, value]) => {
|
||||
const rest = key.split('+').filter((keySegment) => keysdown.has(keySegment) === false);
|
||||
const keys = key.split('+')
|
||||
|
||||
if (rest.length > 0) return;
|
||||
for(key of keysdown) {
|
||||
if(keys.includes(key) === false) return;
|
||||
}
|
||||
for(key of keys) {
|
||||
if(keysdown.has(key) === false) return;
|
||||
}
|
||||
|
||||
for (let i = 0; i < value.length; i++) {
|
||||
let cancel = false;
|
||||
|
||||
@@ -55,6 +55,7 @@ export default defineComponent({
|
||||
if (props.value.avatar?.id) {
|
||||
return `${getRootPath()}assets/${props.value.avatar.id}?key=system-small-cover`;
|
||||
}
|
||||
return null
|
||||
});
|
||||
|
||||
return { src };
|
||||
|
||||
@@ -924,6 +924,7 @@
|
||||
"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_docs_global": "**Documentation Overview** — Docs tailored specifically to this project's version and schema.",
|
||||
"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.",
|
||||
@@ -977,6 +978,8 @@
|
||||
"collection_removed": "Collection Removed",
|
||||
"collection_updated": "Collection Updated",
|
||||
"collections_and_fields": "Collection & Fields",
|
||||
"singleton": "Singleton",
|
||||
"singleton_label": "Treat as single object",
|
||||
|
||||
"fields": {
|
||||
"directus_activity": {
|
||||
|
||||
445
app/src/modules/docs/components/markdown.vue
Normal file
445
app/src/modules/docs/components/markdown.vue
Normal file
@@ -0,0 +1,445 @@
|
||||
<template>
|
||||
<div class="md" v-html="html" @click="onClick" />
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, computed, watch, PropType, onMounted, onUpdated } from '@vue/composition-api';
|
||||
import marked, { Renderer } from 'marked';
|
||||
import highlight from 'highlight.js';
|
||||
|
||||
export default defineComponent({
|
||||
setup(props, { slots }) {
|
||||
const html = ref('');
|
||||
|
||||
onMounted(generateHTML);
|
||||
onUpdated(generateHTML);
|
||||
|
||||
return { html, onClick };
|
||||
|
||||
async function onClick($event: Event) {
|
||||
if ($event.target instanceof HTMLElement && $event.target.classList.contains('copy')) {
|
||||
await navigator.clipboard.writeText(
|
||||
window.location.href.split('#')[0] + $event.target.getAttribute('href')
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
function generateHTML() {
|
||||
if (slots.default === null || !slots.default()?.[0]?.text) {
|
||||
html.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
let htmlString = slots.default()[0].text!;
|
||||
const hintRegex = /<p>:::(.*?) (.*?)\r?\n((\s|.)*?):::<\/p>/gm;
|
||||
|
||||
const renderer: Partial<Renderer> = {
|
||||
heading(text, level) {
|
||||
const escapedText = text.toLowerCase().replace(/[^\w]+/g, '-');
|
||||
|
||||
return `
|
||||
<h${level} id="${escapedText}">
|
||||
<a class="heading-link copy" href="#${escapedText}">#</a>
|
||||
${text}
|
||||
</h${level}>`;
|
||||
},
|
||||
};
|
||||
|
||||
// Marked merges it's default rendered with our extension. It's typed as a full rendered however
|
||||
marked.use({ renderer } as any);
|
||||
|
||||
htmlString = marked(htmlString, {
|
||||
highlight: (code, lang) => {
|
||||
return highlight.highlightAuto(code, [lang]).value;
|
||||
},
|
||||
});
|
||||
|
||||
htmlString = htmlString.replaceAll(
|
||||
hintRegex,
|
||||
(match: string, type: string, title: string, body: string) => {
|
||||
return `<div class="hint ${type}"><p class="hint-title">${title}</p><p class="hint-body">${body}</p></div>`;
|
||||
}
|
||||
);
|
||||
|
||||
html.value = htmlString;
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.error {
|
||||
padding: 20vh 0;
|
||||
}
|
||||
|
||||
.md {
|
||||
::v-deep {
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
line-height: 27px;
|
||||
|
||||
& > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
& > *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
position: relative;
|
||||
margin: 40px 0 8px;
|
||||
padding: 0;
|
||||
font-weight: 600;
|
||||
cursor: text;
|
||||
|
||||
a {
|
||||
position: absolute;
|
||||
right: 100%;
|
||||
padding-right: 4px;
|
||||
opacity: 0;
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
&:hover a {
|
||||
opacity: 1;
|
||||
}
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 40px;
|
||||
font-size: 35px;
|
||||
line-height: 44px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 60px;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 12px;
|
||||
font-size: 26px;
|
||||
line-height: 33px;
|
||||
border-bottom: 2px solid var(--border-subdued);
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 0px;
|
||||
font-size: 19px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h6 {
|
||||
color: var(--foreground-normal);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.heading-link {
|
||||
color: var(--foreground-subdued);
|
||||
font-size: 16px;
|
||||
|
||||
&:hover {
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 16px 20px;
|
||||
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 1px;
|
||||
padding: 0 4px;
|
||||
font-size: 15px;
|
||||
font-family: var(--family-monospace);
|
||||
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;
|
||||
}
|
||||
|
||||
p,
|
||||
blockquote,
|
||||
ul,
|
||||
ol,
|
||||
dl,
|
||||
li,
|
||||
table,
|
||||
pre {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
}
|
||||
|
||||
h3 + p {
|
||||
margin-block-start: 0.5em;
|
||||
}
|
||||
|
||||
& > h2:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
& > h1:first-child {
|
||||
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 {
|
||||
margin: 20px 0;
|
||||
padding-left: 20px;
|
||||
|
||||
li {
|
||||
margin: 8px 0;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
margin: 4px 0;
|
||||
|
||||
li {
|
||||
margin: 4px 0;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
padding: 0 20px;
|
||||
color: var(--foreground-subdued);
|
||||
font-size: 18px;
|
||||
border-left: 2px solid var(--background-normal);
|
||||
}
|
||||
|
||||
blockquote > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
blockquote > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
min-width: 100%;
|
||||
margin: 40px 0;
|
||||
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: 8px 20px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
border: 1px solid var(--background-normal);
|
||||
}
|
||||
|
||||
table tr td {
|
||||
margin: 0;
|
||||
padding: 8px 20px;
|
||||
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%;
|
||||
margin: 20px 0;
|
||||
|
||||
&.no-margin {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&.full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.shadow {
|
||||
box-shadow: 0px 5px 10px 0px rgba(23, 41, 64, 0.1), 0px 2px 40px 0px rgba(23, 41, 64, 0.05);
|
||||
}
|
||||
}
|
||||
|
||||
.highlight pre {
|
||||
padding: 8px 20px;
|
||||
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: 40px auto;
|
||||
border: none;
|
||||
border-top: 2px solid var(--background-normal);
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hint {
|
||||
display: inline-block;
|
||||
width: 100%;
|
||||
margin: 20px 0;
|
||||
padding: 0 20px;
|
||||
background-color: var(--background-subdued);
|
||||
border-left: 2px solid var(--primary);
|
||||
|
||||
&-title {
|
||||
margin-bottom: 0.5em;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
&-body {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
&.tip {
|
||||
border-left: 2px solid var(--success);
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background-color: var(--warning-10);
|
||||
border-left: 2px solid var(--warning);
|
||||
}
|
||||
|
||||
&.danger {
|
||||
background-color: var(--danger-10);
|
||||
border-left: 2px solid var(--danger);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
@@ -1,20 +1,6 @@
|
||||
<template>
|
||||
<v-list-item v-if="section.children === undefined" :to="section.to" :dense="dense" :subdued="subdued">
|
||||
<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>
|
||||
</v-list-item>
|
||||
<div v-else-if="section.flat === true">
|
||||
<v-divider></v-divider>
|
||||
<navigation-list-item
|
||||
v-for="(childSection, index) in section.children"
|
||||
:key="index"
|
||||
:section="childSection"
|
||||
dense
|
||||
/>
|
||||
</div>
|
||||
<v-list-group v-else>
|
||||
<v-divider v-if="section.divider" />
|
||||
<v-list-group v-else-if="section.children" :dense="dense">
|
||||
<template #activator>
|
||||
<v-list-item-icon v-if="section.icon !== undefined"><v-icon :name="section.icon" /></v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
@@ -28,48 +14,30 @@
|
||||
dense
|
||||
/>
|
||||
</v-list-group>
|
||||
|
||||
<v-list-item v-else :to="`/docs${section.to}`" :dense="dense">
|
||||
<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>
|
||||
</v-list-item>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, PropType } from '@vue/composition-api';
|
||||
import { Section } from './sections';
|
||||
import { Link, Group } from '@directus/docs';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'navigation-list-item',
|
||||
props: {
|
||||
section: {
|
||||
type: Object as PropType<Section>,
|
||||
type: Object as PropType<Link | Group>,
|
||||
default: null,
|
||||
},
|
||||
dense: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
subdued: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
},
|
||||
});
|
||||
</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>
|
||||
|
||||
@@ -1,18 +1,18 @@
|
||||
<template>
|
||||
<v-list large>
|
||||
<navigation-item v-for="item in sections" :key="item.to" :section="item"></navigation-item>
|
||||
<navigation-item v-for="item in navSections" :key="item.name" :section="item" />
|
||||
</v-list>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from '@vue/composition-api';
|
||||
import { defineComponent, PropType, computed } from '@vue/composition-api';
|
||||
import NavigationItem from './navigation-item.vue';
|
||||
import sections from './sections';
|
||||
import { nav } from '@directus/docs';
|
||||
|
||||
export default defineComponent({
|
||||
components: { NavigationItem },
|
||||
setup() {
|
||||
return { sections };
|
||||
return { navSections: nav.app };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -1,188 +0,0 @@
|
||||
export type Section = {
|
||||
name: string;
|
||||
to: string;
|
||||
description?: string;
|
||||
icon?: string;
|
||||
sectionIcon?: string;
|
||||
sectionName?: string;
|
||||
children?: Section[];
|
||||
default?: string;
|
||||
flat?: boolean;
|
||||
};
|
||||
|
||||
export const defaultSection = '/docs/getting-started/introduction';
|
||||
|
||||
const sections: Section[] = [
|
||||
{
|
||||
icon: 'play_arrow',
|
||||
name: 'Getting Started',
|
||||
to: '/docs/getting-started',
|
||||
default: '',
|
||||
children: [
|
||||
{
|
||||
name: 'Introduction',
|
||||
to: '/docs/getting-started/introduction',
|
||||
},
|
||||
{
|
||||
name: 'Support & FAQ',
|
||||
to: '/docs/getting-started/support',
|
||||
},
|
||||
{
|
||||
name: 'Contributing',
|
||||
to: '/docs/getting-started/contributing',
|
||||
},
|
||||
{
|
||||
name: 'Backing Directus',
|
||||
to: '/docs/getting-started/backing-directus',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: 'school',
|
||||
name: 'Concepts',
|
||||
to: '/docs/concepts',
|
||||
default: 'readme',
|
||||
children: [
|
||||
{
|
||||
name: 'Platform Overview',
|
||||
to: '/docs/concepts/platform-overview',
|
||||
},
|
||||
{
|
||||
name: 'App Overview',
|
||||
to: '/docs/concepts/app-overview',
|
||||
},
|
||||
{
|
||||
name: 'App Extensions',
|
||||
to: '/docs/concepts/app-extensions',
|
||||
},
|
||||
{
|
||||
name: 'Activity & Versions',
|
||||
to: '/docs/concepts/activity-and-versions',
|
||||
},
|
||||
{
|
||||
name: 'Files & Thumbnails',
|
||||
to: '/docs/concepts/files-and-thumbnails',
|
||||
},
|
||||
{
|
||||
name: 'Internationalization',
|
||||
to: '/docs/concepts/internationalization',
|
||||
},
|
||||
{
|
||||
name: 'Relationships',
|
||||
to: '/docs/concepts/relationships',
|
||||
},
|
||||
{
|
||||
name: 'Users, Roles & Permissions',
|
||||
to: '/docs/concepts/users-roles-and-permissions',
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: 'article',
|
||||
name: 'Guides',
|
||||
to: '/docs/guides',
|
||||
default: 'readme',
|
||||
children: [
|
||||
{
|
||||
name: 'Collections',
|
||||
to: '/docs/guides/collections',
|
||||
},
|
||||
{
|
||||
name: 'Fields',
|
||||
to: '/docs/guides/fields',
|
||||
},
|
||||
{
|
||||
name: 'Presets',
|
||||
to: '/docs/guides/presets',
|
||||
},
|
||||
{
|
||||
name: 'Projects',
|
||||
to: '/docs/guides/projects',
|
||||
},
|
||||
{
|
||||
name: 'Roles & Permissions',
|
||||
to: '/docs/guides/roles-and-permissions',
|
||||
},
|
||||
{
|
||||
name: 'Users',
|
||||
to: '/docs/guides/users',
|
||||
},
|
||||
{
|
||||
name: 'Webhooks',
|
||||
to: '/docs/guides/webhooks',
|
||||
},
|
||||
{
|
||||
name: 'White-Labeling',
|
||||
to: '/docs/guides/white-labeling',
|
||||
},
|
||||
{
|
||||
name: 'Extensions',
|
||||
to: '/docs/guides/extensions',
|
||||
children: [
|
||||
{
|
||||
name: 'Custom Displays',
|
||||
to: '/docs/guides/extensions/creating-a-custom-display',
|
||||
},
|
||||
{
|
||||
name: 'Custom Interfaces',
|
||||
to: '/docs/guides/extensions/creating-a-custom-interface',
|
||||
},
|
||||
{
|
||||
name: 'Custom Layouts',
|
||||
to: '/docs/guides/extensions/creating-a-custom-layout',
|
||||
},
|
||||
{
|
||||
name: 'Custom Modules',
|
||||
to: '/docs/guides/extensions/creating-a-custom-module',
|
||||
},
|
||||
{
|
||||
name: 'Custom API Endpoints',
|
||||
to: '/docs/guides/extensions/creating-a-custom-api-endpoint',
|
||||
},
|
||||
{
|
||||
name: 'Custom API Hooks',
|
||||
to: '/docs/guides/extensions/creating-a-custom-api-hook',
|
||||
},
|
||||
{
|
||||
name: 'Custom Email Templates',
|
||||
to: '/docs/guides/extensions/creating-a-custom-email-template',
|
||||
},
|
||||
{
|
||||
name: 'Custom Storage Adapters',
|
||||
to: '/docs/guides/extensions/creating-a-custom-storage-adapter',
|
||||
},
|
||||
{
|
||||
name: 'Accessing Data',
|
||||
to: '/docs/guides/extensions/accessing-data',
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
icon: 'code',
|
||||
name: 'Reference',
|
||||
to: '/docs/reference',
|
||||
default: 'readme',
|
||||
children: [
|
||||
{
|
||||
name: 'Environment Variables',
|
||||
to: '/docs/reference/environment-variables',
|
||||
},
|
||||
{
|
||||
name: 'Command Line Interface',
|
||||
to: '/docs/reference/command-line-interface',
|
||||
},
|
||||
{
|
||||
name: 'Error Codes',
|
||||
to: '/docs/reference/error-codes',
|
||||
},
|
||||
{
|
||||
name: 'Item Rules',
|
||||
to: '/docs/reference/item-rules',
|
||||
},
|
||||
],
|
||||
},
|
||||
];
|
||||
|
||||
export default sections;
|
||||
@@ -1,71 +1,49 @@
|
||||
import { defineModule } from '@/modules/define';
|
||||
import Docs from './routes/docs.vue';
|
||||
import sections, { Section, defaultSection } from './components/sections';
|
||||
import { Route } from 'vue-router';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { RouteConfig } from 'vue-router';
|
||||
import { files, Directory } from '@directus/docs';
|
||||
import StaticDocs from './routes/static.vue';
|
||||
import NotFound from './routes/not-found.vue';
|
||||
|
||||
function urlSplitter(url: string) {
|
||||
if (url.startsWith('/docs')) url = url.replace('/docs', '');
|
||||
if (url.startsWith('/')) url = url.substr(1);
|
||||
return url.split('/');
|
||||
}
|
||||
|
||||
function urlToSection(urlSections: string[], sections: Section[]): Section | null {
|
||||
let section = sections.find((s) => urlSplitter(s.to).pop() === urlSections[0]);
|
||||
|
||||
if (section === undefined) {
|
||||
return null;
|
||||
}
|
||||
|
||||
section = cloneDeep(section);
|
||||
|
||||
if (urlSections.length === 1) {
|
||||
let finalSection = section;
|
||||
while (finalSection.children !== undefined) {
|
||||
finalSection = finalSection.children[0];
|
||||
}
|
||||
if (section.icon) finalSection.icon = section.icon;
|
||||
if (finalSection.sectionName === undefined) finalSection.sectionName = section.name;
|
||||
return finalSection;
|
||||
}
|
||||
|
||||
if (section.children === undefined) return null;
|
||||
|
||||
const sectionDeep = urlToSection(urlSections.slice(1), section.children);
|
||||
|
||||
if (sectionDeep !== null && sectionDeep.sectionName === undefined) {
|
||||
sectionDeep.sectionName = section.name;
|
||||
}
|
||||
|
||||
if (
|
||||
sectionDeep !== null &&
|
||||
sectionDeep.icon === undefined &&
|
||||
sectionDeep.sectionIcon === undefined &&
|
||||
section.icon !== undefined
|
||||
)
|
||||
sectionDeep.sectionIcon = section.icon;
|
||||
return sectionDeep;
|
||||
}
|
||||
|
||||
function props(route: Route) {
|
||||
const section = urlToSection(urlSplitter(route.path), sections);
|
||||
return { section };
|
||||
}
|
||||
|
||||
export default defineModule(({ i18n }) => ({
|
||||
id: 'docs',
|
||||
name: i18n.t('documentation'),
|
||||
icon: 'info',
|
||||
routes: [
|
||||
export default defineModule(({ i18n }) => {
|
||||
const routes: RouteConfig[] = [
|
||||
{
|
||||
path: '/',
|
||||
component: StaticDocs,
|
||||
},
|
||||
...parseRoutes(files),
|
||||
{
|
||||
path: '/*',
|
||||
beforeEnter: (to, from, next) => {
|
||||
if (to.path === '/docs/') next(defaultSection);
|
||||
else next();
|
||||
},
|
||||
component: Docs,
|
||||
props: props,
|
||||
component: NotFound,
|
||||
},
|
||||
],
|
||||
order: 20,
|
||||
}));
|
||||
];
|
||||
|
||||
return {
|
||||
id: 'docs',
|
||||
name: i18n.t('documentation'),
|
||||
icon: 'info',
|
||||
routes,
|
||||
order: 20,
|
||||
};
|
||||
|
||||
function parseRoutes(directory: Directory): RouteConfig[] {
|
||||
const routes: RouteConfig[] = [];
|
||||
|
||||
for (const doc of directory.children) {
|
||||
if (doc.type === 'file') {
|
||||
routes.push({
|
||||
path: '/' + doc.path.replace('.md', ''),
|
||||
component: StaticDocs,
|
||||
});
|
||||
} else if (doc.type === 'directory') {
|
||||
routes.push({
|
||||
path: '/' + doc.path,
|
||||
redirect: '/' + doc.children![0].path.replace('.md', ''),
|
||||
});
|
||||
|
||||
routes.push(...parseRoutes(doc));
|
||||
}
|
||||
}
|
||||
|
||||
return routes;
|
||||
}
|
||||
});
|
||||
|
||||
@@ -1,95 +0,0 @@
|
||||
<template>
|
||||
<private-view :title="notFound ? $t('page_not_found') : title">
|
||||
<template #headline>{{ $t('documentation') }}</template>
|
||||
|
||||
<template #title-outer:prepend>
|
||||
<v-button rounded disabled icon>
|
||||
<v-icon :name="isAPIReference ? 'code' : section.icon || section.sectionIcon" />
|
||||
</v-button>
|
||||
</template>
|
||||
|
||||
<template #navigation>
|
||||
<docs-navigation />
|
||||
</template>
|
||||
|
||||
<div v-if="notFound" class="not-found">
|
||||
<v-info :title="$t('page_not_found')" icon="not_interested">
|
||||
{{ $t('page_not_found_body') }}
|
||||
</v-info>
|
||||
</div>
|
||||
|
||||
<markdown v-else>{{ mdString }}</markdown>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, computed, watch, PropType } from '@vue/composition-api';
|
||||
import DocsNavigation from '../components/navigation.vue';
|
||||
import { Section } from '../components/sections';
|
||||
import Markdown from './markdown.vue';
|
||||
import i18n from '@/lang';
|
||||
|
||||
declare module '*.md';
|
||||
|
||||
export default defineComponent({
|
||||
components: { DocsNavigation, Markdown },
|
||||
props: {
|
||||
section: {
|
||||
type: Object as PropType<Section>,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
setup(props) {
|
||||
const mdString = ref<string | null>(null);
|
||||
const loading = ref(true);
|
||||
const error = ref(null);
|
||||
|
||||
const isAPIReference = computed(() => props.section && props.section.to.startsWith('/docs/api-reference'));
|
||||
const notFound = computed(() => {
|
||||
return props.section === null || error.value !== null;
|
||||
});
|
||||
|
||||
const title = computed(() => {
|
||||
return isAPIReference.value ? i18n.t('api_reference') : props.section.sectionName;
|
||||
});
|
||||
|
||||
watch(() => props.section, loadMD, { immediate: true });
|
||||
|
||||
return { isAPIReference, notFound, title, mdString };
|
||||
|
||||
async function loadMD() {
|
||||
loading.value = true;
|
||||
error.value = null;
|
||||
|
||||
if (props.section === null) {
|
||||
mdString.value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
const loadString = props.section.to.replace('/docs', '');
|
||||
|
||||
try {
|
||||
const md = await import(`raw-loader!@directus/docs${loadString}.md`);
|
||||
mdString.value = md.default;
|
||||
} catch (err) {
|
||||
mdString.value = null;
|
||||
error.value = err;
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
<style lang="scss" scoped>
|
||||
.v-info {
|
||||
padding: 20vh 0;
|
||||
}
|
||||
|
||||
.not-found {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20vh 0;
|
||||
}
|
||||
</style>
|
||||
@@ -1,407 +0,0 @@
|
||||
<template>
|
||||
<div class="docs selectable">
|
||||
<div class="md" v-html="html" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, computed, watch, PropType, onMounted, onUpdated } from '@vue/composition-api';
|
||||
import marked from 'marked';
|
||||
import highlight from 'highlight.js';
|
||||
import 'highlight.js/styles/github.css'
|
||||
|
||||
export default defineComponent({
|
||||
setup(props, { slots }) {
|
||||
const html = ref('');
|
||||
|
||||
onMounted(generateHTML);
|
||||
onUpdated(generateHTML);
|
||||
|
||||
return { html };
|
||||
|
||||
function generateHTML() {
|
||||
if (slots.default === null || !slots.default()?.[0]?.text) {
|
||||
html.value = '';
|
||||
return;
|
||||
}
|
||||
|
||||
let htmlString = slots.default()[0].text!;
|
||||
const hintRegex = /<p>:::(.*?) (.*?)\r?\n((\s|.)*?):::<\/p>/gm;
|
||||
|
||||
htmlString = marked(htmlString, {
|
||||
highlight: (code, lang) => {
|
||||
return highlight.highlightAuto(code, [lang]).value
|
||||
},
|
||||
});
|
||||
|
||||
htmlString = htmlString.replaceAll(
|
||||
hintRegex,
|
||||
(match: string, type: string, title: string, body: string) => {
|
||||
return `<div class="hint ${type}"><p class="hint-title">${title}</p><p class="hint-body">${body}</p></div>`;
|
||||
}
|
||||
);
|
||||
|
||||
html.value = htmlString;
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.error {
|
||||
padding: 20vh 0;
|
||||
}
|
||||
|
||||
.docs {
|
||||
padding: 0 var(--content-padding) var(--content-padding-bottom);
|
||||
|
||||
.md {
|
||||
max-width: 740px;
|
||||
|
||||
::v-deep {
|
||||
font-weight: 400;
|
||||
font-size: 16px;
|
||||
line-height: 27px;
|
||||
|
||||
& > *:first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
& > *:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
a {
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5,
|
||||
h6 {
|
||||
position: relative;
|
||||
margin: 40px 0 8px;
|
||||
padding: 0;
|
||||
font-weight: 600;
|
||||
cursor: text;
|
||||
}
|
||||
|
||||
h1 {
|
||||
margin-bottom: 40px;
|
||||
font-size: 35px;
|
||||
line-height: 44px;
|
||||
}
|
||||
|
||||
h2 {
|
||||
margin-top: 60px;
|
||||
margin-bottom: 20px;
|
||||
padding-bottom: 12px;
|
||||
font-size: 26px;
|
||||
line-height: 33px;
|
||||
border-bottom: 2px solid var(--border-subdued);
|
||||
}
|
||||
|
||||
h3 {
|
||||
margin-bottom: 0px;
|
||||
font-size: 19px;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
h6 {
|
||||
color: var(--foreground-normal);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
pre {
|
||||
padding: 16px 20px;
|
||||
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 1px;
|
||||
padding: 0 4px;
|
||||
font-family: var(--family-monospace);
|
||||
font-size: 15px;
|
||||
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;
|
||||
}
|
||||
|
||||
p,
|
||||
blockquote,
|
||||
ul,
|
||||
ol,
|
||||
dl,
|
||||
li,
|
||||
table,
|
||||
pre {
|
||||
margin: 8px 0;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-block-start: 1em;
|
||||
margin-block-end: 1em;
|
||||
margin-inline-start: 0px;
|
||||
margin-inline-end: 0px;
|
||||
}
|
||||
|
||||
h3 + p {
|
||||
margin-block-start: 0.5em;
|
||||
}
|
||||
|
||||
& > h2:first-child {
|
||||
margin-top: 0;
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
& > h1:first-child {
|
||||
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 {
|
||||
margin: 20px 0;
|
||||
padding-left: 20px;
|
||||
|
||||
li {
|
||||
margin: 8px 0;
|
||||
line-height: 24px;
|
||||
}
|
||||
|
||||
ul,
|
||||
ol {
|
||||
margin: 4px 0;
|
||||
|
||||
li {
|
||||
margin: 4px 0;
|
||||
line-height: 24px;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
blockquote {
|
||||
font-size: 18px;
|
||||
padding: 0 20px;
|
||||
color: var(--foreground-subdued);
|
||||
border-left: 2px solid var(--background-normal);
|
||||
}
|
||||
|
||||
blockquote > :first-child {
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
blockquote > :last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
table {
|
||||
min-width: 100%;
|
||||
margin: 40px 0;
|
||||
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: 8px 20px;
|
||||
font-weight: bold;
|
||||
text-align: left;
|
||||
border: 1px solid var(--background-normal);
|
||||
}
|
||||
|
||||
table tr td {
|
||||
margin: 0;
|
||||
padding: 8px 20px;
|
||||
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%;
|
||||
margin: 20px 0;
|
||||
|
||||
&.no-margin {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&.full {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
&.shadow {
|
||||
box-shadow: 0px 5px 10px 0px rgba(23,41,64,0.1),
|
||||
0px 2px 40px 0px rgba(23,41,64,0.05);
|
||||
}
|
||||
}
|
||||
|
||||
.highlight pre {
|
||||
padding: 8px 20px;
|
||||
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: 40px auto;
|
||||
border: none;
|
||||
border-top: 2px solid var(--background-normal);
|
||||
}
|
||||
|
||||
b,
|
||||
strong {
|
||||
font-weight: 600;
|
||||
}
|
||||
|
||||
.hint {
|
||||
display: inline-block;
|
||||
margin: 20px 0;
|
||||
padding: 0 20px;
|
||||
background-color: var(--background-subdued);
|
||||
border-left: 2px solid var(--primary);
|
||||
width: 100%;
|
||||
|
||||
&-title {
|
||||
font-weight: bold;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
&-body {
|
||||
margin-top: 0.5em;
|
||||
}
|
||||
|
||||
&.tip {
|
||||
border-left: 2px solid var(--success);
|
||||
}
|
||||
|
||||
&.warning {
|
||||
background-color: var(--warning-10);
|
||||
border-left: 2px solid var(--warning);
|
||||
}
|
||||
|
||||
&.danger {
|
||||
background-color: var(--danger-10);
|
||||
border-left: 2px solid var(--danger);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
32
app/src/modules/docs/routes/not-found.vue
Normal file
32
app/src/modules/docs/routes/not-found.vue
Normal file
@@ -0,0 +1,32 @@
|
||||
<template>
|
||||
<private-view :title="$t('page_not_found')">
|
||||
<template #navigation>
|
||||
<docs-navigation />
|
||||
</template>
|
||||
|
||||
<div class="not-found">
|
||||
<v-info :title="$t('page_not_found')" icon="not_interested">
|
||||
{{ $t('page_not_found_body') }}
|
||||
</v-info>
|
||||
</div>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from '@vue/composition-api';
|
||||
import DocsNavigation from '../components/navigation.vue';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'NotFound',
|
||||
components: { DocsNavigation },
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.not-found {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 20vh 0;
|
||||
}
|
||||
</style>
|
||||
96
app/src/modules/docs/routes/static.vue
Normal file
96
app/src/modules/docs/routes/static.vue
Normal file
@@ -0,0 +1,96 @@
|
||||
<template>
|
||||
<private-view :title="title" ref="view">
|
||||
<template #headline>Documentation</template>
|
||||
|
||||
<template #title-outer:prepend>
|
||||
<v-button rounded disabled icon>
|
||||
<v-icon name="info" />
|
||||
</v-button>
|
||||
</template>
|
||||
|
||||
<template #navigation>
|
||||
<docs-navigation />
|
||||
</template>
|
||||
|
||||
<div class="docs-content selectable">
|
||||
<markdown>{{ markdownWithoutTitle }}</markdown>
|
||||
</div>
|
||||
|
||||
<template #drawer>
|
||||
<drawer-detail icon="info_outline" :title="$t('information')" close>
|
||||
<div class="page-description" v-html="marked($t('page_help_docs_global'))" />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, ref, computed, inject, onUpdated } from '@vue/composition-api';
|
||||
import DocsNavigation from '../components/navigation.vue';
|
||||
import Markdown from '../components/markdown.vue';
|
||||
import marked from 'marked';
|
||||
|
||||
async function getMarkdownForPath(path: string) {
|
||||
const pathParts = path.split('/');
|
||||
|
||||
while (pathParts.includes('docs')) {
|
||||
pathParts.shift();
|
||||
}
|
||||
|
||||
let docsPath = pathParts.join('/');
|
||||
|
||||
// Home
|
||||
if (!docsPath) {
|
||||
docsPath = 'readme';
|
||||
}
|
||||
|
||||
const mdModule = await import('raw-loader!@directus/docs/' + docsPath + '.md');
|
||||
|
||||
return mdModule.default;
|
||||
}
|
||||
|
||||
export default defineComponent({
|
||||
name: 'StaticDocs',
|
||||
components: { DocsNavigation, Markdown },
|
||||
async beforeRouteEnter(to, from, next) {
|
||||
const md = await getMarkdownForPath(to.path);
|
||||
|
||||
next((vm) => {
|
||||
(vm as any).markdown = md;
|
||||
});
|
||||
},
|
||||
async beforeRouteUpdate(to, from, next) {
|
||||
this.markdown = await getMarkdownForPath(to.path);
|
||||
|
||||
next();
|
||||
},
|
||||
setup() {
|
||||
const markdown = ref('');
|
||||
const view = ref<Vue>();
|
||||
|
||||
const title = computed(() => {
|
||||
const firstLine = markdown.value.split('\n').shift();
|
||||
return firstLine?.substring(2).trim();
|
||||
});
|
||||
|
||||
const markdownWithoutTitle = computed(() => {
|
||||
const lines = markdown.value.split('\n');
|
||||
lines.shift();
|
||||
return lines.join('\n');
|
||||
});
|
||||
|
||||
onUpdated(() => {
|
||||
view.value?.$data.contentEl?.scrollTo({ top: 0 });
|
||||
});
|
||||
|
||||
return { markdown, title, markdownWithoutTitle, view, marked };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
.docs-content {
|
||||
max-width: 740px;
|
||||
padding: 0 var(--content-padding) var(--content-padding-bottom);
|
||||
}
|
||||
</style>
|
||||
@@ -65,13 +65,13 @@ export default defineComponent({
|
||||
{
|
||||
icon: 'bug_report',
|
||||
name: i18n.t('report_bug'),
|
||||
href: 'https://github.com/directus/directus/issues/new/choose',
|
||||
href: 'https://github.com/directus/next/issues/new?body=%23%23%23+Project+Details%0A%60%60%60%0ADirectus+Version:+'+version+'%0AEnvironment:+Development%0AOS:+Mac%0ADatabase:+MySQL+5.2%0A%60%60%60',
|
||||
outline: true,
|
||||
},
|
||||
{
|
||||
icon: 'new_releases',
|
||||
name: i18n.t('request_feature'),
|
||||
href: 'https://github.com/directus/directus/discussions/new',
|
||||
href: 'https://github.com/directus/next/discussions/new',
|
||||
outline: true,
|
||||
},
|
||||
];
|
||||
|
||||
@@ -291,21 +291,21 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
await Promise.all(
|
||||
state.newCollections.map((newCollection: Partial<Collection> & { $type: string }) => {
|
||||
state.newCollections.map((newCollection: Partial<Collection> & { $type?: string }) => {
|
||||
delete newCollection.$type;
|
||||
return api.post(`/collections`, newCollection);
|
||||
})
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
state.newFields.map((newField: Partial<Field> & { $type: string }) => {
|
||||
state.newFields.map((newField: Partial<Field> & { $type?: string }) => {
|
||||
delete newField.$type;
|
||||
return api.post(`/fields/${newField.collection}`, newField);
|
||||
})
|
||||
);
|
||||
|
||||
await Promise.all(
|
||||
state.updateFields.map((updateField: Partial<Field> & { $type: string }) => {
|
||||
state.updateFields.map((updateField: Partial<Field> & { $type?: string }) => {
|
||||
delete updateField.$type;
|
||||
return api.post(`/fields/${updateField.collection}/${updateField.field}`, updateField);
|
||||
})
|
||||
|
||||
@@ -298,7 +298,7 @@ export default defineComponent({
|
||||
};
|
||||
|
||||
async function saveDuplicate() {
|
||||
const newField = {
|
||||
const newField: any = {
|
||||
...props.field,
|
||||
field: duplicateName.value,
|
||||
collection: duplicateTo.value,
|
||||
|
||||
@@ -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,7 +79,7 @@
|
||||
<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">
|
||||
<template #prepend>
|
||||
@@ -124,6 +130,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 +191,7 @@ export default defineComponent({
|
||||
collectionName,
|
||||
saveError,
|
||||
saving,
|
||||
singleton
|
||||
};
|
||||
|
||||
async function save() {
|
||||
@@ -198,6 +206,7 @@ export default defineComponent({
|
||||
archive_field: archiveField.value,
|
||||
archive_value: archiveValue.value,
|
||||
unarchive_value: unarchiveValue.value,
|
||||
singleton: singleton.value
|
||||
},
|
||||
});
|
||||
|
||||
@@ -412,22 +421,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 {
|
||||
|
||||
@@ -106,7 +106,7 @@ import PresetsInfoDrawerDetail from './components/presets-info-drawer-detail.vue
|
||||
|
||||
type PresetRaw = {
|
||||
id: number;
|
||||
title: null | string;
|
||||
bookmark: null | string;
|
||||
user: null | { first_name: string; last_name: string };
|
||||
role: null | { name: string };
|
||||
collection: string;
|
||||
@@ -184,7 +184,7 @@ export default defineComponent({
|
||||
scope: scope,
|
||||
collection: collection,
|
||||
layout: layout,
|
||||
name: preset.title,
|
||||
name: preset.bookmark,
|
||||
} as Preset;
|
||||
});
|
||||
});
|
||||
@@ -199,7 +199,7 @@ export default defineComponent({
|
||||
params: {
|
||||
fields: [
|
||||
'id',
|
||||
'title',
|
||||
'bookmark',
|
||||
'user.first_name',
|
||||
'user.last_name',
|
||||
'role.name',
|
||||
|
||||
@@ -40,7 +40,7 @@ export default defineComponent({
|
||||
try {
|
||||
const response = await api.get(`/presets`, {
|
||||
params: {
|
||||
[`filter[title][nnull]`]: 1,
|
||||
[`filter[bookmark][_nnull]`]: 1,
|
||||
fields: ['id'],
|
||||
meta: 'filter_count,total_count',
|
||||
},
|
||||
|
||||
@@ -4,16 +4,43 @@ const { promisify } = require('util');
|
||||
const copyfiles = promisify(require('copyfiles'));
|
||||
const rimraf = promisify(require('rimraf'));
|
||||
const dirTree = require('directory-tree');
|
||||
const yaml = require('js-yaml');
|
||||
|
||||
async function build() {
|
||||
console.log('Building docs...');
|
||||
|
||||
const start = Date.now();
|
||||
|
||||
const distPath = path.resolve(__dirname, './dist');
|
||||
|
||||
await rimraf(distPath);
|
||||
|
||||
const tree = dirTree('.', { extensions: /\.md/, exclude: /dist/ });
|
||||
|
||||
await fse.ensureDir(distPath);
|
||||
|
||||
const tree = dirTree('.', { extensions: /\.md/ });
|
||||
await fse.writeFile('./dist/index.json', JSON.stringify(tree, null, '\t'));
|
||||
await fse.writeJSON('./dist/index.json', tree);
|
||||
|
||||
await copyfiles(['./**/*.md', distPath]);
|
||||
|
||||
const yamlFiles = [];
|
||||
const filesInRoot = await fse.readdir(__dirname);
|
||||
|
||||
for (const file of filesInRoot) {
|
||||
if (file.endsWith('.yaml')) {
|
||||
yamlFiles.push(file);
|
||||
}
|
||||
}
|
||||
|
||||
for (const yamlFile of yamlFiles) {
|
||||
const yamlString = await fse.readFile(yamlFile, 'utf8');
|
||||
await fse.writeJSON(
|
||||
'./dist/' + yamlFile.replace('.yaml', '.json'),
|
||||
yaml.safeLoad(yamlString)
|
||||
);
|
||||
}
|
||||
|
||||
console.log(`Built docs in ${Date.now() - start} ms`);
|
||||
}
|
||||
|
||||
build();
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
### 1. Module Bar
|
||||
|
||||
* **Project Logo** — Displays your configured project logo and project color (defaults to the Directus logo and color). If configured, clicking this component will navigate to the Project URL. During platform activity, an indeterminate progress indicator will also be shown here.
|
||||
* **Project Logo** — Displays your configured project logo and project color (defaults to the Directus logo and color). If [configured](#), clicking this component will navigate to the Project URL. During platform activity, an indeterminate progress indicator will also be shown here.
|
||||
* **Modules** — Any available [modules](#) are listed below the project logo. These may be turned off or reordered based on your [role's configuration](#), but by default this includes:
|
||||
* [Collections](#)
|
||||
* [User Directory](#)
|
||||
|
||||
@@ -76,18 +76,21 @@ git checkout -b YOUR-BRANCH-NAME
|
||||
|
||||
```bash
|
||||
npm install
|
||||
npm run setup
|
||||
```
|
||||
|
||||
### 5. Setup the Database & Env File
|
||||
|
||||
For this step, you'll need to already have a SQL database up-and-running, otherwise you can only use the SQLite driver, which will create the database for you.
|
||||
For this step, you'll need to already have a SQL database up-and-running, otherwise you can only use the SQLite driver, which will create the database for you. Run the following command from within the `/api` directory.
|
||||
|
||||
```bash
|
||||
@TODO
|
||||
./cli.js init
|
||||
```
|
||||
|
||||
### 6. Start the development server
|
||||
|
||||
Run the following command from the root directory.
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
```
|
||||
|
||||
@@ -12,11 +12,13 @@ Our [Discord](https://discord.gg/directus) community is another great way to get
|
||||
|
||||
Premium support is included with our Enterprise Cloud service. On-Demand Cloud customers and On-Premise users interested in learning more about our monthly retainer agreements should contact us at [support@directus.io](mailto:support@directus.io).
|
||||
|
||||
## Commissioned Features
|
||||
## Sponsored Work
|
||||
|
||||
### Commissioned Features
|
||||
|
||||
If you need a specific feature added to Directus faster than the normal development timeline, [reach out to us](#) for a quote. Our parent agency will often help subsidize the cost of developing new features if they pass our [80/20 Rule](#) and can be merged into the core codebase. Other custom/proprietary development will be built bespoke within our robust extension system.
|
||||
|
||||
## Expedited Fixes
|
||||
### Expedited Fixes
|
||||
|
||||
We triage all reported bugs based on priority and how long the fix is estimated to take. If you need a specific issue resolved sooner, [reach out to us](#) for a quote.
|
||||
|
||||
|
||||
@@ -11,11 +11,11 @@ Directus currently supports the following databases, with our minimum version be
|
||||
| Database | Version |
|
||||
| ------------- | ------- |
|
||||
| PostgreSQL | 9.5+ |
|
||||
| MySQL | 5.6 |
|
||||
| SQLite | 3 |
|
||||
| MySQL | 5.6+ |
|
||||
| SQLite | 3+ |
|
||||
| MS-SQL Server | 13.0+ |
|
||||
| OracleDB | TBD |
|
||||
| MariaDB | 10.1 |
|
||||
| MariaDB | 10.1+ |
|
||||
|
||||
::: Variants
|
||||
In addition to the databases above, other variants are also supported, including **AWS Aurora** (MySQL), and **AWS Redshift** (PostgreSQL).
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Webhooks
|
||||
|
||||
>
|
||||
> In addition to writing custom code for more complex [event hooks](#), Directus provides a way to quickly configure webhooks through the App. These send HTTP requests when a specific event is triggered within the project.
|
||||
|
||||
## Creating Webhooks
|
||||
|
||||
|
||||
@@ -1,13 +1,65 @@
|
||||
# White-Labeling a Project
|
||||
|
||||
> TK
|
||||
> The Directus App UX/UI is meant to be _transparent_, and uses "form follows function" as the guiding design principle. This allows the platform to be completely tailored to your branding, end-to-end.
|
||||
|
||||
## Project Settings
|
||||
|
||||
FavIcon
|
||||
1. Navigate to **Settings > Project Settings**
|
||||
2. Configure any of the following **branding fields**
|
||||
|
||||
* **Project Name** — The name used at the top of the [Navigation Bar](#) and on the login/public pages
|
||||
* **Project URL** — The URL when clicking the logo at the top of the [Module Bar](#)
|
||||
* **Project Color** — The color used behind the logo at the top of the [Module Bar](#), on the login/public pages, and for the browser's FavIcon
|
||||
* **Project Logo** — A 40x40 pixel logo at the top of the [Module Bar](#) and on the login/public pages
|
||||
|
||||
::: Recommended Logo Styling
|
||||
The 40x40 pixel Project Logo is inset within the 64x64 pixel Project Color square. To avoid a "boxy" look, we recommend using a SVG or PNG logo with transparency.
|
||||
:::
|
||||
|
||||
::: Browser FavIcon & Title
|
||||
The project color and logo are also used to set the dynamic favicon, and the project title is used in the browser's title. This furthers the bespoke appearance of your platform and makes it easier to differentiate between different Directus projects.
|
||||
:::
|
||||
|
||||
### Public Page Styling
|
||||
|
||||
In addition to the above options, you can also apply the following additional styling to your prject's [public pages](#).
|
||||
|
||||
* **Public Foreground** — An image shown on the right-side pane of public pages; max 400px width
|
||||
* **Public Background** — An image displayed behind the above foreground image, shown full-bleed within the right-side pane of public pages
|
||||
* **Public Note** — A helpful note displayed at the bottom of the right-side pane of public pages; supports markdown for rich-text formatting
|
||||
|
||||
::: Default Background Color
|
||||
When a Public Background image is not set, the right-side pane of public pages uses the Project Color instead.
|
||||
:::
|
||||
|
||||
## Themes & Custom CSS
|
||||
|
||||
The Directus App has been developed with customization and extensibility in mind. Colors and styles referenced within the codebase all use CSS variables, and therefore it is easy to make comprehensive changes to the App styling.
|
||||
|
||||
* **Themes** — See the [Light Theme](https://github.com/directus/next/blob/main/app/src/styles/themes/_light.scss) or [Dark Theme](https://github.com/directus/next/blob/main/app/src/styles/themes/_dark.scss)
|
||||
* **Typography** — See the [Fonts](https://github.com/directus/next/blob/main/app/src/styles/_type-styles.scss) and [Type Styles](https://github.com/directus/next/blob/main/app/src/styles/mixins/type-styles.scss)
|
||||
* **Variables** — See the [Global Variables](https://github.com/directus/next/blob/main/app/src/styles/_variables.scss)
|
||||
|
||||
You can override any core CSS, including the above variables, directly within the App through project Settings.
|
||||
|
||||
1. Navigate to **Settings > Project Settings**
|
||||
2. Scroll to the **CSS Overrides** field
|
||||
3. Enter any **valid CSS**
|
||||
4. Click the **Save** action button in the header
|
||||
|
||||
::: Action Styling
|
||||
The `--primary` variable (and its shades) control call-to-actions and all other "Directus blue" elements within the App. While it may be tempting to override this variable with your brand's color, please first review the following warnings:
|
||||
|
||||
* Avoid using yellow, orange, or red hues that give a sense of "danger"
|
||||
* Avoid low-contrast colors like yellows, grays, etc, that might not be easily visible
|
||||
* Avoid low-saturation colors like black, which might not properly highlight CTAs
|
||||
|
||||
:::
|
||||
|
||||
## API Reference
|
||||
|
||||
In addition to the static core docs, Directus also includes a [Dynamic API Reference](#) based on your project's schema. This includes tailored endpoint info for each collection within your data model, customizing the documentation to your specific project.
|
||||
|
||||
## System Table Prefix
|
||||
|
||||
Most white-labeling takes place in the presentation layer of the platform's App, but in some cases even the API and/or database needs to be a bit more agnostic. For that reason, Directus allows changing the prefix used by system tables. By default this is set to use `directus_*` to avoid any potential conflicts, but you can override this within the [Environment Variables](#).
|
||||
|
||||
37
docs/index.d.ts
vendored
Normal file
37
docs/index.d.ts
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
export type File = {
|
||||
type: 'file';
|
||||
size: number;
|
||||
path: string;
|
||||
name: string;
|
||||
extension: string;
|
||||
};
|
||||
|
||||
export type Directory = {
|
||||
type: 'directory';
|
||||
size: number;
|
||||
path: string;
|
||||
name: string;
|
||||
children: (Directory | File)[];
|
||||
};
|
||||
|
||||
export type Link = {
|
||||
name: string;
|
||||
to: string;
|
||||
};
|
||||
|
||||
export type Group = {
|
||||
name: string;
|
||||
children: (Group | Link | Divider)[];
|
||||
icon?: string;
|
||||
};
|
||||
|
||||
export type Divider = {
|
||||
divider: true;
|
||||
};
|
||||
|
||||
export const files: Directory;
|
||||
|
||||
export const nav: {
|
||||
app: (Group | Link | Divider)[];
|
||||
web: (Group | Link | Divider)[];
|
||||
};
|
||||
11
docs/index.js
Normal file
11
docs/index.js
Normal file
@@ -0,0 +1,11 @@
|
||||
const appNav = require('./dist/nav-app.json');
|
||||
const webNav = require('./dist/nav-web.json');
|
||||
const index = require('./dist/index.json');
|
||||
|
||||
module.exports = {
|
||||
files: index,
|
||||
nav: {
|
||||
app: appNav,
|
||||
web: webNav,
|
||||
},
|
||||
};
|
||||
86
docs/nav-app.yaml
Normal file
86
docs/nav-app.yaml
Normal file
@@ -0,0 +1,86 @@
|
||||
- name: Getting Started
|
||||
icon: play_arrow
|
||||
children:
|
||||
- name: Introduction
|
||||
to: "/getting-started/introduction"
|
||||
- name: Support & FAQ
|
||||
to: "/getting-started/support"
|
||||
- name: Contributing
|
||||
to: "/getting-started/contributing"
|
||||
- name: Backing Directus
|
||||
to: "/getting-started/backing-directus"
|
||||
|
||||
- name: Concepts
|
||||
icon: school
|
||||
children:
|
||||
- name: Platform Overview
|
||||
to: "/concepts/platform-overview"
|
||||
- name: App Overview
|
||||
to: "/concepts/app-overview"
|
||||
- name: App Extensions
|
||||
to: "/concepts/app-extensions"
|
||||
- name: Activity & Versions
|
||||
to: "/concepts/activity-and-versions"
|
||||
- name: Files & Thumbnails
|
||||
to: "/concepts/files-and-thumbnails"
|
||||
- name: Internationalization
|
||||
to: "/concepts/internationalization"
|
||||
- name: Relationships
|
||||
to: "/concepts/relationships"
|
||||
- name: Users, Roles & Permissions
|
||||
to: "/concepts/users-roles-and-permissions"
|
||||
|
||||
- name: Guides
|
||||
icon: article
|
||||
children:
|
||||
- name: Collections
|
||||
to: "/guides/collections"
|
||||
- name: Fields
|
||||
to: "/guides/fields"
|
||||
- name: Presets
|
||||
to: "/guides/presets"
|
||||
- name: Projects
|
||||
to: "/guides/projects"
|
||||
- name: Roles & Permissions
|
||||
to: "/guides/roles-and-permissions"
|
||||
- name: Users
|
||||
to: "/guides/users"
|
||||
- name: Webhooks
|
||||
to: "/guides/webhooks"
|
||||
- name: White-Labeling
|
||||
to: "/guides/white-labeling"
|
||||
- name: Extensions
|
||||
to: "/guides/extensions"
|
||||
children:
|
||||
- name: Displays
|
||||
to: "/guides/extensions/displays"
|
||||
- name: Interfaces
|
||||
to: "/guides/extensions/interfaces"
|
||||
- name: Layouts
|
||||
to: "/guides/extensions/layouts"
|
||||
- name: Modules
|
||||
to: "/guides/extensions/modules"
|
||||
- name: API Endpoints
|
||||
to: "/guides/extensions/api-endpoints"
|
||||
- name: API Hooks
|
||||
to: "/guides/extensions/api-hooks"
|
||||
- name: Email Templates
|
||||
to: "/guides/extensions/email-templates"
|
||||
- name: Storage Adapters
|
||||
to: "/guides/extensions/storage-adapters"
|
||||
- name: Accessing Data
|
||||
to: "/guides/extensions/accessing-data"
|
||||
|
||||
- name: Reference
|
||||
icon: code
|
||||
children:
|
||||
- name: Command Line Interface
|
||||
to: "/reference/command-line-interface"
|
||||
- name: Environment Variables
|
||||
to: "/reference/environment-variables"
|
||||
- name: Error Codes
|
||||
to: "/reference/error-codes"
|
||||
- name: Filter Rules
|
||||
to: "/reference/filter-rules"
|
||||
- name: Item Objects
|
||||
to: "/reference/item-objects"
|
||||
84
docs/nav-web.yaml
Normal file
84
docs/nav-web.yaml
Normal file
@@ -0,0 +1,84 @@
|
||||
- name: Getting Started
|
||||
emoji: 🐰
|
||||
children:
|
||||
- name: Introduction
|
||||
to: "/getting-started/introduction"
|
||||
- name: Support & FAQ
|
||||
to: "/getting-started/support"
|
||||
- name: Contributing
|
||||
to: "/getting-started/contributing"
|
||||
- name: Backing Directus
|
||||
to: "/getting-started/backing-directus"
|
||||
|
||||
- name: Concepts
|
||||
emoji: 🎓
|
||||
children:
|
||||
- name: Platform Overview
|
||||
to: "/concepts/platform-overview"
|
||||
- name: App Overview
|
||||
to: "/concepts/app-overview"
|
||||
- name: App Extensions
|
||||
to: "/concepts/app-extensions"
|
||||
- name: Activity & Versions
|
||||
to: "/concepts/activity-and-versions"
|
||||
- name: Files & Thumbnails
|
||||
to: "/concepts/files-and-thumbnails"
|
||||
- name: Internationalization
|
||||
to: "/concepts/internationalization"
|
||||
- name: Relationships
|
||||
to: "/concepts/relationships"
|
||||
- name: Users, Roles & Permissions
|
||||
to: "/concepts/users-roles-and-permissions"
|
||||
|
||||
- name: Guides
|
||||
emoji: 📖
|
||||
children:
|
||||
- name: Collections
|
||||
to: "/guides/collections"
|
||||
- name: Fields
|
||||
to: "/guides/fields"
|
||||
- name: Presets
|
||||
to: "/guides/presets"
|
||||
- name: Projects
|
||||
to: "/guides/projects"
|
||||
- name: Roles & Permissions
|
||||
to: "/guides/roles-and-permissions"
|
||||
- name: Users
|
||||
to: "/guides/users"
|
||||
- name: Webhooks
|
||||
to: "/guides/webhooks"
|
||||
- name: White-Labeling
|
||||
to: "/guides/white-labeling"
|
||||
- name: Extensions
|
||||
to: "/guides/extensions"
|
||||
children:
|
||||
- name: Custom Displays
|
||||
to: "/guides/extensions/creating-a-custom-display"
|
||||
- name: Custom Interfaces
|
||||
to: "/guides/extensions/creating-a-custom-interface"
|
||||
- name: Custom Layouts
|
||||
to: "/guides/extensions/creating-a-custom-layout"
|
||||
- name: Custom Modules
|
||||
to: "/guides/extensions/creating-a-custom-module"
|
||||
- name: Custom API Endpoints
|
||||
to: "/guides/extensions/creating-a-custom-api-endpoint"
|
||||
- name: Custom API Hooks
|
||||
to: "/guides/extensions/creating-a-custom-api-hook"
|
||||
- name: Custom Email Templates
|
||||
to: "/guides/extensions/creating-a-custom-email-template"
|
||||
- name: Custom Storage Adapters
|
||||
to: "/guides/extensions/creating-a-custom-storage-adapter"
|
||||
- name: Accessing Data
|
||||
to: "/guides/extensions/accessing-data"
|
||||
|
||||
- name: Reference
|
||||
emoji: 🚀
|
||||
children:
|
||||
- name: Environment Variables
|
||||
to: "/reference/environment-variables"
|
||||
- name: Command Line Interface
|
||||
to: "/reference/command-line-interface"
|
||||
- name: Error Codes
|
||||
to: "/reference/error-codes"
|
||||
- name: Item Rules
|
||||
to: "/reference/item-rules"
|
||||
1082
docs/package-lock.json
generated
Normal file
1082
docs/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,12 +1,22 @@
|
||||
{
|
||||
"name": "@directus/docs",
|
||||
"private": false,
|
||||
"version": "9.0.0-beta.9",
|
||||
"version": "9.0.0-beta.10",
|
||||
"description": "",
|
||||
"main": "dist/index.json",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"build": "node build.js",
|
||||
"prepublish": "npm run build"
|
||||
"prepublish": "npm run build",
|
||||
"dev": "npm-watch build"
|
||||
},
|
||||
"watch": {
|
||||
"build": {
|
||||
"patterns": ["."],
|
||||
"ignore": "dist",
|
||||
"extensions": "md,yaml",
|
||||
"silent": true,
|
||||
"quiet": true
|
||||
}
|
||||
},
|
||||
"files": [
|
||||
"dist"
|
||||
@@ -14,5 +24,8 @@
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"gitHead": "4476da28dbbc2824e680137aa28b2b91b5afabec"
|
||||
"gitHead": "4476da28dbbc2824e680137aa28b2b91b5afabec",
|
||||
"devDependencies": {
|
||||
"npm-watch": "^0.7.0"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
"docs",
|
||||
"packages/*"
|
||||
],
|
||||
"version": "9.0.0-beta.9",
|
||||
"version": "9.0.0-beta.10",
|
||||
"command": {
|
||||
"bootstrap": {
|
||||
"npmClientArgs": [
|
||||
|
||||
13
package-lock.json
generated
13
package-lock.json
generated
@@ -1453,7 +1453,6 @@
|
||||
"mitt": "^2.1.0",
|
||||
"mousetrap": "^1.6.5",
|
||||
"nanoid": "^3.1.10",
|
||||
"openapi3-ts": "^1.4.0",
|
||||
"pinia": "^0.0.7",
|
||||
"portal-vue": "^2.1.7",
|
||||
"pretty-ms": "^7.0.0",
|
||||
@@ -26348,9 +26347,12 @@
|
||||
}
|
||||
},
|
||||
"openapi3-ts": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/openapi3-ts/-/openapi3-ts-1.4.0.tgz",
|
||||
"integrity": "sha512-8DmE2oKayvSkIR3XSZ4+pRliBsx19bSNeIzkTPswY8r4wvjX86bMxsORdqwAwMxE8PefOcSAT2auvi/0TZe9yA=="
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/openapi3-ts/-/openapi3-ts-2.0.0.tgz",
|
||||
"integrity": "sha512-q4p8OX/mD7qXeDKkhdLhpEz1Zh/IxPBDWmuq7f07fQJpo7exUW20sMrHfws1xzihYPktTXVV5MDOZkG/1uguEg==",
|
||||
"requires": {
|
||||
"yaml": "^1.10.0"
|
||||
}
|
||||
},
|
||||
"opencollective-postinstall": {
|
||||
"version": "2.0.3",
|
||||
@@ -37444,8 +37446,7 @@
|
||||
"yaml": {
|
||||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz",
|
||||
"integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg=="
|
||||
},
|
||||
"yargs": {
|
||||
"version": "13.3.2",
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "lerna run dev --stream --parallel",
|
||||
"release": "lerna publish --force-publish"
|
||||
"release": "lerna publish --force-publish",
|
||||
"setup": "lerna exec npm install && lerna run build"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
|
||||
383
packages/create-directus-project/package-lock.json
generated
Normal file
383
packages/create-directus-project/package-lock.json
generated
Normal file
@@ -0,0 +1,383 @@
|
||||
{
|
||||
"name": "create-directus-project",
|
||||
"version": "9.0.0-beta.10",
|
||||
"lockfileVersion": 1,
|
||||
"requires": true,
|
||||
"dependencies": {
|
||||
"ansi-regex": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz",
|
||||
"integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg=="
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"at-least-node": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz",
|
||||
"integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg=="
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"cli-cursor": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz",
|
||||
"integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==",
|
||||
"requires": {
|
||||
"restore-cursor": "^3.1.0"
|
||||
}
|
||||
},
|
||||
"cli-spinners": {
|
||||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.4.0.tgz",
|
||||
"integrity": "sha512-sJAofoarcm76ZGpuooaO0eDy8saEy+YoZBLjC4h8srt4jeBnkYeOgqxgsJQTpyt2LjI5PTfLJHSL+41Yu4fEJA=="
|
||||
},
|
||||
"clone": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
|
||||
"integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4="
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"commander": {
|
||||
"version": "6.1.0",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-6.1.0.tgz",
|
||||
"integrity": "sha512-wl7PNrYWd2y5mp1OK/LhTlv8Ff4kQJQRXXAvF+uU/TPNiVJUxZLRYGj/B0y/lPGAVcSbJqH2Za/cvHmrPMC8mA=="
|
||||
},
|
||||
"cross-spawn": {
|
||||
"version": "7.0.3",
|
||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||
"integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==",
|
||||
"requires": {
|
||||
"path-key": "^3.1.0",
|
||||
"shebang-command": "^2.0.0",
|
||||
"which": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"defaults": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz",
|
||||
"integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=",
|
||||
"requires": {
|
||||
"clone": "^1.0.2"
|
||||
}
|
||||
},
|
||||
"end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
"integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
|
||||
"requires": {
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
|
||||
},
|
||||
"execa": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/execa/-/execa-4.0.3.tgz",
|
||||
"integrity": "sha512-WFDXGHckXPWZX19t1kCsXzOpqX9LWYNqn4C+HqZlk/V0imTkzJZqf87ZBhvpHaftERYknpk0fjSylnXVlVgI0A==",
|
||||
"requires": {
|
||||
"cross-spawn": "^7.0.0",
|
||||
"get-stream": "^5.0.0",
|
||||
"human-signals": "^1.1.1",
|
||||
"is-stream": "^2.0.0",
|
||||
"merge-stream": "^2.0.0",
|
||||
"npm-run-path": "^4.0.0",
|
||||
"onetime": "^5.1.0",
|
||||
"signal-exit": "^3.0.2",
|
||||
"strip-final-newline": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"fs-extra": {
|
||||
"version": "9.0.1",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.1.tgz",
|
||||
"integrity": "sha512-h2iAoN838FqAFJY2/qVpzFXy+EBxfVE220PalAqQLDVsFOHLJrZvut5puAbCdNv6WJk+B8ihI+k0c7JK5erwqQ==",
|
||||
"requires": {
|
||||
"at-least-node": "^1.0.0",
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
"universalify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"get-stream": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz",
|
||||
"integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==",
|
||||
"requires": {
|
||||
"pump": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"graceful-fs": {
|
||||
"version": "4.2.4",
|
||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
|
||||
"integrity": "sha512-WjKPNJF79dtJAVniUlGGWHYGz2jWxT6VhN/4m1NdkbZ2nOsEF+cI1Edgql5zCRhs/VsQYRvrXctxktVXZUkixw=="
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
|
||||
},
|
||||
"human-signals": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz",
|
||||
"integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw=="
|
||||
},
|
||||
"is-interactive": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz",
|
||||
"integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w=="
|
||||
},
|
||||
"is-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw=="
|
||||
},
|
||||
"isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
"integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
|
||||
},
|
||||
"jsonfile": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.0.1.tgz",
|
||||
"integrity": "sha512-jR2b5v7d2vIOust+w3wtFKZIfpC2pnRmFAhAC/BuweZFQR8qZzxH1OyrQ10HmdVYiXWkYUqPVsz91cG7EL2FBg==",
|
||||
"requires": {
|
||||
"graceful-fs": "^4.1.6",
|
||||
"universalify": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"log-symbols": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-3.0.0.tgz",
|
||||
"integrity": "sha512-dSkNGuI7iG3mfvDzUuYZyvk5dD9ocYCYzNU6CYDE6+Xqd+gwme6Z00NS3dUh8mq/73HaEtT7m6W+yUPtU6BZnQ==",
|
||||
"requires": {
|
||||
"chalk": "^2.4.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"requires": {
|
||||
"color-convert": "^1.9.0"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"requires": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"requires": {
|
||||
"has-flag": "^3.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"merge-stream": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz",
|
||||
"integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w=="
|
||||
},
|
||||
"mimic-fn": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz",
|
||||
"integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg=="
|
||||
},
|
||||
"mute-stream": {
|
||||
"version": "0.0.8",
|
||||
"resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz",
|
||||
"integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA=="
|
||||
},
|
||||
"npm-run-path": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz",
|
||||
"integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==",
|
||||
"requires": {
|
||||
"path-key": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"once": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||
"requires": {
|
||||
"wrappy": "1"
|
||||
}
|
||||
},
|
||||
"onetime": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz",
|
||||
"integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==",
|
||||
"requires": {
|
||||
"mimic-fn": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"ora": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ora/-/ora-4.1.1.tgz",
|
||||
"integrity": "sha512-sjYP8QyVWBpBZWD6Vr1M/KwknSw6kJOz41tvGMlwWeClHBtYKTbHMki1PsLZnxKpXMPbTKv9b3pjQu3REib96A==",
|
||||
"requires": {
|
||||
"chalk": "^3.0.0",
|
||||
"cli-cursor": "^3.1.0",
|
||||
"cli-spinners": "^2.2.0",
|
||||
"is-interactive": "^1.0.0",
|
||||
"log-symbols": "^3.0.0",
|
||||
"mute-stream": "0.0.8",
|
||||
"strip-ansi": "^6.0.0",
|
||||
"wcwidth": "^1.0.1"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz",
|
||||
"integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==",
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"path-key": {
|
||||
"version": "3.1.1",
|
||||
"resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz",
|
||||
"integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="
|
||||
},
|
||||
"pump": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz",
|
||||
"integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==",
|
||||
"requires": {
|
||||
"end-of-stream": "^1.1.0",
|
||||
"once": "^1.3.1"
|
||||
}
|
||||
},
|
||||
"restore-cursor": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz",
|
||||
"integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==",
|
||||
"requires": {
|
||||
"onetime": "^5.1.0",
|
||||
"signal-exit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"shebang-command": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||
"integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==",
|
||||
"requires": {
|
||||
"shebang-regex": "^3.0.0"
|
||||
}
|
||||
},
|
||||
"shebang-regex": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz",
|
||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="
|
||||
},
|
||||
"signal-exit": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
|
||||
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
|
||||
},
|
||||
"strip-ansi": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||
"integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==",
|
||||
"requires": {
|
||||
"ansi-regex": "^5.0.0"
|
||||
}
|
||||
},
|
||||
"strip-final-newline": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz",
|
||||
"integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"universalify": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-1.0.0.tgz",
|
||||
"integrity": "sha512-rb6X1W158d7pRQBg5gkR8uPaSfiids68LTJQYOtEUhoJUWBdaQHsuT/EUduxXYxcrt4r5PJ4fuHW1MHT6p0qug=="
|
||||
},
|
||||
"wcwidth": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz",
|
||||
"integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=",
|
||||
"requires": {
|
||||
"defaults": "^1.0.3"
|
||||
}
|
||||
},
|
||||
"which": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||
"integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==",
|
||||
"requires": {
|
||||
"isexe": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"wrappy": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "create-directus-project",
|
||||
"version": "9.0.0-beta.9",
|
||||
"version": "9.0.0-beta.10",
|
||||
"description": "A small installer util that will create a directory, add boilerplate folders, and install Directus through npm.",
|
||||
"main": "lib/index.js",
|
||||
"bin": "./lib/index.js",
|
||||
|
||||
1423
packages/spec/package-lock.json
generated
Normal file
1423
packages/spec/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,14 +1,23 @@
|
||||
{
|
||||
"name": "@directus/specs",
|
||||
"version": "9.0.0-beta.9",
|
||||
"description": "Specification of the Directus Api",
|
||||
"version": "9.0.0-beta.10",
|
||||
"description": "OpenAPI Specification of the Directus API",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"ui:watch": "swagger-ui-watcher specs/openapi.yaml",
|
||||
"validate": "swagger-cli validate specs/openapi.yaml",
|
||||
"build": "swagger-cli bundle specs/openapi.yaml -o dist/openapi.json",
|
||||
"build:deref": "swagger-cli bundle specs/openapi.yaml -o dist/openapi-deref.json --dereference",
|
||||
"prepublishOnly": "npm run build && npm run build:deref"
|
||||
"prepublishOnly": "npm run build && npm run build:deref",
|
||||
"dev": "npm-watch build"
|
||||
},
|
||||
"watch": {
|
||||
"build": {
|
||||
"patterns": ["specs"],
|
||||
"extensions": "yaml",
|
||||
"quiet": true,
|
||||
"silent": true
|
||||
}
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -26,5 +35,9 @@
|
||||
"README.md",
|
||||
"index.js"
|
||||
],
|
||||
"gitHead": "4476da28dbbc2824e680137aa28b2b91b5afabec"
|
||||
"gitHead": "4476da28dbbc2824e680137aa28b2b91b5afabec",
|
||||
"devDependencies": {
|
||||
"npm-watch": "^0.7.0",
|
||||
"swagger-cli": "^4.0.4"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,39 +8,44 @@ properties:
|
||||
description: Action that was performed.
|
||||
example: update
|
||||
type: string
|
||||
enum: [authenticate, comment, upload, create, update, delete, soft-delete, revert, invalid-credentials]
|
||||
enum:
|
||||
- create
|
||||
- update
|
||||
- delete
|
||||
- authenticate
|
||||
user:
|
||||
description: Unique identifier of the user account who caused this action.
|
||||
example: 63716273-0f29-4648-8a2a-2af2948f6f78
|
||||
type: string
|
||||
nullable: true # States the SQL structure
|
||||
description: The user who performed this action.
|
||||
oneOf:
|
||||
- type: string
|
||||
- $ref: "../openapi.yaml#/components/schemas/User"
|
||||
nullable: true
|
||||
timestamp:
|
||||
description: When the action happened.
|
||||
example: '2019-12-05 22:52:09'
|
||||
example: "2019-12-05T22:52:09Z"
|
||||
type: string
|
||||
format: date-time
|
||||
ip:
|
||||
description: The IP address of the user at the time the action took place.
|
||||
example: 160.72.72.58
|
||||
example: 127.0.0.1
|
||||
oneOf:
|
||||
- type: string
|
||||
format: ipv4
|
||||
- type: string
|
||||
enum: [localhost]
|
||||
user_agent:
|
||||
description: User agent string of the browser the user used when the action took place.
|
||||
example: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_1) AppleWebKit/537.36 (KHTML,like Gecko) Chrome/78.0.3904.108 Safari/537.36
|
||||
type: string
|
||||
collection:
|
||||
description: Collection identifier in which the item resides.
|
||||
example: movies
|
||||
type: string
|
||||
oneOf:
|
||||
- type: string
|
||||
- $ref: "../openapi.yaml#/components/schemas/Collection"
|
||||
item:
|
||||
description: Unique identifier for the item the action applied to. This is always a string, even for integer primary keys.
|
||||
example: '328'
|
||||
example: "328"
|
||||
type: string
|
||||
comment:
|
||||
description: User comment. This will store the comments that show up in the right
|
||||
description:
|
||||
User comment. This will store the comments that show up in the right
|
||||
sidebar of the item edit page in the admin app.
|
||||
example: null
|
||||
type: string
|
||||
|
||||
@@ -1,43 +1,85 @@
|
||||
type: object
|
||||
properties:
|
||||
collection:
|
||||
description: The collection name.
|
||||
description: The collection key.
|
||||
example: customers
|
||||
type: string
|
||||
meta:
|
||||
description: Metadata of the collection.
|
||||
type: object
|
||||
example: null
|
||||
nullable: true
|
||||
properties:
|
||||
collection:
|
||||
description: The collection name again!
|
||||
description: The collection key.
|
||||
example: customers
|
||||
type: string
|
||||
hidden:
|
||||
type: boolean
|
||||
singleton:
|
||||
type: boolean
|
||||
icon:
|
||||
description: Name of a Google Material Design Icon that's assigned to this collection.
|
||||
type: string
|
||||
example: people
|
||||
nullable: true
|
||||
note:
|
||||
description: A note describing the collection.
|
||||
type: string
|
||||
nullable: true
|
||||
translation:
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
display_template:
|
||||
description: Text representation of how items from this collection are shown across the system.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
hidden:
|
||||
description: Whether or not the collection is hidden from the navigation in the admin app.
|
||||
type: boolean
|
||||
example: false
|
||||
singleton:
|
||||
description: Whether or not the collection is treated as a single object.
|
||||
type: boolean
|
||||
example: false
|
||||
translations:
|
||||
description: Key value pairs of how to show this collection's name in different languages in the admin app.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
archive_field:
|
||||
description: What field holds the archive value.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
archive_app_filter:
|
||||
description: What value to use for "archived" items.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
archive_value:
|
||||
description: What value to use to "unarchive" items.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
unarchive_value:
|
||||
description: Whether or not to show the "archived" filter.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
sort_field:
|
||||
description: The sort field in the collection.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: The collection key.
|
||||
type: string
|
||||
example: customers
|
||||
schema:
|
||||
description: Database schema (pg only).
|
||||
example: public
|
||||
type: string
|
||||
comment:
|
||||
description: Comment as saved in the database.
|
||||
type: string
|
||||
collation:
|
||||
type: string
|
||||
engine:
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
description: Unique identifier for the field in the `directus_fields` collection.
|
||||
example: 167
|
||||
type: integer
|
||||
nullable: true
|
||||
collection:
|
||||
description: Unique name of the collection this field is in.
|
||||
example: about_us
|
||||
@@ -13,102 +8,159 @@ properties:
|
||||
description: Unique name of the field. Field name is unique within the collection.
|
||||
example: id
|
||||
type: string
|
||||
auto_increment:
|
||||
description: If the value in this field is auto incremented. Only applies to integer
|
||||
type fields.
|
||||
example: true
|
||||
type: boolean
|
||||
datatype:
|
||||
description: SQL datatype of the column that corresponds to this field.
|
||||
example: INT
|
||||
type: string
|
||||
nullable: true
|
||||
group:
|
||||
description: What field group this field is part of.
|
||||
example: null
|
||||
type: integer
|
||||
nullable: true
|
||||
hidden_browse:
|
||||
description: If this field should be hidden from the item browse (listing) page.
|
||||
example: true
|
||||
type: boolean
|
||||
hidden_detail:
|
||||
description: If this field should be hidden from the item detail (edit) page.
|
||||
example: true
|
||||
type: boolean
|
||||
interface:
|
||||
description: What interface is used in the admin app to edit the value for this
|
||||
field.
|
||||
example: primary-key
|
||||
type: string
|
||||
nullable: true
|
||||
length:
|
||||
description: Length of the field. Will be used in SQL to set the `length` property
|
||||
of the colummn.
|
||||
example: '10'
|
||||
type: string
|
||||
nullable: true
|
||||
locked:
|
||||
description: If the field can be altered by the end user. Directus system fields
|
||||
have this value set to `true`.
|
||||
example: true
|
||||
type: boolean
|
||||
note:
|
||||
description: A user provided note for the field. Will be rendered alongside the
|
||||
interface on the edit page.
|
||||
example: ''
|
||||
type: string
|
||||
nullable: true
|
||||
options:
|
||||
description: Options for the interface that's used. This format is based on the
|
||||
individual interface.
|
||||
example: null
|
||||
type: object
|
||||
nullable: true
|
||||
primary_key:
|
||||
description: If this field is the primary key of the collection.
|
||||
example: true
|
||||
type: boolean
|
||||
readonly:
|
||||
description: Prevents the user from editing the value in the field.
|
||||
example: false
|
||||
type: boolean
|
||||
required:
|
||||
description: If this field requires a value.
|
||||
example: true
|
||||
type: boolean
|
||||
signed:
|
||||
description: If the value is signed or not. Only applies to integer type fields.
|
||||
example: false
|
||||
type: boolean
|
||||
sort:
|
||||
description: Sort order of this field on the edit page of the admin app.
|
||||
example: 1
|
||||
type: integer
|
||||
nullable: true
|
||||
translation:
|
||||
description: 'Key value pair of `<locale>: <translation>` that allows the user
|
||||
to change the displayed name of the field in the admin app.'
|
||||
example: null
|
||||
type: object
|
||||
nullable: true
|
||||
type:
|
||||
description: Directus specific data type. Used to cast values in the API.
|
||||
example: integer
|
||||
type: string
|
||||
unique:
|
||||
description: If the value of this field should be unique within the collection.
|
||||
example: false
|
||||
type: boolean
|
||||
validation:
|
||||
description: User provided regex that will be used in the API to validate incoming
|
||||
values. It uses the PHP flavor of RegEX.
|
||||
example: null
|
||||
type: string
|
||||
schema:
|
||||
description: The schema info.
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: The name of the field.
|
||||
example: title
|
||||
type: string
|
||||
table:
|
||||
description: The collection of the field.
|
||||
example: posts
|
||||
type: string
|
||||
type:
|
||||
description: The datatype of the field.
|
||||
example: string
|
||||
type: string
|
||||
default_value:
|
||||
description: The default value of the field.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
max_length:
|
||||
description: The max length of the field.
|
||||
example: null
|
||||
type: integer
|
||||
nullable: true
|
||||
is_nullable:
|
||||
description: If the field is nullable.
|
||||
example: false
|
||||
type: boolean
|
||||
is_primary_key:
|
||||
description: If the field is primary key.
|
||||
example: false
|
||||
type: boolean
|
||||
has_auto_increment:
|
||||
description: If the field has auto increment.
|
||||
example: false
|
||||
type: boolean
|
||||
foreign_key_column:
|
||||
description: Related column from the foreign key constraint.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
foreign_key_table:
|
||||
description: Related table from the foreign key constraint.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
comment:
|
||||
description: Comment as saved in the database.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
schema:
|
||||
description: Database schema (pg only).
|
||||
example: public
|
||||
type: string
|
||||
foreign_key_schema:
|
||||
description: Related schema from the foreign key constraint (pg only).
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
meta:
|
||||
description: The meta info.
|
||||
type: object
|
||||
nullable: true
|
||||
width:
|
||||
description: Width of the field on the edit form.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
enum: [half, half-left, half-right, full, fill, null]
|
||||
properties:
|
||||
id:
|
||||
description: Unique identifier for the field in the `directus_fields` collection.
|
||||
example: 3
|
||||
type: integer
|
||||
collection:
|
||||
description: Unique name of the collection this field is in.
|
||||
example: posts
|
||||
type: string
|
||||
field:
|
||||
description: Unique name of the field. Field name is unique within the collection.
|
||||
example: title
|
||||
type: string
|
||||
special:
|
||||
description: Transformation flags for field
|
||||
example: null
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
interface:
|
||||
description:
|
||||
What interface is used in the admin app to edit the value for this field.
|
||||
example: primary-key
|
||||
type: string
|
||||
nullable: true
|
||||
options:
|
||||
description:
|
||||
Options for the interface that's used. This format is based on the individual interface.
|
||||
example: null
|
||||
type: object
|
||||
nullable: true
|
||||
display:
|
||||
description: What display is used in the admin app to display the value for this field.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
display_options:
|
||||
description: Options for the display that's used. This format is based on the individual display.
|
||||
example: null
|
||||
type: object
|
||||
nullable: true
|
||||
locked:
|
||||
description:
|
||||
If the field can be altered by the end user. Most Directus system fields
|
||||
have this value set to `true`.
|
||||
example: true
|
||||
type: boolean
|
||||
readonly:
|
||||
description: Prevents the user from editing the value in the field.
|
||||
example: false
|
||||
type: boolean
|
||||
hidden:
|
||||
description: If this field should be hidden.
|
||||
example: true
|
||||
type: boolean
|
||||
sort:
|
||||
description: Sort order of this field on the edit page of the admin app.
|
||||
example: 1
|
||||
type: integer
|
||||
nullable: true
|
||||
width:
|
||||
description: Width of the field on the edit form.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
enum: [half, half-left, half-right, full, fill, null]
|
||||
group:
|
||||
description: What field group this field is part of.
|
||||
example: null
|
||||
type: integer
|
||||
nullable: true
|
||||
translations:
|
||||
description:
|
||||
"Key value pair of `<locale>: <translation>` that allows the user
|
||||
to change the displayed name of the field in the admin app."
|
||||
example: null
|
||||
type: object
|
||||
nullable: true
|
||||
note:
|
||||
description:
|
||||
A user provided note for the field. Will be rendered alongside the
|
||||
interface on the edit page.
|
||||
example: ""
|
||||
type: string
|
||||
nullable: true
|
||||
|
||||
@@ -1,60 +1,71 @@
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
description: Unique identifier for the file.
|
||||
example: 8cbb43fe-4cdf-4991-8352-c461779cec02
|
||||
type: string
|
||||
storage:
|
||||
description:
|
||||
Where the file is stored. Either `local` for the local filesystem
|
||||
or the name of the storage adapter (for example `s3`).
|
||||
example: local
|
||||
type: string
|
||||
filename_disk:
|
||||
description:
|
||||
Name of the file on disk. By default, Directus uses a random hash
|
||||
for the filename.
|
||||
example: a88c3b72-ac58-5436-a4ec-b2858531333a.jpg
|
||||
type: string
|
||||
filename_download:
|
||||
description: How you want to the file to be named when it's being downloaded.
|
||||
example: avatar.jpg
|
||||
type: string
|
||||
title:
|
||||
description:
|
||||
Title for the file. Is extracted from the filename on upload, but
|
||||
can be edited by the user.
|
||||
example: User Avatar
|
||||
type: string
|
||||
type:
|
||||
description: MIME type of the file.
|
||||
example: image/jpeg
|
||||
type: string
|
||||
folder:
|
||||
description: Virtual folder where this file resides in.
|
||||
example: null
|
||||
oneOf:
|
||||
- type: string
|
||||
- $ref: "../openapi.yaml#/components/schemas/Folder"
|
||||
nullable: true
|
||||
uploaded_by:
|
||||
description: Who uploaded the file.
|
||||
example: 63716273-0f29-4648-8a2a-2af2948f6f78
|
||||
oneOf:
|
||||
- type: string
|
||||
- $ref: "../openapi.yaml#/components/schemas/User"
|
||||
uploaded_on:
|
||||
description: When the file was uploaded.
|
||||
example: "2019-12-03T00:10:15+00:00"
|
||||
type: string
|
||||
format: date-time
|
||||
charset:
|
||||
description: Character set of the file.
|
||||
example: binary
|
||||
type: string
|
||||
nullable: true # Should not be null?
|
||||
checksum:
|
||||
description: Represents the sum of the correct digits of the file, can be used
|
||||
to detect errors in and duplicates of the file later.
|
||||
example: d41d8cd98f00b204e9800998ecf8427e
|
||||
type: string
|
||||
data:
|
||||
example:
|
||||
embed: null
|
||||
full_url: 'https://demo.directus.io/uploads/thumper/originals/a88c3b72-ac58-5436-a4ec-b2858531333a.jpg'
|
||||
thumbnails:
|
||||
dimension: 64x64
|
||||
height: 64
|
||||
relative_url: '/thumper/assets/pnw7s9lqy68048g0?key=directus-small-crop'
|
||||
url: 'https://demo.directus.io/thumper/assets/pnw7s9lqy68048g0?key=directus-small-crop'
|
||||
width: 64
|
||||
url: '/uploads/thumper/originals/a88c3b72-ac58-5436-a4ec-b2858531333a.jpg'
|
||||
properties:
|
||||
full_url:
|
||||
description: Full URL to the original file.
|
||||
type: string
|
||||
thumbnails:
|
||||
description: List of all available asset sizes with links.
|
||||
type: array
|
||||
nullable: true
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
dimension:
|
||||
description: Width x height of the thumbnail.
|
||||
type: string
|
||||
height:
|
||||
description: Height of the thumbnail in pixels.
|
||||
type: integer
|
||||
relative_url:
|
||||
description: Relative URL to the thumbnail.
|
||||
type: string
|
||||
url:
|
||||
description: Full URL to the thumbnail.
|
||||
type: string
|
||||
width:
|
||||
description: Width of the thumbnail in pixels.
|
||||
type: integer
|
||||
url:
|
||||
description: Relative URL to the original file.
|
||||
type: string
|
||||
type: object
|
||||
description:
|
||||
description: Description for the file.
|
||||
example: ''
|
||||
type: string
|
||||
nullable: true
|
||||
filesize:
|
||||
description: Size of the file in bytes.
|
||||
example: 137862
|
||||
type: integer
|
||||
width:
|
||||
description: Width of the file in pixels. Only applies to images.
|
||||
example: 800
|
||||
type: integer
|
||||
nullable: true
|
||||
height:
|
||||
description: Height of the file in pixels. Only applies to images.
|
||||
example: 838
|
||||
type: integer
|
||||
nullable: true
|
||||
duration:
|
||||
description: Duration of the file in seconds. Only applies to audio and video.
|
||||
@@ -66,82 +77,25 @@ properties:
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
filename_disk:
|
||||
description: Name of the file on disk. By default, Directus uses a random hash
|
||||
for the filename.
|
||||
example: a88c3b72-ac58-5436-a4ec-b2858531333a.jpg
|
||||
description:
|
||||
description: Description for the file.
|
||||
type: string
|
||||
filename_download:
|
||||
description: How you want to the file to be named when it's being downloaded.
|
||||
example: avatar.jpg
|
||||
type: string
|
||||
filesize:
|
||||
description: Size of the file in bytes.
|
||||
example: 137862
|
||||
type: integer
|
||||
folder:
|
||||
description: Virtual folder where this file resides in.
|
||||
example: null
|
||||
$ref: '../openapi.yaml#/components/schemas/Folder'
|
||||
nullable: true
|
||||
height:
|
||||
description: Height of the file in pixels. Only applies to images.
|
||||
example: 838
|
||||
type: integer
|
||||
nullable: true
|
||||
id:
|
||||
description: Unique identifier for the file.
|
||||
example: 8cbb43fe-4cdf-4991-8352-c461779cec02
|
||||
type: string
|
||||
location:
|
||||
description: Where the file was created. Is automatically populated based on EXIF
|
||||
description:
|
||||
Where the file was created. Is automatically populated based on EXIF
|
||||
data for images.
|
||||
type: string
|
||||
nullable: true
|
||||
metadata:
|
||||
description: User provided miscellaneous key value pairs that serve as additional
|
||||
metadata for the file.
|
||||
example: null
|
||||
type: object
|
||||
nullable: true
|
||||
private_hash:
|
||||
description: Random hash used to access the file privately. This can be rotated
|
||||
to prevent unauthorized access to the file.
|
||||
example: pnw7s9lqy68048g0
|
||||
type: string
|
||||
storage:
|
||||
description: Where the file is stored. Either `local` for the local filesystem
|
||||
or the name of the storage adapter (for example `s3`).
|
||||
example: local
|
||||
type: string
|
||||
tags:
|
||||
description: Tags for the file. Is automatically populated based on EXIF data
|
||||
for images.
|
||||
description:
|
||||
Tags for the file. Is automatically populated based on EXIF data for images.
|
||||
type: array
|
||||
nullable: true
|
||||
items:
|
||||
type: string
|
||||
title:
|
||||
description: Title for the file. Is extracted from the filename on upload, but
|
||||
can be edited by the user.
|
||||
example: User Avatar
|
||||
type: string
|
||||
type:
|
||||
description: MIME type of the file.
|
||||
example: image/jpeg
|
||||
type: string
|
||||
uploaded_by:
|
||||
description: Who uploaded the file.
|
||||
example: 63716273-0f29-4648-8a2a-2af2948f6f78
|
||||
type: string
|
||||
# $ref: '../openapi.yaml#/components/schemas/User'
|
||||
uploaded_on:
|
||||
description: When the file was uploaded.
|
||||
example: '2019-12-03T00:10:15+00:00'
|
||||
type: string
|
||||
format: date-time
|
||||
width:
|
||||
description: Width of the file in pixels. Only applies to images.
|
||||
example: 800
|
||||
type: integer
|
||||
nullable: true
|
||||
metadata:
|
||||
description:
|
||||
IPTC, EXIF, and ICC metadata extracted from file
|
||||
type: object
|
||||
nullable: true
|
||||
|
||||
@@ -11,5 +11,7 @@ properties:
|
||||
parent:
|
||||
description: Unique identifier of the parent folder. This allows for nested folders.
|
||||
example: null
|
||||
type: string
|
||||
oneOf:
|
||||
- type: string
|
||||
- $ref: "../openapi.yaml#/components/schemas/Folder"
|
||||
nullable: true
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
type: object
|
||||
properties: {}
|
||||
properties: {}
|
||||
|
||||
@@ -1,70 +1,46 @@
|
||||
type: object
|
||||
properties:
|
||||
collection:
|
||||
description: What collection this permission applies to.
|
||||
example: customers
|
||||
type: string
|
||||
comment:
|
||||
description: If the user can post comments.
|
||||
example: update
|
||||
type: string
|
||||
enum: [none, create, update, full]
|
||||
create:
|
||||
description: If the user can create items.
|
||||
example: full
|
||||
type: string
|
||||
enum: [none, full]
|
||||
delete:
|
||||
description: If the user can update items.
|
||||
example: none
|
||||
type: string
|
||||
enum: [none, mine, role, full]
|
||||
explain:
|
||||
description: If the user is required to leave a comment explaining what was changed.
|
||||
example: none
|
||||
type: string
|
||||
enum: [none, create, update, always]
|
||||
id:
|
||||
description: Unique identifier for the permission.
|
||||
example: 1
|
||||
type: integer
|
||||
read:
|
||||
description: If the user can read items.
|
||||
example: mine
|
||||
type: string
|
||||
enum: [none, mine, role, full]
|
||||
read_field_blacklist:
|
||||
description: Explicitly denies read access for specific fields.
|
||||
example: []
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
role:
|
||||
description: Unique identifier of the role this permission applies to.
|
||||
example: 2f24211d-d928-469a-aea3-3c8f53d4e426
|
||||
type: string
|
||||
nullable: true # Should this be nullable?
|
||||
status:
|
||||
description: What status this permission applies to.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
status_blacklist:
|
||||
description: Explicitly denies specific statuses to be used.
|
||||
example: []
|
||||
oneOf:
|
||||
- type: array
|
||||
nullable: true
|
||||
items:
|
||||
type: string
|
||||
update:
|
||||
description: If the user can update items.
|
||||
example: none
|
||||
collection:
|
||||
description: What collection this permission applies to.
|
||||
example: customers
|
||||
type: string
|
||||
enum: [none, mine, role, full]
|
||||
write_field_blacklist:
|
||||
description: Explicitly denies write access for specific fields.
|
||||
example: []
|
||||
action:
|
||||
description: What action this permission applies to.
|
||||
example: create
|
||||
type: string
|
||||
enum:
|
||||
- create
|
||||
- read
|
||||
- update
|
||||
- delete
|
||||
permissions:
|
||||
description: JSON structure containing the permissions checks for this permission.
|
||||
type: object
|
||||
nullable: true
|
||||
validation:
|
||||
description: JSON structure containing the validation checks for this permission.
|
||||
type: object
|
||||
nullable: true
|
||||
presets:
|
||||
description: JSON structure containing the preset value for created/updated items.
|
||||
type: object
|
||||
nullable: true
|
||||
fields:
|
||||
description: CSV of fields that the user is allowed to interact with.
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
type: string
|
||||
nullable: true
|
||||
limit:
|
||||
description: Maximum amount of items the user can interact with at a time.
|
||||
type: number
|
||||
nullable: true
|
||||
|
||||
@@ -1,73 +1,72 @@
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
description: Unique identifier for this single collection preset.
|
||||
example: 155
|
||||
type: integer
|
||||
bookmark:
|
||||
description:
|
||||
Name for the bookmark. If this is set, the preset will be considered a bookmark.
|
||||
nullable: true
|
||||
type: string
|
||||
user:
|
||||
description:
|
||||
The unique identifier of the user to whom this collection preset applies.
|
||||
example: 63716273-0f29-4648-8a2a-2af2948f6f78
|
||||
nullable: true
|
||||
oneOf:
|
||||
- type: string
|
||||
- $ref: "../openapi.yaml#/components/schemas/User"
|
||||
role:
|
||||
description:
|
||||
The unique identifier of a role in the platform. If `user` is null,
|
||||
this will be used to apply the collection preset or bookmark for all users in
|
||||
the role.
|
||||
example: 50419801-0f30-8644-2b3c-9bc2d980d0a0
|
||||
nullable: true
|
||||
oneOf:
|
||||
- type: string
|
||||
- $ref: "../openapi.yaml#/components/schemas/Role"
|
||||
collection:
|
||||
description: What collection this collection preset is used for.
|
||||
example: articles
|
||||
oneOf:
|
||||
- type: string
|
||||
- $ref: "../openapi.yaml#/components/schemas/Collection"
|
||||
search:
|
||||
description: Search query.
|
||||
type: string
|
||||
nullable: true
|
||||
filters:
|
||||
description: The filters that the user applied.
|
||||
example:
|
||||
field: title
|
||||
operator: contains
|
||||
value: Hello
|
||||
- key: 7RwVrquB5dPmfbrI1rcWy
|
||||
field: title
|
||||
operator: contains
|
||||
value: Hello
|
||||
type: array
|
||||
nullable: true
|
||||
items:
|
||||
type: object
|
||||
id:
|
||||
description: Unique identifier for this single collection preset.
|
||||
example: '155'
|
||||
type: integer
|
||||
role:
|
||||
description: The unique identifier of a role in the platform. If `user` is null,
|
||||
this will be used to apply the collection preset or bookmark for all users in
|
||||
the role.
|
||||
example: 63716273-0f29-4648-8a2a-2af2948f6f78
|
||||
nullable: true
|
||||
layout:
|
||||
description: Key of the layout that is used.
|
||||
type: string
|
||||
search_query:
|
||||
description: What the user searched for in search/filter in the header bar.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
title:
|
||||
description: Name for the bookmark. If this is set, the collection preset will
|
||||
be considered to be a bookmark.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
translation:
|
||||
description: Key value pair of language-translation. Can be used to translate
|
||||
the bookmark title in multiple languages.
|
||||
example: null
|
||||
type: object
|
||||
nullable: true
|
||||
user:
|
||||
description: The unique identifier of the user to whom this collection preset
|
||||
applies.
|
||||
example: 63716273-0f29-4648-8a2a-2af2948f6f78
|
||||
nullable: true
|
||||
type: string
|
||||
view_options:
|
||||
description: Options of the views. The properties in here are controlled by the
|
||||
layout.
|
||||
example:
|
||||
timeline:
|
||||
color: action
|
||||
content: excerpt
|
||||
date: published_on
|
||||
title: '{{ title }} ({{ author.first_name }} {{ author.last_name }})'
|
||||
type: object
|
||||
nullable: true
|
||||
view_query:
|
||||
description: View query that's saved per view type. Controls what data is fetched
|
||||
layout_query:
|
||||
description:
|
||||
Layout query that's saved per layout type. Controls what data is fetched
|
||||
on load. These follow the same format as the JS SDK parameters.
|
||||
example:
|
||||
timeline:
|
||||
cards:
|
||||
sort: -published_on
|
||||
type: object
|
||||
nullable: true
|
||||
view_type:
|
||||
description: Name of the view type that is used.
|
||||
example: timeline
|
||||
type: string
|
||||
layout_options:
|
||||
description:
|
||||
Options of the views. The properties in here are controlled by the layout.
|
||||
example:
|
||||
cards:
|
||||
icon: account_circle
|
||||
title: "{{ first_name }} {{ last_name }}"
|
||||
subtitle: "{{ title }}"
|
||||
size: 3
|
||||
nullable: true
|
||||
|
||||
@@ -1,5 +1,9 @@
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
description: Unique identifier for the relation.
|
||||
example: 1
|
||||
type: integer
|
||||
many_collection:
|
||||
description: Collection that has the field that holds the foreign key.
|
||||
example: directus_activity
|
||||
@@ -9,7 +13,7 @@ properties:
|
||||
example: user
|
||||
type: string
|
||||
many_primary:
|
||||
description: The primary field.
|
||||
description: The primary key field of the current collection.
|
||||
example: id
|
||||
type: string
|
||||
one_collection:
|
||||
@@ -22,16 +26,12 @@ properties:
|
||||
type: string
|
||||
nullable: true
|
||||
one_primary:
|
||||
description: The primary field.
|
||||
description: The primary key field of the related collection.
|
||||
example: id
|
||||
type: string
|
||||
id:
|
||||
description: Unique identifier for the relation.
|
||||
example: 1
|
||||
type: integer
|
||||
junction_field:
|
||||
description: Field on the junction table that holds the primary key of the related
|
||||
collection.
|
||||
description:
|
||||
Field on the junction table that holds the many field of the related relation.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
|
||||
@@ -1,12 +1,24 @@
|
||||
type: object
|
||||
properties:
|
||||
activity:
|
||||
description: Unique identifier for the [activity](/api/activity) record.
|
||||
example: 2
|
||||
id:
|
||||
description: Unique identifier for the revision.
|
||||
example: 1
|
||||
type: integer
|
||||
activity:
|
||||
description: Unique identifier for the activity record.
|
||||
example: 2
|
||||
oneOf:
|
||||
- type: integer
|
||||
- $ref: "../openapi.yaml#/components/schemas/Activity"
|
||||
collection:
|
||||
description: Collection of the updated item.
|
||||
example: articles
|
||||
oneOf:
|
||||
- type: string
|
||||
- $ref: "../openapi.yaml#/components/schemas/Collection"
|
||||
item:
|
||||
description: Primary key of updated item.
|
||||
example: "168"
|
||||
type: string
|
||||
data:
|
||||
description: Copy of item state at time of update.
|
||||
@@ -14,38 +26,18 @@ properties:
|
||||
author: 1
|
||||
body: This is my first post
|
||||
featured_image: 15
|
||||
id: '168'
|
||||
id: "168"
|
||||
title: Hello, World!
|
||||
type: object
|
||||
nullable: true # Should this be nullable?
|
||||
nullable: true
|
||||
delta:
|
||||
description: Changes between the previous and the current revision.
|
||||
example:
|
||||
title: Hello, World!
|
||||
oneOf:
|
||||
- type: object
|
||||
id:
|
||||
description: Unique identifier for the revision.
|
||||
example: 1
|
||||
type: object
|
||||
parent:
|
||||
description:
|
||||
If the current item was updated relationally, this is the id of the parent revision record
|
||||
example: null
|
||||
type: integer
|
||||
item:
|
||||
description: Primary key of updated item.
|
||||
example: '168'
|
||||
type: string
|
||||
parent_changed:
|
||||
description: If the current item was updated relationally, this shows if the parent
|
||||
item was updated as well.
|
||||
example: false
|
||||
type: boolean
|
||||
parent_collection:
|
||||
description: If the current item was updated relationally, this is the collection
|
||||
of the parent item.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
parent_item:
|
||||
description: If the current item was updated relationally, this is the unique
|
||||
identifier of the parent item.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
@@ -1,43 +1,51 @@
|
||||
type: object
|
||||
properties:
|
||||
collection_listing:
|
||||
description: Custom override for the admin app collection navigation.
|
||||
example: null
|
||||
type: object
|
||||
nullable: true
|
||||
id:
|
||||
description: Unique identifier for the role.
|
||||
example: 2f24211d-d928-469a-aea3-3c8f53d4e426
|
||||
type: string
|
||||
name:
|
||||
description: Name of the role.
|
||||
example: Administrator
|
||||
type: string
|
||||
icon:
|
||||
description: The role's icon.
|
||||
example: verified_user
|
||||
type: string
|
||||
description:
|
||||
description: Description of the role.
|
||||
example: Admins have access to all managed data within the system by default
|
||||
type: string
|
||||
nullable: true
|
||||
enforce_tfa:
|
||||
description: Whether or not this role enforces the use of 2FA.
|
||||
example: false
|
||||
type: boolean
|
||||
external_id:
|
||||
description: ID used with external services in SCIM.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
id:
|
||||
description: Unique identifier for the role.
|
||||
example: 2f24211d-d928-469a-aea3-3c8f53d4e426
|
||||
type: string
|
||||
ip_whitelist:
|
||||
description: Array of IP addresses that are allowed to connect to the API as a
|
||||
ip_access:
|
||||
description:
|
||||
Array of IP addresses that are allowed to connect to the API as a
|
||||
user of this role.
|
||||
example: []
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
module_listing:
|
||||
enforce_tfa:
|
||||
description: Whether or not this role enforces the use of 2FA.
|
||||
example: false
|
||||
type: boolean
|
||||
module_list:
|
||||
description: Custom override for the admin app module bar navigation.
|
||||
example: null
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
nullable: true
|
||||
name:
|
||||
description: Name of the role.
|
||||
example: Administrator
|
||||
type: string
|
||||
collection_list:
|
||||
description: Custom override for the admin app collection navigation.
|
||||
example: null
|
||||
type: object
|
||||
nullable: true
|
||||
admin_access:
|
||||
description: Admin role. If true, skips all permission checks.
|
||||
example: false
|
||||
type: boolean
|
||||
app_access:
|
||||
description: The users in the role are allowed to use the app.
|
||||
example: true
|
||||
type: boolean
|
||||
|
||||
@@ -2,6 +2,82 @@ type: object
|
||||
properties:
|
||||
id:
|
||||
description: Unique identifier for the setting.
|
||||
example: 1
|
||||
type: integer
|
||||
additionalProperties: true
|
||||
example: 1
|
||||
project_name:
|
||||
description: The name of the project.
|
||||
type: string
|
||||
example: Directus
|
||||
project_url:
|
||||
description: The url of the project.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
project_color:
|
||||
description: The brand color of the project.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
project_logo:
|
||||
description: The logo of the project.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
public_foreground:
|
||||
description: The foreground of the project.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
public_background:
|
||||
description: The background of the project.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
public_note:
|
||||
description: Note rendered on the public pages of the app.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
auth_login_attempts:
|
||||
description: Allowed authentication login attempts before the user's status is set to blocked.
|
||||
type: integer
|
||||
example: 25
|
||||
auth_password_policy:
|
||||
description: Authentication password policy.
|
||||
type: string
|
||||
nullable: true
|
||||
storage_asset_transform:
|
||||
description: What transformations are allowed in the assets endpoint.
|
||||
type: string
|
||||
enum:
|
||||
- all
|
||||
- none
|
||||
- presets
|
||||
example: "all"
|
||||
nullable: true
|
||||
storage_asset_presets:
|
||||
description: Array of allowed
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
key:
|
||||
description: Key for the asset. Used in the assets endpoint.
|
||||
type: string
|
||||
fit:
|
||||
description: Whether to crop the thumbnail to match the size, or maintain the aspect ratio.
|
||||
type: string
|
||||
enum:
|
||||
- cover
|
||||
- contain
|
||||
width:
|
||||
description: Width of the thumbnail.
|
||||
type: integer
|
||||
height:
|
||||
description: Height of the thumbnail.
|
||||
type: integer
|
||||
quality:
|
||||
description: Quality of the compression used.
|
||||
type: integer
|
||||
example: null
|
||||
nullable: true
|
||||
|
||||
@@ -1,76 +1,91 @@
|
||||
type: object
|
||||
properties:
|
||||
tfa_secret:
|
||||
description: The 2FA secret string that's used to generate one time passwords.
|
||||
example: null
|
||||
id:
|
||||
description: Unique identifier for the user.
|
||||
example: 63716273-0f29-4648-8a2a-2af2948f6f78
|
||||
type: string
|
||||
first_name:
|
||||
description: First name of the user.
|
||||
example: Admin
|
||||
type: string
|
||||
last_name:
|
||||
description: Last name of the user.
|
||||
example: User
|
||||
type: string
|
||||
nullable: true
|
||||
avatar:
|
||||
description: The user's avatar.
|
||||
example: null
|
||||
oneOf:
|
||||
- type: integer
|
||||
nullable: true
|
||||
- type: string
|
||||
- $ref: '../openapi.yaml#/components/schemas/File'
|
||||
nullable: true
|
||||
email:
|
||||
description: Unique email address for the user.
|
||||
example: admin@example.com
|
||||
type: string
|
||||
format: email
|
||||
external_id:
|
||||
description: ID used for SCIM.
|
||||
password:
|
||||
description: Password of the user.
|
||||
type: string
|
||||
location:
|
||||
description: The user's location.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
first_name:
|
||||
description: First name of the user.
|
||||
example: Admin
|
||||
type: string
|
||||
id:
|
||||
description: Unique identifier for the user.
|
||||
example: 63716273-0f29-4648-8a2a-2af2948f6f78
|
||||
type: string
|
||||
last_login:
|
||||
description: When this user logged in last.
|
||||
example: '2020-05-31 14:32:37'
|
||||
title:
|
||||
description: The user's title.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
format: date-time
|
||||
last_name:
|
||||
description: First name of the user.
|
||||
example: User
|
||||
type: string
|
||||
last_page:
|
||||
description: Last page that the user was on.
|
||||
example: /my-project/settings/collections/a
|
||||
description:
|
||||
description: The user's description.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
tags:
|
||||
description: The user's tags.
|
||||
example: null
|
||||
type: array
|
||||
nullable: true
|
||||
items:
|
||||
type: string
|
||||
avatar:
|
||||
description: The user's avatar.
|
||||
example: null
|
||||
oneOf:
|
||||
- type: string
|
||||
- $ref: "../openapi.yaml#/components/schemas/File"
|
||||
nullable: true
|
||||
language:
|
||||
description: The user's language used in Directus.
|
||||
example: en-US
|
||||
type: string
|
||||
role:
|
||||
description: Unique identifier of the role of this user.
|
||||
example: 2f24211d-d928-469a-aea3-3c8f53d4e426
|
||||
type: string
|
||||
status:
|
||||
description: Status of the user.
|
||||
example: active
|
||||
type: string
|
||||
enum: [active, invited, draft, suspended, deleted]
|
||||
theme:
|
||||
description: What theme the user is using.
|
||||
example: auto
|
||||
type: string
|
||||
enum: [light, dark, auto]
|
||||
timezone:
|
||||
description: The user's timezone.
|
||||
example: America/New_York
|
||||
type: string
|
||||
title:
|
||||
description: The user's title.
|
||||
tfa_secret:
|
||||
description: The 2FA secret string that's used to generate one time passwords.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
nullable: true
|
||||
status:
|
||||
description: Status of the user.
|
||||
example: active
|
||||
type: string
|
||||
enum: [active, invited, draft, suspended, deleted]
|
||||
role:
|
||||
description: Unique identifier of the role of this user.
|
||||
example: 2f24211d-d928-469a-aea3-3c8f53d4e426
|
||||
oneOf:
|
||||
- type: string
|
||||
- $ref: "../openapi.yaml#/components/schemas/Role"
|
||||
token:
|
||||
description: Static token for the user.
|
||||
type: string
|
||||
nullable: true
|
||||
last_acces:
|
||||
description: When this user used the API last.
|
||||
example: "2020-05-31T14:32:37Z"
|
||||
type: string
|
||||
nullable: true
|
||||
format: date-time
|
||||
last_page:
|
||||
description: Last page that the user was on.
|
||||
example: /my-project/settings/collections/a
|
||||
type: string
|
||||
nullable: true
|
||||
|
||||
@@ -3,4 +3,39 @@ properties:
|
||||
id:
|
||||
description: The index of the webhook.
|
||||
type: integer
|
||||
example: 1
|
||||
example: 1
|
||||
name:
|
||||
description: The name of the webhook.
|
||||
type: string
|
||||
example: create articles
|
||||
method:
|
||||
description: Method used in the webhook.
|
||||
type: string
|
||||
example: POST
|
||||
url:
|
||||
description: The url of the webhook.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
status:
|
||||
description: The status of the webhook.
|
||||
type: string
|
||||
example: inactive
|
||||
data:
|
||||
description: If yes, send the content of what was done
|
||||
type: boolean
|
||||
example: true
|
||||
actions:
|
||||
description: The actions that triggers this webhook.
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
collections:
|
||||
description: The collections that triggers this webhook.
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Directus SDK
|
||||
title: Directus API
|
||||
description: Template for generating any kind of SDK.
|
||||
contact:
|
||||
email: contact@directus.io
|
||||
license:
|
||||
name: GPL-3.0
|
||||
url: 'https://www.gnu.org/licenses/gpl-3.0.de.html'
|
||||
version: 1.0.0
|
||||
url: "https://www.gnu.org/licenses/gpl-3.0.html"
|
||||
version: 9.0.0
|
||||
externalDocs:
|
||||
description: Directus Docs
|
||||
url: 'https://docs.directus.io'
|
||||
servers:
|
||||
- url: 'https://demo.directus.io/'
|
||||
- url: '/'
|
||||
url: "https://docs.directus.io"
|
||||
tags:
|
||||
- name: Activity
|
||||
description: All events that happen within Directus are tracked and stored in the activities collection. This gives you full accountability over everything that happens.
|
||||
@@ -21,8 +18,8 @@ tags:
|
||||
description: Image typed files can be dynamically resized and transformed to fit any need.
|
||||
- name: Authentication
|
||||
description: All events that happen within Directus are tracked and stored in the activities collection. This gives you full accountability over everything that happens.
|
||||
- name: Collection presets
|
||||
description: Collection presets hold the preferences of individual users of the platform. This allows Directus to show and maintain custom item listings for users of the app.
|
||||
- name: Presets
|
||||
description: Presets hold the preferences of individual users of the platform. This allows Directus to show and maintain custom item listings for users of the app.
|
||||
- name: Collections
|
||||
description: Collections are the individual collections of items, similar to tables in a database. Changes to collections will alter the schema of the database.
|
||||
- name: Extensions
|
||||
@@ -35,20 +32,14 @@ tags:
|
||||
description: Folders don't do anything yet, but will be used in the (near) future to be able to group files.
|
||||
- name: Items
|
||||
description: Items are individual pieces of data in your database. They can be anything, from articles, to IoT status checks.
|
||||
- name: Mail
|
||||
description: Send electronic mail through the electronic post.
|
||||
- name: Permissions
|
||||
description: Permissions control who has access to what and when.
|
||||
- name: Projects
|
||||
description: Projects are the individual tenants of the platform. Each project has its own database and data.
|
||||
- name: Relations
|
||||
description: What data is linked to what other data. Allows you to assign authors to articles, products to sales, and whatever other structures you can think of.
|
||||
- name: Revisions
|
||||
description: Revisions are individual changes to items made. Directus keeps track of changes made, so you're able to revert to a previous state at will.
|
||||
- name: Roles
|
||||
description: Roles are groups of users that share permissions.
|
||||
- name: SCIM
|
||||
description: Directus partially supports Version 2 of System for Cross-domain Identity Management (SCIM). It is an open standard that allows for the exchange of user information between systems, therefore allowing users to be externally managed using the endpoints described below.
|
||||
- name: Server
|
||||
description: Access to where Directus runs. Allows you to make sure your server has everything needed to run the platform, and check what kind of latency we're dealing with.
|
||||
- name: Settings
|
||||
@@ -60,244 +51,234 @@ tags:
|
||||
- name: Webhooks
|
||||
description: Webhooks.
|
||||
paths:
|
||||
|
||||
# Activity
|
||||
/activity:
|
||||
$ref: './paths/activity/activitys.yaml'
|
||||
/activity/comment:
|
||||
$ref: './paths/activity/activity-comments.yaml'
|
||||
/activity/{id}:
|
||||
$ref: './paths/activity/activity.yaml'
|
||||
/activity/comment/{id}:
|
||||
$ref: './paths/activity/activity-comment.yaml'
|
||||
$ref: "./paths/activity/activities.yaml"
|
||||
# /activity/comment:
|
||||
# $ref: "./paths/activity/activity-comments.yaml"
|
||||
# /activity/{id}:
|
||||
# $ref: "./paths/activity/activity.yaml"
|
||||
# /activity/comment/{id}:
|
||||
# $ref: "./paths/activity/activity-comment.yaml"
|
||||
|
||||
# Assets
|
||||
/assets/{key}:
|
||||
$ref: './paths/assets/assets.yaml'
|
||||
# # Assets
|
||||
# /assets/{id}:
|
||||
# $ref: "./paths/assets/assets.yaml"
|
||||
|
||||
# Authentication
|
||||
/auth/login:
|
||||
$ref: './paths/auth/login.yaml'
|
||||
/auth/refresh:
|
||||
$ref: './paths/auth/refresh.yaml'
|
||||
/auth/logout:
|
||||
$ref: './paths/auth/logout.yaml'
|
||||
/auth/password/request:
|
||||
$ref: './paths/auth/password-request.yaml'
|
||||
/auth/password/reset:
|
||||
$ref: './paths/auth/password-reset.yaml'
|
||||
/auth/sso:
|
||||
$ref: './paths/auth/sso.yaml'
|
||||
/auth/sso/{provider}:
|
||||
$ref: './paths/auth/sso-provider.yaml'
|
||||
# # Authentication
|
||||
# /auth/login:
|
||||
# $ref: "./paths/auth/login.yaml"
|
||||
# /auth/refresh:
|
||||
# $ref: "./paths/auth/refresh.yaml"
|
||||
# /auth/logout:
|
||||
# $ref: "./paths/auth/logout.yaml"
|
||||
# /auth/password/request:
|
||||
# $ref: "./paths/auth/password-request.yaml"
|
||||
# /auth/password/reset:
|
||||
# $ref: "./paths/auth/password-reset.yaml"
|
||||
# /auth/sso:
|
||||
# $ref: "./paths/auth/sso.yaml"
|
||||
# /auth/sso/{provider}:
|
||||
# $ref: "./paths/auth/sso-provider.yaml"
|
||||
|
||||
# Items
|
||||
/items/{collection}:
|
||||
$ref: './paths/items/items.yaml'
|
||||
/items/{collection}/{id}:
|
||||
$ref: './paths/items/item.yaml'
|
||||
# # Items
|
||||
# /items/{collection}:
|
||||
# $ref: "./paths/items/items.yaml"
|
||||
# /items/{collection}/{id}:
|
||||
# $ref: "./paths/items/item.yaml"
|
||||
|
||||
# Presets
|
||||
/presets:
|
||||
$ref: './paths/presets/presets.yaml'
|
||||
/presets/{id}:
|
||||
$ref: './paths/presets/preset.yaml'
|
||||
# # Presets
|
||||
# /presets:
|
||||
# $ref: "./paths/presets/presets.yaml"
|
||||
# /presets/{id}:
|
||||
# $ref: "./paths/presets/preset.yaml"
|
||||
|
||||
# Collections
|
||||
/collections:
|
||||
$ref: './paths/collections/collections.yaml'
|
||||
/collections/{collection}:
|
||||
$ref: './paths/collections/collection.yaml'
|
||||
|
||||
# Extensions
|
||||
/interfaces:
|
||||
$ref: './paths/extensions/interfaces.yaml'
|
||||
/layouts:
|
||||
$ref: './paths/extensions/layouts.yaml'
|
||||
/modules:
|
||||
$ref: './paths/extensions/modules.yaml'
|
||||
# # Collections
|
||||
# /collections:
|
||||
# $ref: "./paths/collections/collections.yaml"
|
||||
# /collections/{id}:
|
||||
# $ref: "./paths/collections/collection.yaml"
|
||||
|
||||
# Fields
|
||||
/fields:
|
||||
$ref: './paths/fields/fields.yaml'
|
||||
/fields/{collection}:
|
||||
$ref: './paths/fields/collection-fields.yaml'
|
||||
/fields/{collection}/{field}:
|
||||
$ref: './paths/fields/collection-field.yaml'
|
||||
# # Extensions
|
||||
# /extensions/interfaces:
|
||||
# $ref: "./paths/extensions/interfaces.yaml"
|
||||
# /extensions/layouts:
|
||||
# $ref: "./paths/extensions/layouts.yaml"
|
||||
# /extensions/displays:
|
||||
# $ref: "./paths/extensions/displays.yaml"
|
||||
# /extensions/modules:
|
||||
# $ref: "./paths/extensions/modules.yaml"
|
||||
|
||||
# Files
|
||||
/files:
|
||||
$ref: './paths/files/files.yaml'
|
||||
/files/{id}:
|
||||
$ref: './paths/files/file.yaml'
|
||||
/files/{id}/revisions:
|
||||
$ref: './paths/files/revisions.yaml'
|
||||
/files/{id}/revisions/{offset}:
|
||||
$ref: './paths/files/revision.yaml'
|
||||
# # Fields
|
||||
# /fields:
|
||||
# $ref: "./paths/fields/fields.yaml"
|
||||
# /fields/{collection}:
|
||||
# $ref: "./paths/fields/collection-fields.yaml"
|
||||
# /fields/{collection}/{id}:
|
||||
# $ref: "./paths/fields/collection-field.yaml"
|
||||
|
||||
# Folders
|
||||
/folders:
|
||||
$ref: './paths/folders/folders.yaml'
|
||||
/folders/{id}:
|
||||
$ref: './paths/folders/folder.yaml'
|
||||
# # Files
|
||||
# /files:
|
||||
# $ref: "./paths/files/files.yaml"
|
||||
# /files/{id}:
|
||||
# $ref: "./paths/files/file.yaml"
|
||||
# /files/{id}/revisions:
|
||||
# $ref: "./paths/files/revisions.yaml"
|
||||
# /files/{id}/revisions/{offset}:
|
||||
# $ref: "./paths/files/revision.yaml"
|
||||
|
||||
# Mail
|
||||
/mail:
|
||||
$ref: './paths/mail/mail.yaml'
|
||||
# # Folders
|
||||
# /folders:
|
||||
# $ref: "./paths/folders/folders.yaml"
|
||||
# /folders/{id}:
|
||||
# $ref: "./paths/folders/folder.yaml"
|
||||
|
||||
# Permissions
|
||||
/permissions:
|
||||
$ref: './paths/permissions/permissions.yaml'
|
||||
/permissions/me:
|
||||
$ref: './paths/permissions/permissions-me.yaml'
|
||||
/permissions/{id}:
|
||||
$ref: './paths/permissions/permission.yaml'
|
||||
/permissions/me/{collection}:
|
||||
$ref: './paths/permissions/permissions-me-collection.yaml'
|
||||
# # Permissions
|
||||
# /permissions:
|
||||
# $ref: "./paths/permissions/permissions.yaml"
|
||||
# /permissions/me:
|
||||
# $ref: "./paths/permissions/permissions-me.yaml"
|
||||
# /permissions/{id}:
|
||||
# $ref: "./paths/permissions/permission.yaml"
|
||||
|
||||
# Relations
|
||||
/relations:
|
||||
$ref: './paths/relations/relations.yaml'
|
||||
/relations/{id}:
|
||||
$ref: './paths/relations/relation.yaml'
|
||||
# # Relations
|
||||
# /relations:
|
||||
# $ref: "./paths/relations/relations.yaml"
|
||||
# /relations/{id}:
|
||||
# $ref: "./paths/relations/relation.yaml"
|
||||
|
||||
# Revisions
|
||||
/revisions:
|
||||
$ref: './paths/revisions/revisions.yaml'
|
||||
/revisions/{id}:
|
||||
$ref: './paths/revisions/revision.yaml'
|
||||
# # Revisions
|
||||
# /revisions:
|
||||
# $ref: "./paths/revisions/revisions.yaml"
|
||||
# /revisions/{id}:
|
||||
# $ref: "./paths/revisions/revision.yaml"
|
||||
|
||||
# Revisions
|
||||
/roles:
|
||||
$ref: './paths/roles/roles.yaml'
|
||||
/roles/{id}:
|
||||
$ref: './paths/roles/role.yaml'
|
||||
# # Roles
|
||||
# /roles:
|
||||
# $ref: "./paths/roles/roles.yaml"
|
||||
# /roles/{id}:
|
||||
# $ref: "./paths/roles/role.yaml"
|
||||
|
||||
# SCIM
|
||||
/scim/v2/Users:
|
||||
$ref: './paths/scim/users.yaml'
|
||||
/scim/v2/Users/{id}:
|
||||
$ref: './paths/scim/user.yaml'
|
||||
/scim/v2/Groups:
|
||||
$ref: './paths/scim/groups.yaml'
|
||||
/scim/v2/Groups/{id}:
|
||||
$ref: './paths/scim/group.yaml'
|
||||
|
||||
# Server
|
||||
/server/info:
|
||||
$ref: './paths/server/info.yaml'
|
||||
servers:
|
||||
- url: 'https://demo.directus.io/'
|
||||
/server/ping:
|
||||
$ref: './paths/server/ping.yaml'
|
||||
servers:
|
||||
- url: 'https://demo.directus.io/'
|
||||
# # Server
|
||||
# /server/info:
|
||||
# $ref: "./paths/server/info.yaml"
|
||||
# /server/ping:
|
||||
# $ref: "./paths/server/ping.yaml"
|
||||
|
||||
# Settings
|
||||
/settings:
|
||||
$ref: './paths/settings/settings.yaml'
|
||||
# # Settings
|
||||
# /settings:
|
||||
# $ref: "./paths/settings/settings.yaml"
|
||||
|
||||
# Users
|
||||
/users:
|
||||
$ref: './paths/users/users.yaml'
|
||||
/users/me:
|
||||
$ref: './paths/users/me.yaml'
|
||||
/users/invite:
|
||||
$ref: './paths/users/user-invite.yaml'
|
||||
/users/{id}:
|
||||
$ref: './paths/users/user.yaml'
|
||||
/users/invite/{token}:
|
||||
$ref: './paths/users/user-invite-token.yaml'
|
||||
/users/{id}/track/page:
|
||||
$ref: './paths/users/user-tracking.yaml'
|
||||
# # Users
|
||||
# /users:
|
||||
# $ref: "./paths/users/users.yaml"
|
||||
# /users/{id}:
|
||||
# $ref: "./paths/users/user.yaml"
|
||||
# /users/{id}/track/page:
|
||||
# $ref: "./paths/users/user-tracking.yaml"
|
||||
# /users/invite:
|
||||
# $ref: "./paths/users/user-invite.yaml"
|
||||
# /users/invite/accept:
|
||||
# $ref: "./paths/users/user-invite-accept.yaml"
|
||||
# /users/me:
|
||||
# $ref: "./paths/users/me.yaml"
|
||||
# /users/me/track/page:
|
||||
# $ref: "./paths/users/me-tracking.yaml"
|
||||
# /users/me/tfa/enable:
|
||||
# $ref: "./paths/users/me-tfa-enable.yaml"
|
||||
# /users/me/tfa/disable:
|
||||
# $ref: "./paths/users/me-tfa-disable.yaml"
|
||||
|
||||
# Utilities
|
||||
/utils/hash:
|
||||
$ref: './paths/utils/hash.yaml'
|
||||
/utils/hash/verify:
|
||||
$ref: './paths/utils/hash-match.yaml'
|
||||
/utils/random/string:
|
||||
$ref: './paths/utils/random.yaml'
|
||||
# # Utilities
|
||||
# /utils/hash:
|
||||
# $ref: "./paths/utils/hash.yaml"
|
||||
# /utils/hash/verify:
|
||||
# $ref: "./paths/utils/hash-match.yaml"
|
||||
# /utils/random/string:
|
||||
# $ref: "./paths/utils/random.yaml"
|
||||
# /utils/sort/{collection}:
|
||||
# $ref: "./paths/utils/sort.yaml"
|
||||
|
||||
# Webhooks
|
||||
/webhooks:
|
||||
$ref: './paths/webhooks/webhooks.yaml'
|
||||
# # Webhooks
|
||||
# /webhooks:
|
||||
# $ref: "./paths/webhooks/webhooks.yaml"
|
||||
# /webhooks/{id}:
|
||||
# $ref: "./paths/webhooks/webhook.yaml"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Activity:
|
||||
$ref: './components/activity.yaml'
|
||||
$ref: "./components/activity.yaml"
|
||||
Preset:
|
||||
$ref: './components/preset.yaml'
|
||||
$ref: "./components/preset.yaml"
|
||||
Collection:
|
||||
$ref: './components/collection.yaml'
|
||||
$ref: "./components/collection.yaml"
|
||||
Field:
|
||||
$ref: './components/field.yaml'
|
||||
$ref: "./components/field.yaml"
|
||||
File:
|
||||
$ref: './components/file.yaml'
|
||||
$ref: "./components/file.yaml"
|
||||
Folder:
|
||||
$ref: './components/folder.yaml'
|
||||
$ref: "./components/folder.yaml"
|
||||
Item:
|
||||
$ref: './components/item.yaml'
|
||||
$ref: "./components/item.yaml"
|
||||
Permissions:
|
||||
$ref: './components/permissions.yaml'
|
||||
$ref: "./components/permissions.yaml"
|
||||
Relation:
|
||||
$ref: './components/relation.yaml'
|
||||
$ref: "./components/relation.yaml"
|
||||
Revision:
|
||||
$ref: './components/revision.yaml'
|
||||
$ref: "./components/revision.yaml"
|
||||
Role:
|
||||
$ref: './components/role.yaml'
|
||||
$ref: "./components/role.yaml"
|
||||
Setting:
|
||||
$ref: './components/setting.yaml'
|
||||
$ref: "./components/setting.yaml"
|
||||
User:
|
||||
$ref: './components/user.yaml'
|
||||
$ref: "./components/user.yaml"
|
||||
Webhook:
|
||||
$ref: './components/webhook.yaml'
|
||||
$ref: "./components/webhook.yaml"
|
||||
parameters:
|
||||
# All path parameters
|
||||
# All path parameters
|
||||
Id:
|
||||
$ref: './parameters/id.yaml'
|
||||
$ref: "./parameters/id.yaml"
|
||||
UUId:
|
||||
$ref: './parameters/uuid.yaml'
|
||||
$ref: "./parameters/uuid.yaml"
|
||||
Collection:
|
||||
$ref: './parameters/collection.yaml'
|
||||
$ref: "./parameters/collection.yaml"
|
||||
|
||||
# All query parameters
|
||||
q:
|
||||
$ref: './parameters/q.yaml'
|
||||
Search:
|
||||
$ref: "./parameters/search.yaml"
|
||||
Page:
|
||||
$ref: './parameters/page.yaml'
|
||||
$ref: "./parameters/page.yaml"
|
||||
Offset:
|
||||
$ref: './parameters/offset.yaml'
|
||||
$ref: "./parameters/offset.yaml"
|
||||
Single:
|
||||
$ref: './parameters/single.yaml'
|
||||
$ref: "./parameters/single.yaml"
|
||||
Sort:
|
||||
$ref: './parameters/sort.yaml'
|
||||
$ref: "./parameters/sort.yaml"
|
||||
Meta:
|
||||
$ref: './parameters/meta.yaml'
|
||||
$ref: "./parameters/meta.yaml"
|
||||
Limit:
|
||||
$ref: './parameters/limit.yaml'
|
||||
$ref: "./parameters/limit.yaml"
|
||||
Filter:
|
||||
$ref: './parameters/filter.yaml'
|
||||
$ref: "./parameters/filter.yaml"
|
||||
Fields:
|
||||
$ref: './parameters/fields.yaml'
|
||||
$ref: "./parameters/fields.yaml"
|
||||
Mode:
|
||||
$ref: './parameters/mode.yaml'
|
||||
$ref: "./parameters/mode.yaml"
|
||||
responses:
|
||||
NotFoundError:
|
||||
$ref: './responses/notFoundError.yaml'
|
||||
$ref: "./responses/notFoundError.yaml"
|
||||
UnauthorizedError:
|
||||
$ref: './responses/unauthorizedError.yaml'
|
||||
$ref: "./responses/unauthorizedError.yaml"
|
||||
securitySchemes:
|
||||
KeyAuth:
|
||||
type: apiKey
|
||||
in: query
|
||||
name: access_token
|
||||
description: Use the key 'admin' to authenticate to the public api.
|
||||
Auth:
|
||||
type: apiKey
|
||||
in: header
|
||||
name: 'Authorization'
|
||||
description: To authenticate, use the "/auth/authenticate" endpoint with the credentials "admin@example.com" | "password". Use the api key here like so "Bearer \<key\>".
|
||||
security:
|
||||
name: "Authorization"
|
||||
security:
|
||||
- Auth: []
|
||||
- KeyAuth: []
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
description: Collection of which you want to retrieve the permissions.
|
||||
description: Collection of which you want to retrieve the items from.
|
||||
name: collection
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
type: string
|
||||
|
||||
@@ -6,4 +6,4 @@ schema:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
pattern: '^(\[[^\[\]]*?\]){1}(\[(=|eq|<>|!=|neq|<|lt|<=|lte|>|gt|>=|gte|in|nin|null|nnull|contains|like|ncontains|nlike|rlike|nrlike|between|nbetween|empty|nempty|all|has)\])?=.*?$'
|
||||
pattern: '^(\[[^\[\]]*?\]){1}(\[(_eq|_neq|_lt|_lte|_gt|_gte|_in|_nin|_null|_nnull|_contains|_ncontains|_between|_nbetween|_empty|_nempty)\])?=.*?$'
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
description: Index of the file.
|
||||
description: Index
|
||||
name: id
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: integer
|
||||
type: integer
|
||||
|
||||
@@ -3,4 +3,4 @@ in: query
|
||||
name: page
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
type: integer
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
description: Filter by items that contain the given search query in one of their fields.
|
||||
in: query
|
||||
name: q
|
||||
name: search
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
type: string
|
||||
30
packages/spec/specs/paths/activity/activities.yaml
Normal file
30
packages/spec/specs/paths/activity/activities.yaml
Normal file
@@ -0,0 +1,30 @@
|
||||
get:
|
||||
operationId: getActivities
|
||||
description: Returns a list of activity actions.
|
||||
parameters:
|
||||
- $ref: "../../openapi.yaml#/components/parameters/Fields"
|
||||
- $ref: "../../openapi.yaml#/components/parameters/Limit"
|
||||
- $ref: "../../openapi.yaml#/components/parameters/Meta"
|
||||
- $ref: "../../openapi.yaml#/components/parameters/Offset"
|
||||
- $ref: "../../openapi.yaml#/components/parameters/Single"
|
||||
- $ref: "../../openapi.yaml#/components/parameters/Sort"
|
||||
- $ref: "../../openapi.yaml#/components/parameters/Filter"
|
||||
- $ref: "../../openapi.yaml#/components/parameters/Search"
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: "../../openapi.yaml#/components/schemas/Activity"
|
||||
description: Successful request
|
||||
"401":
|
||||
$ref: "../../openapi.yaml#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../openapi.yaml#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Activity
|
||||
@@ -2,7 +2,8 @@ patch:
|
||||
description: Update the content of an existing comment.
|
||||
operationId: updateComment
|
||||
parameters:
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Meta'
|
||||
- $ref: "../../#/components/parameters/Id"
|
||||
- $ref: "../../#/components/parameters/Meta"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
@@ -13,32 +14,32 @@ patch:
|
||||
type: string
|
||||
example: My updated comment
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: '../../openapi.yaml#/components/schemas/Activity'
|
||||
$ref: "../../#/components/schemas/Activity"
|
||||
description: Successful request
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Activity
|
||||
- Activity
|
||||
delete:
|
||||
description: Delete an existing comment. Deleted comments can not be retrieved.
|
||||
operationId: deleteComment
|
||||
parameters:
|
||||
- $ref: "../../#/components/parameters/Id"
|
||||
responses:
|
||||
'203':
|
||||
"203":
|
||||
description: Deleted succsessfully
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Activity
|
||||
parameters:
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Id'
|
||||
- Activity
|
||||
|
||||
@@ -2,13 +2,13 @@ post:
|
||||
description: Creates a new comment.
|
||||
operationId: createComment
|
||||
parameters:
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Meta'
|
||||
- $ref: "../../#/components/parameters/Meta"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [ "collection", "item", "comment" ]
|
||||
required: ["collection", "item", "comment"]
|
||||
properties:
|
||||
collection:
|
||||
type: string
|
||||
@@ -20,18 +20,18 @@ post:
|
||||
type: string
|
||||
example: A new comment
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: '../../openapi.yaml#/components/schemas/Activity'
|
||||
$ref: "../../#/components/schemas/Activity"
|
||||
description: Successful request
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Activity
|
||||
- Activity
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
get:
|
||||
description: Retrieves the details of an existing activity action. Provide the primary
|
||||
description:
|
||||
Retrieves the details of an existing activity action. Provide the primary
|
||||
key of the activity action and Directus will return the corresponding information.
|
||||
operationId: getActivity
|
||||
parameters:
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Id'
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Fields'
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Meta'
|
||||
- $ref: "../../#/components/parameters/Id"
|
||||
- $ref: "../../#/components/parameters/Fields"
|
||||
- $ref: "../../#/components/parameters/Meta"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successful request
|
||||
content:
|
||||
application/json:
|
||||
@@ -15,10 +16,10 @@ get:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: '../../openapi.yaml#/components/schemas/Activity'
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
$ref: "../../#/components/schemas/Activity"
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Activity
|
||||
- Activity
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
get:
|
||||
operationId: getActivitys
|
||||
description: Returns a list of activity actions.
|
||||
parameters:
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Fields'
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Limit'
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Meta'
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Offset'
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Single'
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Sort'
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Filter'
|
||||
- $ref: '../../openapi.yaml#/components/parameters/q'
|
||||
responses:
|
||||
'200':
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: '../../openapi.yaml#/components/schemas/Activity'
|
||||
description: Successful request
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
tags:
|
||||
- Activity
|
||||
@@ -3,12 +3,12 @@ get:
|
||||
- Assets
|
||||
operationId: getAsset
|
||||
description: Image typed files can be dynamically resized and transformed to fit any need.
|
||||
security:
|
||||
security:
|
||||
- Auth: []
|
||||
parameters:
|
||||
- name: key
|
||||
- name: id
|
||||
in: path
|
||||
description: private_hash of the file
|
||||
description: The id of the file.
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
@@ -41,11 +41,11 @@ get:
|
||||
minimum: 1
|
||||
maximum: 100
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successful request
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
|
||||
@@ -8,7 +8,7 @@ post:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [ email, password ]
|
||||
required: [email, password]
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
@@ -21,26 +21,29 @@ post:
|
||||
example: password
|
||||
mode:
|
||||
type: string
|
||||
enum: [jwt, cookie]
|
||||
default: jwt
|
||||
enum: ["json", cookie]
|
||||
default: "json"
|
||||
description: Choose between retrieving the token as a string, or setting it as a cookie.
|
||||
otp:
|
||||
type: string
|
||||
description: If 2FA is enabled, you need to pass the one time password.
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successful authentification
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
public:
|
||||
type: boolean
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
token:
|
||||
access_token:
|
||||
type: string
|
||||
user:
|
||||
$ref: '../../openapi.yaml#/components/schemas/User'
|
||||
example: eyJhbGciOiJI...
|
||||
expires:
|
||||
type: integer
|
||||
example: 900
|
||||
refresh_token:
|
||||
type: string
|
||||
example: yuOJkjdPXMd...
|
||||
|
||||
@@ -3,6 +3,17 @@ post:
|
||||
tags:
|
||||
- Authentication
|
||||
operationId: logout
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [token]
|
||||
properties:
|
||||
refresh_token:
|
||||
type: string
|
||||
example: eyJ0eXAiOiJKV...
|
||||
description: JWT access token you want to logout.
|
||||
responses:
|
||||
'200':
|
||||
description: Request successful
|
||||
"200":
|
||||
description: Request successful
|
||||
|
||||
@@ -8,16 +8,12 @@ post:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [ email ]
|
||||
required: [email]
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
example: admin@example.com
|
||||
description: Email address of the user you're requesting a reset for.
|
||||
reset_url:
|
||||
type: string
|
||||
example: https://mydomain.com/passwordreset
|
||||
description: Provide a custom reset url which the link in the Email will lead to. The reset token will be passed as a parameter.
|
||||
responses:
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
|
||||
@@ -8,7 +8,7 @@ post:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [ token, password ]
|
||||
required: [token, password]
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
@@ -20,5 +20,5 @@ post:
|
||||
format: password
|
||||
description: New password for the user.
|
||||
responses:
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
|
||||
@@ -8,26 +8,31 @@ post:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [ token ]
|
||||
required: [token]
|
||||
properties:
|
||||
refresh_token:
|
||||
type: string
|
||||
example: eyJ0eXAiOiJKV...
|
||||
description: JWT access token you want to refresh. This token can't be expired.
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successful request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
public:
|
||||
type: boolean
|
||||
data:
|
||||
type: object
|
||||
properties:
|
||||
token:
|
||||
access_token:
|
||||
type: string
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
example: eyJhbGciOiJI...
|
||||
expires:
|
||||
type: integer
|
||||
example: 900
|
||||
refresh_token:
|
||||
type: string
|
||||
example: Gy-caJMpmGTA...
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
|
||||
@@ -10,7 +10,7 @@ get:
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Mode'
|
||||
- $ref: "../../#/components/parameters/Mode"
|
||||
- name: redirect_url
|
||||
in: query
|
||||
required: true
|
||||
@@ -18,7 +18,7 @@ get:
|
||||
schema:
|
||||
type: string
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successful request
|
||||
content:
|
||||
application/json:
|
||||
@@ -32,5 +32,5 @@ get:
|
||||
properties:
|
||||
token:
|
||||
type: string
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
|
||||
@@ -4,7 +4,7 @@ get:
|
||||
operationId: sso
|
||||
description: List the SSO providers.
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successful request
|
||||
content:
|
||||
application/json:
|
||||
@@ -18,5 +18,5 @@ get:
|
||||
example: ["github", "facebook"]
|
||||
items:
|
||||
type: string
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
|
||||
@@ -2,84 +2,123 @@ get:
|
||||
description: Retrieves the details of a single collection.
|
||||
operationId: getCollection
|
||||
parameters:
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Meta'
|
||||
- $ref: "../../#/components/parameters/Meta"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: '../../openapi.yaml#/components/schemas/Collection'
|
||||
$ref: "../../#/components/schemas/Collection"
|
||||
description: Successful request
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Collections
|
||||
- Collections
|
||||
patch:
|
||||
description: Update an existing collection.
|
||||
operationId: updateCollection
|
||||
parameters:
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Meta'
|
||||
- $ref: "../../#/components/parameters/Meta"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
note:
|
||||
type: string
|
||||
description: A note describing the collection.
|
||||
hidden:
|
||||
type: boolean
|
||||
description: Whether or not the collection is hidden from the navigation in the admin app.
|
||||
single:
|
||||
type: string
|
||||
description: Whether or not the collection is treated as a single record.
|
||||
managed:
|
||||
type: string
|
||||
description: If Directus is tracking and managing this collection currently.
|
||||
icon:
|
||||
type: string
|
||||
description: Name of a Google Material Design Icon that's assigned to this collection.
|
||||
translation:
|
||||
meta:
|
||||
description: Metadata of the collection.
|
||||
type: object
|
||||
description: Key value pairs of how to show this collection's name in different languages in the admin app.
|
||||
properties:
|
||||
icon:
|
||||
description: Name of a Google Material Design Icon that's assigned to this collection.
|
||||
type: string
|
||||
example: people
|
||||
nullable: true
|
||||
note:
|
||||
description: A note describing the collection.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
display_template:
|
||||
description: Text representation of how items from this collection are shown across the system.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
hidden:
|
||||
description: Whether or not the collection is hidden from the navigation in the admin app.
|
||||
type: boolean
|
||||
example: false
|
||||
singleton:
|
||||
description: Whether or not the collection is treated as a single object.
|
||||
type: boolean
|
||||
example: false
|
||||
translation:
|
||||
description: Key value pairs of how to show this collection's name in different languages in the admin app.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
archive_field:
|
||||
description: What field holds the archive value.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
archive_app_filter:
|
||||
description: What value to use for "archived" items.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
archive_value:
|
||||
description: What value to use to "unarchive" items.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
unarchive_value:
|
||||
description: Whether or not to show the "archived" filter.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
sort_field:
|
||||
description: The sort field in the collection.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: '../../openapi.yaml#/components/schemas/Collection'
|
||||
$ref: "../../#/components/schemas/Collection"
|
||||
description: Successful request
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Collections
|
||||
- Collections
|
||||
delete:
|
||||
description: "Delete an existing collection. Warning: This will delete the whole collection, including the items within. Proceed with caution."
|
||||
operationId: deleteCollection
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successful request
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Collections
|
||||
- Collections
|
||||
parameters:
|
||||
- name: collection
|
||||
- name: id
|
||||
in: path
|
||||
required: true
|
||||
description: The unique name of the collection.
|
||||
description: Unique identifier of the collection.
|
||||
schema:
|
||||
type: string
|
||||
type: string
|
||||
|
||||
@@ -2,11 +2,11 @@ get:
|
||||
description: Returns a list of the collections available in the project.
|
||||
operationId: getCollections
|
||||
parameters:
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Offset'
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Single'
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Meta'
|
||||
- $ref: "../../#/components/parameters/Offset"
|
||||
- $ref: "../../#/components/parameters/Single"
|
||||
- $ref: "../../#/components/parameters/Meta"
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successful request
|
||||
content:
|
||||
application/json:
|
||||
@@ -16,63 +16,100 @@ get:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
$ref: '../../openapi.yaml#/components/schemas/Collection'
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
$ref: "../../#/components/schemas/Collection"
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Collections
|
||||
- Collections
|
||||
post:
|
||||
description: Create a new collection in Directus.
|
||||
operationId: createCollection
|
||||
parameters:
|
||||
- $ref: '../../openapi.yaml#/components/parameters/Meta'
|
||||
- $ref: "../../#/components/parameters/Meta"
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
required: [ collection, fields ]
|
||||
required: [collection, fields]
|
||||
properties:
|
||||
collection:
|
||||
type: string
|
||||
description: Unique name of the collection.
|
||||
example: my_collection
|
||||
fields:
|
||||
type: object
|
||||
type: array
|
||||
description: The fields contained in this collection. See the fields reference for more information. Each individual field requires field, type, and interface to be provided.
|
||||
note:
|
||||
type: string
|
||||
description: A note describing the collection.
|
||||
hidden:
|
||||
type: string
|
||||
description: Whether or not the collection is hidden from the navigation in the admin app.
|
||||
single:
|
||||
type: string
|
||||
description: Whether or not the collection is treated as a single record.
|
||||
managed:
|
||||
type: string
|
||||
description: If Directus is tracking and managing this collection currently.
|
||||
items:
|
||||
type: object
|
||||
icon:
|
||||
type: string
|
||||
description: Name of a Google Material Design Icon that's assigned to this collection.
|
||||
translation:
|
||||
type: string
|
||||
example: people
|
||||
nullable: true
|
||||
note:
|
||||
description: A note describing the collection.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
display_template:
|
||||
description: Text representation of how items from this collection are shown across the system.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
hidden:
|
||||
description: Whether or not the collection is hidden from the navigation in the admin app.
|
||||
type: boolean
|
||||
example: false
|
||||
singleton:
|
||||
description: Whether or not the collection is treated as a single object.
|
||||
type: boolean
|
||||
example: false
|
||||
translation:
|
||||
description: Key value pairs of how to show this collection's name in different languages in the admin app.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
archive_field:
|
||||
description: What field holds the archive value.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
archive_app_filter:
|
||||
description: What value to use for "archived" items.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
archive_value:
|
||||
description: What value to use to "unarchive" items.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
unarchive_value:
|
||||
description: Whether or not to show the "archived" filter.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
sort_field:
|
||||
description: The sort field in the collection.
|
||||
type: string
|
||||
example: null
|
||||
nullable: true
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: '../../openapi.yaml#/components/schemas/Collection'
|
||||
$ref: "../../#/components/schemas/Collection"
|
||||
description: Successful request
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Collections
|
||||
- Collections
|
||||
|
||||
21
packages/spec/specs/paths/extensions/displays.yaml
Normal file
21
packages/spec/specs/paths/extensions/displays.yaml
Normal file
@@ -0,0 +1,21 @@
|
||||
get:
|
||||
description: List all installed custom displays.
|
||||
operationId: getDisplays
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
description: Successful request
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Extensions
|
||||
@@ -2,7 +2,7 @@ get:
|
||||
description: List all installed custom interfaces.
|
||||
operationId: getInterfaces
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successful request
|
||||
content:
|
||||
application/json:
|
||||
@@ -13,9 +13,9 @@ get:
|
||||
type: array
|
||||
items:
|
||||
type: object
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Extensions
|
||||
- Extensions
|
||||
|
||||
@@ -2,7 +2,7 @@ get:
|
||||
description: List all installed custom layouts.
|
||||
operationId: getLayouts
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -13,9 +13,9 @@ get:
|
||||
items:
|
||||
type: object
|
||||
description: Successful request
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Extensions
|
||||
- Extensions
|
||||
|
||||
@@ -2,7 +2,7 @@ get:
|
||||
description: List all installed custom modules.
|
||||
operationId: getModules
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -13,9 +13,9 @@ get:
|
||||
items:
|
||||
type: object
|
||||
description: Successful request
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Extensions
|
||||
- Extensions
|
||||
|
||||
@@ -2,7 +2,7 @@ get:
|
||||
description: Retrieves the details of a single field in a given collection.
|
||||
operationId: getCollectionField
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successful request
|
||||
content:
|
||||
application/json:
|
||||
@@ -10,13 +10,13 @@ get:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: '../../openapi.yaml#/components/schemas/Field'
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
$ref: "../../#/components/schemas/Field"
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Fields
|
||||
- Fields
|
||||
patch:
|
||||
description: Update an existing field.
|
||||
operationId: updateField
|
||||
@@ -24,68 +24,172 @@ patch:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
datatype:
|
||||
description: SQL datatype of the column that corresponds to this field.
|
||||
type: string
|
||||
auto_increment:
|
||||
description: If the value in this field is auto incremented. Only applies to integer type fields.
|
||||
type: boolean
|
||||
group:
|
||||
description: What field group this field is part of.
|
||||
type: string
|
||||
hidden_browse:
|
||||
description: If this field should be hidden from the item browse (listing) page.
|
||||
type: boolean
|
||||
hidden_detail:
|
||||
description: If this field should be hidden from the item detail (edit) page.
|
||||
type: boolean
|
||||
interface:
|
||||
description: What interface is used in the admin app to edit the value for this field.
|
||||
type: string
|
||||
locked:
|
||||
description: If the field can be altered by the end user. Directus system fields have this value set to `true`.
|
||||
type: boolean
|
||||
note:
|
||||
description: A user provided note for the field. Will be rendered alongside the interface on the edit page.
|
||||
type: string
|
||||
options:
|
||||
description: Options for the interface that's used. This format is based on the individual interface.
|
||||
type: object
|
||||
primary_key:
|
||||
description: If this field is the primary key of the collection.
|
||||
type: boolean
|
||||
readonly:
|
||||
description: Prevents the user from editing the value in the field.
|
||||
type: boolean
|
||||
required:
|
||||
description: If this field requires a value.
|
||||
type: boolean
|
||||
signed:
|
||||
description: If the value is signed or not. Only applies to integer type fields.
|
||||
type: boolean
|
||||
sort:
|
||||
description: Sort order of this field on the edit page of the admin app.
|
||||
type: integer
|
||||
translation:
|
||||
description: 'Key value pair of `<locale>: <translation>` that allows the user to change the displayed name of the field in the admin app.'
|
||||
type: object
|
||||
unique:
|
||||
description: If the value of this field should be unique within the collection.
|
||||
type: boolean
|
||||
validation:
|
||||
description: User provided regex that will be used in the API to validate incoming values.
|
||||
type: string
|
||||
width:
|
||||
description: Width of the field on the edit form.
|
||||
type: string
|
||||
enum: [half, half-left, half-right, full, fill]
|
||||
length:
|
||||
description: Length of the field. Will be used in SQL to set the length property of the colummn. Requirement of this attribute depends on the provided datatype.
|
||||
type: integer
|
||||
type: object
|
||||
properties:
|
||||
field:
|
||||
description: Unique name of the field. Field name is unique within the collection.
|
||||
example: id
|
||||
type: string
|
||||
type:
|
||||
description: Directus specific data type. Used to cast values in the API.
|
||||
example: integer
|
||||
type: string
|
||||
schema:
|
||||
description: The schema info.
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
description: The name of the field.
|
||||
example: title
|
||||
type: string
|
||||
table:
|
||||
description: The collection of the field.
|
||||
example: posts
|
||||
type: string
|
||||
type:
|
||||
description: The type of the field.
|
||||
example: string
|
||||
type: string
|
||||
default_value:
|
||||
description: The default value of the field.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
max_length:
|
||||
description: The max length of the field.
|
||||
example: null
|
||||
type: integer
|
||||
nullable: true
|
||||
is_nullable:
|
||||
description: If the field is nullable.
|
||||
example: false
|
||||
type: boolean
|
||||
is_primary_key:
|
||||
description: If the field is primary key.
|
||||
example: false
|
||||
type: boolean
|
||||
has_auto_increment:
|
||||
description: If the field has auto increment.
|
||||
example: false
|
||||
type: boolean
|
||||
foreign_key_column:
|
||||
description: Related column from the foreign key constraint.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
foreign_key_table:
|
||||
description: Related table from the foreign key constraint.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
comment:
|
||||
description: Comment as saved in the database.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
schema:
|
||||
description: Database schema (pg only).
|
||||
example: public
|
||||
type: string
|
||||
foreign_key_schema:
|
||||
description: Related schema from the foreign key constraint (pg only).
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
meta:
|
||||
description: The meta info.
|
||||
type: object
|
||||
nullable: true
|
||||
properties:
|
||||
id:
|
||||
description: Unique identifier for the field in the `directus_fields` collection.
|
||||
example: 3
|
||||
type: integer
|
||||
collection:
|
||||
description: Unique name of the collection this field is in.
|
||||
example: posts
|
||||
type: string
|
||||
field:
|
||||
description: Unique name of the field. Field name is unique within the collection.
|
||||
example: title
|
||||
type: string
|
||||
special:
|
||||
description: Transformation flag for field
|
||||
example: null
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
nullable: true
|
||||
interface:
|
||||
description:
|
||||
What interface is used in the admin app to edit the value for this
|
||||
field.
|
||||
example: primary-key
|
||||
type: string
|
||||
nullable: true
|
||||
options:
|
||||
description:
|
||||
Options for the interface that's used. This format is based on the
|
||||
individual interface.
|
||||
example: null
|
||||
type: object
|
||||
nullable: true
|
||||
display:
|
||||
description: What display is used in the admin app to display the value for this field.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
display_options:
|
||||
description: Options for the display that's used. This format is based on the individual display.
|
||||
example: null
|
||||
type: object
|
||||
nullable: true
|
||||
locked:
|
||||
description:
|
||||
If the field can be altered by the end user. Directus system fields
|
||||
have this value set to `true`.
|
||||
example: true
|
||||
type: boolean
|
||||
readonly:
|
||||
description: Prevents the user from editing the value in the field.
|
||||
example: false
|
||||
type: boolean
|
||||
hidden:
|
||||
description: If this field should be hidden.
|
||||
example: true
|
||||
type: boolean
|
||||
sort:
|
||||
description: Sort order of this field on the edit page of the admin app.
|
||||
example: 1
|
||||
type: integer
|
||||
nullable: true
|
||||
width:
|
||||
description: Width of the field on the edit form.
|
||||
example: null
|
||||
type: string
|
||||
nullable: true
|
||||
enum: [half, half-left, half-right, full, fill, null]
|
||||
group:
|
||||
description: What field group this field is part of.
|
||||
example: null
|
||||
type: integer
|
||||
nullable: true
|
||||
translation:
|
||||
description:
|
||||
"Key value pair of `<locale>: <translation>` that allows the user
|
||||
to change the displayed name of the field in the admin app."
|
||||
example: null
|
||||
type: object
|
||||
nullable: true
|
||||
note:
|
||||
description:
|
||||
A user provided note for the field. Will be rendered alongside the
|
||||
interface on the edit page.
|
||||
example: ""
|
||||
type: string
|
||||
nullable: true
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successful request
|
||||
content:
|
||||
application/json:
|
||||
@@ -93,26 +197,25 @@ patch:
|
||||
type: object
|
||||
properties:
|
||||
data:
|
||||
$ref: '../../openapi.yaml#/components/schemas/Field'
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
$ref: "../../#/components/schemas/Field"
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Fields
|
||||
|
||||
- Fields
|
||||
delete:
|
||||
description: Delete an existing field.
|
||||
operationId: deleteField
|
||||
responses:
|
||||
'200':
|
||||
"200":
|
||||
description: Successful request
|
||||
'401':
|
||||
$ref: '../../openapi.yaml#/components/responses/UnauthorizedError'
|
||||
'404':
|
||||
$ref: '../../openapi.yaml#/components/responses/NotFoundError'
|
||||
"401":
|
||||
$ref: "../../#/components/responses/UnauthorizedError"
|
||||
"404":
|
||||
$ref: "../../#/components/responses/NotFoundError"
|
||||
tags:
|
||||
- Fields
|
||||
- Fields
|
||||
parameters:
|
||||
- name: collection
|
||||
in: path
|
||||
@@ -120,9 +223,9 @@ parameters:
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
- name: field
|
||||
- name: id
|
||||
in: path
|
||||
description: The unique name of the field.
|
||||
description: Unique identifier of the field.
|
||||
schema:
|
||||
type: string
|
||||
required: true
|
||||
required: true
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user