mirror of
https://github.com/directus/directus.git
synced 2026-04-25 03:00:53 -04:00
App type improvements (#6151)
* Fix v-table interalItems type * Fix useGroupable return type * Fix useCollection return type * Fix useCustomSelection return type * Fix useElementSize return type * Fix useFormFields return type * Fix useItem return type * Fix useItems return type * Prepend composable return type name with "Usable" * Fix usePreset return type * Fix useScrollDistance return type * Fix useTitle return type * Fix useWindowSize return type * Fix usePermissions return type * Fix useTemplateData return type * Fix a few type issues in field store * Fix extension getter return types * Fix hydrate store type issue and double-hydrating users store * Fix code interface type issue * Fix m2m composables return types * Fix html editor composables return types * Fix collections module composables return types * Fix files module composable return type * Fix settings module composable return type * Fix settings module roles composables return types * Fix settings module users composable return type * Fix return type issues in utils and a nasty parameter overwrite * Fix modelValue casing in template
This commit is contained in:
committed by
GitHub
parent
70c8e08476
commit
12a3b22aa1
@@ -276,7 +276,7 @@ export default defineComponent({
|
||||
if (internalSort.value.desc === true) return itemsSorted.reverse();
|
||||
return itemsSorted;
|
||||
},
|
||||
set: (value: Record<string, any>) => {
|
||||
set: (value: Item[]) => {
|
||||
emit('update:items', value);
|
||||
},
|
||||
});
|
||||
|
||||
@@ -18,7 +18,14 @@ type GroupableOptions = {
|
||||
watch?: boolean;
|
||||
};
|
||||
|
||||
export function useGroupable(options?: GroupableOptions): Record<string, any> {
|
||||
type UsableGroupable = {
|
||||
active: Ref<boolean>;
|
||||
toggle: () => void;
|
||||
activate: () => void;
|
||||
deactivate: () => void;
|
||||
};
|
||||
|
||||
export function useGroupable(options?: GroupableOptions): UsableGroupable {
|
||||
// Injects the registration / toggle functions from the parent scope
|
||||
const parentFunctions = inject(options?.group || 'item-group', null);
|
||||
|
||||
@@ -95,6 +102,14 @@ type GroupableParentOptions = {
|
||||
multiple?: Ref<boolean>;
|
||||
};
|
||||
|
||||
type UsableGroupableParent = {
|
||||
items: Ref<GroupableInstance[]>;
|
||||
selection: Ref<readonly (string | number)[]>;
|
||||
internalSelection: Ref<(string | number)[]>;
|
||||
getValueForItem: (item: GroupableInstance) => string | number;
|
||||
updateChildren: () => void;
|
||||
};
|
||||
|
||||
/**
|
||||
* Used to make a component a group parent component. Provides the registration / toggle functions
|
||||
* to its group children
|
||||
@@ -103,7 +118,7 @@ export function useGroupableParent(
|
||||
state: GroupableParentState = {},
|
||||
options: GroupableParentOptions = {},
|
||||
group = 'item-group'
|
||||
): Record<string, any> {
|
||||
): UsableGroupableParent {
|
||||
// References to the active state and value of the individual child items
|
||||
const items = shallowRef<GroupableInstance[]>([]);
|
||||
|
||||
|
||||
@@ -1,19 +1,19 @@
|
||||
import { useCollectionsStore, useFieldsStore } from '@/stores/';
|
||||
import { Collection, Field } from '@/types';
|
||||
import { computed, Ref, ref } from 'vue';
|
||||
import { computed, ref, Ref, ComputedRef } from 'vue';
|
||||
|
||||
type CollectionInfo = {
|
||||
info: Ref<Collection | null>;
|
||||
fields: Ref<Field[]>;
|
||||
type UsableCollection = {
|
||||
info: ComputedRef<Collection | null>;
|
||||
fields: ComputedRef<Field[]>;
|
||||
defaults: Record<string, any>;
|
||||
primaryKeyField: Ref<Field | null>;
|
||||
userCreatedField: Ref<Field | null>;
|
||||
sortField: Ref<string | null>;
|
||||
isSingleton: Ref<boolean>;
|
||||
accountabilityScope: Ref<'all' | 'activity' | null>;
|
||||
primaryKeyField: ComputedRef<Field | null>;
|
||||
userCreatedField: ComputedRef<Field | null>;
|
||||
sortField: ComputedRef<string | null>;
|
||||
isSingleton: ComputedRef<boolean>;
|
||||
accountabilityScope: ComputedRef<'all' | 'activity' | null>;
|
||||
};
|
||||
|
||||
export function useCollection(collectionKey: string | Ref<string | null>): CollectionInfo {
|
||||
export function useCollection(collectionKey: string | Ref<string | null>): UsableCollection {
|
||||
const collectionsStore = useCollectionsStore();
|
||||
const fieldsStore = useFieldsStore();
|
||||
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
import { nanoid } from 'nanoid';
|
||||
import { computed, ComputedRef, Ref, ref, watch } from 'vue';
|
||||
|
||||
type UsableCustomSelection = {
|
||||
otherValue: Ref<string | null>;
|
||||
usesOtherValue: ComputedRef<boolean>;
|
||||
};
|
||||
|
||||
export function useCustomSelection(
|
||||
currentValue: Ref<string>,
|
||||
items: Ref<any[]>,
|
||||
emit: (event: string | null) => void
|
||||
): Record<string, ComputedRef> {
|
||||
): UsableCustomSelection {
|
||||
const localOtherValue = ref('');
|
||||
|
||||
const otherValue = computed({
|
||||
@@ -36,16 +41,22 @@ export function useCustomSelection(
|
||||
return { otherValue, usesOtherValue };
|
||||
}
|
||||
|
||||
type OtherValue = {
|
||||
key: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
type UsableCustomSelectionMultiple = {
|
||||
otherValues: Ref<OtherValue[]>;
|
||||
addOtherValue: (value?: string) => void;
|
||||
setOtherValue: (key: string, newValue: string | null) => void;
|
||||
};
|
||||
|
||||
export function useCustomSelectionMultiple(
|
||||
currentValues: Ref<string[]>,
|
||||
items: Ref<any[]>,
|
||||
emit: (event: string[] | null) => void
|
||||
): Record<string, any> {
|
||||
type OtherValue = {
|
||||
key: string;
|
||||
value: string;
|
||||
};
|
||||
|
||||
): UsableCustomSelectionMultiple {
|
||||
const otherValues = ref<OtherValue[]>([]);
|
||||
|
||||
watch(currentValues, (newValue) => {
|
||||
|
||||
@@ -9,7 +9,10 @@ declare global {
|
||||
|
||||
export default function useElementSize<T extends Element>(
|
||||
target: T | Ref<T> | Ref<undefined>
|
||||
): Record<string, Ref<number>> {
|
||||
): {
|
||||
width: Ref<number>;
|
||||
height: Ref<number>;
|
||||
} {
|
||||
const width = ref(0);
|
||||
const height = ref(0);
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { useFieldsStore, useRelationsStore } from '@/stores/';
|
||||
import { Field, Relation } from '@/types';
|
||||
import { getRelationType } from '@/utils/get-relation-type';
|
||||
import { cloneDeep } from 'lodash';
|
||||
import { computed, Ref } from 'vue';
|
||||
import { computed, Ref, ComputedRef } from 'vue';
|
||||
|
||||
type FieldOption = { name: string; field: string; key: string; children?: FieldOption[] };
|
||||
|
||||
@@ -12,7 +12,7 @@ export default function useFieldTree(
|
||||
strict = false,
|
||||
inject?: Ref<{ fields: Field[]; relations: Relation[] } | null>,
|
||||
filter: (field: Field) => boolean = () => true
|
||||
): { tree: Ref<FieldOption[]> } {
|
||||
): { tree: ComputedRef<FieldOption[]> } {
|
||||
const fieldsStore = useFieldsStore();
|
||||
const relationsStore = useRelationsStore();
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import { getDefaultInterfaceForType } from '@/utils/get-default-interface-for-ty
|
||||
import { clone } from 'lodash';
|
||||
import { computed, ComputedRef, Ref } from 'vue';
|
||||
|
||||
export default function useFormFields(fields: Ref<Field[]>): { formFields: ComputedRef } {
|
||||
export default function useFormFields(fields: Ref<Field[]>): { formFields: ComputedRef<Field[]> } {
|
||||
const { interfaces } = getInterfaces();
|
||||
|
||||
const formFields = computed(() => {
|
||||
|
||||
@@ -6,14 +6,34 @@ import { APIError } from '@/types';
|
||||
import { notify } from '@/utils/notify';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
import { AxiosResponse } from 'axios';
|
||||
import { computed, Ref, ref, watch } from 'vue';
|
||||
import { computed, ComputedRef, Ref, ref, watch } from 'vue';
|
||||
|
||||
export function useItem(collection: Ref<string>, primaryKey: Ref<string | number | null>): Record<string, any> {
|
||||
type UsableItem = {
|
||||
edits: Ref<Record<string, any>>;
|
||||
item: Ref<Record<string, any> | null>;
|
||||
error: Ref<any>;
|
||||
loading: Ref<boolean>;
|
||||
saving: Ref<boolean>;
|
||||
refresh: () => void;
|
||||
save: () => Promise<any>;
|
||||
isNew: ComputedRef<boolean>;
|
||||
remove: () => Promise<void>;
|
||||
deleting: Ref<boolean>;
|
||||
archive: () => Promise<void>;
|
||||
isArchived: ComputedRef<boolean | null>;
|
||||
archiving: Ref<boolean>;
|
||||
saveAsCopy: () => Promise<any>;
|
||||
isBatch: ComputedRef<boolean>;
|
||||
getItem: () => Promise<void>;
|
||||
validationErrors: Ref<any[]>;
|
||||
};
|
||||
|
||||
export function useItem(collection: Ref<string>, primaryKey: Ref<string | number | null>): UsableItem {
|
||||
const { info: collectionInfo, primaryKeyField } = useCollection(collection);
|
||||
|
||||
const item = ref<Record<string, any> | null>(null);
|
||||
const error = ref(null);
|
||||
const validationErrors = ref([]);
|
||||
const error = ref<any>(null);
|
||||
const validationErrors = ref<any[]>([]);
|
||||
const loading = ref(false);
|
||||
const saving = ref(false);
|
||||
const deleting = ref(false);
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Filter, Item } from '@/types/';
|
||||
import filtersToQuery from '@/utils/filters-to-query';
|
||||
import moveInArray from '@/utils/move-in-array';
|
||||
import { isEqual, orderBy, throttle } from 'lodash';
|
||||
import { computed, nextTick, ref, Ref, watch } from 'vue';
|
||||
import { computed, ComputedRef, nextTick, ref, Ref, watch } from 'vue';
|
||||
|
||||
type Query = {
|
||||
limit: Ref<number>;
|
||||
@@ -20,18 +20,18 @@ type ManualSortData = {
|
||||
to: string | number;
|
||||
};
|
||||
|
||||
type ItemsInfo = {
|
||||
type UsableItems = {
|
||||
itemCount: Ref<number | null>;
|
||||
totalCount: Ref<number | null>;
|
||||
items: Ref<Item[]>;
|
||||
totalPages: Ref<number>;
|
||||
totalPages: ComputedRef<number>;
|
||||
loading: Ref<boolean>;
|
||||
error: Ref<any>;
|
||||
changeManualSort: (data: ManualSortData) => Promise<void>;
|
||||
getItems: () => Promise<void>;
|
||||
};
|
||||
|
||||
export function useItems(collection: Ref<string | null>, query: Query, fetchOnInit = true): ItemsInfo {
|
||||
export function useItems(collection: Ref<string | null>, query: Query, fetchOnInit = true): UsableItems {
|
||||
const { primaryKeyField, sortField } = useCollection(collection);
|
||||
|
||||
let loadingTimeout: number | null = null;
|
||||
|
||||
@@ -5,11 +5,16 @@ import { cloneDeep } from 'lodash';
|
||||
import { isAllowed } from '../utils/is-allowed';
|
||||
import { useCollection } from './use-collection';
|
||||
|
||||
export function usePermissions(
|
||||
collection: Ref<string>,
|
||||
item: Ref<any>,
|
||||
isNew: Ref<boolean>
|
||||
): Record<string, ComputedRef> {
|
||||
type UsablePermissions = {
|
||||
deleteAllowed: ComputedRef<boolean>;
|
||||
saveAllowed: ComputedRef<boolean>;
|
||||
archiveAllowed: ComputedRef<boolean>;
|
||||
updateAllowed: ComputedRef<boolean>;
|
||||
fields: ComputedRef<Field[]>;
|
||||
revisionsAllowed: ComputedRef<boolean>;
|
||||
};
|
||||
|
||||
export function usePermissions(collection: Ref<string>, item: Ref<any>, isNew: Ref<boolean>): UsablePermissions {
|
||||
const userStore = useUserStore();
|
||||
const permissionsStore = usePermissionsStore();
|
||||
|
||||
|
||||
@@ -2,13 +2,32 @@ import { useCollection } from '@/composables/use-collection';
|
||||
import { usePresetsStore, useUserStore } from '@/stores';
|
||||
import { Filter, Preset } from '@/types/';
|
||||
import { debounce, isEqual } from 'lodash';
|
||||
import { computed, ref, Ref, watch } from 'vue';
|
||||
import { computed, ComputedRef, ref, Ref, watch } from 'vue';
|
||||
|
||||
type UsablePreset = {
|
||||
bookmarkExists: ComputedRef<boolean>;
|
||||
layout: Ref<string | null>;
|
||||
layoutOptions: Ref<Record<string, any>>;
|
||||
layoutQuery: Ref<Record<string, any>>;
|
||||
filters: Ref<readonly Filter[]>;
|
||||
searchQuery: Ref<string | null>;
|
||||
refreshInterval: Ref<number | null>;
|
||||
savePreset: (preset?: Partial<Preset> | undefined) => Promise<any>;
|
||||
saveCurrentAsBookmark: (overrides: Partial<Preset>) => Promise<any>;
|
||||
bookmarkTitle: Ref<string | null>;
|
||||
resetPreset: () => Promise<void>;
|
||||
bookmarkSaved: Ref<boolean>;
|
||||
bookmarkIsMine: ComputedRef<boolean>;
|
||||
busy: Ref<boolean>;
|
||||
clearLocalSave: () => void;
|
||||
localPreset: Ref<Partial<Preset>>;
|
||||
};
|
||||
|
||||
export function usePreset(
|
||||
collection: Ref<string>,
|
||||
bookmark: Ref<number | null> = ref(null),
|
||||
temporary = false
|
||||
): Record<string, any> {
|
||||
): UsablePreset {
|
||||
const presetsStore = usePresetsStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
import { throttle } from 'lodash';
|
||||
import { ComponentPublicInstance, computed, isRef, onMounted, onUnmounted, ref, Ref } from 'vue';
|
||||
import { ComponentPublicInstance, computed, isRef, onMounted, onUnmounted, ref, Ref, ComputedRef } from 'vue';
|
||||
|
||||
type UsableScrollDistance = {
|
||||
top: Ref<number | undefined>;
|
||||
left: Ref<number | undefined>;
|
||||
target: ComputedRef<Element | null>;
|
||||
};
|
||||
|
||||
export default function useScrollDistance<T extends Element>(
|
||||
t: T | Ref<T | null | ComponentPublicInstance>
|
||||
): Record<string, Ref> {
|
||||
): UsableScrollDistance {
|
||||
const top = ref<number>();
|
||||
const left = ref<number>();
|
||||
|
||||
|
||||
@@ -1,15 +1,21 @@
|
||||
import api from '@/api';
|
||||
import { Collection } from '@/types';
|
||||
import { getFieldsFromTemplate } from '@/utils/get-fields-from-template';
|
||||
import { computed, ComputedRef, Ref, ref, watch } from 'vue';
|
||||
import { computed, Ref, ref, watch } from 'vue';
|
||||
|
||||
type UsableTemplateData = {
|
||||
templateData: Ref<Record<string, any> | undefined>;
|
||||
loading: Ref<boolean>;
|
||||
error: Ref<any>;
|
||||
};
|
||||
|
||||
export default function useTemplateData(
|
||||
collection: ComputedRef<Collection | undefined>,
|
||||
collection: Ref<Collection | null>,
|
||||
primaryKey: Ref<string>
|
||||
): Record<string, any> {
|
||||
): UsableTemplateData {
|
||||
const templateData = ref<Record<string, any>>();
|
||||
const loading = ref(false);
|
||||
const error = ref(null);
|
||||
const error = ref<any>(null);
|
||||
|
||||
const fields = computed(() => {
|
||||
if (!collection.value?.meta?.display_template) return null;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ref, Ref, watch } from 'vue';
|
||||
|
||||
export function useTitle(newTitle: string | Ref<string>): Ref | undefined {
|
||||
export function useTitle(newTitle: string | Ref<string>): Ref<string> | undefined {
|
||||
if (newTitle === undefined || newTitle === null) return;
|
||||
|
||||
const titleRef = typeof newTitle === 'string' ? ref(newTitle) : newTitle;
|
||||
|
||||
@@ -5,7 +5,10 @@ type WindowSizeOptions = {
|
||||
throttle: number;
|
||||
};
|
||||
|
||||
export default function useWindowSize(options: WindowSizeOptions = { throttle: 100 }): Record<string, Ref> {
|
||||
export default function useWindowSize(options: WindowSizeOptions = { throttle: 100 }): {
|
||||
width: Ref<number>;
|
||||
height: Ref<number>;
|
||||
} {
|
||||
const width = ref(0);
|
||||
const height = ref(0);
|
||||
|
||||
|
||||
@@ -4,6 +4,6 @@ import { DisplayConfig } from './types';
|
||||
const displaysRaw: Ref<DisplayConfig[]> = shallowRef([]);
|
||||
const displays: Ref<DisplayConfig[]> = shallowRef([]);
|
||||
|
||||
export function getDisplays(): Record<string, Ref<DisplayConfig[]>> {
|
||||
export function getDisplays(): { displays: Ref<DisplayConfig[]>; displaysRaw: Ref<DisplayConfig[]> } {
|
||||
return { displays, displaysRaw };
|
||||
}
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
} from '@/stores';
|
||||
|
||||
type GenericStore = {
|
||||
id: string;
|
||||
$id: string;
|
||||
hydrate?: () => Promise<void>;
|
||||
dehydrate?: () => Promise<void>;
|
||||
|
||||
@@ -60,7 +60,7 @@ export async function hydrate(stores = useStores()): Promise<void> {
|
||||
await userStore.hydrate();
|
||||
|
||||
if (userStore.currentUser?.role) {
|
||||
await Promise.all(stores.filter(({ id }) => id !== 'userStore').map((store) => store.hydrate?.()));
|
||||
await Promise.all(stores.filter(({ $id }) => $id !== 'userStore').map((store) => store.hydrate?.()));
|
||||
await registerModules();
|
||||
await setLanguage((userStore.currentUser?.language as Language) || 'en-US');
|
||||
}
|
||||
|
||||
@@ -4,6 +4,6 @@ import { InterfaceConfig } from './types';
|
||||
const interfacesRaw: Ref<InterfaceConfig[]> = shallowRef([]);
|
||||
const interfaces: Ref<InterfaceConfig[]> = shallowRef([]);
|
||||
|
||||
export function getInterfaces(): Record<string, Ref<InterfaceConfig[]>> {
|
||||
export function getInterfaces(): { interfaces: Ref<InterfaceConfig[]>; interfacesRaw: Ref<InterfaceConfig[]> } {
|
||||
return { interfaces, interfacesRaw };
|
||||
}
|
||||
|
||||
@@ -144,7 +144,7 @@ export default defineComponent({
|
||||
codemirror.setOption('mode', { name: 'javascript', json: true });
|
||||
|
||||
CodeMirror.registerHelper('lint', 'json', (text: string) => {
|
||||
const found: Record<string, any> = [];
|
||||
const found: Record<string, any>[] = [];
|
||||
const parser = jsonlint.parser;
|
||||
|
||||
parser.parseError = (str: string, hash: any) => {
|
||||
|
||||
@@ -10,7 +10,23 @@ type ImageSelection = {
|
||||
height?: number;
|
||||
};
|
||||
|
||||
export default function useImage(editor: Ref<any>, imageToken: Ref<string>): Record<string, any> {
|
||||
type ImageButton = {
|
||||
icon: string;
|
||||
tooltip: string;
|
||||
onAction: (buttonApi: any) => void;
|
||||
onSetup: (buttonApi: any) => () => void;
|
||||
};
|
||||
|
||||
type UsableImage = {
|
||||
imageDrawerOpen: Ref<boolean>;
|
||||
imageSelection: Ref<ImageSelection | null>;
|
||||
closeImageDrawer: () => void;
|
||||
onImageSelect: (image: Record<string, any>) => void;
|
||||
saveImage: () => void;
|
||||
imageButton: ImageButton;
|
||||
};
|
||||
|
||||
export default function useImage(editor: Ref<any>, imageToken: Ref<string>): UsableImage {
|
||||
const imageDrawerOpen = ref(false);
|
||||
const imageSelection = ref<ImageSelection | null>(null);
|
||||
|
||||
|
||||
@@ -8,7 +8,22 @@ type LinkSelection = {
|
||||
newTab: boolean;
|
||||
};
|
||||
|
||||
export default function useLink(editor: Ref<any>): Record<string, any> {
|
||||
type LinkButton = {
|
||||
icon: string;
|
||||
tooltip: string;
|
||||
onAction: (buttonApi: any) => void;
|
||||
onSetup: (buttonApi: any) => () => void;
|
||||
};
|
||||
|
||||
type UsableLink = {
|
||||
linkDrawerOpen: Ref<boolean>;
|
||||
linkSelection: Ref<LinkSelection>;
|
||||
closeLinkDrawer: () => void;
|
||||
saveLink: () => void;
|
||||
linkButton: LinkButton;
|
||||
};
|
||||
|
||||
export default function useLink(editor: Ref<any>): UsableLink {
|
||||
const linkDrawerOpen = ref(false);
|
||||
const linkSelection = ref<LinkSelection>({
|
||||
url: null,
|
||||
|
||||
@@ -9,7 +9,29 @@ type MediaSelection = {
|
||||
height?: number;
|
||||
};
|
||||
|
||||
export default function useMedia(editor: Ref<any>, imageToken: Ref<string>): Record<string, any> {
|
||||
type MediaButton = {
|
||||
icon: string;
|
||||
tooltip: string;
|
||||
onAction: (buttonApi: any) => void;
|
||||
onSetup: (buttonApi: any) => () => void;
|
||||
};
|
||||
|
||||
type UsableMedia = {
|
||||
mediaDrawerOpen: Ref<boolean>;
|
||||
mediaSelection: Ref<MediaSelection | null>;
|
||||
closeMediaDrawer: () => void;
|
||||
openMediaTab: Ref<string[]>;
|
||||
onMediaSelect: (media: Record<string, any>) => void;
|
||||
embed: Ref<string>;
|
||||
saveMedia: () => void;
|
||||
startEmbed: Ref<string>;
|
||||
mediaHeight: Ref<number | undefined>;
|
||||
mediaWidth: Ref<number | undefined>;
|
||||
mediaSource: Ref<any>;
|
||||
mediaButton: MediaButton;
|
||||
};
|
||||
|
||||
export default function useMedia(editor: Ref<any>, imageToken: Ref<string>): UsableMedia {
|
||||
const mediaDrawerOpen = ref(false);
|
||||
const mediaSelection = ref<MediaSelection | null>(null);
|
||||
const openMediaTab = ref(['video']);
|
||||
|
||||
@@ -1,7 +1,21 @@
|
||||
import { i18n } from '@/lang';
|
||||
import { Ref, ref } from 'vue';
|
||||
|
||||
export default function useSourceCode(editor: Ref<any>): Record<string, any> {
|
||||
type SourceCodeButton = {
|
||||
icon: string;
|
||||
tooltip: string;
|
||||
onAction: () => void;
|
||||
};
|
||||
|
||||
type UsableSourceCode = {
|
||||
codeDrawerOpen: Ref<boolean>;
|
||||
code: Ref<string | undefined>;
|
||||
closeCodeDrawer: () => void;
|
||||
saveCode: () => void;
|
||||
sourceCodeButton: SourceCodeButton;
|
||||
};
|
||||
|
||||
export default function useSourceCode(editor: Ref<any>): UsableSourceCode {
|
||||
const codeDrawerOpen = ref(false);
|
||||
const code = ref<string>();
|
||||
|
||||
|
||||
@@ -2,11 +2,23 @@ import { get, has, isEqual } from 'lodash';
|
||||
import { Ref } from 'vue';
|
||||
import { RelationInfo } from './use-relation';
|
||||
|
||||
type UsableActions = {
|
||||
getJunctionItem: (id: string | number) => string | number | Record<string, any> | null;
|
||||
getNewSelectedItems: () => Record<string, any>[];
|
||||
getNewItems: () => Record<string, any>[];
|
||||
getUpdatedItems: () => Record<string, any>[];
|
||||
getExistingItems: () => (string | number | Record<string, any>)[];
|
||||
getPrimaryKeys: () => (string | number)[];
|
||||
getRelatedPrimaryKeys: () => (string | number)[];
|
||||
getJunctionFromRelatedId: (id: string | number, items: Record<string, any>[]) => Record<string, any> | null;
|
||||
deleteItem: (deletingItem: Record<string, any>) => void;
|
||||
};
|
||||
|
||||
export default function useActions(
|
||||
value: Ref<(string | number | Record<string, any>)[] | null>,
|
||||
relation: Ref<RelationInfo>,
|
||||
emit: (newValue: any[] | null) => void
|
||||
): Record<string, any> {
|
||||
): UsableActions {
|
||||
// Returns the junction item with the given Id.
|
||||
function getJunctionItem(id: string | number) {
|
||||
const { junctionPkField } = relation.value;
|
||||
@@ -88,6 +100,12 @@ export default function useActions(
|
||||
}, []) as (string | number)[];
|
||||
}
|
||||
|
||||
function getJunctionFromRelatedId(id: string | number, items: Record<string, any>[]) {
|
||||
const { relationPkField, junctionField } = relation.value;
|
||||
|
||||
return items.find((item) => get(item, [junctionField, relationPkField]) === id) || null;
|
||||
}
|
||||
|
||||
function deleteItem(deletingItem: Record<string, any>) {
|
||||
if (value.value === null) return;
|
||||
const { junctionField, relationPkField, junctionPkField } = relation.value;
|
||||
@@ -121,12 +139,6 @@ export default function useActions(
|
||||
emit(newValue);
|
||||
}
|
||||
|
||||
function getJunctionFromRelatedId(id: string | number, items: Record<string, any>[]) {
|
||||
const { relationPkField, junctionField } = relation.value;
|
||||
|
||||
return items.find((item) => get(item, [junctionField, relationPkField]) === id) || null;
|
||||
}
|
||||
|
||||
return {
|
||||
getJunctionItem,
|
||||
getNewSelectedItems,
|
||||
|
||||
@@ -1,11 +1,22 @@
|
||||
import { Ref, ref } from 'vue';
|
||||
import { get, isEqual } from 'lodash';
|
||||
import { RelationInfo } from './use-relation';
|
||||
|
||||
type UsableEdit = {
|
||||
currentlyEditing: Ref<string | number | null>;
|
||||
editItem: (item: any) => void;
|
||||
editsAtStart: Ref<Record<string, any>>;
|
||||
stageEdits: (edits: any) => void;
|
||||
cancelEdit: () => void;
|
||||
relatedPrimaryKey: Ref<string | number | null>;
|
||||
editModalActive: Ref<boolean>;
|
||||
};
|
||||
|
||||
export default function useEdit(
|
||||
value: Ref<(string | number | Record<string, any>)[] | null>,
|
||||
relation: Ref<RelationInfo>,
|
||||
emit: (newVal: any[] | null) => void
|
||||
): Record<string, any> {
|
||||
): UsableEdit {
|
||||
const editModalActive = ref(false);
|
||||
const currentlyEditing = ref<string | number | null>(null);
|
||||
const relatedPrimaryKey = ref<string | number | null>(null);
|
||||
|
||||
@@ -7,6 +7,13 @@ import { cloneDeep, get } from 'lodash';
|
||||
import { Ref, ref, watch } from 'vue';
|
||||
import { RelationInfo } from './use-relation';
|
||||
|
||||
type UsablePreview = {
|
||||
tableHeaders: Ref<Header[]>;
|
||||
items: Ref<Record<string, any>[]>;
|
||||
loading: Ref<boolean>;
|
||||
error: Ref<any>;
|
||||
};
|
||||
|
||||
export default function usePreview(
|
||||
value: Ref<(string | number | Record<string, any>)[] | null>,
|
||||
fields: Ref<string[]>,
|
||||
@@ -15,7 +22,7 @@ export default function usePreview(
|
||||
getUpdatedItems: () => Record<string, any>[],
|
||||
getNewItems: () => Record<string, any>[],
|
||||
getPrimaryKeys: () => (string | number)[]
|
||||
): Record<string, Ref> {
|
||||
): UsablePreview {
|
||||
// Using a ref for the table headers here means that the table itself can update the
|
||||
// values if it needs to. This allows the user to manually resize the columns for example
|
||||
|
||||
@@ -23,7 +30,7 @@ export default function usePreview(
|
||||
const tableHeaders = ref<Header[]>([]);
|
||||
const loading = ref(false);
|
||||
const items = ref<Record<string, any>[]>([]);
|
||||
const error = ref(null);
|
||||
const error = ref<any>(null);
|
||||
|
||||
watch(
|
||||
() => value.value,
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import useCollection from '@/composables/use-collection';
|
||||
import { useCollectionsStore, useRelationsStore } from '@/stores/';
|
||||
import { Relation } from '@/types';
|
||||
import { computed, Ref } from 'vue';
|
||||
import { Collection, Field, Relation } from '@/types';
|
||||
import { computed, ComputedRef, Ref } from 'vue';
|
||||
|
||||
export type RelationInfo = {
|
||||
junctionPkField: string;
|
||||
@@ -12,7 +12,17 @@ export type RelationInfo = {
|
||||
relationCollection: string;
|
||||
};
|
||||
|
||||
export default function useRelation(collection: Ref<string>, field: Ref<string>): Record<string, any> {
|
||||
type UsableRelation = {
|
||||
junction: ComputedRef<Relation>;
|
||||
junctionCollection: ComputedRef<Collection>;
|
||||
relation: ComputedRef<Relation>;
|
||||
relationCollection: ComputedRef<Collection>;
|
||||
relationInfo: ComputedRef<RelationInfo>;
|
||||
junctionPrimaryKeyField: ComputedRef<Field | null>;
|
||||
relationPrimaryKeyField: ComputedRef<Field | null>;
|
||||
};
|
||||
|
||||
export default function useRelation(collection: Ref<string>, field: Ref<string>): UsableRelation {
|
||||
const relationsStore = useRelationsStore();
|
||||
const collectionsStore = useCollectionsStore();
|
||||
|
||||
|
||||
@@ -1,14 +1,21 @@
|
||||
import { Filter } from '@/types';
|
||||
import { get } from 'lodash';
|
||||
import { computed, Ref, ref } from 'vue';
|
||||
import { computed, ComputedRef, Ref, ref } from 'vue';
|
||||
import { RelationInfo } from './use-relation';
|
||||
|
||||
type UsableSelection = {
|
||||
stageSelection: (newSelection: (number | string)[]) => void;
|
||||
selectModalActive: Ref<boolean>;
|
||||
selectedPrimaryKeys: ComputedRef<(string | number)[]>;
|
||||
selectionFilters: ComputedRef<Filter[]>;
|
||||
};
|
||||
|
||||
export default function useSelection(
|
||||
value: Ref<(string | number | Record<string, any>)[] | null>,
|
||||
items: Ref<Record<string, any>[]>,
|
||||
relation: Ref<RelationInfo>,
|
||||
emit: (newVal: any[] | null) => void
|
||||
): Record<string, any> {
|
||||
): UsableSelection {
|
||||
const selectModalActive = ref(false);
|
||||
|
||||
const selectedPrimaryKeys = computed(() => {
|
||||
|
||||
@@ -1,14 +1,20 @@
|
||||
import { Sort } from '@/components/v-table/types';
|
||||
import { sortBy } from 'lodash';
|
||||
import { computed, Ref, ref } from 'vue';
|
||||
import { computed, ComputedRef, Ref, ref } from 'vue';
|
||||
import { RelationInfo } from './use-relation';
|
||||
|
||||
type UsableSort = {
|
||||
sort: Ref<Sort>;
|
||||
sortItems: (newItems: Record<string, any>[]) => void;
|
||||
sortedItems: ComputedRef<Record<string, any>[]>;
|
||||
};
|
||||
|
||||
export default function useSort(
|
||||
relation: Ref<RelationInfo>,
|
||||
fields: Ref<string[]>,
|
||||
items: Ref<Record<string, any>[]>,
|
||||
emit: (newVal: any[] | null) => void
|
||||
): Record<string, any> {
|
||||
): UsableSort {
|
||||
const sort = ref<Sort>({ by: relation.value.sortField || fields.value[0], desc: false });
|
||||
|
||||
const sortedItems = computed(() => {
|
||||
|
||||
@@ -4,6 +4,6 @@ import { LayoutConfig } from './types';
|
||||
const layoutsRaw: Ref<LayoutConfig[]> = shallowRef([]);
|
||||
const layouts: Ref<LayoutConfig[]> = shallowRef([]);
|
||||
|
||||
export function getLayouts(): Record<string, Ref<LayoutConfig[]>> {
|
||||
export function getLayouts(): { layouts: Ref<LayoutConfig[]>; layoutsRaw: Ref<LayoutConfig[]> } {
|
||||
return { layouts, layoutsRaw };
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { useCollectionsStore, useUserStore } from '@/stores/';
|
||||
import { Collection } from '@/types';
|
||||
import { computed, Ref, ref } from 'vue';
|
||||
import { computed, ComputedRef, Ref, ref } from 'vue';
|
||||
|
||||
export type NavItem = {
|
||||
collection: string;
|
||||
@@ -31,7 +31,16 @@ function collectionToNavItem(collection: Collection): NavItem {
|
||||
};
|
||||
}
|
||||
|
||||
export default function useNavigation(searchQuery?: Ref<string | null>): Record<string, any> {
|
||||
type UsableNavigation = {
|
||||
customNavItems: ComputedRef<NavItemGroup[] | null>;
|
||||
navItems: ComputedRef<NavItem[]>;
|
||||
activeGroups: Ref<string[]>;
|
||||
hiddenNavItems: ComputedRef<NavItem[]>;
|
||||
hiddenShown: Ref<boolean>;
|
||||
search: (item: NavItem) => boolean;
|
||||
};
|
||||
|
||||
export default function useNavigation(searchQuery?: Ref<string | null>): UsableNavigation {
|
||||
const collectionsStore = useCollectionsStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
|
||||
@@ -3,6 +3,6 @@ import { ref, Ref } from 'vue';
|
||||
const searchQuery = ref<string | null>(null);
|
||||
const visible = ref<number | null>(null);
|
||||
|
||||
export function useSearch(): Record<string, Ref> {
|
||||
export function useSearch(): { visible: Ref<number | null>; searchQuery: Ref<string | null> } {
|
||||
return { visible, searchQuery };
|
||||
}
|
||||
|
||||
@@ -14,6 +14,15 @@ export type Folder = {
|
||||
children?: Folder[];
|
||||
};
|
||||
|
||||
type UsableFolders = {
|
||||
loading: Ref<boolean>;
|
||||
folders: Ref<Folder[] | null>;
|
||||
nestedFolders: Ref<Folder[] | null>;
|
||||
error: Ref<any>;
|
||||
fetchFolders: () => Promise<void>;
|
||||
openFolders: Ref<string[] | null>;
|
||||
};
|
||||
|
||||
let loading: Ref<boolean> | null = null;
|
||||
let folders: Ref<Folder[] | null> | null = null;
|
||||
let nestedFolders: Ref<Folder[] | null> | null = null;
|
||||
@@ -21,7 +30,7 @@ let openFolders: Ref<string[] | null> | null = null;
|
||||
|
||||
let error: Ref<any> | null = null;
|
||||
|
||||
export default function useFolders(): Record<string, any> {
|
||||
export default function useFolders(): UsableFolders {
|
||||
if (loading === null) loading = ref(false);
|
||||
if (folders === null) folders = ref<Folder[] | null>(null);
|
||||
if (nestedFolders === null) nestedFolders = ref<Folder[] | null>(null);
|
||||
|
||||
@@ -4,6 +4,6 @@ import { ModuleConfig } from './types';
|
||||
const modulesRaw: Ref<ModuleConfig[]> = shallowRef([]);
|
||||
const modules: Ref<ModuleConfig[]> = shallowRef([]);
|
||||
|
||||
export function getModules(): Record<string, Ref<ModuleConfig[]>> {
|
||||
export function getModules(): { modules: Ref<ModuleConfig[]>; modulesRaw: Ref<ModuleConfig[]> } {
|
||||
return { modules, modulesRaw };
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import api from '@/api';
|
||||
import bytes from 'bytes';
|
||||
import prettyMS from 'pretty-ms';
|
||||
import { computed, ref, Ref } from 'vue';
|
||||
import { computed, ComputedRef, ref, Ref } from 'vue';
|
||||
|
||||
type ServerInfo = {
|
||||
directus: {
|
||||
@@ -19,7 +19,28 @@ type ServerInfo = {
|
||||
};
|
||||
};
|
||||
|
||||
export function useProjectInfo(): Record<string, Ref> {
|
||||
type UsableProjectInfo = {
|
||||
info: Ref<ServerInfo | undefined>;
|
||||
parsedInfo: ComputedRef<{
|
||||
directus: {
|
||||
version: string;
|
||||
};
|
||||
node: {
|
||||
version: string;
|
||||
uptime: string;
|
||||
};
|
||||
os: {
|
||||
type: string;
|
||||
version: string;
|
||||
uptime: string;
|
||||
totalmem: string;
|
||||
};
|
||||
} | null>;
|
||||
loading: Ref<boolean>;
|
||||
error: Ref<any>;
|
||||
};
|
||||
|
||||
export function useProjectInfo(): UsableProjectInfo {
|
||||
const info = ref<ServerInfo>();
|
||||
const loading = ref(false);
|
||||
const error = ref<any>();
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
<div class="grid">
|
||||
<div class="field">
|
||||
<div class="type-label">{{ t('this_collection') }}</div>
|
||||
<v-input disabled :modelValue="relations[0].collection" />
|
||||
<v-input disabled :model-value="relations[0].collection" />
|
||||
</div>
|
||||
<div class="field">
|
||||
<div class="type-label">{{ t('related_collection') }}</div>
|
||||
|
||||
@@ -61,13 +61,13 @@ function initLocalStore(collection: string, field: string, type: typeof localTyp
|
||||
|
||||
availableDisplays = computed(() => {
|
||||
return displays.value
|
||||
.filter((inter: InterfaceConfig) => {
|
||||
.filter((inter: DisplayConfig) => {
|
||||
const matchesType = inter.types.includes(state.fieldData?.type || 'alias');
|
||||
const matchesLocalType = (inter.groups || ['standard']).includes(type) || true;
|
||||
|
||||
return matchesType && matchesLocalType;
|
||||
})
|
||||
.sort((a: InterfaceConfig, b: InterfaceConfig) => (a.name > b.name ? 1 : -1));
|
||||
.sort((a: DisplayConfig, b: DisplayConfig) => (a.name > b.name ? 1 : -1));
|
||||
});
|
||||
|
||||
generationInfo = computed(() => {
|
||||
|
||||
@@ -2,7 +2,16 @@ import api from '@/api';
|
||||
import { Permission } from '@/types';
|
||||
import { ref, Ref, watch } from 'vue';
|
||||
|
||||
export default function usePermissions(role: Ref<number>): Record<string, any> {
|
||||
type UsablePermissions = {
|
||||
loading: Ref<boolean>;
|
||||
error: Ref<null>;
|
||||
permissions: Ref<Permission[] | null>;
|
||||
fetchPermissions: () => Promise<void>;
|
||||
savePermission: (updates: Partial<Permission>) => Promise<void>;
|
||||
saveAll: (create: Partial<Permission>[], update: Partial<Permission>[]) => Promise<void>;
|
||||
};
|
||||
|
||||
export default function usePermissions(role: Ref<number>): UsablePermissions {
|
||||
const loading = ref(false);
|
||||
const error = ref(null);
|
||||
const permissions = ref<Permission[] | null>(null);
|
||||
|
||||
@@ -3,11 +3,19 @@ import { Collection, Permission } from '@/types';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
import { inject, ref, Ref } from 'vue';
|
||||
|
||||
type UsableUpdatePermissions = {
|
||||
getPermission: (action: string) => Permission | undefined;
|
||||
setFullAccess: (action: 'create' | 'read' | 'update' | 'delete') => Promise<void>;
|
||||
setNoAccess: (action: 'create' | 'read' | 'update' | 'delete') => Promise<void>;
|
||||
setFullAccessAll: () => Promise<void>;
|
||||
setNoAccessAll: () => Promise<void>;
|
||||
};
|
||||
|
||||
export default function useUpdatePermissions(
|
||||
collection: Ref<Collection>,
|
||||
permissions: Ref<Permission[]>,
|
||||
role: Ref<string>
|
||||
): Record<string, any> {
|
||||
): UsableUpdatePermissions {
|
||||
const saving = ref(false);
|
||||
const refresh = inject<() => Promise<void>>('refresh-permissions');
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@ import { ref, Ref } from 'vue';
|
||||
let roles: Ref<Role[] | null> | null = null;
|
||||
let loading: Ref<boolean> | null = null;
|
||||
|
||||
export default function useNavigation(): Record<string, Ref> {
|
||||
export default function useNavigation(): { roles: Ref<Role[] | null>; loading: Ref<boolean> } {
|
||||
if (roles === null) {
|
||||
roles = ref<Role[] | null>(null);
|
||||
}
|
||||
|
||||
@@ -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,14 +1,14 @@
|
||||
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.global.t(val.replace('$t:', ''));
|
||||
(newObj as Record<string, any>)[key] = i18n.global.t(val.replace('$t:', ''));
|
||||
});
|
||||
|
||||
return obj;
|
||||
return newObj;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user