mirror of
https://github.com/directus/directus.git
synced 2026-04-03 03:00:39 -04:00
Merge branch 'main' into insights
This commit is contained in:
22
app/src/utils/async-pool.ts
Normal file
22
app/src/utils/async-pool.ts
Normal file
@@ -0,0 +1,22 @@
|
||||
export async function asyncPool<IN, OUT>(
|
||||
poolLimit: number,
|
||||
array: ReadonlyArray<IN>,
|
||||
iteratorFn: (generator: IN, array: ReadonlyArray<IN>) => Promise<OUT>
|
||||
): Promise<OUT[]> {
|
||||
const ret = [];
|
||||
const executing: any[] = [];
|
||||
|
||||
for (const item of array) {
|
||||
const p = Promise.resolve().then(() => iteratorFn(item, array));
|
||||
ret.push(p);
|
||||
|
||||
if (poolLimit <= array.length) {
|
||||
const e = p.then(() => executing.splice(executing.indexOf(e), 1));
|
||||
executing.push(e);
|
||||
if (executing.length >= poolLimit) {
|
||||
await Promise.race(executing);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Promise.all(ret);
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Filter } from '@/types/';
|
||||
import { clone } from 'lodash';
|
||||
|
||||
export default function filtersToQuery(filters: readonly Filter[]): any {
|
||||
export default function filtersToQuery(filters: readonly Filter[]): { filter: Record<string, any> } {
|
||||
const filterList: Record<string, any>[] = [];
|
||||
|
||||
for (const filter of filters) {
|
||||
|
||||
@@ -64,7 +64,7 @@ const defaults: JoiOptions = {
|
||||
allowUnknown: true,
|
||||
};
|
||||
|
||||
export default function generateJoi(filter: Record<string, any> | null, options?: JoiOptions): any {
|
||||
export default function generateJoi(filter: Record<string, any> | null, options?: JoiOptions): AnySchema {
|
||||
filter = filter || {};
|
||||
|
||||
options = {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
import { i18n } from '@/lang';
|
||||
import { Locale } from 'date-fns';
|
||||
|
||||
import importDateLocale from './import-date-locale';
|
||||
|
||||
export async function getDateFNSLocale(): Promise<Locale> {
|
||||
const lang = i18n.locale;
|
||||
const lang = i18n.global.locale.value;
|
||||
|
||||
const localesToTry = [lang, lang.split('-')[0], 'en-US'];
|
||||
|
||||
@@ -9,10 +12,7 @@ export async function getDateFNSLocale(): Promise<Locale> {
|
||||
|
||||
for (const l of localesToTry) {
|
||||
try {
|
||||
const mod = await import(
|
||||
/* webpackMode: 'lazy', webpackChunkName: 'df-[index]' */
|
||||
`date-fns/locale/${l}/index.js`
|
||||
);
|
||||
const mod = await importDateLocale(l);
|
||||
|
||||
locale = mod.default;
|
||||
break;
|
||||
|
||||
166
app/src/utils/get-date-fns-locale/import-date-locale.ts
Normal file
166
app/src/utils/get-date-fns-locale/import-date-locale.ts
Normal file
@@ -0,0 +1,166 @@
|
||||
export default function importDateLocale(locale: string): Promise<any> {
|
||||
switch (locale) {
|
||||
case 'af':
|
||||
return import('date-fns/locale/af/index.js');
|
||||
case 'ar-DZ':
|
||||
return import('date-fns/locale/ar-DZ/index.js');
|
||||
case 'ar-MA':
|
||||
return import('date-fns/locale/ar-MA/index.js');
|
||||
case 'ar-SA':
|
||||
return import('date-fns/locale/ar-SA/index.js');
|
||||
case 'az':
|
||||
return import('date-fns/locale/az/index.js');
|
||||
case 'be':
|
||||
return import('date-fns/locale/be/index.js');
|
||||
case 'bg':
|
||||
return import('date-fns/locale/bg/index.js');
|
||||
case 'bn':
|
||||
return import('date-fns/locale/bn/index.js');
|
||||
case 'ca':
|
||||
return import('date-fns/locale/ca/index.js');
|
||||
case 'cs':
|
||||
return import('date-fns/locale/cs/index.js');
|
||||
case 'cy':
|
||||
return import('date-fns/locale/cy/index.js');
|
||||
case 'da':
|
||||
return import('date-fns/locale/da/index.js');
|
||||
case 'de':
|
||||
return import('date-fns/locale/de/index.js');
|
||||
case 'de-AT':
|
||||
return import('date-fns/locale/de-AT/index.js');
|
||||
case 'el':
|
||||
return import('date-fns/locale/el/index.js');
|
||||
case 'en-AU':
|
||||
return import('date-fns/locale/en-AU/index.js');
|
||||
case 'en-CA':
|
||||
return import('date-fns/locale/en-CA/index.js');
|
||||
case 'en-GB':
|
||||
return import('date-fns/locale/en-GB/index.js');
|
||||
case 'en-IN':
|
||||
return import('date-fns/locale/en-IN/index.js');
|
||||
case 'en-NZ':
|
||||
return import('date-fns/locale/en-NZ/index.js');
|
||||
case 'en-US':
|
||||
return import('date-fns/locale/en-US/index.js');
|
||||
case 'en-ZA':
|
||||
return import('date-fns/locale/en-ZA/index.js');
|
||||
case 'eo':
|
||||
return import('date-fns/locale/eo/index.js');
|
||||
case 'es':
|
||||
return import('date-fns/locale/es/index.js');
|
||||
case 'et':
|
||||
return import('date-fns/locale/et/index.js');
|
||||
case 'eu':
|
||||
return import('date-fns/locale/eu/index.js');
|
||||
case 'fa-IR':
|
||||
return import('date-fns/locale/fa-IR/index.js');
|
||||
case 'fi':
|
||||
return import('date-fns/locale/fi/index.js');
|
||||
case 'fr':
|
||||
return import('date-fns/locale/fr/index.js');
|
||||
case 'fr-CA':
|
||||
return import('date-fns/locale/fr-CA/index.js');
|
||||
case 'fr-CH':
|
||||
return import('date-fns/locale/fr-CH/index.js');
|
||||
case 'gd':
|
||||
return import('date-fns/locale/gd/index.js');
|
||||
case 'gl':
|
||||
return import('date-fns/locale/gl/index.js');
|
||||
case 'gu':
|
||||
return import('date-fns/locale/gu/index.js');
|
||||
case 'he':
|
||||
return import('date-fns/locale/he/index.js');
|
||||
case 'hi':
|
||||
return import('date-fns/locale/hi/index.js');
|
||||
case 'hr':
|
||||
return import('date-fns/locale/hr/index.js');
|
||||
case 'ht':
|
||||
return import('date-fns/locale/ht/index.js');
|
||||
case 'hu':
|
||||
return import('date-fns/locale/hu/index.js');
|
||||
case 'hy':
|
||||
return import('date-fns/locale/hy/index.js');
|
||||
case 'id':
|
||||
return import('date-fns/locale/id/index.js');
|
||||
case 'is':
|
||||
return import('date-fns/locale/is/index.js');
|
||||
case 'it':
|
||||
return import('date-fns/locale/it/index.js');
|
||||
case 'ja':
|
||||
return import('date-fns/locale/ja/index.js');
|
||||
case 'ka':
|
||||
return import('date-fns/locale/ka/index.js');
|
||||
case 'kk':
|
||||
return import('date-fns/locale/kk/index.js');
|
||||
case 'kn':
|
||||
return import('date-fns/locale/kn/index.js');
|
||||
case 'ko':
|
||||
return import('date-fns/locale/ko/index.js');
|
||||
case 'lb':
|
||||
return import('date-fns/locale/lb/index.js');
|
||||
case 'lt':
|
||||
return import('date-fns/locale/lt/index.js');
|
||||
case 'lv':
|
||||
return import('date-fns/locale/lv/index.js');
|
||||
case 'mk':
|
||||
return import('date-fns/locale/mk/index.js');
|
||||
case 'mn':
|
||||
return import('date-fns/locale/mn/index.js');
|
||||
case 'ms':
|
||||
return import('date-fns/locale/ms/index.js');
|
||||
case 'mt':
|
||||
return import('date-fns/locale/mt/index.js');
|
||||
case 'nb':
|
||||
return import('date-fns/locale/nb/index.js');
|
||||
case 'nl':
|
||||
return import('date-fns/locale/nl/index.js');
|
||||
case 'nl-BE':
|
||||
return import('date-fns/locale/nl-BE/index.js');
|
||||
case 'nn':
|
||||
return import('date-fns/locale/nn/index.js');
|
||||
case 'pl':
|
||||
return import('date-fns/locale/pl/index.js');
|
||||
case 'pt':
|
||||
return import('date-fns/locale/pt/index.js');
|
||||
case 'pt-BR':
|
||||
return import('date-fns/locale/pt-BR/index.js');
|
||||
case 'ro':
|
||||
return import('date-fns/locale/ro/index.js');
|
||||
case 'ru':
|
||||
return import('date-fns/locale/ru/index.js');
|
||||
case 'sk':
|
||||
return import('date-fns/locale/sk/index.js');
|
||||
case 'sl':
|
||||
return import('date-fns/locale/sl/index.js');
|
||||
case 'sq':
|
||||
return import('date-fns/locale/sq/index.js');
|
||||
case 'sr':
|
||||
return import('date-fns/locale/sr/index.js');
|
||||
case 'sr-Latn':
|
||||
return import('date-fns/locale/sr-Latn/index.js');
|
||||
case 'sv':
|
||||
return import('date-fns/locale/sv/index.js');
|
||||
case 'ta':
|
||||
return import('date-fns/locale/ta/index.js');
|
||||
case 'te':
|
||||
return import('date-fns/locale/te/index.js');
|
||||
case 'th':
|
||||
return import('date-fns/locale/th/index.js');
|
||||
case 'tr':
|
||||
return import('date-fns/locale/tr/index.js');
|
||||
case 'ug':
|
||||
return import('date-fns/locale/ug/index.js');
|
||||
case 'uk':
|
||||
return import('date-fns/locale/uk/index.js');
|
||||
case 'uz':
|
||||
return import('date-fns/locale/uz/index.js');
|
||||
case 'vi':
|
||||
return import('date-fns/locale/vi/index.js');
|
||||
case 'zh-CN':
|
||||
return import('date-fns/locale/zh-CN/index.js');
|
||||
case 'zh-TW':
|
||||
return import('date-fns/locale/zh-TW/index.js');
|
||||
default:
|
||||
return Promise.resolve();
|
||||
}
|
||||
}
|
||||
@@ -11,9 +11,9 @@ export function isAllowed(
|
||||
const permissionsStore = usePermissionsStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
if (userStore.isAdmin.value === true) return true;
|
||||
if (userStore.isAdmin === true) return true;
|
||||
|
||||
const permissions = permissionsStore.state.permissions;
|
||||
const permissions = permissionsStore.permissions;
|
||||
|
||||
const permissionInfo = permissions.find(
|
||||
(permission) => permission.action === action && permission.collection === collection
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import marked from 'marked';
|
||||
import { sanitize } from 'dompurify';
|
||||
import dompurify from 'dompurify';
|
||||
|
||||
/**
|
||||
* Render and sanitize a markdown string
|
||||
*/
|
||||
export function md(str: string): string {
|
||||
return sanitize(marked(str));
|
||||
return dompurify.sanitize(marked(str));
|
||||
}
|
||||
|
||||
@@ -14,8 +14,8 @@ export function parseFilter(filter: Record<string, any>): Record<string, any> {
|
||||
}
|
||||
|
||||
if (val === '$NOW') return new Date();
|
||||
if (val === '$CURRENT_USER') return userStore.state?.currentUser?.id || null;
|
||||
if (val === '$CURRENT_ROLE') return userStore.state?.currentUser?.role?.id || null;
|
||||
if (val === '$CURRENT_USER') return userStore?.currentUser?.id || null;
|
||||
if (val === '$CURRENT_ROLE') return userStore?.currentUser?.role?.id || null;
|
||||
|
||||
return val;
|
||||
});
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
import registerComponent from './register-component';
|
||||
|
||||
export { registerComponent };
|
||||
export default registerComponent;
|
||||
@@ -1,15 +0,0 @@
|
||||
# `registerComponent`
|
||||
|
||||
Registers a component into the global Vue context.
|
||||
|
||||
## Usage
|
||||
|
||||
```js
|
||||
registerComponent('v-button', VButton);
|
||||
```
|
||||
|
||||
## Vue.component() vs registerComponent()
|
||||
|
||||
`registerComponent` internally calls `Vue.component()` directly, and doesn't do anything else. The function is purely to
|
||||
extend the accepted TypeScript type for the second parameter. Vue accepts the second parameter to be of type
|
||||
`Component`, yet it's `Vue.component()` function doesn't actually have that type in it's definition.
|
||||
@@ -1,12 +0,0 @@
|
||||
import Vue, { AsyncComponent, Component } from 'vue';
|
||||
|
||||
function registerComponent(id: string, component: Component | AsyncComponent): void;
|
||||
function registerComponent(id: string, component: Parameters<typeof Vue.component>[1]): void;
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
||||
function registerComponent(id: string, component: any): void {
|
||||
Vue.component(id, component);
|
||||
}
|
||||
|
||||
export { registerComponent };
|
||||
export default registerComponent;
|
||||
@@ -1,5 +1,5 @@
|
||||
import { computed, ComputedRef, Ref } from '@vue/composition-api';
|
||||
import { render } from 'micromustache';
|
||||
import { computed, ComputedRef, Ref } from 'vue';
|
||||
import { getFieldsFromTemplate } from './get-fields-from-template';
|
||||
|
||||
type StringTemplate = {
|
||||
@@ -28,14 +28,14 @@ export function renderStringTemplate(
|
||||
return { fieldsInTemplate, displayValue };
|
||||
}
|
||||
|
||||
export function renderPlainStringTemplate(template: string, item?: Record<string, any> | null): string | false {
|
||||
export function renderPlainStringTemplate(template: string, item?: Record<string, any> | null): string | null {
|
||||
const fieldsInTemplate = getFieldsFromTemplate(template);
|
||||
|
||||
if (!item || !template || !fieldsInTemplate) return false;
|
||||
if (!item || !template || !fieldsInTemplate) return null;
|
||||
|
||||
try {
|
||||
return render(template, item, { propsExist: true });
|
||||
} catch {
|
||||
return false;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
8
app/src/utils/router-passthrough.ts
Normal file
8
app/src/utils/router-passthrough.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
import { h, Component } from 'vue';
|
||||
import { RouterView } from 'vue-router';
|
||||
|
||||
const component: Component = () => h(RouterView);
|
||||
|
||||
component.displayName = 'router-passthrough';
|
||||
|
||||
export default component;
|
||||
@@ -1,14 +1,14 @@
|
||||
import i18n from '@/lang';
|
||||
import { i18n } from '@/lang';
|
||||
import { cloneDeep } from 'lodash';
|
||||
|
||||
export function translate<T extends Record<string, any>>(obj: T): any {
|
||||
obj = cloneDeep(obj);
|
||||
export function translate<T extends Record<string, any>>(obj: T): T {
|
||||
const newObj = cloneDeep(obj);
|
||||
|
||||
Object.entries(obj).forEach(([key, val]) => {
|
||||
if (val && typeof val === 'object') (obj as Record<string, any>)[key] = translate(val);
|
||||
Object.entries(newObj).forEach(([key, val]) => {
|
||||
if (val && typeof val === 'object') (newObj as Record<string, any>)[key] = translate(val);
|
||||
if (val && typeof val === 'string' && val.startsWith('$t:'))
|
||||
(obj as Record<string, any>)[key] = i18n.t(val.replace('$t:', ''));
|
||||
(newObj as Record<string, any>)[key] = i18n.global.t(val.replace('$t:', ''));
|
||||
});
|
||||
|
||||
return obj;
|
||||
return newObj;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ export function unexpectedError(error: Error | RequestError | APIError): void {
|
||||
console.warn(error);
|
||||
|
||||
store.add({
|
||||
title: i18n.t(`errors.${code}`),
|
||||
title: i18n.global.t(`errors.${code}`),
|
||||
text: message,
|
||||
type: 'error',
|
||||
dialog: true,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import api from '@/api';
|
||||
import emitter, { Events } from '@/events';
|
||||
import i18n from '@/lang';
|
||||
import { i18n } from '@/lang';
|
||||
import { notify } from '@/utils/notify';
|
||||
import { unexpectedError } from '../unexpected-error';
|
||||
|
||||
@@ -39,7 +39,7 @@ export default async function uploadFile(
|
||||
|
||||
if (options?.notifications) {
|
||||
notify({
|
||||
title: i18n.t('upload_file_success'),
|
||||
title: i18n.global.t('upload_file_success'),
|
||||
type: 'success',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import i18n from '@/lang';
|
||||
import { i18n } from '@/lang';
|
||||
import { notify } from '@/utils/notify';
|
||||
import uploadFile from '@/utils/upload-file';
|
||||
import { unexpectedError } from '../unexpected-error';
|
||||
@@ -29,7 +29,7 @@ export default async function uploadFiles(
|
||||
|
||||
if (options?.notifications) {
|
||||
notify({
|
||||
title: i18n.t('upload_files_success', { count: files.length }),
|
||||
title: i18n.global.t('upload_files_success', { count: files.length }),
|
||||
type: 'success',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -14,5 +14,5 @@ export function userName(user: Partial<User>): string {
|
||||
return user.email;
|
||||
}
|
||||
|
||||
return i18n.t('unknown_user') as string;
|
||||
return i18n.global.t('unknown_user') as string;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user