mirror of
https://github.com/directus/directus.git
synced 2026-02-16 03:15:05 -05:00
Add options for create/select (#5301)
* Hide add/select based on permissions Fixes #4874 * Add enable create/select options to interfaces
This commit is contained in:
@@ -39,8 +39,8 @@
|
||||
</v-list>
|
||||
|
||||
<div class="actions" v-if="!disabled">
|
||||
<v-button class="new" @click="editModalActive = true">{{ $t('create_new') }}</v-button>
|
||||
<v-button class="existing" @click="selectModalActive = true">
|
||||
<v-button v-if="enableCreate && createAllowed" @click="editModalActive = true">{{ $t('create_new') }}</v-button>
|
||||
<v-button v-if="enableSelect && selectAllowed" @click="selectModalActive = true">
|
||||
{{ $t('add_existing') }}
|
||||
</v-button>
|
||||
</div>
|
||||
@@ -85,6 +85,7 @@ import useSelection from './use-selection';
|
||||
import useSort from './use-sort';
|
||||
import { getFieldsFromTemplate } from '@/utils/get-fields-from-template';
|
||||
import adjustFieldsForDisplays from '@/utils/adjust-fields-for-displays';
|
||||
import { usePermissionsStore, useUserStore } from '@/stores';
|
||||
|
||||
export default defineComponent({
|
||||
components: { DrawerItem, DrawerCollection, Draggable },
|
||||
@@ -113,8 +114,19 @@ export default defineComponent({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
enableCreate: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
enableSelect: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const permissionsStore = usePermissionsStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const { value, collection, field } = toRefs(props);
|
||||
|
||||
const { junction, junctionCollection, relation, relationCollection, relationInfo } = useRelation(collection, field);
|
||||
@@ -173,9 +185,10 @@ export default defineComponent({
|
||||
} = useEdit(value, relationInfo, emitter);
|
||||
|
||||
const { stageSelection, selectModalActive, selectionFilters } = useSelection(value, items, relationInfo, emitter);
|
||||
|
||||
const { sort, sortItems, sortedItems } = useSort(relationInfo, fields, items, emitter);
|
||||
|
||||
const { createAllowed, selectAllowed } = usePermissions();
|
||||
|
||||
return {
|
||||
junction,
|
||||
relation,
|
||||
@@ -201,11 +214,46 @@ export default defineComponent({
|
||||
sortItems,
|
||||
sortedItems,
|
||||
templateWithDefaults,
|
||||
createAllowed,
|
||||
selectAllowed,
|
||||
};
|
||||
|
||||
function emitter(newVal: any[] | null) {
|
||||
emit('input', newVal);
|
||||
}
|
||||
|
||||
function usePermissions() {
|
||||
const createAllowed = computed(() => {
|
||||
const admin = userStore.state?.currentUser?.role.admin_access === true;
|
||||
if (admin) return true;
|
||||
|
||||
const hasJunctionPermissions = !!permissionsStore.state.permissions.find(
|
||||
(permission) =>
|
||||
permission.action === 'create' && permission.collection === junctionCollection.value.collection
|
||||
);
|
||||
|
||||
const hasRelatedPermissions = !!permissionsStore.state.permissions.find(
|
||||
(permission) =>
|
||||
permission.action === 'create' && permission.collection === relationCollection.value.collection
|
||||
);
|
||||
|
||||
return hasJunctionPermissions && hasRelatedPermissions;
|
||||
});
|
||||
|
||||
const selectAllowed = computed(() => {
|
||||
const admin = userStore.state?.currentUser?.role.admin_access === true;
|
||||
if (admin) return true;
|
||||
|
||||
const hasJunctionPermissions = !!permissionsStore.state.permissions.find(
|
||||
(permission) =>
|
||||
permission.action === 'create' && permission.collection === junctionCollection.value.collection
|
||||
);
|
||||
|
||||
return hasJunctionPermissions;
|
||||
});
|
||||
|
||||
return { createAllowed, selectAllowed };
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -217,10 +265,10 @@ export default defineComponent({
|
||||
|
||||
.actions {
|
||||
margin-top: 12px;
|
||||
}
|
||||
|
||||
.existing {
|
||||
margin-left: 12px;
|
||||
.v-button + .v-button {
|
||||
margin-left: 12px;
|
||||
}
|
||||
}
|
||||
|
||||
.deselect {
|
||||
|
||||
@@ -15,6 +15,16 @@
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="field half-left">
|
||||
<p class="type-label">{{ $t('creating_items') }}</p>
|
||||
<v-checkbox block :label="$t('enable_create_button')" v-model="enableCreate" />
|
||||
</div>
|
||||
|
||||
<div class="field half-right">
|
||||
<p class="type-label">{{ $t('selecting_items') }}</p>
|
||||
<v-checkbox block :label="$t('enable_select_button')" v-model="enableSelect" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -65,6 +75,30 @@ export default defineComponent({
|
||||
},
|
||||
});
|
||||
|
||||
const enableCreate = computed({
|
||||
get() {
|
||||
return props.value?.enableCreate ?? true;
|
||||
},
|
||||
set(val: boolean) {
|
||||
emit('input', {
|
||||
...(props.value || {}),
|
||||
enableCreate: val,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const enableSelect = computed({
|
||||
get() {
|
||||
return props.value?.enableSelect ?? true;
|
||||
},
|
||||
set(val: boolean) {
|
||||
emit('input', {
|
||||
...(props.value || {}),
|
||||
enableSelect: val,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const junctionCollection = computed(() => {
|
||||
if (!props.fieldData || !props.relations || props.relations.length === 0) return null;
|
||||
const { field } = props.fieldData;
|
||||
@@ -80,7 +114,7 @@ export default defineComponent({
|
||||
return collectionsStore.getCollection(junctionCollection.value);
|
||||
});
|
||||
|
||||
return { template, junctionCollection, junctionCollectionInfo };
|
||||
return { template, enableCreate, enableSelect, junctionCollection, junctionCollectionInfo };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -28,19 +28,22 @@
|
||||
v-for="item in sortedItems"
|
||||
:key="item.id"
|
||||
block
|
||||
:disabled="disabled || updateAllowed === false"
|
||||
@click="editItem(item)"
|
||||
>
|
||||
<v-icon v-if="relation.sort_field" name="drag_handle" class="drag-handle" left @click.stop="() => {}" />
|
||||
<render-template :collection="relation.many_collection" :item="item" :template="templateWithDefaults" />
|
||||
<div class="spacer" />
|
||||
<v-icon v-if="!disabled" name="close" @click.stop="deleteItem(item)" />
|
||||
<v-icon v-if="!disabled && updateAllowed" name="close" @click.stop="deleteItem(item)" />
|
||||
</v-list-item>
|
||||
</draggable>
|
||||
</v-list>
|
||||
|
||||
<div class="actions" v-if="!disabled">
|
||||
<v-button class="new" @click="currentlyEditing = '+'">{{ $t('create_new') }}</v-button>
|
||||
<v-button class="existing" @click="selectModalActive = true">
|
||||
<v-button v-if="enableCreate && createAllowed && updateAllowed" @click="currentlyEditing = '+'">
|
||||
{{ $t('create_new') }}
|
||||
</v-button>
|
||||
<v-button v-if="enableSelect && updateAllowed" @click="selectModalActive = true">
|
||||
{{ $t('add_existing') }}
|
||||
</v-button>
|
||||
</div>
|
||||
@@ -72,7 +75,7 @@
|
||||
import { defineComponent, ref, computed, watch, PropType } from '@vue/composition-api';
|
||||
import api from '@/api';
|
||||
import useCollection from '@/composables/use-collection';
|
||||
import { useCollectionsStore, useRelationsStore, useFieldsStore } from '@/stores/';
|
||||
import { useCollectionsStore, useRelationsStore, useFieldsStore, usePermissionsStore, useUserStore } from '@/stores/';
|
||||
import DrawerItem from '@/views/private/components/drawer-item';
|
||||
import DrawerCollection from '@/views/private/components/drawer-collection';
|
||||
import { Filter, Field } from '@/types';
|
||||
@@ -110,11 +113,21 @@ export default defineComponent({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
enableCreate: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
enableSelect: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const relationsStore = useRelationsStore();
|
||||
const collectionsStore = useCollectionsStore();
|
||||
const fieldsStore = useFieldsStore();
|
||||
const permissionsStore = usePermissionsStore();
|
||||
const userStore = useUserStore();
|
||||
|
||||
const { relation, relatedCollection, relatedPrimaryKeyField } = useRelation();
|
||||
|
||||
@@ -131,6 +144,8 @@ export default defineComponent({
|
||||
const { stageSelection, selectModalActive, selectionFilters } = useSelection();
|
||||
const { sort, sortItems, sortedItems } = useSort();
|
||||
|
||||
const { createAllowed, updateAllowed } = usePermissions();
|
||||
|
||||
return {
|
||||
relation,
|
||||
loading,
|
||||
@@ -151,6 +166,8 @@ export default defineComponent({
|
||||
get,
|
||||
getItemFromIndex,
|
||||
templateWithDefaults,
|
||||
createAllowed,
|
||||
updateAllowed,
|
||||
};
|
||||
|
||||
function getItemFromIndex(index: number) {
|
||||
@@ -426,6 +443,28 @@ export default defineComponent({
|
||||
const fields = fieldsStore.getFieldsForCollection(relatedCollection.value.collection);
|
||||
return fields.slice(0, 3).map((field: Field) => field.field);
|
||||
}
|
||||
|
||||
function usePermissions() {
|
||||
const createAllowed = computed(() => {
|
||||
const admin = userStore.state?.currentUser?.role.admin_access === true;
|
||||
if (admin) return true;
|
||||
|
||||
return !!permissionsStore.state.permissions.find(
|
||||
(permission) => permission.action === 'create' && permission.collection === relatedCollection.value.collection
|
||||
);
|
||||
});
|
||||
|
||||
const updateAllowed = computed(() => {
|
||||
const admin = userStore.state?.currentUser?.role.admin_access === true;
|
||||
if (admin) return true;
|
||||
|
||||
return !!permissionsStore.state.permissions.find(
|
||||
(permission) => permission.action === 'update' && permission.collection === relatedCollection.value.collection
|
||||
);
|
||||
});
|
||||
|
||||
return { createAllowed, updateAllowed };
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -437,10 +476,10 @@ export default defineComponent({
|
||||
|
||||
.actions {
|
||||
margin-top: 8px;
|
||||
}
|
||||
|
||||
.existing {
|
||||
margin-left: 8px;
|
||||
.v-button + .v-button {
|
||||
margin-left: 8px;
|
||||
}
|
||||
}
|
||||
|
||||
.deselect {
|
||||
|
||||
@@ -15,6 +15,16 @@
|
||||
"
|
||||
/>
|
||||
</div>
|
||||
|
||||
<div class="field half-left">
|
||||
<p class="type-label">{{ $t('creating_items') }}</p>
|
||||
<v-checkbox block :label="$t('enable_create_button')" v-model="enableCreate" />
|
||||
</div>
|
||||
|
||||
<div class="field half-right">
|
||||
<p class="type-label">{{ $t('selecting_items') }}</p>
|
||||
<v-checkbox block :label="$t('enable_select_button')" v-model="enableSelect" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -65,6 +75,30 @@ export default defineComponent({
|
||||
},
|
||||
});
|
||||
|
||||
const enableCreate = computed({
|
||||
get() {
|
||||
return props.value?.enableCreate ?? true;
|
||||
},
|
||||
set(val: boolean) {
|
||||
emit('input', {
|
||||
...(props.value || {}),
|
||||
enableCreate: val,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const enableSelect = computed({
|
||||
get() {
|
||||
return props.value?.enableSelect ?? true;
|
||||
},
|
||||
set(val: boolean) {
|
||||
emit('input', {
|
||||
...(props.value || {}),
|
||||
enableSelect: val,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const relatedCollection = computed(() => {
|
||||
if (!props.fieldData || !props.relations || props.relations.length === 0) return null;
|
||||
const { field } = props.fieldData;
|
||||
@@ -79,7 +113,7 @@ export default defineComponent({
|
||||
return collectionsStore.getCollection(relatedCollection.value);
|
||||
});
|
||||
|
||||
return { template, relatedCollection, relatedCollectionInfo };
|
||||
return { template, enableCreate, enableSelect, relatedCollection, relatedCollectionInfo };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -7,6 +7,16 @@
|
||||
<p class="type-label">{{ $t('interfaces.many-to-one.display_template') }}</p>
|
||||
<v-field-template :collection="collection" v-model="template" :depth="1"></v-field-template>
|
||||
</div>
|
||||
|
||||
<div class="field half-left">
|
||||
<p class="type-label">{{ $t('creating_items') }}</p>
|
||||
<v-checkbox block :label="$t('enable_create_button')" v-model="enableCreate" />
|
||||
</div>
|
||||
|
||||
<div class="field half-right">
|
||||
<p class="type-label">{{ $t('selecting_items') }}</p>
|
||||
<v-checkbox block :label="$t('enable_select_button')" v-model="enableSelect" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
@@ -46,7 +56,31 @@ export default defineComponent({
|
||||
},
|
||||
});
|
||||
|
||||
return { template };
|
||||
const enableCreate = computed({
|
||||
get() {
|
||||
return props.value?.enableCreate ?? true;
|
||||
},
|
||||
set(val: boolean) {
|
||||
emit('input', {
|
||||
...(props.value || {}),
|
||||
enableCreate: val,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
const enableSelect = computed({
|
||||
get() {
|
||||
return props.value?.enableSelect ?? true;
|
||||
},
|
||||
set(val: boolean) {
|
||||
emit('input', {
|
||||
...(props.value || {}),
|
||||
enableSelect: val,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
return { template, enableCreate, enableSelect };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
|
||||
@@ -18,8 +18,8 @@
|
||||
/>
|
||||
|
||||
<div class="actions" v-if="!disabled">
|
||||
<v-button class="new" @click="addNewActive = true">{{ $t('create_new') }}</v-button>
|
||||
<v-button class="existing" @click="selectDrawer = true">
|
||||
<v-button v-if="enableCreate" @click="addNewActive = true">{{ $t('create_new') }}</v-button>
|
||||
<v-button v-if="enableSelect" @click="selectDrawer = true">
|
||||
{{ $t('add_existing') }}
|
||||
</v-button>
|
||||
</div>
|
||||
@@ -88,6 +88,14 @@ export default defineComponent({
|
||||
type: [String, Number],
|
||||
default: undefined,
|
||||
},
|
||||
enableCreate: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
enableSelect: {
|
||||
type: Boolean,
|
||||
default: true,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const relationsStore = useRelationsStore();
|
||||
|
||||
Reference in New Issue
Block a user