mirror of
https://github.com/directus/directus.git
synced 2026-04-03 03:00:39 -04:00
Stores (#417)
* Fix store identifier * Add relations store * Remove rolesStore in favor of composition for user nav * Fix tests
This commit is contained in:
@@ -3,6 +3,8 @@ import VueCompositionAPI from '@vue/composition-api';
|
||||
import { useAppStore } from '@/stores/app';
|
||||
import { useStores, hydrate, dehydrate } from './hydrate';
|
||||
|
||||
jest.mock('@/api');
|
||||
|
||||
describe('Stores / App', () => {
|
||||
beforeAll(() => {
|
||||
Vue.use(VueCompositionAPI);
|
||||
|
||||
@@ -8,7 +8,7 @@ import { useSettingsStore } from '@/stores/settings/';
|
||||
import { useProjectsStore } from '@/stores/projects/';
|
||||
import { useLatencyStore } from '@/stores/latency';
|
||||
import { usePermissionsStore } from '@/stores/permissions';
|
||||
import { useRolesStore } from '@/stores/roles';
|
||||
import { useRelationsStore } from '@/stores/relations';
|
||||
|
||||
type GenericStore = {
|
||||
id: string;
|
||||
@@ -29,7 +29,7 @@ export function useStores(
|
||||
useProjectsStore,
|
||||
useLatencyStore,
|
||||
usePermissionsStore,
|
||||
useRolesStore,
|
||||
useRelationsStore,
|
||||
]
|
||||
) {
|
||||
return stores.map((useStore) => useStore()) as GenericStore[];
|
||||
|
||||
@@ -5,7 +5,13 @@
|
||||
<v-list-item-content>{{ $t('all_users') }}</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-divider />
|
||||
<v-divider v-if="(roles && roles.length > 0) || loading" />
|
||||
|
||||
<template v-if="loading">
|
||||
<v-list-item v-for="n in 4" :key="n">
|
||||
<v-skeleton-loader type="list-item-icon" />
|
||||
</v-list-item>
|
||||
</template>
|
||||
|
||||
<v-list-item v-for="{ name, id } in roles" :key="id" :to="`/${project}/users/${id}`">
|
||||
<v-list-item-icon><v-icon name="people" /></v-list-item-icon>
|
||||
@@ -16,15 +22,15 @@
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent } from '@vue/composition-api';
|
||||
import useRolesStore from '@/stores/roles';
|
||||
import useProjectsStore from '@/stores/projects';
|
||||
import useNavigation from '../../compositions/use-navigation';
|
||||
|
||||
export default defineComponent({
|
||||
setup() {
|
||||
const rolesStore = useRolesStore();
|
||||
const projectsStore = useProjectsStore();
|
||||
const { roles, loading } = useNavigation();
|
||||
|
||||
return { roles: rolesStore.state.roles, project: projectsStore.state.currentProjectKey };
|
||||
return { roles, loading, project: projectsStore.state.currentProjectKey };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
34
src/modules/users/compositions/use-navigation.ts
Normal file
34
src/modules/users/compositions/use-navigation.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { ref, Ref } from '@vue/composition-api';
|
||||
import useProjectsStore from '@/stores/projects';
|
||||
import api from '@/api';
|
||||
import { Role } from '@/stores/user/types';
|
||||
|
||||
let roles: Ref<Role[] | null> | null = null;
|
||||
let loading: Ref<boolean> | null = null;
|
||||
|
||||
export default function useNavigation() {
|
||||
if (roles === null) {
|
||||
roles = ref<Role[]>(null);
|
||||
}
|
||||
|
||||
if (loading === null) {
|
||||
loading = ref(false);
|
||||
}
|
||||
|
||||
if (roles.value === null && loading?.value === false) {
|
||||
fetchRoles();
|
||||
}
|
||||
|
||||
return { roles, loading };
|
||||
|
||||
async function fetchRoles() {
|
||||
if (!loading || !roles) return;
|
||||
loading.value = true;
|
||||
const projectsStore = useProjectsStore();
|
||||
const currentProjectKey = projectsStore.state.currentProjectKey;
|
||||
|
||||
const rolesResponse = await api.get(`/${currentProjectKey}/roles`);
|
||||
roles.value = rolesResponse.data.data;
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
4
src/stores/relations/index.ts
Normal file
4
src/stores/relations/index.ts
Normal file
@@ -0,0 +1,4 @@
|
||||
import { useRelationsStore } from './relations';
|
||||
|
||||
export { useRelationsStore };
|
||||
export default useRelationsStore;
|
||||
32
src/stores/relations/relations.ts
Normal file
32
src/stores/relations/relations.ts
Normal file
@@ -0,0 +1,32 @@
|
||||
import { createStore } from 'pinia';
|
||||
import { Relation } from './types';
|
||||
import useProjectsStore from '@/stores/projects';
|
||||
import api from '@/api';
|
||||
|
||||
export const useRelationsStore = createStore({
|
||||
id: 'relationsStore',
|
||||
state: () => ({
|
||||
relations: [] as Relation[],
|
||||
}),
|
||||
actions: {
|
||||
async hydrate() {
|
||||
const projectsStore = useProjectsStore();
|
||||
const currentProjectKey = projectsStore.state.currentProjectKey;
|
||||
|
||||
const response = await api.get(`/${currentProjectKey}/relations`);
|
||||
|
||||
this.state.relations = response.data.data;
|
||||
},
|
||||
async dehydrate() {
|
||||
this.reset();
|
||||
},
|
||||
getRelationForField(collection: string, field: string) {
|
||||
return this.state.relations.filter((relation) => {
|
||||
return (
|
||||
(relation.collection_many === collection && relation.field_many === field) ||
|
||||
(relation.collection_one === collection && relation.field_one === field)
|
||||
);
|
||||
});
|
||||
},
|
||||
},
|
||||
});
|
||||
8
src/stores/relations/types.ts
Normal file
8
src/stores/relations/types.ts
Normal file
@@ -0,0 +1,8 @@
|
||||
export type Relation = {
|
||||
id: number;
|
||||
collection_many: string;
|
||||
field_many: string;
|
||||
collection_one: string;
|
||||
field_one: null | string;
|
||||
junction_field: null | string;
|
||||
};
|
||||
@@ -1,4 +0,0 @@
|
||||
import { useRolesStore } from './roles';
|
||||
|
||||
export { useRolesStore };
|
||||
export default useRolesStore;
|
||||
@@ -1,25 +0,0 @@
|
||||
import { createStore } from 'pinia';
|
||||
import api from '@/api';
|
||||
import { useProjectsStore } from '@/stores/projects';
|
||||
|
||||
import { Role } from './types';
|
||||
|
||||
export const useRolesStore = createStore({
|
||||
id: 'rolesStore',
|
||||
state: () => ({
|
||||
roles: [] as Role[],
|
||||
}),
|
||||
actions: {
|
||||
async hydrate() {
|
||||
const projectsStore = useProjectsStore();
|
||||
const currentProjectKey = projectsStore.state.currentProjectKey;
|
||||
|
||||
const rolesResponse = await api.get(`/${currentProjectKey}/roles`);
|
||||
|
||||
this.state.roles = rolesResponse.data.data;
|
||||
},
|
||||
async dehydrate() {
|
||||
this.reset();
|
||||
},
|
||||
},
|
||||
});
|
||||
@@ -1,10 +0,0 @@
|
||||
export type Role = {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
collection_listing: null;
|
||||
module_listing: null;
|
||||
enforce_2fa: null | boolean;
|
||||
external_id: null | string;
|
||||
ip_whitelist: string[];
|
||||
};
|
||||
@@ -15,7 +15,7 @@ import { i18n } from '@/lang';
|
||||
*/
|
||||
|
||||
export const useSettingsStore = createStore({
|
||||
id: 'settings',
|
||||
id: 'settingsStore',
|
||||
state: () => ({
|
||||
settings: [] as Setting[],
|
||||
}),
|
||||
|
||||
@@ -1,4 +1,13 @@
|
||||
import { Role } from '@/stores/roles/types';
|
||||
export type Role = {
|
||||
id: number;
|
||||
name: string;
|
||||
description: string;
|
||||
collection_listing: null;
|
||||
module_listing: null;
|
||||
enforce_2fa: null | boolean;
|
||||
external_id: null | string;
|
||||
ip_whitelist: string[];
|
||||
};
|
||||
|
||||
export type Avatar = {
|
||||
data: {
|
||||
|
||||
Reference in New Issue
Block a user