Restructure seeds, add database install cli command

This commit is contained in:
rijkvanzanten
2020-09-17 16:19:09 -04:00
parent d4191aaba2
commit 9ffc056bd3
37 changed files with 2315 additions and 2243 deletions

View File

@@ -0,0 +1,8 @@
import Knex from 'knex';
import run from '../../../database/seeds/run';
export default async function start() {
const database = require('../../../database/index').default as Knex;
await run(database);
database.destroy();
}

View File

@@ -9,7 +9,7 @@ import ora from 'ora';
import argon2 from 'argon2';
import runSeed from '../../../database/run-seed';
import runSeed from '../../../database/seeds/run';
import createDBConnection, { Credentials } from '../../utils/create-db-connection';
@@ -39,7 +39,7 @@ export default async function init(options: Record<string, any>) {
const db = createDBConnection(dbClient, credentials);
await runSeed(db, 'system');
await runSeed(db);
await createEnv(dbClient, credentials, rootPath);

View File

@@ -6,6 +6,7 @@ const pkg = require('../../package.json');
import start from './commands/start';
import init from './commands/init';
import dbInstall from './commands/database/install';
program.version(pkg.version, '-v, --version');
@@ -13,5 +14,6 @@ program.name('directus').usage('[command] [options]');
program.command('start').description('Start the Directus API').action(start);
program.command('init').description('Create a new Directus Project').action(init);
program.command('database install').description('Install the database').action(dbInstall);
program.parseAsync(process.argv);

View File

@@ -1,137 +0,0 @@
import Knex, { ColumnBuilder } from 'knex';
import fse from 'fs-extra';
import path from 'path';
import yaml from 'js-yaml';
import { types, Item } from '../types';
import { isObject, merge, reduce } from 'lodash';
type SeedData = {
tables?: {
[table: string]: {
[column: string]: {
type?: typeof types[number];
primary?: boolean;
nullable?: boolean;
default?: any;
length?: number;
increments?: boolean;
unsigned?: boolean;
unique?: boolean;
references?: {
table: string;
column: string;
};
};
};
};
rows?: {
[table: string]: {
defaults: Record<string, any>;
data: Record<string, any>[];
};
};
};
export default async function runSeed(knex: Knex, seed: string) {
const yamlRaw = await fse.readFile(path.resolve(__dirname, './seeds', seed + '.yaml'), 'utf8');
const seedData = yaml.safeLoad(yamlRaw) as SeedData;
await knex.transaction(async (transaction) => {
if (seedData.tables) {
for (const [tableName, columns] of Object.entries(seedData.tables)) {
await transaction.schema.dropTableIfExists(tableName);
await transaction.schema.createTable(tableName, (table) => {
for (const [columnName, columnInfo] of Object.entries(columns)) {
let column: ColumnBuilder;
if (columnInfo.type === 'string') {
column = table.string(columnName, columnInfo.length);
} else if (columnInfo.increments) {
column = table.increments();
} else if (columnInfo.type === 'csv') {
column = table.string(columnName);
} else {
column = table[columnInfo.type!](columnName);
}
if (columnInfo.primary) {
column.primary();
}
if (columnInfo.nullable !== undefined && columnInfo.nullable === false) {
column.notNullable();
}
if (columnInfo.default !== undefined) {
let defaultValue = columnInfo.default;
if (isObject(defaultValue) || Array.isArray(defaultValue))
defaultValue = JSON.stringify(defaultValue);
if (defaultValue === '$now') {
defaultValue = knex.fn.now();
}
column.defaultTo(defaultValue);
}
if (columnInfo.unique) {
column.unique();
}
if (columnInfo.unsigned) {
column.unsigned();
}
if (columnInfo.references) {
table
.foreign(columnName)
.references(columnInfo.references.column)
.inTable(columnInfo.references.table);
}
}
});
}
}
if (seedData.rows) {
for (const [table, { defaults, data }] of Object.entries(seedData.rows)) {
const dataWithDefaults = data.map((row) => {
// Stringify all nested JSON values
for (const [key, value] of Object.entries(row)) {
if (value !== null && (typeof value === 'object' || Array.isArray(value))) {
row[key] = JSON.stringify(value);
}
}
return merge({}, defaults, row);
});
const chunks = chunkArray(dataWithDefaults, 25);
for (const chunk of chunks) {
await transaction(table).insert(chunk);
}
}
}
});
}
function chunkArray(array: Item[], chunkSize: number) {
return reduce(
array,
(result: Item[][], value) => {
let lastChunk: Item[] = result[result.length - 1];
if (lastChunk.length < chunkSize) {
lastChunk.push(value);
} else {
result.push([value]);
}
return result;
},
[[]]
);
}

View File

@@ -0,0 +1,40 @@
table: directus_collections
columns:
collection:
type: string
primary: true
icon:
type: string
length: 30
note:
type: text
display_template:
type: string
length: 255
hidden:
type: boolean
nullable: false
default: false
singleton:
type: boolean
nullable: false
default: false
translation:
type: json
archive_field:
type: string
length: 64
archive_app_filter:
type: boolean
nullable: false
default: true
archive_value:
type: string
length: 255
unarchive_value:
type: string
length: 255
sort_field:
type: string
length: 64

View File

@@ -0,0 +1,35 @@
table: directus_roles
columns:
id:
type: uuid
primary: true
name:
type: string
length: 100
nullable: false
icon:
type: string
length: 30
nullable: false
default: supervised_user_circle
description:
type: text
ip_access:
type: json
enforce_tfa:
type: boolean
nullable: false
default: false
module_list:
type: json
collection_list:
type: json
admin:
type: boolean
nullable: false
default: false
app_access:
type: boolean
nullable: false
default: true

View File

@@ -0,0 +1,65 @@
table: directus_users
columns:
id:
type: uuid
primary: true
first_name:
type: string
length: 50
last_name:
type: string
length: 50
email:
type: string
length: 128
nullable: false
password:
type: string
length: 255
location:
type: string
length: 255
title:
type: string
length: 50
description:
type: text
tags:
type: json
avatar:
type: uuid
timezone:
type: string
length: 255
default: 'America/New_York'
language:
type: string
length: 8
default: 'en-US'
theme:
type: string
length: 20
default: auto
tfa_secret:
type: string
length: 255
status:
type: string
length: 16
nullable: false
default: draft
role:
type: uuid
nullable: true
references:
table: directus_roles
column: id
token:
type: string
length: 255
last_login:
type: timestamp
last_page:
type: string
length: 255

View File

@@ -0,0 +1,58 @@
table: directus_fields
columns:
id:
increments: true
collection:
type: string
length: 64
nullable: false
references:
table: directus_collections
column: collection
field:
type: string
length: 64
nullable: false
special:
type: string
length: 64
interface:
type: string
length: 64
options:
type: json
display:
type: string
length: 64
display_options:
type: json
locked:
type: boolean
default: false
nullable: false
readonly:
type: boolean
default: false
nullable: false
hidden:
type: boolean
default: false
nullable: false
sort:
type: integer
unsigned: true
width:
type: string
length: 30
default: full
group:
type: integer
unsigned: true
references:
table: directus_fields
column: id
translation:
type: json
note:
type: text

View File

@@ -0,0 +1,36 @@
table: directus_activity
columns:
id:
increments: true
action:
type: string
length: 45
nullable: false
action_by:
type: uuid
action_on:
type: timestamp
nullable: false
default: '$now'
ip:
type: string
length: 50
nullable: false
user_agent:
type: string
length: 255
nullabel: false
collection:
type: string
length: 64
nullable: false
references:
table: directus_collections
column: collection
item:
type: string
length: 255
nullable: false
comment:
type: text

View File

@@ -0,0 +1,16 @@
table: directus_folders
columns:
id:
type: uuid
primary: true
nullable: false
name:
type: string
length: 255
nullable: false
parent_folder:
type: uuid
references:
table: directus_folders
column: id

View File

@@ -0,0 +1,65 @@
table: directus_files
columns:
id:
type: uuid
primary: true
nullable: false
storage:
type: string
nullable: false
filename_disk:
type: string
length: 255
filename_download:
type: string
length: 255
nullable: false
title:
type: string
length: 255
type:
type: string
length: 255
folder:
type: uuid
references:
table: directus_folders
column: id
uploaded_by:
type: uuid
references:
table: directus_users
column: id
uploaded_on:
type: timestamp
nullable: false
default: '$now'
charset:
type: string
length: 50
filesize:
type: integer
nullable: false
default: 0
unsigned: true
width:
type: integer
unsigned: true
height:
type: integer
unsigned: true
duration:
type: integer
unsigned: true
embed:
type: string
length: 200
description:
type: text
location:
type: text
tags:
type: text
metadata:
type: json

View File

@@ -0,0 +1,32 @@
table: directus_permissions
columns:
id:
increments: true
role:
type: uuid
references:
table: directus_roles
column: id
collection:
type: string
length: 64
nullable: false
references:
table: directus_collections
column: collection
action:
type: string
length: 10
nullable: false
permissions:
type: json
validation:
type: json
presets:
type: json
fields:
type: text
limit:
type: integer
unsigned: true

View File

@@ -0,0 +1,37 @@
table: directus_presets
columns:
id:
increments: true
bookmark:
type: string
length: 255
user:
type: uuid
references:
table: directus_users
column: id
role:
type: uuid
references:
table: directus_roles
column: id
collection:
type: string
length: 64
references:
table: directus_collections
column: collection
search:
type: string
length: 100
filters:
type: json
layout:
type: string
length: 100
default: tabular
layout_query:
type: json
layout_options:
type: json

View File

@@ -0,0 +1,37 @@
table: directus_relations
columns:
id:
increments: true
many_collection:
type: string
length: 64
nullable: false
references:
table: directus_collections
column: collection
many_field:
type: string
length: 64
nullable: false
many_primary:
type: string
length: 64
nullable: false
one_collection:
type: string
length: 64
nullable: false
references:
table: directus_collections
column: collection
one_field:
type: string
length: 64
one_primary:
type: string
length: 64
nullable: false
junction_field:
type: string
length: 64

View File

@@ -0,0 +1,33 @@
table: directus_revisions
columns:
id:
increments: true
activity:
type: integer
unsigned: true
nullable: false
references:
table: directus_activity
column: id
collection:
type: string
length: 64
nullable: false
references:
table: directus_collections
column: collection
item:
type: string
length: 255
nullable: false
data:
type: json
delta:
type: json
parent:
type: integer
unsigned: true
references:
table: directus_revisions
column: id

View File

@@ -0,0 +1,23 @@
table: directus_sessions
columns:
token:
type: string
length: 64
primary: true
nullable: false
user:
type: uuid
nullable: false
references:
table: directus_users
column: id
expires:
type: timestamp
nullable: false
ip:
type: string
length: 255
user_agent:
type: string
length: 255

View File

@@ -0,0 +1,50 @@
table: directus_settings
columns:
id:
increments: true
project_name:
type: string
length: 100
nullable: false
default: 'Directus'
project_url:
type: string
length: 255
project_color:
type: string
length: 10
project_logo:
type: uuid
references:
table: directus_files
column: id
public_foreground:
type: uuid
references:
table: directus_files
column: id
public_background:
type: uuid
references:
table: directus_files
column: id
public_note:
type: text
auth_idle_timeout:
type: integer
unsigned: true
default: 10080
auth_login_attempts:
type: integer
default: 25
unsigned: true
auth_password_policy:
type: string
length: 100
storage_asset_transform:
type: string # One of: 'all', 'none', 'presets'
length: 7
default: all
storage_asset_presets:
type: json

View File

@@ -0,0 +1,28 @@
table: directus_webhooks
columns:
id:
increments: true
name:
type: string
length: 255
method:
type: string
length: 10
default: POST
url:
type: string
length: 255
status:
type: string
length: 10
default: inactive
data:
type: boolean
default: false
actions:
type: string
length: 100
collections:
type: string
length: 255

View File

@@ -0,0 +1,29 @@
table: directus_collections
defaults:
collection: null
hidden: false
singleton: false
icon: null
note: null
translation: null
display_template: null
data:
- collection: directus_activity
- collection: directus_collections
- collection: directus_fields
- collection: directus_files
- collection: directus_folders
- collection: directus_permissions
- collection: directus_presets
- collection: directus_relations
- collection: directus_revisions
- collection: directus_roles
- collection: directus_sessions
- collection: directus_settings
- collection: directus_users
archive_field: status
archive_value: archived
unarchive_value: draft
- collection: directus_webhooks

View File

@@ -0,0 +1,17 @@
table: directus_permissions
defaults:
role: null
collection: null
action: null
permissions: null
validation: null
presets: null
fields: null
limit: null
data:
- collection: directus_settings
action: read
permissions: {}
fields: 'project_name,project_logo,project_color,public_foreground,public_background,public_note'

View File

@@ -0,0 +1,53 @@
table: directus_presets
defaults:
bookmark: null
user: null
role: null
collection: null
search: null
filters: '[]'
layout: tabular
layout_query: null
layout_options: null
data:
- collection: directus_files
layout: cards
layout_query:
cards:
sort: -uploaded_on
layout_options:
cards:
icon: insert_drive_file
title: '{{ title }}'
subtitle: '{{ type }} • {{ filesize }}'
size: 4
imageFit: crop
- collection: directus_users
layout: cards
layout_options:
cards:
icon: account_circle
title: '{{ first_name }} {{ last_name }}'
subtitle: '{{ title }}'
size: 4
- collection: directus_activity
layout: tabular
layout_query:
tabular:
sort: -action_on
fields:
- action
- collection
- action_on
- action_by
layout_options:
tabular:
widths:
action: 100
collection: 210
action_on: 240
action_by: 240

View File

@@ -0,0 +1,60 @@
table: directus_relations
defaults:
many_collection: directus_users
many_field: null
many_primary: null
one_collection: null
one_field: null
one_primary: null
junction_field: null
data:
- many_collection: directus_users
many_field: role
many_primary: id
one_collection: directus_roles
one_field: users
one_primary: id
- many_collection: directus_users
many_field: avatar
many_primary: id
one_collection: directus_files
one_primary: id
- many_collection: directus_revisions
many_field: activity
many_primary: id
one_collection: directus_activity
one_field: revisions
one_primary: id
- many_collection: directus_presets
many_field: user
many_primary: id
one_collection: directus_users
one_primary: id
- many_collection: directus_folders
many_field: parent_folder
many_primary: id
one_collection: directus_folders
one_primary: id
- many_collection: directus_files
many_field: folder
many_primary: id
one_collection: directus_folders
one_primary: id
- many_collection: directus_files
many_field: uploaded_by
many_primary: id
one_collection: directus_users
one_primary: id
- many_collection: directus_fields
many_field: collection
many_primary: id
one_collection: directus_collections
one_field: fields
one_primary: id
- many_collection: directus_activity
many_field: action_by
many_primary: id
one_collection: directus_users
one_primary: id

View File

@@ -0,0 +1,165 @@
table: directus_collections
fields:
- collection: directus_collections
field: collection_divider
special: alias
interface: divider
options:
icon: box
title: Collection Setup
color: '#2F80ED'
locked: true
sort: 1
width: full
- collection: directus_collections
field: collection
interface: text-input
options:
font: monospace
locked: true
readonly: true
sort: 2
width: half
- collection: directus_collections
field: icon
interface: icon
options:
locked: true
sort: 3
width: half
- collection: directus_collections
field: note
interface: text-input
options:
placeholder: A description of this collection...
locked: true
sort: 4
width: full
- collection: directus_collections
field: display_template
interface: display-template
options:
collectionField: collection
locked: true
sort: 5
width: full
- collection: directus_collections
field: hidden
special: boolean
interface: toggle
options:
label: Hide within the App
locked: true
sort: 6
width: half
- collection: directus_collections
field: singleton
special: boolean
interface: toggle
options:
label: Treat as single object
locked: true
sort: 7
width: half
- collection: directus_collections
field: translation
special: json
interface: repeater
options:
template: '{{ translation }} ({{ locale }})'
fields:
- field: locale
name: Language
type: string
schema:
default_value: en-US
meta:
interface: system-language
width: half
- field: translation
name: Translation
type: string
meta:
interface: text-input
width: half
options:
placeholder: Enter a translation...
locked: true
sort: 8
width: full
- collection: directus_collections
field: archive_divider
special: alias
interface: divider
options:
icon: archive
title: Archive
color: '#2F80ED'
locked: true
sort: 9
width: full
- collection: directus_collections
field: archive_field
interface: field
options:
collectionField: collection
allowNone: true
placeholder: Choose a field...
locked: true
sort: 10
width: half
- collection: directus_collections
field: archive_app_filter
interface: toggle
special: boolean
options:
label: Enable App Archive Filter
locked: true
sort: 11
width: half
- collection: directus_collections
field: archive_value
interface: text-input
options:
font: monospace
iconRight: archive
placeholder: Value set when archiving...
locked: true
sort: 12
width: half
- collection: directus_collections
field: unarchive_value
interface: text-input
options:
font: monospace
iconRight: unarchive
placeholder: Value set when unarchiving...
locked: true
sort: 13
width: half
- collection: directus_collections
field: sort_divider
special: alias
interface: divider
options:
icon: sort
title: Sort
color: '#2F80ED'
locked: true
sort: 14
width: full
- collection: directus_collections
field: sort_field
interface: field
options:
collectionField: collection
placeholder: Choose a field...
typeAllowList:
- float
- decimal
- integer
allowNone: true
locked: true
sort: 15
width: half

View File

@@ -0,0 +1,158 @@
table: directus_roles
fields:
- collection: directus_roles
field: id
hidden: true
interface: text-input
locked: true
special: uuid
- collection: directus_roles
field: name
interface: text-input
options:
placeholder: The unique name for this role...
locked: true
sort: 1
width: half
- collection: directus_roles
field: icon
interface: icon
locked: true
sort: 2
width: half
- collection: directus_roles
field: description
interface: text-input
options:
placeholder: A description of this role...
locked: true
sort: 3
width: full
- collection: directus_roles
field: app_access
interface: toggle
locked: true
special: boolean
sort: 4
width: half
- collection: directus_roles
field: admin
interface: toggle
locked: true
special: boolean
sort: 5
width: half
- collection: directus_roles
field: ip_access
interface: tags
options:
placeholder: Add allowed IP addresses, leave empty to allow all...
locked: true
special: json
sort: 6
width: full
- collection: directus_roles
field: enforce_tfa
interface: toggle
locked: true
sort: 7
special: boolean
width: half
- collection: directus_roles
field: users
interface: one-to-many
locked: true
special: o2m
sort: 8
options:
fields:
- first_name
- last_name
width: full
- collection: directus_roles
field: module_list
interface: repeater
locked: true
options:
template: '{{ name }}'
createItemText: Add Module
fields:
- name: Icon
field: icon
type: string
meta:
interface: icon
width: half
- name: Name
field: name
type: string
meta:
interface: text-input
width: half
options:
iconRight: title
placeholder: Enter a title...
- name: Link
field: link
type: string
meta:
interface: text-input
width: full
options:
iconRight: link
placeholder: Relative or absolute URL...
special: json
sort: 9
width: full
- collection: directus_roles
field: collection_list
interface: repeater
locked: true
options:
template: '{{ group_name }}'
createItemText: Add Group
fields:
- name: Group Name
field: group_name
type: string
meta:
width: half
interface: text-input
options:
iconRight: title
placeholder: Label this group...
- name: Accordion
field: accordion
type: string
schema:
default_value: always_open
meta:
width: half
interface: dropdown
options:
choices:
- value: always_open
text: Always Open
- value: start_open
text: Start Open
- value: start_collapsed
text: Start Collapsed
- name: Collections
field: collections
type: JSON
meta:
interface: repeater
options:
createItemText: Add Collection
template: '{{ collection }}'
fields:
- name: Collection
field: collection
type: string
meta:
interface: collection
width: full
special: json
sort: 10
width: full

View File

@@ -0,0 +1,39 @@
# directus_fields isn't surfaced in the app
table: directus_fields
fields:
- collection: directus_fields
field: options
hidden: true
locked: true
special: json
- collection: directus_fields
field: display_options
hidden: true
locked: true
special: json
- collection: directus_fields
field: locked
hidden: true
locked: true
special: boolean
- collection: directus_fields
field: readonly
hidden: true
locked: true
special: boolean
- collection: directus_fields
field: hidden
hidden: true
locked: true
special: boolean
- collection: directus_fields
field: special
hidden: true
locked: true
special: csv
- collection: directus_fields
field: translation
hidden: true
locked: true
special: json

View File

@@ -0,0 +1,525 @@
table: directus_users
fields:
- collection: directus_users
field: first_name
interface: text-input
locked: true
options:
iconRight: account_circle
sort: 1
width: half
- collection: directus_users
field: last_name
interface: text-input
locked: true
options:
iconRight: account_circle
sort: 2
width: half
- collection: directus_users
field: email
interface: text-input
locked: true
options:
iconRight: email
sort: 3
width: half
- collection: directus_users
field: password
special: hash, conceal
interface: hash
locked: true
options:
iconRight: lock
masked: true
sort: 4
width: half
- collection: directus_users
field: avatar
interface: file
locked: true
sort: 5
width: full
- collection: directus_users
field: location
interface: text-input
options:
iconRight: place
sort: 6
width: half
- collection: directus_users
field: title
interface: text-input
options:
iconRight: work
sort: 7
width: half
- collection: directus_users
field: description
interface: textarea
sort: 8
width: full
- collection: directus_users
field: tags
interface: tags
special: json
sort: 9
width: full
options:
iconRight: local_offer
- collection: directus_users
field: preferences_divider
interface: divider
options:
icon: face
title: User Preferences
color: '#2F80ED'
special: alias
sort: 10
width: full
- collection: directus_users
field: timezone
interface: dropdown
options:
choices:
- value: Pacific/Midway
text: '(UTC-11:00) Midway Island'
- value: Pacific/Samoa
text: '(UTC-11:00) Samoa'
- value: Pacific/Honolulu
text: '(UTC-10:00) Hawaii'
- value: US/Alaska
text: '(UTC-09:00) Alaska'
- value: America/Los_Angeles
text: '(UTC-08:00) Pacific Time (US & Canada)'
- value: America/Tijuana
text: '(UTC-08:00) Tijuana'
- value: US/Arizona
text: '(UTC-07:00) Arizona'
- value: America/Chihuahua
text: '(UTC-07:00) Chihuahua'
- value: America/Mexico/La_Paz
text: '(UTC-07:00) La Paz'
- value: America/Mazatlan
text: '(UTC-07:00) Mazatlan'
- value: US/Mountain
text: '(UTC-07:00) Mountain Time (US & Canada)'
- value: America/Managua
text: '(UTC-06:00) Central America'
- value: US/Central
text: '(UTC-06:00) Central Time (US & Canada)'
- value: America/Guadalajara
text: '(UTC-06:00) Guadalajara'
- value: America/Mexico_City
text: '(UTC-06:00) Mexico City'
- value: America/Monterrey
text: '(UTC-06:00) Monterrey'
- value: Canada/Saskatchewan
text: '(UTC-06:00) Saskatchewan'
- value: America/Bogota
text: '(UTC-05:00) Bogota'
- value: US/Eastern
text: '(UTC-05:00) Eastern Time (US & Canada)'
- value: US/East_Indiana
text: '(UTC-05:00) Indiana (East)'
- value: America/Lima
text: '(UTC-05:00) Lima'
- value: America/Quito
text: '(UTC-05:00) Quito'
- value: Canada/Atlantic
text: '(UTC-04:00) Atlantic Time (Canada)'
- value: America/New_York
text: '(UTC-04:00) New York'
- value: America/Caracas
text: '(UTC-04:30) Caracas'
- value: America/La_Paz
text: '(UTC-04:00) La Paz'
- value: America/Santiago
text: '(UTC-04:00) Santiago'
- value: America/Santo_Domingo
text: '(UTC-04:00) Santo Domingo'
- value: Canada/Newfoundland
text: '(UTC-03:30) Newfoundland'
- value: America/Sao_Paulo
text: '(UTC-03:00) Brasilia'
- value: America/Argentina/Buenos_Aires
text: '(UTC-03:00) Buenos Aires'
- value: America/Argentina/GeorgeTown
text: '(UTC-03:00) Georgetown'
- value: America/Godthab
text: '(UTC-03:00) Greenland'
- value: America/Noronha
text: '(UTC-02:00) Mid-Atlantic'
- value: Atlantic/Azores
text: '(UTC-01:00) Azores'
- value: Atlantic/Cape_Verde
text: '(UTC-01:00) Cape Verde Is.'
- value: Africa/Casablanca
text: '(UTC+00:00) Casablanca'
- value: Europe/Edinburgh
text: '(UTC+00:00) Edinburgh'
- value: Etc/Greenwich
text: '(UTC+00:00) Greenwich Mean Time'
- value: Europe/Lisbon
text: '(UTC+00:00) Lisbon'
- value: Europe/London
text: '(UTC+00:00) London'
- value: Africa/Monrovia
text: '(UTC+00:00) Monrovia'
- value: UTC
text: '(UTC+00:00) UTC'
- value: Europe/Amsterdam
text: '(UTC+01:00) Amsterdam'
- value: Europe/Belgrade
text: '(UTC+01:00) Belgrade'
- value: Europe/Berlin
text: '(UTC+01:00) Berlin'
- value: Europe/Bern
text: '(UTC+01:00) Bern'
- value: Europe/Bratislava
text: '(UTC+01:00) Bratislava'
- value: Europe/Brussels
text: '(UTC+01:00) Brussels'
- value: Europe/Budapest
text: '(UTC+01:00) Budapest'
- value: Europe/Copenhagen
text: '(UTC+01:00) Copenhagen'
- value: Europe/Ljubljana
text: '(UTC+01:00) Ljubljana'
- value: Europe/Madrid
text: '(UTC+01:00) Madrid'
- value: Europe/Paris
text: '(UTC+01:00) Paris'
- value: Europe/Prague
text: '(UTC+01:00) Prague'
- value: Europe/Rome
text: '(UTC+01:00) Rome'
- value: Europe/Sarajevo
text: '(UTC+01:00) Sarajevo'
- value: Europe/Skopje
text: '(UTC+01:00) Skopje'
- value: Europe/Stockholm
text: '(UTC+01:00) Stockholm'
- value: Europe/Vienna
text: '(UTC+01:00) Vienna'
- value: Europe/Warsaw
text: '(UTC+01:00) Warsaw'
- value: Africa/Lagos
text: '(UTC+01:00) West Central Africa'
- value: Europe/Zagreb
text: '(UTC+01:00) Zagreb'
- value: Europe/Athens
text: '(UTC+02:00) Athens'
- value: Europe/Bucharest
text: '(UTC+02:00) Bucharest'
- value: Africa/Cairo
text: '(UTC+02:00) Cairo'
- value: Africa/Harare
text: '(UTC+02:00) Harare'
- value: Europe/Helsinki
text: '(UTC+02:00) Helsinki'
- value: Europe/Istanbul
text: '(UTC+02:00) Istanbul'
- value: Asia/Jerusalem
text: '(UTC+02:00) Jerusalem'
- value: Europe/Kyiv
text: '(UTC+02:00) Kyiv'
- value: Africa/Johannesburg
text: '(UTC+02:00) Pretoria'
- value: Europe/Riga
text: '(UTC+02:00) Riga'
- value: Europe/Sofia
text: '(UTC+02:00) Sofia'
- value: Europe/Tallinn
text: '(UTC+02:00) Tallinn'
- value: Europe/Vilnius
text: '(UTC+02:00) Vilnius'
- value: Asia/Baghdad
text: '(UTC+03:00) Baghdad'
- value: Asia/Kuwait
text: '(UTC+03:00) Kuwait'
- value: Europe/Minsk
text: '(UTC+03:00) Minsk'
- value: Africa/Nairobi
text: '(UTC+03:00) Nairobi'
- value: Asia/Riyadh
text: '(UTC+03:00) Riyadh'
- value: Europe/Volgograd
text: '(UTC+03:00) Volgograd'
- value: Asia/Tehran
text: '(UTC+03:30) Tehran'
- value: Asia/Abu_Dhabi
text: '(UTC+04:00) Abu Dhabi'
- value: Asia/Baku
text: '(UTC+04:00) Baku'
- value: Europe/Moscow
text: '(UTC+04:00) Moscow'
- value: Asia/Muscat
text: '(UTC+04:00) Muscat'
- value: Europe/St_Petersburg
text: '(UTC+04:00) St. Petersburg'
- value: Asia/Tbilisi
text: '(UTC+04:00) Tbilisi'
- value: Asia/Yerevan
text: '(UTC+04:00) Yerevan'
- value: Asia/Kabul
text: '(UTC+04:30) Kabul'
- value: Asia/Islamabad
text: '(UTC+05:00) Islamabad'
- value: Asia/Karachi
text: '(UTC+05:00) Karachi'
- value: Asia/Tashkent
text: '(UTC+05:00) Tashkent'
- value: Asia/Calcutta
text: '(UTC+05:30) Chennai'
- value: Asia/Kolkata
text: '(UTC+05:30) Kolkata'
- value: Asia/Mumbai
text: '(UTC+05:30) Mumbai'
- value: Asia/New_Delhi
text: '(UTC+05:30) New Delhi'
- value: Asia/Sri_Jayawardenepura
text: '(UTC+05:30) Sri Jayawardenepura'
- value: Asia/Katmandu
text: '(UTC+05:45) Kathmandu'
- value: Asia/Almaty
text: '(UTC+06:00) Almaty'
- value: Asia/Astana
text: '(UTC+06:00) Astana'
- value: Asia/Dhaka
text: '(UTC+06:00) Dhaka'
- value: Asia/Yekaterinburg
text: '(UTC+06:00) Ekaterinburg'
- value: Asia/Rangoon
text: '(UTC+06:30) Rangoon'
- value: Asia/Bangkok
text: '(UTC+07:00) Bangkok'
- value: Asia/Hanoi
text: '(UTC+07:00) Hanoi'
- value: Asia/Jakarta
text: '(UTC+07:00) Jakarta'
- value: Asia/Novosibirsk
text: '(UTC+07:00) Novosibirsk'
- value: Asia/Beijing
text: '(UTC+08:00) Beijing'
- value: Asia/Chongqing
text: '(UTC+08:00) Chongqing'
- value: Asia/Hong_Kong
text: '(UTC+08:00) Hong Kong'
- value: Asia/Krasnoyarsk
text: '(UTC+08:00) Krasnoyarsk'
- value: Asia/Kuala_Lumpur
text: '(UTC+08:00) Kuala Lumpur'
- value: Australia/Perth
text: '(UTC+08:00) Perth'
- value: Asia/Singapore
text: '(UTC+08:00) Singapore'
- value: Asia/Taipei
text: '(UTC+08:00) Taipei'
- value: Asia/Ulan_Bator
text: '(UTC+08:00) Ulaan Bataar'
- value: Asia/Urumqi
text: '(UTC+08:00) Urumqi'
- value: Asia/Irkutsk
text: '(UTC+09:00) Irkutsk'
- value: Asia/Osaka
text: '(UTC+09:00) Osaka'
- value: Asia/Sapporo
text: '(UTC+09:00) Sapporo'
- value: Asia/Seoul
text: '(UTC+09:00) Seoul'
- value: Asia/Tokyo
text: '(UTC+09:00) Tokyo'
- value: Australia/Adelaide
text: '(UTC+09:30) Adelaide'
- value: Australia/Darwin
text: '(UTC+09:30) Darwin'
- value: Australia/Brisbane
text: '(UTC+10:00) Brisbane'
- value: Australia/Canberra
text: '(UTC+10:00) Canberra'
- value: Pacific/Guam
text: '(UTC+10:00) Guam'
- value: Australia/Hobart
text: '(UTC+10:00) Hobart'
- value: Australia/Melbourne
text: '(UTC+10:00) Melbourne'
- value: Pacific/Port_Moresby
text: '(UTC+10:00) Port Moresby'
- value: Australia/Sydney
text: '(UTC+10:00) Sydney'
- value: Asia/Yakutsk
text: '(UTC+10:00) Yakutsk'
- value: Asia/Vladivostok
text: '(UTC+11:00) Vladivostok'
- value: Pacific/Auckland
text: '(UTC+12:00) Auckland'
- value: Pacific/Fiji
text: '(UTC+12:00) Fiji'
- value: Pacific/Kwajalein
text: '(UTC+12:00) International Date Line West'
- value: Asia/Kamchatka
text: '(UTC+12:00) Kamchatka'
- value: Asia/Magadan
text: '(UTC+12:00) Magadan'
- value: Pacific/Marshall_Is
text: '(UTC+12:00) Marshall Is.'
- value: Asia/New_Caledonia
text: '(UTC+12:00) New Caledonia'
- value: Asia/Solomon_Is
text: '(UTC+12:00) Solomon Is.'
- value: Pacific/Wellington
text: '(UTC+12:00) Wellington'
- value: Pacific/Tongatapu
text: "(UTC+13:00) Nuku'alofa"
placeholder: Choose a timezone...
sort: 11
width: half
- collection: directus_users
field: language
interface: dropdown
locked: true
options:
choices:
- text: Afrikaans (South Africa)
value: af-ZA
- text: Arabic (Saudi Arabia)
value: ar-SA
- text: Catalan (Spain)
value: ca-ES
- text: Chinese (Simplified)
value: zh-CN
- text: Czech (Czech Republic)
value: cs-CZ
- text: Danish (Denmark)
value: da-DK
- text: Dutch (Netherlands)
value: nl-NL
- text: English (United States)
value: en-US
- text: Finnish (Finland)
value: fi-FI
- text: French (France)
value: fr-FR
- text: German (Germany)
value: de-DE
- text: Greek (Greece)
value: el-GR
- text: Hebrew (Israel)
value: he-IL
- text: Hungarian (Hungary)
value: hu-HU
- text: Icelandic (Iceland)
value: is-IS
- text: Indonesian (Indonesia)
value: id-ID
- text: Italian (Italy)
value: it-IT
- text: Japanese (Japan)
value: ja-JP
- text: Korean (Korea)
value: ko-KR
- text: Malay (Malaysia)
value: ms-MY
- text: Norwegian (Norway)
value: no-NO
- text: Polish (Poland)
value: pl-PL
- text: Portuguese (Brazil)
value: pt-BR
- text: Portuguese (Portugal)
value: pt-PT
- text: Russian (Russian Federation)
value: ru-RU
- text: Spanish (Spain)
value: es-ES
- text: Spanish (Latin America)
value: es-419
- text: Taiwanese Mandarin (Taiwan)
value: zh-TW
- text: Turkish (Turkey)
value: tr-TR
- text: Ukrainian (Ukraine)
value: uk-UA
- text: Vietnamese (Vietnam)
value: vi-VN
sort: 12
width: half
- collection: directus_users
field: theme
interface: dropdown
locked: true
options:
choices:
- value: auto
text: Automatic (Based on System)
- value: light
text: Light Mode
- value: dark
text: Dark Mode
sort: 13
width: half
- collection: directus_users
field: tfa_secret
interface: tfa-setup
locked: true
special: conceal
sort: 14
width: half
- collection: directus_users
field: admin_divider
interface: divider
locked: true
options:
icon: verified_user
title: Admin Options
color: '#F2994A'
special: alias
sort: 15
width: full
- collection: directus_users
field: status
interface: dropdown
locked: true
options:
choices:
- text: Draft
value: draft
- text: Invited
value: invited
- text: Active
value: active
- text: Suspended
value: suspended
- text: Archived
value: archived
sort: 16
width: half
- collection: directus_users
field: role
interface: many-to-one
locked: true
options:
template: '{{ name }}'
special: m2o
sort: 17
width: half
- collection: directus_users
field: token
interface: token
locked: true
options:
iconRight: vpn_key
placeholder: Enter a secure access token...
sort: 18
width: full
- collection: directus_users
field: id
special: uuid
interface: text-input
locked: true
options:
iconRight: vpn_key
sort: 19
width: full

View File

@@ -0,0 +1,8 @@
table: directus_folders
fields:
- collection: directus_folders
field: id
interface: text-input
locked: true
special: uuid

View File

@@ -0,0 +1,93 @@
table: directus_files
fields:
- collection: directus_files
field: id
hidden: true
interface: text-input
locked: true
special: uuid
- collection: directus_files
field: title
interface: text-input
locked: true
options:
iconRight: title
placeholder: A unique title...
sort: 1
width: full
- collection: directus_files
field: description
interface: textarea
locked: true
sort: 2
width: full
options:
placeholder: An optional description...
- collection: directus_files
field: tags
interface: tags
locked: true
options:
iconRight: local_offer
special: json
sort: 3
width: full
- collection: directus_files
field: location
interface: text-input
locked: true
options:
iconRight: place
placeholder: An optional location...
sort: 4
width: half
- collection: directus_files
field: storage
interface: text-input
locked: true
options:
iconRight: storage
sort: 5
width: half
readonly: true
- collection: directus_files
field: storage_divider
interface: divider
locked: true
options:
icon: insert_drive_file
title: File Naming
color: '#2F80ED'
special: alias
sort: 6
width: full
- collection: directus_files
field: filename_disk
interface: text-input
locked: true
options:
iconRight: publish
placeholder: Name on disk storage...
sort: 7
width: half
- collection: directus_files
field: filename_download
interface: text-input
locked: true
options:
iconRight: get_app
placeholder: Name when downloading...
sort: 8
width: half
- collection: directus_files
field: metadata
hidden: true
locked: true
special: json
- collection: directus_files
field: type
display: mime-type
- collection: directus_files
field: filesize
display: filesize

View File

@@ -0,0 +1,14 @@
# directus_permissions isn't surfaced in the app
table: directus_permissions
fields:
- collection: directus_permissions
field: permissions
hidden: true
locked: true
special: json
- collection: directus_permissions
field: presets
hidden: true
locked: true
special: json

View File

@@ -0,0 +1,19 @@
table: directus_presets
fields:
# directus_presets isn't surfaced in the app
- collection: directus_presets
field: filters
hidden: true
locked: true
special: json
- collection: directus_presets
field: layout_query
hidden: true
locked: true
special: json
- collection: directus_presets
field: layout_options
hidden: true
locked: true
special: json

View File

@@ -0,0 +1,14 @@
table: directus_revisions
fields:
# directus_revisions isn't surfaced in the app
- collection: directus_revisions
field: data
hidden: true
locked: true
special: json
- collection: directus_revisions
field: delta
hidden: true
locked: true
special: json

View File

@@ -0,0 +1,224 @@
table: directus_settings
fields:
- collection: directus_settings
field: project_name
interface: text-input
locked: true
options:
iconRight: title
placeholder: My project...
sort: 1
translation:
locale: en-US
translation: Name
width: half
- collection: directus_settings
field: project_url
interface: text-input
locked: true
options:
iconRight: link
placeholder: https://example.com
sort: 2
translation:
locale: en-US
translation: Website
width: half
- collection: directus_settings
field: project_color
interface: color
locked: true
note: Login & Logo Background
sort: 3
translation:
locale: en-US
translation: Brand Color
width: half
- collection: directus_settings
field: project_logo
interface: file
locked: true
note: White 40x40 SVG/PNG
sort: 4
translation:
locale: en-US
translation: Brand Logo
width: half
- collection: directus_settings
field: public_divider
interface: divider
locked: true
options:
icon: public
title: Public Pages
color: '#2F80ED'
special: alias
sort: 5
width: full
- collection: directus_settings
field: public_foreground
interface: file
locked: true
sort: 6
translation:
locale: en-US
translation: Login Foreground
width: half
- collection: directus_settings
field: public_background
interface: file
locked: true
sort: 7
translation:
locale: en-US
translation: Login Background
width: half
- collection: directus_settings
field: public_note
interface: textarea
locked: true
options:
placeholder: A short, public message that supports markdown formatting...
sort: 8
width: full
- collection: directus_settings
field: security_divider
interface: divider
locked: true
options:
icon: security
title: Security
color: '#2F80ED'
special: alias
sort: 9
width: full
- collection: directus_settings
field: auth_password_policy
interface: dropdown
locked: true
options:
choices:
- value: null
text: None  Not Recommended
- value: '/^.{8,}$/'
text: Weak Minimum 8 Characters
- value: "/(?=^.{8,}$)(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()_+}{';'?>.<,])(?!.*\\s).*$/"
text: Strong Upper / Lowercase / Numbers / Special
sort: 10
width: half
- collection: directus_settings
field: auth_idle_timeout
interface: numeric
locked: true
options:
iconRight: timer
sort: 11
width: half
- collection: directus_settings
field: auth_login_attempts
interface: numeric
locked: true
options:
iconRight: lock
sort: 12
width: half
- collection: directus_settings
field: files_divider
interface: divider
locked: true
options:
icon: storage
title: Files & Thumbnails
color: '#2F80ED'
special: alias
sort: 13
width: full
- collection: directus_settings
field: storage_asset_presets
interface: repeater
locked: true
options:
fields:
- field: key
name: Key
type: string
meta:
interface: slug
options:
onlyOnCreate: false
required: true
width: half
- field: fit
name: Fit
type: string
meta:
interface: dropdown
options:
choices:
- value: contain
text: Contain (preserve aspect ratio)
- value: cover
text: Cover (forces exact size)
required: true
width: half
- field: width
name: Width
type: integer
meta:
interface: numeric
required: true
width: half
- field: height
name: Height
type: integer
meta:
interface: numeric
required: true
width: half
- field: quality
type: integer
name: Quality
schema:
default_value: 80
meta:
interface: slider
options:
max: 100
min: 0
step: 1
required: true
width: full
template: '{{key}}'
special: json
sort: 14
width: full
- collection: directus_settings
field: storage_asset_transform
interface: dropdown
locked: true
options:
choices:
- value: all
text: All
- value: none
text: None
- value: presets
text: Presets Only
sort: 15
width: half
- collection: directus_settings
field: misc_divider
interface: divider
locked: true
options:
icon: pending
title: Miscellaneous
color: '#2F80ED'
special: alias
sort: 16
width: full
- collection: directus_settings
field: id
hidden: true
locked: true

View File

@@ -0,0 +1,82 @@
table: directus_webhooks
fields:
- collection: directus_webhooks
field: id
hidden: true
locked: true
- collection: directus_webhooks
field: name
interface: text-input
locked: true
sort: 1
width: full
- collection: directus_webhooks
field: method
interface: dropdown
locked: true
options:
choices:
- GET
- POST
sort: 2
width: half
- collection: directus_webhooks
field: url
interface: text-input
locked: true
options:
iconRight: link
sort: 3
width: half
- collection: directus_webhooks
field: status
interface: dropdown
locked: true
options:
choices:
- text: Active
value: active
- text: Inactive
value: inactive
sort: 4
width: half
- collection: directus_webhooks
field: data
interface: toggle
locked: true
options:
choices:
label: Include item data in request
sort: 5
width: half
- collection: directus_webhooks
field: triggers_divider
interface: divider
options:
icon: api
title: Triggers
color: '#2F80ED'
special: alias
sort: 6
width: full
- collection: directus_webhooks
field: actions
interface: checkboxes
options:
choices:
- text: Create
value: create
- text: Update
value: update
- text: Delete
value: delete
special: csv
sort: 7
width: full
- collection: directus_webhooks
field: collections
interface: collections
special: csv
sort: 8
width: full

View File

@@ -0,0 +1,64 @@
table: directus_activity
fields:
- collection: directus_activity
field: action
display: badge
display_options:
defaultForeground: '#263238'
defaultBackground: '#eceff1'
choices:
- text: Create
value: create
foreground: '#27ae60'
background: '#c9ebd7'
- text: Update
value: update
foreground: '#2f80ed'
background: '#cbdffb'
- text: Delete
value: delete
foreground: '#eb5757'
background: '#fad5d5'
- text: Login
value: authenticate
foreground: '#9b51e0'
background: '#e6d3f7'
- collection: directus_activity
field: collection
display: collection
display_options:
icon: true
- collection: directus_activity
field: action_on
display: datetime
options:
relative: true
- collection: directus_activity
field: action_by
display: user
- collection: directus_activity
field: comment
display: formatted-text
display_options:
subdued: true
- collection: directus_activity
field: user_agent
display: formatted-text
display_options:
font: monospace
- collection: directus_activity
field: ip
display: formatted-text
display_options:
font: monospace
- collection: directus_activity
field: revisions
interface: one-to-many
locked: true
special: o2m
options:
fields:
- collection
- item
width: full

View File

@@ -0,0 +1,15 @@
collection: null
field: null
special: null
interface: null
options: null
display: null
display_options: null
locked: false
readonly: false
hidden: false
sort: null
width: full
group: null
translation: null
note: null

View File

@@ -0,0 +1,169 @@
import Knex, { ColumnBuilder } from 'knex';
import fse from 'fs-extra';
import path from 'path';
import yaml from 'js-yaml';
import { types } from '../../types';
import { isObject, merge } from 'lodash';
type TableSeed = {
table: string;
columns: {
[column: string]: {
type?: typeof types[number];
primary?: boolean;
nullable?: boolean;
default?: any;
length?: number;
increments?: boolean;
unsigned?: boolean;
unique?: boolean;
references?: {
table: string;
column: string;
};
};
}
}
type RowSeed = {
table: string;
defaults: Record<string, any>;
data: Record<string, any>[];
}
type FieldSeed = {
table: string;
fields: {
collection: string;
field: string;
special: string | null;
interface: string | null;
options: Record<string, any> | null;
display: string | null;
display_options: Record<string, any> | null;
locked: boolean;
readonly: boolean;
hidden: boolean;
sort: number | null;
width: string | null;
group: number | null;
translation: Record<string, any> | null;
note: string | null;
}[];
}
export default async function runSeed(database: Knex) {
await createTables(database);
await insertRows(database);
await insertFields(database);
}
async function createTables(database: Knex) {
const tableSeeds = await fse.readdir(path.resolve(__dirname, './01-tables/'));
for (const tableSeedFile of tableSeeds) {
const yamlRaw = await fse.readFile(path.resolve(__dirname, './01-tables', tableSeedFile), 'utf8');
const seedData = yaml.safeLoad(yamlRaw) as TableSeed;
await database.schema.createTable(seedData.table, tableBuilder => {
for (const [columnName, columnInfo] of Object.entries(seedData.columns)) {
let column: ColumnBuilder;
if (columnInfo.type === 'string') {
column = tableBuilder.string(columnName, columnInfo.length);
} else if (columnInfo.increments) {
column = tableBuilder.increments();
} else if (columnInfo.type === 'csv') {
column = tableBuilder.string(columnName);
} else {
column = tableBuilder[columnInfo.type!](columnName);
}
if (columnInfo.primary) {
column.primary();
}
if (columnInfo.nullable !== undefined && columnInfo.nullable === false) {
column.notNullable();
}
if (columnInfo.default !== undefined) {
let defaultValue = columnInfo.default;
if (isObject(defaultValue) || Array.isArray(defaultValue))
defaultValue = JSON.stringify(defaultValue);
if (defaultValue === '$now') {
defaultValue = database!.fn.now();
}
column.defaultTo(defaultValue);
}
if (columnInfo.unique) {
column.unique();
}
if (columnInfo.unsigned) {
column.unsigned();
}
if (columnInfo.references) {
tableBuilder
.foreign(columnName)
.references(columnInfo.references.column)
.inTable(columnInfo.references.table);
}
}
});
}
}
async function insertRows(database: Knex) {
const rowSeeds = await fse.readdir(path.resolve(__dirname, './02-rows/'));
for (const rowSeedFile of rowSeeds) {
const yamlRaw = await fse.readFile(path.resolve(__dirname, './02-rows', rowSeedFile), 'utf8');
const seedData = yaml.safeLoad(yamlRaw) as RowSeed;
const dataWithDefaults = seedData.data.map((row) => {
for (const [key, value] of Object.entries(row)) {
if (value !== null && (typeof value === 'object' || Array.isArray(value))) {
row[key] = JSON.stringify(value);
}
}
return merge({}, seedData.defaults, row);
});
await database.batchInsert(seedData.table, dataWithDefaults);
}
}
async function insertFields(database: Knex) {
const fieldSeeds = await fse.readdir(path.resolve(__dirname, './03-fields/'));
let defaults: Record<string, any> = {};
for (const fieldSeedFile of fieldSeeds) {
const yamlRaw = await fse.readFile(path.resolve(__dirname, './03-fields', fieldSeedFile), 'utf8');
const seedData = yaml.safeLoad(yamlRaw) as FieldSeed;
if (fieldSeedFile === '_defaults.yaml') {
defaults = seedData;
continue;
}
const dataWithDefaults = seedData.fields.map((row) => {
for (const [key, value] of Object.entries(row)) {
if (value !== null && (typeof value === 'object' || Array.isArray(value))) {
(row as any)[key] = JSON.stringify(value);
}
}
return merge({}, defaults, row);
});
await database.batchInsert('directus_fields', dataWithDefaults);
}
}

File diff suppressed because it is too large Load Diff