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:
Rijk van Zanten
2020-03-20 22:00:39 -04:00
committed by GitHub
parent 7bbe8fe194
commit 6e6ba35ce9
11 changed files with 277 additions and 7 deletions

View File

@@ -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[];
}

View File

@@ -1,7 +1,7 @@
import { createStore } from 'pinia';
export const useAppStore = createStore({
id: 'app',
id: 'appStore',
state: () => ({
hydrated: false,
hydrating: false,

View 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');
});
});
});
});

View 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;
});
}
}
});

View File

@@ -0,0 +1,4 @@
import { useCollectionPresetsStore } from './collection-presets';
export { useCollectionPresetsStore };
export default useCollectionPresetsStore;

View 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;
};

View File

@@ -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[]
}),

View File

@@ -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[]
}),

View File

@@ -8,7 +8,7 @@ type LoadingError = null | {
};
export const useProjectsStore = createStore({
id: 'projects',
id: 'projectsStore',
state: () => ({
needsInstall: false,
error: null as LoadingError,

View File

@@ -2,7 +2,7 @@ import { createStore } from 'pinia';
import nanoid from 'nanoid';
export const useRequestsStore = createStore({
id: 'requests',
id: 'requestsStore',
state: () => ({
queue: [] as string[]
}),

View File

@@ -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
}),