mirror of
https://github.com/directus/directus.git
synced 2026-01-23 12:48:10 -05:00
Add custom interface for presets (#4870)
* add custom interface for presets * add defaults and change naming * Fix type issue, put current selection on top * Fetch email as name fallback * Opinionated code changes Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
This commit is contained in:
11
app/src/interfaces/_system/scope/index.ts
Normal file
11
app/src/interfaces/_system/scope/index.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
import { defineInterface } from '@/interfaces/define';
|
||||
import Scope from './scope.vue';
|
||||
|
||||
export default defineInterface({
|
||||
id: 'scope',
|
||||
name: '$t:scope',
|
||||
icon: 'arrow_drop_down_circle',
|
||||
component: Scope,
|
||||
types: ['string'],
|
||||
options: [],
|
||||
});
|
||||
125
app/src/interfaces/_system/scope/scope.vue
Normal file
125
app/src/interfaces/_system/scope/scope.vue
Normal file
@@ -0,0 +1,125 @@
|
||||
<template>
|
||||
<div>
|
||||
<v-skeleton-loader v-if="loading"></v-skeleton-loader>
|
||||
<v-select v-else :value="value" @input="onSelect" :items="options" />
|
||||
<drawer-collection
|
||||
v-if="collection !== null"
|
||||
:active="collection !== null"
|
||||
@update:active="collection = null"
|
||||
@input="onSelectItem"
|
||||
:collection="collection"
|
||||
/>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { computed, defineComponent, ref, watch } from '@vue/composition-api';
|
||||
import i18n from '@/lang';
|
||||
import DrawerCollection from '@/views/private/components/drawer-collection';
|
||||
import api from '@/api';
|
||||
import { userName } from '@/utils/user-name';
|
||||
|
||||
export default defineComponent({
|
||||
components: {
|
||||
DrawerCollection,
|
||||
},
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const collection = ref<string | null>(null);
|
||||
const itemName = ref<string | null>(null);
|
||||
const loading = ref(false);
|
||||
|
||||
const isItem = computed(
|
||||
() => props.value !== null && (props.value.startsWith('role_') || props.value.startsWith('user_'))
|
||||
);
|
||||
|
||||
watch(() => props.value, loadItemName);
|
||||
|
||||
loadItemName();
|
||||
|
||||
const options = computed(() => {
|
||||
let options: any[] = [
|
||||
{
|
||||
text: i18n.t('global') + ': ' + i18n.t('all_users'),
|
||||
value: 'all',
|
||||
},
|
||||
{
|
||||
text: i18n.t('user') + ': ' + i18n.t('select'),
|
||||
value: 'directus_users',
|
||||
},
|
||||
{
|
||||
text: i18n.t('role') + ': ' + i18n.t('select'),
|
||||
value: 'directus_roles',
|
||||
},
|
||||
];
|
||||
|
||||
if (isItem.value) {
|
||||
const [type, id] = props.value.split('_');
|
||||
|
||||
options = [
|
||||
{
|
||||
text: i18n.t(type) + ': ' + (itemName.value || id),
|
||||
value: props.value,
|
||||
},
|
||||
{ divider: true },
|
||||
...options,
|
||||
];
|
||||
}
|
||||
|
||||
return options;
|
||||
});
|
||||
|
||||
return { options, collection, onSelect, onSelectItem, loading };
|
||||
|
||||
function onSelect(value: string) {
|
||||
if (value === 'all') {
|
||||
collection.value = null;
|
||||
return emit('input', 'all');
|
||||
}
|
||||
|
||||
collection.value = value;
|
||||
}
|
||||
|
||||
function onSelectItem(value: string[]) {
|
||||
if (collection.value === 'directus_users') return emit('input', 'user_' + value[0]);
|
||||
if (collection.value === 'directus_roles') return emit('input', 'role_' + value[0]);
|
||||
}
|
||||
|
||||
async function loadItemName() {
|
||||
if (!isItem.value) {
|
||||
itemName.value = null;
|
||||
return;
|
||||
}
|
||||
|
||||
loading.value = true;
|
||||
|
||||
const [endpoint, id] = props.value.split('_');
|
||||
|
||||
if (endpoint === 'role') {
|
||||
const result = await api.get('/roles/' + id, {
|
||||
params: {
|
||||
fields: ['id', 'name'],
|
||||
},
|
||||
});
|
||||
|
||||
itemName.value = result.data.data.name;
|
||||
} else if (endpoint === 'user') {
|
||||
const result = await api.get('/users/' + id, {
|
||||
params: {
|
||||
fields: ['id', 'first_name', 'last_name', 'email'],
|
||||
},
|
||||
});
|
||||
|
||||
itemName.value = userName(result.data.data);
|
||||
}
|
||||
|
||||
loading.value = false;
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -603,10 +603,11 @@ settings_project: Project Settings
|
||||
settings_webhooks: Webhooks
|
||||
settings_presets: Presets & Bookmarks
|
||||
scope: Scope
|
||||
select: Select...
|
||||
layout: Layout
|
||||
tree_view: Tree View
|
||||
changes_are_permanent: Changes are permanent
|
||||
preset_name_placeholder: Name of bookmark...
|
||||
preset_name_placeholder: Serves as default when empty...
|
||||
preset_search_placeholder: Search query...
|
||||
editing_preset: Editing Preset
|
||||
layout_preview: Layout Preview
|
||||
|
||||
@@ -160,9 +160,7 @@ export default defineComponent({
|
||||
|
||||
const isNew = computed(() => props.id === '+');
|
||||
|
||||
const { loading: usersLoading, users } = useUsers();
|
||||
const { loading: rolesLoading, roles } = useRoles();
|
||||
const { loading: presetLoading, preset } = usePreset();
|
||||
const { loading, preset } = usePreset();
|
||||
const { fields } = useForm();
|
||||
const {
|
||||
edits,
|
||||
@@ -177,8 +175,6 @@ export default defineComponent({
|
||||
const { save, saving } = useSave();
|
||||
const { deleting, deleteAndQuit, confirmDelete } = useDelete();
|
||||
|
||||
const loading = computed(() => usersLoading.value || presetLoading.value || rolesLoading.value);
|
||||
|
||||
return {
|
||||
backLink,
|
||||
loading,
|
||||
@@ -275,8 +271,9 @@ export default defineComponent({
|
||||
const hasEdits = computed(() => Object.keys(edits.value).length > 0);
|
||||
|
||||
const initialValues = computed(() => {
|
||||
if (isNew.value === true) return {};
|
||||
if (preset.value === null) return {};
|
||||
const defaultValues = { scope: 'all', layout: 'tabular' };
|
||||
if (isNew.value === true) return defaultValues;
|
||||
if (preset.value === null) return defaultValues;
|
||||
|
||||
let scope = 'all';
|
||||
|
||||
@@ -400,85 +397,7 @@ export default defineComponent({
|
||||
return { backLink };
|
||||
}
|
||||
|
||||
function useUsers() {
|
||||
const loading = ref(false);
|
||||
const users = ref<User[] | null>(null);
|
||||
|
||||
fetchUsers();
|
||||
|
||||
return { loading, users };
|
||||
|
||||
async function fetchUsers() {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await api.get(`/users`, {
|
||||
params: {
|
||||
fields: ['email', 'first_name', 'last_name', 'id'],
|
||||
},
|
||||
});
|
||||
|
||||
users.value = response.data.data.map((user: any) => ({
|
||||
name: userName(user),
|
||||
id: user.id,
|
||||
}));
|
||||
} catch (err) {
|
||||
unexpectedError(err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function useRoles() {
|
||||
const loading = ref(false);
|
||||
const roles = ref<Role[] | null>(null);
|
||||
|
||||
fetchRoles();
|
||||
|
||||
return { loading, roles };
|
||||
|
||||
async function fetchRoles() {
|
||||
loading.value = true;
|
||||
|
||||
try {
|
||||
const response = await api.get(`/roles`, {
|
||||
params: {
|
||||
fields: ['name', 'id'],
|
||||
},
|
||||
});
|
||||
|
||||
roles.value = response.data.data;
|
||||
} catch (err) {
|
||||
unexpectedError(err);
|
||||
} finally {
|
||||
loading.value = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function useForm() {
|
||||
const scopeChoices = computed(() => {
|
||||
if (usersLoading.value || rolesLoading.value) return [];
|
||||
|
||||
const options = [
|
||||
{
|
||||
text: i18n.t('global') + ': ' + i18n.t('all'),
|
||||
value: 'all',
|
||||
},
|
||||
];
|
||||
|
||||
roles.value?.forEach((role) => {
|
||||
options.push({ text: i18n.t('role') + ': ' + role.name, value: `role_${role.id}` });
|
||||
});
|
||||
|
||||
users.value?.forEach((user) => {
|
||||
options.push({ text: i18n.t('user') + ': ' + user.name, value: `user_${user.id}` });
|
||||
});
|
||||
|
||||
return options;
|
||||
});
|
||||
|
||||
const systemCollectionWhiteList = ['directus_users', 'directus_files', 'directus_activity'];
|
||||
|
||||
const fields = computed(() => [
|
||||
@@ -508,10 +427,7 @@ export default defineComponent({
|
||||
name: i18n.t('scope'),
|
||||
type: 'string',
|
||||
meta: {
|
||||
interface: 'dropdown',
|
||||
options: {
|
||||
choices: scopeChoices.value,
|
||||
},
|
||||
interface: 'scope',
|
||||
width: 'half',
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user