mirror of
https://github.com/directus/directus.git
synced 2026-02-04 20:45:20 -05:00
Merge branch 'main' into aggregation
This commit is contained in:
@@ -14,6 +14,7 @@ export function getGeometryHelper(): KnexSpatial {
|
||||
mariadb: KnexSpatial_MySQL,
|
||||
sqlite3: KnexSpatial,
|
||||
pg: KnexSpatial_PG,
|
||||
postgres: KnexSpatial_PG,
|
||||
redshift: KnexSpatial_Redshift,
|
||||
mssql: KnexSpatial_MSSQL,
|
||||
oracledb: KnexSpatial_Oracle,
|
||||
|
||||
@@ -8,6 +8,7 @@ import { validateEnv } from '../utils/validate-env';
|
||||
import fse from 'fs-extra';
|
||||
import path from 'path';
|
||||
import { merge } from 'lodash';
|
||||
import { promisify } from 'util';
|
||||
|
||||
let database: Knex | null = null;
|
||||
let inspector: ReturnType<typeof SchemaInspector> | null = null;
|
||||
@@ -22,6 +23,7 @@ export default function getDatabase(): Knex {
|
||||
'DB_SEARCH_PATH',
|
||||
'DB_CONNECTION_STRING',
|
||||
'DB_POOL',
|
||||
'DB_EXCLUDE_TABLES',
|
||||
]);
|
||||
|
||||
const poolConfig = getConfigFromEnv('DB_POOL');
|
||||
@@ -54,7 +56,12 @@ export default function getDatabase(): Knex {
|
||||
connection: env.DB_CONNECTION_STRING || connectionConfig,
|
||||
log: {
|
||||
warn: (msg) => {
|
||||
// Ignore warnings about returning not being supported in some DBs
|
||||
if (msg.startsWith('.returning()')) return;
|
||||
|
||||
// Ignore warning about MySQL not supporting TRX for DDL
|
||||
if (msg.startsWith('Transaction was implicitly committed, do not mix transactions and DDL with MySQL')) return;
|
||||
|
||||
return logger.warn(msg);
|
||||
},
|
||||
error: (msg) => logger.error(msg),
|
||||
@@ -66,8 +73,14 @@ export default function getDatabase(): Knex {
|
||||
|
||||
if (env.DB_CLIENT === 'sqlite3') {
|
||||
knexConfig.useNullAsDefault = true;
|
||||
poolConfig.afterCreate = (conn: any, cb: any) => {
|
||||
conn.run('PRAGMA foreign_keys = ON', cb);
|
||||
|
||||
poolConfig.afterCreate = async (conn: any, callback: any) => {
|
||||
logger.trace('Enabling SQLite Foreign Keys support...');
|
||||
|
||||
const run = promisify(conn.run.bind(conn));
|
||||
await run('PRAGMA foreign_keys = ON');
|
||||
|
||||
callback(null, conn);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -111,7 +124,7 @@ export async function hasDatabaseConnection(database?: Knex): Promise<boolean> {
|
||||
database = database ?? getDatabase();
|
||||
|
||||
try {
|
||||
if (env.DB_CLIENT === 'oracledb') {
|
||||
if (getDatabaseClient(database) === 'oracle') {
|
||||
await database.raw('select 1 from DUAL');
|
||||
} else {
|
||||
await database.raw('SELECT 1');
|
||||
@@ -123,28 +136,48 @@ export async function hasDatabaseConnection(database?: Knex): Promise<boolean> {
|
||||
}
|
||||
}
|
||||
|
||||
export async function validateDBConnection(database?: Knex): Promise<void> {
|
||||
export async function validateDatabaseConnection(database?: Knex): Promise<void> {
|
||||
database = database ?? getDatabase();
|
||||
|
||||
try {
|
||||
if (env.DB_CLIENT === 'oracledb') {
|
||||
if (getDatabaseClient(database) === 'oracle') {
|
||||
await database.raw('select 1 from DUAL');
|
||||
} else {
|
||||
await database.raw('SELECT 1');
|
||||
}
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
logger.error(`Can't connect to the database.`);
|
||||
logger.error(error);
|
||||
process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
export function getDatabaseClient(database?: Knex): 'mysql' | 'postgres' | 'sqlite' | 'oracle' | 'mssql' {
|
||||
database = database ?? getDatabase();
|
||||
|
||||
switch (database.client.constructor.name) {
|
||||
case 'Client_MySQL':
|
||||
return 'mysql';
|
||||
case 'Client_PG':
|
||||
return 'postgres';
|
||||
case 'Client_SQLite3':
|
||||
return 'sqlite';
|
||||
case 'Client_Oracledb':
|
||||
case 'Client_Oracle':
|
||||
return 'oracle';
|
||||
case 'Client_MSSQL':
|
||||
return 'mssql';
|
||||
}
|
||||
|
||||
throw new Error(`Couldn't extract database client`);
|
||||
}
|
||||
|
||||
export async function isInstalled(): Promise<boolean> {
|
||||
const inspector = getSchemaInspector();
|
||||
|
||||
// The existence of a directus_collections table alone isn't a "proper" check to see if everything
|
||||
// is installed correctly of course, but it's safe enough to assume that this collection only
|
||||
// exists when using the installer CLI.
|
||||
// exists when Directus is properly installed.
|
||||
return await inspector.hasTable('directus_collections');
|
||||
}
|
||||
|
||||
@@ -173,9 +206,45 @@ export async function validateMigrations(): Promise<boolean> {
|
||||
);
|
||||
|
||||
return requiredVersions.every((version) => completedVersions.includes(version));
|
||||
} catch (error) {
|
||||
} catch (error: any) {
|
||||
logger.error(`Database migrations cannot be found`);
|
||||
logger.error(error);
|
||||
throw process.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* These database extensions should be optional, so we don't throw or return any problem states when they don't
|
||||
*/
|
||||
export async function validateDatabaseExtensions(): Promise<void> {
|
||||
const database = getDatabase();
|
||||
const databaseClient = getDatabaseClient(database);
|
||||
|
||||
if (databaseClient === 'postgres') {
|
||||
let available = false;
|
||||
let installed = false;
|
||||
|
||||
const exists = await database.raw(`SELECT name FROM pg_available_extensions WHERE name = 'postgis';`);
|
||||
|
||||
if (exists.rows.length > 0) {
|
||||
available = true;
|
||||
}
|
||||
|
||||
if (available) {
|
||||
try {
|
||||
await database.raw(`SELECT PostGIS_version();`);
|
||||
installed = true;
|
||||
} catch {
|
||||
installed = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (available === false) {
|
||||
logger.warn(`PostGIS isn't installed. Geometry type support will be limited.`);
|
||||
} else if (available === true && installed === false) {
|
||||
logger.warn(
|
||||
`PostGIS is installed, but hasn't been activated on this database. Geometry type support will be limited.`
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -68,7 +68,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
await knex(constraint.many_collection)
|
||||
.update({ [constraint.many_field]: null })
|
||||
.whereIn(currentPrimaryKeyField, ids);
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
logger.error(
|
||||
`${constraint.many_collection}.${constraint.many_field} contains illegal foreign keys which couldn't be set to NULL. Please fix these references and rerun this migration to complete the upgrade.`
|
||||
);
|
||||
@@ -111,7 +111,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
builder.onDelete('SET NULL');
|
||||
}
|
||||
});
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
logger.warn(
|
||||
`Couldn't add foreign key constraint for ${constraint.many_collection}.${constraint.many_field}<->${constraint.one_collection}`
|
||||
);
|
||||
@@ -140,7 +140,7 @@ export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.alterTable(relation.many_collection, (table) => {
|
||||
table.dropForeign([relation.many_field]);
|
||||
});
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
logger.warn(
|
||||
`Couldn't drop foreign key constraint for ${relation.many_collection}.${relation.many_field}<->${relation.one_collection}`
|
||||
);
|
||||
|
||||
@@ -99,7 +99,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
await knex.schema.alterTable(update.table, (table) => {
|
||||
table.dropForeign([constraint.column], existingForeignKey?.constraint_name || undefined);
|
||||
});
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
logger.warn(`Couldn't drop foreign key ${update.table}.${constraint.column}->${constraint.references}`);
|
||||
logger.warn(err);
|
||||
}
|
||||
@@ -114,7 +114,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
// Knex uses a default convention for index names: `table_column_type`
|
||||
table.dropIndex([constraint.column], `${update.table}_${constraint.column}_foreign`);
|
||||
});
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
logger.warn(
|
||||
`Couldn't clean up index for foreign key ${update.table}.${constraint.column}->${constraint.references}`
|
||||
);
|
||||
@@ -126,7 +126,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
await knex.schema.alterTable(update.table, (table) => {
|
||||
table.foreign(constraint.column).references(constraint.references).onDelete(constraint.on_delete);
|
||||
});
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
logger.warn(`Couldn't add foreign key to ${update.table}.${constraint.column}->${constraint.references}`);
|
||||
logger.warn(err);
|
||||
}
|
||||
@@ -141,7 +141,7 @@ export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.alterTable(update.table, (table) => {
|
||||
table.dropForeign([constraint.column]);
|
||||
});
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
logger.warn(`Couldn't drop foreign key ${update.table}.${constraint.column}->${constraint.references}`);
|
||||
logger.warn(err);
|
||||
}
|
||||
@@ -156,7 +156,7 @@ export async function down(knex: Knex): Promise<void> {
|
||||
// Knex uses a default convention for index names: `table_column_type`
|
||||
table.dropIndex([constraint.column], `${update.table}_${constraint.column}_foreign`);
|
||||
});
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
logger.warn(
|
||||
`Couldn't clean up index for foreign key ${update.table}.${constraint.column}->${constraint.references}`
|
||||
);
|
||||
@@ -168,7 +168,7 @@ export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.alterTable(update.table, (table) => {
|
||||
table.foreign(constraint.column).references(constraint.references);
|
||||
});
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
logger.warn(`Couldn't add foreign key to ${update.table}.${constraint.column}->${constraint.references}`);
|
||||
logger.warn(err);
|
||||
}
|
||||
|
||||
@@ -14,7 +14,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
|
||||
if (options.icon) newOptions.headerIcon = options.icon;
|
||||
if (options.color) newOptions.headerColor = options.color;
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
logger.warn(`Couldn't convert previous options from field ${dividerGroup.collection}.${dividerGroup.field}`);
|
||||
logger.warn(err);
|
||||
}
|
||||
@@ -27,7 +27,7 @@ export async function up(knex: Knex): Promise<void> {
|
||||
options: JSON.stringify(newOptions),
|
||||
})
|
||||
.where('id', '=', dividerGroup.id);
|
||||
} catch (err) {
|
||||
} catch (err: any) {
|
||||
logger.warn(`Couldn't update ${dividerGroup.collection}.${dividerGroup.field} to new group interface`);
|
||||
logger.warn(err);
|
||||
}
|
||||
|
||||
13
api/src/database/migrations/20210831A-remove-limit-column.ts
Normal file
13
api/src/database/migrations/20210831A-remove-limit-column.ts
Normal file
@@ -0,0 +1,13 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
await knex.schema.alterTable('directus_permissions', (table) => {
|
||||
table.dropColumn('limit');
|
||||
});
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.alterTable('directus_permissions', (table) => {
|
||||
table.integer('limit').unsigned();
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
import { Knex } from 'knex';
|
||||
|
||||
export async function up(knex: Knex): Promise<void> {
|
||||
await knex.schema.alterTable('directus_webhooks', (table) => {
|
||||
table.text('collections').notNullable().alter();
|
||||
});
|
||||
}
|
||||
|
||||
export async function down(knex: Knex): Promise<void> {
|
||||
await knex.schema.alterTable('directus_webhooks', (table) => {
|
||||
table.text('collections').alter();
|
||||
});
|
||||
}
|
||||
@@ -1,10 +1,9 @@
|
||||
/* eslint-disable no-console */
|
||||
|
||||
import formatTitle from '@directus/format-title';
|
||||
import fse from 'fs-extra';
|
||||
import { Knex } from 'knex';
|
||||
import path from 'path';
|
||||
import env from '../../env';
|
||||
import logger from '../../logger';
|
||||
import { Migration } from '../../types';
|
||||
|
||||
export default async function run(database: Knex, direction: 'up' | 'down' | 'latest'): Promise<void> {
|
||||
@@ -62,7 +61,7 @@ export default async function run(database: Knex, direction: 'up' | 'down' | 'la
|
||||
|
||||
const { up } = require(nextVersion.file);
|
||||
|
||||
console.log(`✨ Applying ${nextVersion.name}...`);
|
||||
logger.info(`Applying ${nextVersion.name}...`);
|
||||
|
||||
await up(database);
|
||||
await database.insert({ version: nextVersion.version, name: nextVersion.name }).into('directus_migrations');
|
||||
@@ -83,7 +82,7 @@ export default async function run(database: Knex, direction: 'up' | 'down' | 'la
|
||||
|
||||
const { down } = require(migration.file);
|
||||
|
||||
console.log(`✨ Undoing ${migration.name}...`);
|
||||
logger.info(`Undoing ${migration.name}...`);
|
||||
|
||||
await down(database);
|
||||
await database('directus_migrations').delete().where({ version: migration.version });
|
||||
@@ -94,7 +93,7 @@ export default async function run(database: Knex, direction: 'up' | 'down' | 'la
|
||||
if (migration.completed === false) {
|
||||
const { up } = require(migration.file);
|
||||
|
||||
console.log(`✨ Applying ${migration.name}...`);
|
||||
logger.info(`Applying ${migration.name}...`);
|
||||
|
||||
await up(database);
|
||||
await database.insert({ version: migration.version, name: migration.name }).into('directus_migrations');
|
||||
|
||||
@@ -8,7 +8,6 @@ const defaults: Partial<Permission> = {
|
||||
validation: null,
|
||||
presets: null,
|
||||
fields: ['*'],
|
||||
limit: null,
|
||||
system: true,
|
||||
};
|
||||
|
||||
|
||||
@@ -12,48 +12,48 @@ defaults:
|
||||
|
||||
data:
|
||||
- collection: directus_activity
|
||||
note: Accountability logs for all events
|
||||
note: $t:directus_collection.directus_activity
|
||||
- collection: directus_collections
|
||||
icon: list_alt
|
||||
note: Additional collection configuration and metadata
|
||||
note: $t:directus_collection.directus_collections
|
||||
- collection: directus_fields
|
||||
icon: input
|
||||
note: Additional field configuration and metadata
|
||||
note: $t:directus_collection.directus_fields
|
||||
- collection: directus_files
|
||||
icon: folder
|
||||
note: Metadata for all managed file assets
|
||||
note: $t:directus_collection.directus_files
|
||||
display_template: '{{ $thumbnail }} {{ title }}'
|
||||
- collection: directus_folders
|
||||
note: Provides virtual directories for files
|
||||
note: $t:directus_collection.directus_folders
|
||||
display_template: '{{ name }}'
|
||||
- collection: directus_migrations
|
||||
note: What version of the database you're using
|
||||
note: $t:directus_collection.directus_migrations
|
||||
- collection: directus_permissions
|
||||
icon: admin_panel_settings
|
||||
note: Access permissions for each role
|
||||
note: $t:directus_collection.directus_permissions
|
||||
- collection: directus_presets
|
||||
icon: bookmark_border
|
||||
note: Presets for collection defaults and bookmarks
|
||||
note: $t:directus_collection.directus_presets
|
||||
accountability: null
|
||||
- collection: directus_relations
|
||||
icon: merge_type
|
||||
note: Relationship configuration and metadata
|
||||
note: $t:directus_collection.directus_relations
|
||||
- collection: directus_revisions
|
||||
note: Data snapshots for all activity
|
||||
note: $t:directus_collection.directus_revisions
|
||||
- collection: directus_roles
|
||||
icon: supervised_user_circle
|
||||
note: Permission groups for system users
|
||||
note: $t:directus_collection.directus_roles
|
||||
- collection: directus_sessions
|
||||
note: User session information
|
||||
note: $t:directus_collection.directus_sessions
|
||||
- collection: directus_settings
|
||||
singleton: true
|
||||
note: Project configuration options
|
||||
note: $t:directus_collection.directus_settings
|
||||
- collection: directus_users
|
||||
archive_field: status
|
||||
archive_value: archived
|
||||
unarchive_value: draft
|
||||
icon: people_alt
|
||||
note: System users for the platform
|
||||
note: $t:directus_collection.directus_users
|
||||
display_template: '{{ first_name }} {{ last_name }}'
|
||||
- collection: directus_webhooks
|
||||
note: Configuration for event-based HTTP requests
|
||||
note: $t:directus_collection.directus_webhooks
|
||||
|
||||
@@ -13,19 +13,19 @@ fields:
|
||||
defaultForeground: 'var(--foreground-normal)'
|
||||
defaultBackground: 'var(--background-normal-alt)'
|
||||
choices:
|
||||
- text: Create
|
||||
- text: $t:field_options.directus_activity.create
|
||||
value: create
|
||||
foreground: 'var(--primary)'
|
||||
background: 'var(--primary-25)'
|
||||
- text: Update
|
||||
- text: $t:field_options.directus_activity.update
|
||||
value: update
|
||||
foreground: 'var(--blue)'
|
||||
background: 'var(--blue-25)'
|
||||
- text: Delete
|
||||
- text: $t:field_options.directus_activity.delete
|
||||
value: delete
|
||||
foreground: 'var(--danger)'
|
||||
background: 'var(--danger-25)'
|
||||
- text: Login
|
||||
- text: $t:field_options.directus_activity.login
|
||||
value: authenticate
|
||||
foreground: 'var(--purple)'
|
||||
background: 'var(--purple-25)'
|
||||
|
||||
@@ -8,7 +8,7 @@ fields:
|
||||
interface: presentation-divider
|
||||
options:
|
||||
icon: box
|
||||
title: Collection Setup
|
||||
title: $t:field_options.directus_collections.collection_setup
|
||||
width: full
|
||||
|
||||
- field: collection
|
||||
@@ -32,7 +32,7 @@ fields:
|
||||
- field: color
|
||||
interface: select-color
|
||||
options:
|
||||
placeholder: Choose a color...
|
||||
placeholder: $t:field_options.directus_collections.note_placeholder
|
||||
width: half
|
||||
|
||||
- field: display_template
|
||||
@@ -45,7 +45,7 @@ fields:
|
||||
special: boolean
|
||||
interface: boolean
|
||||
options:
|
||||
label: Hide within the App
|
||||
label: $t:field_options.directus_collections.hidden_label
|
||||
width: half
|
||||
|
||||
- field: singleton
|
||||
@@ -102,7 +102,7 @@ fields:
|
||||
interface: presentation-divider
|
||||
options:
|
||||
icon: archive
|
||||
title: Archive
|
||||
title: $t:field_options.directus_collections.archive_divider
|
||||
width: full
|
||||
|
||||
- field: archive_field
|
||||
@@ -110,14 +110,14 @@ fields:
|
||||
options:
|
||||
collectionField: collection
|
||||
allowNone: true
|
||||
placeholder: Choose a field...
|
||||
placeholder: $t:field_options.directus_collections.archive_field
|
||||
width: half
|
||||
|
||||
- field: archive_app_filter
|
||||
interface: boolean
|
||||
special: boolean
|
||||
options:
|
||||
label: Enable App Archive Filter
|
||||
label: $t:field_options.directus_collections.archive_app_filter
|
||||
width: half
|
||||
|
||||
- field: archive_value
|
||||
@@ -125,7 +125,7 @@ fields:
|
||||
options:
|
||||
font: monospace
|
||||
iconRight: archive
|
||||
placeholder: Value set when archiving...
|
||||
placeholder: $t:field_options.directus_collections.archive_value
|
||||
width: half
|
||||
|
||||
- field: unarchive_value
|
||||
@@ -133,7 +133,7 @@ fields:
|
||||
options:
|
||||
font: monospace
|
||||
iconRight: unarchive
|
||||
placeholder: Value set when unarchiving...
|
||||
placeholder: $t:field_options.directus_collections.unarchive_value
|
||||
width: half
|
||||
|
||||
- field: sort_divider
|
||||
@@ -143,14 +143,14 @@ fields:
|
||||
interface: presentation-divider
|
||||
options:
|
||||
icon: sort
|
||||
title: Sort
|
||||
title: $t:field_options.directus_collections.divider
|
||||
width: full
|
||||
|
||||
- field: sort_field
|
||||
interface: system-field
|
||||
options:
|
||||
collectionField: collection
|
||||
placeholder: Choose a field...
|
||||
placeholder: $t:field_options.directus_collections.sort_field
|
||||
typeAllowList:
|
||||
- float
|
||||
- decimal
|
||||
@@ -165,7 +165,7 @@ fields:
|
||||
interface: presentation-divider
|
||||
options:
|
||||
icon: admin_panel_settings
|
||||
title: Accountability
|
||||
title: $t:field_options.directus_collections.accountability_divider
|
||||
width: full
|
||||
|
||||
- field: accountability
|
||||
|
||||
@@ -10,14 +10,14 @@ fields:
|
||||
interface: input
|
||||
options:
|
||||
iconRight: title
|
||||
placeholder: A unique title...
|
||||
placeholder: $t:field_options.directus_files.title
|
||||
width: full
|
||||
|
||||
- field: description
|
||||
interface: input-multiline
|
||||
width: full
|
||||
options:
|
||||
placeholder: An optional description...
|
||||
placeholder: $t:field_options.directus_files.description
|
||||
|
||||
- field: tags
|
||||
interface: tags
|
||||
@@ -35,7 +35,7 @@ fields:
|
||||
interface: input
|
||||
options:
|
||||
iconRight: place
|
||||
placeholder: An optional location...
|
||||
placeholder: $t:field_options.directus_files.location
|
||||
width: half
|
||||
|
||||
- field: storage
|
||||
@@ -49,7 +49,7 @@ fields:
|
||||
interface: presentation-divider
|
||||
options:
|
||||
icon: insert_drive_file
|
||||
title: File Naming
|
||||
title: $t:field_options.directus_files.storage_divider
|
||||
special:
|
||||
- alias
|
||||
- no-data
|
||||
@@ -59,7 +59,7 @@ fields:
|
||||
interface: input
|
||||
options:
|
||||
iconRight: publish
|
||||
placeholder: Name on disk storage...
|
||||
placeholder: $t:field_options.directus_files.filename_disk
|
||||
readonly: true
|
||||
width: half
|
||||
|
||||
@@ -67,7 +67,7 @@ fields:
|
||||
interface: input
|
||||
options:
|
||||
iconRight: get_app
|
||||
placeholder: Name when downloading...
|
||||
placeholder: $t:field_options.directus_files.filename_download
|
||||
width: half
|
||||
|
||||
- field: metadata
|
||||
@@ -106,6 +106,7 @@ fields:
|
||||
display: user
|
||||
width: half
|
||||
hidden: true
|
||||
special: user-created
|
||||
|
||||
- field: uploaded_on
|
||||
display: datetime
|
||||
|
||||
@@ -15,9 +15,6 @@ fields:
|
||||
- field: role
|
||||
width: half
|
||||
|
||||
- field: limit
|
||||
width: half
|
||||
|
||||
- field: collection
|
||||
width: half
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ fields:
|
||||
- field: name
|
||||
interface: input
|
||||
options:
|
||||
placeholder: The unique name for this role...
|
||||
placeholder: $t:field_options.directus_roles.name
|
||||
width: half
|
||||
|
||||
- field: icon
|
||||
@@ -20,7 +20,7 @@ fields:
|
||||
- field: description
|
||||
interface: input
|
||||
options:
|
||||
placeholder: A description of this role...
|
||||
placeholder: $t:field_options.directus_roles.description
|
||||
width: full
|
||||
|
||||
- field: app_access
|
||||
@@ -36,7 +36,7 @@ fields:
|
||||
- field: ip_access
|
||||
interface: tags
|
||||
options:
|
||||
placeholder: Add allowed IP addresses, leave empty to allow all...
|
||||
placeholder: $t:field_options.directus_roles.ip_access
|
||||
special: csv
|
||||
width: full
|
||||
|
||||
@@ -60,13 +60,13 @@ fields:
|
||||
template: '{{ name }}'
|
||||
addLabel: Add New Module...
|
||||
fields:
|
||||
- name: Icon
|
||||
- name: $t:field_options.directus_roles.fields.icon_name
|
||||
field: icon
|
||||
type: string
|
||||
meta:
|
||||
interface: select-icon
|
||||
width: half
|
||||
- name: Name
|
||||
- name: $t:field_options.directus_roles.fields.name_name
|
||||
field: name
|
||||
type: string
|
||||
meta:
|
||||
@@ -74,8 +74,8 @@ fields:
|
||||
width: half
|
||||
options:
|
||||
iconRight: title
|
||||
placeholder: Enter a title...
|
||||
- name: Link
|
||||
placeholder:
|
||||
- name: $t:field_options.directus_roles.fields.link_name
|
||||
field: link
|
||||
type: string
|
||||
meta:
|
||||
@@ -83,7 +83,7 @@ fields:
|
||||
width: full
|
||||
options:
|
||||
iconRight: link
|
||||
placeholder: Relative or absolute URL...
|
||||
placeholder: $t:field_options.directus_roles.fields.link_placeholder
|
||||
special: json
|
||||
width: full
|
||||
|
||||
@@ -91,9 +91,9 @@ fields:
|
||||
interface: list
|
||||
options:
|
||||
template: '{{ group_name }}'
|
||||
addLabel: Add New Group...
|
||||
addLabel: $t:field_options.directus_roles.collection_list.group_name_addLabel
|
||||
fields:
|
||||
- name: Group Name
|
||||
- name: $t:field_options.directus_roles.collection_list.fields.group_name
|
||||
field: group_name
|
||||
type: string
|
||||
meta:
|
||||
@@ -101,10 +101,10 @@ fields:
|
||||
interface: input
|
||||
options:
|
||||
iconRight: title
|
||||
placeholder: Label this group...
|
||||
placeholder: $t:field_options.directus_roles.collection_list.fields.group_placeholder
|
||||
schema:
|
||||
is_nullable: false
|
||||
- name: Type
|
||||
- name: $t:field_options.directus_roles.collection_list.fields.type_name
|
||||
field: accordion
|
||||
type: string
|
||||
schema:
|
||||
@@ -115,21 +115,21 @@ fields:
|
||||
options:
|
||||
choices:
|
||||
- value: always_open
|
||||
text: Always Open
|
||||
text: $t:field_options.directus_roles.collection_list.fields.choices_always
|
||||
- value: start_open
|
||||
text: Start Open
|
||||
text: $t:field_options.directus_roles.collection_list.fields.choices_start_open
|
||||
- value: start_collapsed
|
||||
text: Start Collapsed
|
||||
- name: Collections
|
||||
text: $t:field_options.directus_roles.collection_list.fields.choices_start_collapsed
|
||||
- name: $t:field_options.directus_roles.collections_name
|
||||
field: collections
|
||||
type: JSON
|
||||
meta:
|
||||
interface: list
|
||||
options:
|
||||
addLabel: Add New Collection...
|
||||
addLabel: $t:field_options.directus_roles.collections_addLabel
|
||||
template: '{{ collection }}'
|
||||
fields:
|
||||
- name: Collection
|
||||
- name: $t:field_options.directus_roles.collections_name
|
||||
field: collection
|
||||
type: string
|
||||
meta:
|
||||
|
||||
@@ -8,7 +8,7 @@ fields:
|
||||
interface: input
|
||||
options:
|
||||
iconRight: title
|
||||
placeholder: My project...
|
||||
placeholder: $t:field_options.directus_settings.project_name_placeholder
|
||||
translations:
|
||||
language: en-US
|
||||
translations: Name
|
||||
@@ -26,7 +26,7 @@ fields:
|
||||
|
||||
- field: project_color
|
||||
interface: select-color
|
||||
note: Login & Logo Background
|
||||
note: $t:field_options.directus_settings.project_logo_note
|
||||
translations:
|
||||
language: en-US
|
||||
translations: Brand Color
|
||||
@@ -67,7 +67,7 @@ fields:
|
||||
- field: public_note
|
||||
interface: input-multiline
|
||||
options:
|
||||
placeholder: A short, public message that supports markdown formatting...
|
||||
placeholder: $t:field_options.directus_settings.public_note_placeholder
|
||||
width: full
|
||||
|
||||
- field: security_divider
|
||||
@@ -85,11 +85,11 @@ fields:
|
||||
options:
|
||||
choices:
|
||||
- value: null
|
||||
text: None – Not Recommended
|
||||
text: $t:field_options.directus_settings.auth_password_policy.none_text
|
||||
- value: '/^.{8,}$/'
|
||||
text: Weak – Minimum 8 Characters
|
||||
text: $t:field_options.directus_settings.auth_password_policy.weak_text
|
||||
- value: "/(?=^.{8,}$)(?=.*\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()_+}{';'?>.<,])(?!.*\\s).*$/"
|
||||
text: Strong – Upper / Lowercase / Numbers / Special
|
||||
text: $t:field_options.directus_settings.auth_password_policy.strong_text
|
||||
allowOther: true
|
||||
width: half
|
||||
|
||||
@@ -135,13 +135,13 @@ fields:
|
||||
options:
|
||||
choices:
|
||||
- value: contain
|
||||
text: Contain (preserve aspect ratio)
|
||||
text: $t:field_options.directus_settings.storage_asset_presets.fit.contain_text
|
||||
- value: cover
|
||||
text: Cover (forces exact size)
|
||||
text: $t:field_options.directus_settings.storage_asset_presets.fit.cover_text
|
||||
- value: inside
|
||||
text: Fit inside
|
||||
text: $t:field_options.directus_settings.storage_asset_presets.fit.fit_text
|
||||
- value: outside
|
||||
text: Fit outside
|
||||
text: $t:field_options.directus_settings.storage_asset_presets.fit.outside_text
|
||||
width: half
|
||||
- field: width
|
||||
name: $t:width
|
||||
@@ -181,7 +181,7 @@ fields:
|
||||
interface: boolean
|
||||
width: half
|
||||
options:
|
||||
label: Don't upscale images
|
||||
label: $t:no_upscale
|
||||
- field: format
|
||||
name: Format
|
||||
type: string
|
||||
@@ -203,15 +203,14 @@ fields:
|
||||
text: Tiff
|
||||
width: half
|
||||
- field: transforms
|
||||
name: Additional Transformations
|
||||
name: $t:field_options.directus_settings.additional_transforms
|
||||
type: json
|
||||
schema:
|
||||
is_nullable: false
|
||||
default_value: []
|
||||
meta:
|
||||
note:
|
||||
The Sharp method name and its arguments. See https://sharp.pixelplumbing.com/api-constructor for more
|
||||
information.
|
||||
note: $t:field_options.directus_settings.transforms_note
|
||||
|
||||
interface: json
|
||||
options:
|
||||
template: >
|
||||
@@ -279,8 +278,8 @@ fields:
|
||||
interface: input
|
||||
options:
|
||||
icon: key
|
||||
title: Mapbox Access Token
|
||||
placeholder: pk.eyJ1Ijo.....
|
||||
title: $t:field_options.directus_settings.mapbox_key
|
||||
placeholder: $t:field_options.directus_settings.mapbox_placeholder
|
||||
iconLeft: vpn_key
|
||||
font: monospace
|
||||
width: half
|
||||
@@ -306,11 +305,11 @@ fields:
|
||||
options:
|
||||
choices:
|
||||
- value: raster
|
||||
text: Raster
|
||||
text: $t:field_options.directus_settings.basemaps_raster
|
||||
- value: tile
|
||||
text: Raster TileJSON
|
||||
text: $t:field_options.directus_settings.basemaps_tile
|
||||
- value: style
|
||||
text: Mapbox Style
|
||||
text: $t:field_options.directus_settings.basemaps_style
|
||||
- field: url
|
||||
name: $t:url
|
||||
schema:
|
||||
@@ -319,3 +318,17 @@ fields:
|
||||
interface: text-input
|
||||
options:
|
||||
placeholder: http://{a-c}.tile.openstreetmap.org/{z}/{x}/{y}.png
|
||||
- field: tileSize
|
||||
name: $t:tile_size
|
||||
schema:
|
||||
is_nullable: true
|
||||
meta:
|
||||
interface: input
|
||||
options:
|
||||
placeholder: '512'
|
||||
conditions:
|
||||
- name: typeNeqRaster
|
||||
rule:
|
||||
type:
|
||||
_neq: 'raster'
|
||||
hidden: true
|
||||
|
||||
Reference in New Issue
Block a user