mirror of
https://github.com/directus/directus.git
synced 2026-04-03 03:00:39 -04:00
Add collection presets store (#226)
* Rename ids of stores to match var names * Add collection presets store * Add collection-presets-store
This commit is contained in:
@@ -3,6 +3,7 @@ import { useCollectionsStore } from '@/stores/collections/';
|
||||
import { useFieldsStore } from '@/stores/fields/';
|
||||
import { useUserStore } from '@/stores/user/';
|
||||
import { useRequestsStore } from '@/stores/requests/';
|
||||
import { useCollectionPresetsStore } from '@/stores/collection-presets/';
|
||||
|
||||
type GenericStore = {
|
||||
id: string;
|
||||
@@ -13,7 +14,13 @@ type GenericStore = {
|
||||
};
|
||||
|
||||
export function useStores(
|
||||
stores = [useCollectionsStore, useFieldsStore, useUserStore, useRequestsStore]
|
||||
stores = [
|
||||
useCollectionsStore,
|
||||
useFieldsStore,
|
||||
useUserStore,
|
||||
useRequestsStore,
|
||||
useCollectionPresetsStore
|
||||
]
|
||||
) {
|
||||
return stores.map(useStore => useStore()) as GenericStore[];
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { createStore } from 'pinia';
|
||||
|
||||
export const useAppStore = createStore({
|
||||
id: 'app',
|
||||
id: 'appStore',
|
||||
state: () => ({
|
||||
hydrated: false,
|
||||
hydrating: false,
|
||||
|
||||
136
src/stores/collection-presets/collection-presets.test.ts
Normal file
136
src/stores/collection-presets/collection-presets.test.ts
Normal file
@@ -0,0 +1,136 @@
|
||||
import { useUserStore } from '@/stores/user/';
|
||||
import { useProjectsStore } from '@/stores/projects/';
|
||||
import { useCollectionPresetsStore } from './collection-presets';
|
||||
import api from '@/api';
|
||||
import mountComposition from '../../../.jest/mount-composition';
|
||||
|
||||
jest.mock('@/api');
|
||||
|
||||
describe('Compositions / Collection Presets', () => {
|
||||
let req: any;
|
||||
|
||||
beforeEach(() => {
|
||||
req = {};
|
||||
});
|
||||
|
||||
describe('Hydrate', () => {
|
||||
it('Calls api.get with the correct parameters', () => {
|
||||
(api.get as jest.Mock).mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
data: {
|
||||
data: []
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
mountComposition(async () => {
|
||||
const userStore = useUserStore(req);
|
||||
(userStore.state.currentUser as any) = { id: 15, role: 25 };
|
||||
const projectsStore = useProjectsStore(req);
|
||||
projectsStore.state.currentProjectKey = 'my-project';
|
||||
const collectionPresetsStore = useCollectionPresetsStore(req);
|
||||
|
||||
await collectionPresetsStore.hydrate();
|
||||
|
||||
expect(api.get).toHaveBeenCalledWith(`/my-project/collection_presets`, {
|
||||
params: {
|
||||
'filter[user][eq]': 15
|
||||
}
|
||||
});
|
||||
|
||||
expect(api.get).toHaveBeenCalledWith(`/my-project/collection_presets`, {
|
||||
params: {
|
||||
'filter[role][eq]': 25,
|
||||
'filter[user][null]': 1
|
||||
}
|
||||
});
|
||||
|
||||
expect(api.get).toHaveBeenCalledWith(`/my-project/collection_presets`, {
|
||||
params: {
|
||||
'filter[role][null]': 1,
|
||||
'filter[user][null]': 1
|
||||
}
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Dehydrate', () => {
|
||||
it('Calls reset', () => {
|
||||
mountComposition(async () => {
|
||||
const collectionPresetsStore = useCollectionPresetsStore(req);
|
||||
jest.spyOn(collectionPresetsStore as any, 'reset');
|
||||
await collectionPresetsStore.dehydrate();
|
||||
expect(collectionPresetsStore.reset).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Create Preset', () => {
|
||||
it('Calls the right endpoint', () => {
|
||||
(api.post as jest.Mock).mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
data: {
|
||||
data: []
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
mountComposition(async () => {
|
||||
const collectionPresetsStore = useCollectionPresetsStore(req);
|
||||
const projectsStore = useProjectsStore(req);
|
||||
projectsStore.state.currentProjectKey = 'my-project';
|
||||
|
||||
await collectionPresetsStore.createCollectionPreset({
|
||||
title: 'test'
|
||||
});
|
||||
|
||||
expect(api.post).toHaveBeenCalledWith('/my-project/collection_presets', {
|
||||
title: 'test'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Update Preset', () => {
|
||||
it('Calls the right endpoint', () => {
|
||||
(api.patch as jest.Mock).mockImplementation(() =>
|
||||
Promise.resolve({
|
||||
data: {
|
||||
data: []
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
mountComposition(async () => {
|
||||
const collectionPresetsStore = useCollectionPresetsStore(req);
|
||||
const projectsStore = useProjectsStore(req);
|
||||
projectsStore.state.currentProjectKey = 'my-project';
|
||||
|
||||
await collectionPresetsStore.updateCollectionPreset(15, {
|
||||
title: 'test'
|
||||
});
|
||||
|
||||
expect(api.patch).toHaveBeenCalledWith('/my-project/collection_presets/15', {
|
||||
title: 'test'
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Delete Preset', () => {
|
||||
it('Calls the right endpoint', () => {
|
||||
(api.delete as jest.Mock).mockImplementation(() => Promise.resolve());
|
||||
|
||||
mountComposition(async () => {
|
||||
const collectionPresetsStore = useCollectionPresetsStore(req);
|
||||
const projectsStore = useProjectsStore(req);
|
||||
projectsStore.state.currentProjectKey = 'my-project';
|
||||
|
||||
await (collectionPresetsStore as any).deleteCollectionPreset(15);
|
||||
|
||||
expect(api.delete).toHaveBeenCalledWith('/my-project/collection_presets/15');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
81
src/stores/collection-presets/collection-presets.ts
Normal file
81
src/stores/collection-presets/collection-presets.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { createStore } from 'pinia';
|
||||
import { CollectionPreset } from './types';
|
||||
import { useUserStore } from '@/stores/user/';
|
||||
import { useProjectsStore } from '@/stores/projects/';
|
||||
import api from '@/api';
|
||||
|
||||
export const useCollectionPresetsStore = createStore({
|
||||
id: 'collectionPresetsStore',
|
||||
state: () => ({
|
||||
collectionPresets: [] as CollectionPreset[]
|
||||
}),
|
||||
actions: {
|
||||
async hydrate() {
|
||||
// Hydrate is only called for logged in users, therefore, currentUser exists
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
const { id, role } = useUserStore().state.currentUser!;
|
||||
const { currentProjectKey } = useProjectsStore().state;
|
||||
|
||||
const values = await Promise.all([
|
||||
// All user saved bookmarks and presets
|
||||
api.get(`/${currentProjectKey}/collection_presets`, {
|
||||
params: {
|
||||
'filter[user][eq]': id
|
||||
}
|
||||
}),
|
||||
// All role saved bookmarks and presets
|
||||
api.get(`/${currentProjectKey}/collection_presets`, {
|
||||
params: {
|
||||
'filter[role][eq]': role,
|
||||
'filter[user][null]': 1
|
||||
}
|
||||
}),
|
||||
// All global saved bookmarks and presets
|
||||
api.get(`/${currentProjectKey}/collection_presets`, {
|
||||
params: {
|
||||
'filter[role][null]': 1,
|
||||
'filter[user][null]': 1
|
||||
}
|
||||
})
|
||||
]);
|
||||
|
||||
this.state.collectionPresets = values.map(response => response.data.data).flat();
|
||||
},
|
||||
async dehydrate() {
|
||||
this.reset();
|
||||
},
|
||||
async createCollectionPreset(newPreset: Partial<CollectionPreset>) {
|
||||
const { currentProjectKey } = useProjectsStore().state;
|
||||
|
||||
const response = await api.post(`/${currentProjectKey}/collection_presets`, newPreset);
|
||||
|
||||
this.state.collectionPresets.push(response.data.data);
|
||||
},
|
||||
async updateCollectionPreset(id: number, updates: Partial<CollectionPreset>) {
|
||||
const { currentProjectKey } = useProjectsStore().state;
|
||||
|
||||
const response = await api.patch(
|
||||
`/${currentProjectKey}/collection_presets/${id}`,
|
||||
updates
|
||||
);
|
||||
|
||||
this.state.collectionPresets = this.state.collectionPresets.map(preset => {
|
||||
const updatedPreset = response.data.data;
|
||||
if (preset.id === updatedPreset.id) {
|
||||
return updatedPreset;
|
||||
}
|
||||
|
||||
return preset;
|
||||
});
|
||||
},
|
||||
async deleteCollectionPreset(id: number) {
|
||||
const { currentProjectKey } = useProjectsStore().state;
|
||||
|
||||
await api.delete(`/${currentProjectKey}/collection_presets/${id}`);
|
||||
|
||||
this.state.collectionPresets = this.state.collectionPresets.filter(preset => {
|
||||
return preset.id !== id;
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
4
src/stores/collection-presets/index.ts
Normal file
4
src/stores/collection-presets/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { useCollectionPresetsStore } from './collection-presets';
|
||||
|
||||
export { useCollectionPresetsStore };
|
||||
export default useCollectionPresetsStore;
|
||||
42
src/stores/collection-presets/types.ts
Normal file
42
src/stores/collection-presets/types.ts
Normal file
@@ -0,0 +1,42 @@
|
||||
export type FilterOperator =
|
||||
| 'eq'
|
||||
| 'neq'
|
||||
| 'lt'
|
||||
| 'lte'
|
||||
| 'gt'
|
||||
| 'gte'
|
||||
| 'in'
|
||||
| 'nin'
|
||||
| 'null'
|
||||
| 'nnull'
|
||||
| 'contains'
|
||||
| 'ncontains'
|
||||
| 'rlike'
|
||||
| 'nrlike'
|
||||
| 'between'
|
||||
| 'nbetween'
|
||||
| 'empty'
|
||||
| 'nempty'
|
||||
| 'all'
|
||||
| 'has';
|
||||
|
||||
export type Filter = {
|
||||
field: string;
|
||||
operator: FilterOperator;
|
||||
value: string;
|
||||
};
|
||||
|
||||
export type CollectionPreset = {
|
||||
id: number;
|
||||
title: string | null;
|
||||
user: number | null;
|
||||
role: number | null;
|
||||
collection: string;
|
||||
search_query: null;
|
||||
filters: Filter[] | null;
|
||||
view_type: string;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
view_query: { [view_type: string]: any } | null;
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
view_options: { [view_type: string]: any } | null;
|
||||
};
|
||||
@@ -8,7 +8,7 @@ import VueI18n from 'vue-i18n';
|
||||
import formatTitle from '@directus/format-title';
|
||||
|
||||
export const useCollectionsStore = createStore({
|
||||
id: 'collections',
|
||||
id: 'collectionsStore',
|
||||
state: () => ({
|
||||
collections: [] as Collection[]
|
||||
}),
|
||||
|
||||
@@ -8,7 +8,7 @@ import { i18n } from '@/lang';
|
||||
import formatTitle from '@directus/format-title';
|
||||
|
||||
export const useFieldsStore = createStore({
|
||||
id: 'fields',
|
||||
id: 'fieldsStore',
|
||||
state: () => ({
|
||||
fields: [] as Field[]
|
||||
}),
|
||||
|
||||
@@ -8,7 +8,7 @@ type LoadingError = null | {
|
||||
};
|
||||
|
||||
export const useProjectsStore = createStore({
|
||||
id: 'projects',
|
||||
id: 'projectsStore',
|
||||
state: () => ({
|
||||
needsInstall: false,
|
||||
error: null as LoadingError,
|
||||
|
||||
@@ -2,7 +2,7 @@ import { createStore } from 'pinia';
|
||||
import nanoid from 'nanoid';
|
||||
|
||||
export const useRequestsStore = createStore({
|
||||
id: 'requests',
|
||||
id: 'requestsStore',
|
||||
state: () => ({
|
||||
queue: [] as string[]
|
||||
}),
|
||||
|
||||
@@ -5,7 +5,7 @@ import api from '@/api';
|
||||
import { User } from './types';
|
||||
|
||||
export const useUserStore = createStore({
|
||||
id: 'user',
|
||||
id: 'userStore',
|
||||
state: () => ({
|
||||
currentUser: null as User | null
|
||||
}),
|
||||
|
||||
Reference in New Issue
Block a user