import { WritingModeProperty, DirectionProperty } from 'csstype' import { GitRefType, WorkerVersionState, WorkerActivityState, ModelVersionState } from './enums' import { TextOrientation } from './types' /* * Build an object from all <meta> tags * Check if `document` exists as it is not defined in unit tests */ const metas: { readonly [name: string]: string } = (typeof document !== 'undefined' && document) ? [...document.getElementsByTagName('meta')].reduce<Record<string, string>>((obj, meta) => { obj[meta.name] = meta.content; return obj }, {}) : {} /* * Get assets path from assets_url when available, and ensure there is an ending slash * See https://webpack.js.org/guides/public-path/ */ // eslint-disable-next-line camelcase __webpack_public_path__ = (metas.assets_url || '').replace(/\/$/, '') + '/' // Support fully specified URL with scheme, but also relative URLs to this page (like /api/v1) let apiBaseUrl = metas.api_base_url || process.env.VUE_APP_API_BASE_URL || '' if (typeof window !== 'undefined' && window) apiBaseUrl = new URL(apiBaseUrl, window.location.href).href export const API_BASE_URL = apiBaseUrl const csrfCookiesExceptions: { readonly [host: string]: string } = { 'ce.preprod.arkindex.teklia.com': 'ce.arkindex.preprod.csrf', 'ee.preprod.arkindex.teklia.com': 'ee.arkindex.preprod.csrf', 'dev.arkindex.teklia.com': 'arkindex.dev.csrf' } export const CSRF_COOKIE_NAME: string = process.env.VUE_APP_CSRF_COOKIE_NAME || ( /* * Build a URI relative to the page's host; if the URI is absolute, the page host will be ignored * Special case in unit tests: window is not defined */ (typeof window !== 'undefined' && window) && csrfCookiesExceptions[new URL(API_BASE_URL, window.location.origin).host] // Fallback to default value ) || 'arkindex.csrf' export const CSRF_COOKIE_HEADER = 'X-CSRFToken' export const CSRF_ALL_ORIGINS = process.env.VUE_APP_CSRF_ALL_ORIGINS === 'true' export const VERSION: string | undefined = process.env.VUE_APP_VERSION export const ROUTER_MODE: string = process.env.VUE_APP_ROUTER_MODE || 'history' export const UNIVERSAL_VIEWER: string | undefined = metas.universal_viewer_url export const MIRADOR: string | undefined = metas.mirador_url export const SENTRY_DSN: string | undefined = metas.sentry_dsn export const SENTRY_ENVIRONMENT: string | undefined = metas.environment export const DOORBELL_ID: string | undefined = metas.doorbell_id export const DOORBELL_APPKEY: string | undefined = metas.doorbell_appkey export const PROCESS_POLLING_DELAY = 4000 export const TASK_POLLING_DELAY = 4000 export const JOBS_POLLING_DELAY = 10000 // How long to wait after the last key press to update the suggested values export const FILTER_BAR_SUGGESTION_DELAY = 1000 /* * Django's UUID matching regex. * Use this in the router for any path parameter of a UUID type via the path-to-regexp custom regex option: * '/element/:id(\\d+)' would require an integer for `id`, * and `/element/:id(${UUID})` will use this regex to get an UUID. */ export const UUID = '[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}' export const UUID_REGEX = new RegExp(`^${UUID}$`) // Limit text displayed length (characters) export const TRUNCATE_LENGTHS = { /** * Limit options text size in `<select>` elements * Also consider using `<span class="select is-truncated">` to truncate using CSS, * but still display the full values when the user clicks on the `<select>`. */ select: 100, /** * Long truncate (e.g. Element names in navigation header or table display) */ long: 80, /** * Short truncate (e.g. Element types, compact components or thumbnails display) */ short: 30, /** * Character limit for notifications */ notification: 500, /** * Character limit for truncated UUIDs */ id: 8 } as const // Maximum length of an element's name. export const ELEMENT_NAME_MAX_LENGTH = 250 // Maximum number of suggestions in SearchableInput component export const SEARCHABLE_SELECT_MAX_MATCHES = 15 // How long wait after the last key press to update the suggested values, in milliseconds export const SEARCHABLE_SELECT_SUGGESTION_DELAY = 250 // Maximum amount of search terms the backend allows in search filters export const SEARCH_FILTER_MAX_TERMS = 10 // Image definition related to available space export const IMAGE_QUALITY = 1.5 // Interactive image zoom factor in percent export const ZOOM_FACTORS = [100, 133, 166, 200, 250, 350, 400, 500] // Image navigation transitions delay for the zoom and the automatic centering (ms) export const IMAGE_TRANSITIONS = 300 // Margins allowed navigating through an interactive image in percentage of the image max(width, height) export const NAVIGATION_MARGINS = 5 // Possible number of elements displayed in a page export const NAVIGATION_PAGE_SIZES = [20, 50, 100, 500] // Default page size, set when no ?page_size query parameter has been set export const DEFAULT_PAGE_SIZE = 20 // Display a warning message once the ratio between the expected and actual image dimensions or area exceeds 80% or 120% export const IMAGE_WARNING_RATIO = 0.8 // Interactive image drawing colors export const DRAWN_POLYGON_COLOR = 'yellow' export const DEFAULT_POLYGON_COLOR = '#28b62c' export const HOVERED_TREE_ITEM_COLOR = '#ebffdb' // Polygon minimal height and width (in pixels relatively to the image dimensions) export const POLYGON_MIN_SIZE = 2 /* * Maximum allowed consecutive distinct points in a polygon in the backend: * AAABBBCCCBBBCCCCDDD has 6 distinct points even though B and C are repeated, * but ABCDA has 4 distinct points because the last point is ignored when it is equal to the first. */ export const POLYGON_MAX_POINTS = 163 export const ELEMENT_LIST_MAX_AUTO_PAGES = 10 /** * Margin applied around a node's label within the Graph component, in pixels. */ export const GRAPH_NODE_MARGIN = 10 export const PROCESS_STATES = { unscheduled: 'Unscheduled', pending: 'Pending', running: 'Running', completed: 'Completed', failed: 'Task error', error: 'System error', stopping: 'Stopping', stopped: 'Stopped' } as const /** * States in which a process is finished; unless a task is forcefully restarted, a run in this state will not budge. */ export const PROCESS_FINAL_STATES: Array<keyof typeof PROCESS_STATES> = ['completed', 'failed', 'error', 'stopped'] export const PROCESS_MODES = { files: 'Files', repository: 'Git', iiif: 'IIIF', workers: 'Workers', template: 'Template', s3: 'S3', dataset: 'Dataset' } as const interface ColorDefinition { readonly cssClass: string readonly background: string readonly foreground?: string } /** * Color coding for Ponos task states. * `cssClass` defines the Bulma CSS class that should normally be used on HTML elements. * `background` and `foreground` define the colors used within a SVG graph. */ export const PROCESS_STATE_COLORS: { readonly [state in keyof typeof PROCESS_STATES | 'default']: ColorDefinition } = { unscheduled: { cssClass: 'is-dark', background: '#909090' }, pending: { cssClass: 'is-warning', background: '#ffdd57' }, running: { cssClass: 'is-primary', background: '#158cba' }, completed: { cssClass: 'is-success', background: '#28b62c' }, failed: { cssClass: 'is-danger', background: '#ff4136' }, error: { cssClass: 'is-danger', background: '#ff4136' }, stopping: { cssClass: 'is-warning', background: '#ffdd57' }, stopped: { cssClass: 'is-danger', background: '#ff4136' }, default: { cssClass: '', background: 'white', foreground: 'black' } } export const LOG_COLORS: { readonly [level: string]: string } = { CRITICAL: '#ff291d', ERROR: '#ff291d', WARNING: '#ff9e26' } /** * Color coding for worker types. * `cssClass` defines the Bulma CSS class that should normally be used on HTML elements. * `background` and `foreground` define the colors used within a SVG graph. */ export const WORKER_TYPE_COLORS: { readonly [workerType: string]: ColorDefinition } = { classifier: { cssClass: 'is-link', background: '#5bb7db' }, ner: { cssClass: 'is-success', background: '#28b62c' }, recognizer: { cssClass: 'is-warning', background: '#ffdd57' }, dla: { cssClass: 'is-light', background: '#363636', foreground: 'white' }, 'word-segmenter': { cssClass: 'is-danger', background: '#ff291d' }, default: { cssClass: 'is-primary', background: '#158cba', foreground: 'black' } } export const ACTIVITY_COLORS: { [key in WorkerActivityState]: string } = { queued: 'is-light', started: 'is-info', processed: 'is-success', error: 'is-danger' } as const export const MONTHS = [ 'January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December' ] as const export const MANUAL_WORKER_VERSION = '__manual__' interface TextOrientationStyle { writing: WritingModeProperty display: string direction?: DirectionProperty } /* * Text orientation values to display and create non-left-to-right language transcriptions. * "writing" is the value of the corresponding "writing-mode" CSS style property. * For horizontal right to left text, a secondary "direction" style property also has to be specified. * Vertical text orientations are currently not handled in the frontend. */ export const TEXT_ORIENTATIONS = { 'horizontal-lr': { writing: 'horizontal-tb', display: 'Left to Right' }, 'horizontal-rl': { writing: 'horizontal-tb', direction: 'rtl', display: 'Right to Left' } } as Record<TextOrientation, TextOrientationStyle> export const CLASSIFICATION_STATES = { pending: 'pending', validated: 'validated', rejected: 'rejected' } as const export const METADATA_TYPES = { text: { icon: 'icon-feather', display: 'Text' }, markdown: { icon: 'icon-doc', display: 'Markdown' }, date: { icon: 'icon-date', display: 'Date' }, location: { icon: 'icon-globe', display: 'Location' }, reference: { icon: 'icon-bookmark', display: 'Reference' }, numeric: { icon: 'icon-number', display: 'Numeric' }, url: { icon: 'icon-link', display: 'URL' } } as const export const NOTIFICATION_TYPES = { info: 'is-info', warning: 'is-warning', error: 'is-danger', success: 'is-success' } as const export const EXPORT_STATES = { created: 'Created', running: 'Running', done: 'Done', failed: 'Failed' } as const export const DATASET_STATES = { open: { display_name: 'Open', color: 'is-info' }, building: { display_name: 'Building', color: 'is-warning' }, complete: { display_name: 'Complete', color: 'is-success' }, error: { display_name: 'Error', color: 'is-danger' } } as const export const GIT_REF_COLORS: { [key in GitRefType]: string } = { branch: 'is-secondary', tag: 'is-success' } as const export const REVISION_STATE_COLORS: { [key in WorkerVersionState]: string } = { created: 'is-info', available: 'is-success', processing: 'is-warning', error: 'is-danger' } as const export const MODEL_VERSION_STATE_COLORS: { [key in ModelVersionState]: string } = { created: 'is-info', available: 'is-success', error: 'is-danger' } as const // TODO: Type this with Partial<Corpus>, where `Corpus` is the type that defines a corpus in the corpora store once it switches to Pinia export const DEFAULT_CORPUS_ATTRS = { public: false, description: '', rights: ['read', 'write', 'admin'], types: [{ slug: 'volume', display_name: 'Volume', folder: true }, { slug: 'page', display_name: 'Page', folder: false }, { slug: 'text_line', display_name: 'Text line', folder: false }, { slug: 'paragraph', display_name: 'Paragraph', folder: false }], created: '2000-01-01T01:00:00.000000Z', authorized_users: 1 } export interface Role { readonly value: number readonly display: string readonly help: string readonly tag: string } // Rights privileges level export const ROLES: { readonly [name: string]: Role } = { admin: { value: 100, display: 'Administrator', help: 'Highest privilege level, allowing to perform any operation (including deletion).', tag: 'is-danger is-light' }, contributor: { value: 50, display: 'Contributor', help: 'Intermediate privilege level, generally represented by a read and write access (e.g. to annotate elements).', tag: 'is-warning is-light' }, guest: { value: 10, display: 'Guest', help: 'Lowest privilege level, allowing to retrieve information only (i.e. no edition).', tag: 'is-info is-light' } } export const BANNER_MESSAGE = metas.banner_message export const BANNER_STYLE = metas.banner_style in NOTIFICATION_TYPES ? metas.banner_style : 'info' /** * MIME types of supported archives in file imports */ export const ARCHIVE_MIME_TYPES = [ // .zip, standard 'application/zip', // .zip, from Windows only 'application/x-zip-compressed', // .tar 'application/x-tar', // .tar.gz, from libmagic only 'application/x-gtar', // .tgz, from browsers only 'application/x-compressed-tar', // .gz from anywhere, .tgz from libmagic only 'application/gzip', // .bz2, from browsers only 'application/x-bzip', // .bz2, from libmagic only 'application/x-bzip2', // .lzma 'application/x-lzma', // .xz 'application/x-xz', // .zst 'application/zstd' ]