mirror of
https://github.com/directus/directus.git
synced 2026-01-28 00:57:55 -05:00
Add view type switch (#424)
* Manage view_type through collection preset composition
* Move view type translation
* Add layout drawer detail component
* Use different icon for tabular
* Render view as section in browse sidebar
* Fix sticky header in table
* Sort return statement values 🤓
* Use viewtype picker on users
* Use layout picker on files
* Default to tabular view when invalid is set
* Render view type dynamically based on setting
This commit is contained in:
@@ -289,7 +289,7 @@ export default defineComponent({
|
||||
padding-right: 0;
|
||||
}
|
||||
|
||||
.fixed th {
|
||||
.fixed {
|
||||
position: sticky;
|
||||
top: var(--v-table-sticky-offset-top);
|
||||
z-index: 2;
|
||||
|
||||
@@ -341,6 +341,10 @@ export default defineComponent({
|
||||
}
|
||||
|
||||
::v-deep {
|
||||
thead {
|
||||
display: contents;
|
||||
}
|
||||
|
||||
tr {
|
||||
display: grid;
|
||||
grid-template-columns: var(--grid-columns);
|
||||
|
||||
@@ -50,6 +50,19 @@ export function useCollectionPreset(collection: Ref<string>) {
|
||||
},
|
||||
});
|
||||
|
||||
const viewType = computed({
|
||||
get() {
|
||||
return localPreset.value.view_type || 'tabular';
|
||||
},
|
||||
set(val) {
|
||||
localPreset.value = {
|
||||
...localPreset.value,
|
||||
view_type: val,
|
||||
};
|
||||
savePreset(localPreset.value);
|
||||
},
|
||||
});
|
||||
|
||||
const filters = computed<Filter[]>({
|
||||
get() {
|
||||
return localPreset.value.filters || [];
|
||||
@@ -63,5 +76,5 @@ export function useCollectionPreset(collection: Ref<string>) {
|
||||
},
|
||||
});
|
||||
|
||||
return { viewOptions, viewQuery, filters };
|
||||
return { viewType, viewOptions, viewQuery, filters };
|
||||
}
|
||||
|
||||
@@ -222,6 +222,7 @@
|
||||
"upload_file_indeterminate": "Uploading File | Uploading files {done}/{total}",
|
||||
"upload_file_success": "File Uploaded | {count} Files Uploaded",
|
||||
"upload_file_failed": "Couldn't Upload File | Couldn't Upload Files",
|
||||
"view_type": "View As...",
|
||||
|
||||
"about_directus": "About Directus",
|
||||
"activity_log": "Activity Log",
|
||||
@@ -677,7 +678,6 @@
|
||||
"values": "Values",
|
||||
"version": "Version",
|
||||
"version_and_updates": "Version and Updates",
|
||||
"view_type": "View As...",
|
||||
"visible_all_users": "Visible for all users",
|
||||
"webhook_count": "No Webhooks | 1 Webhook | {count} Webhooks",
|
||||
"weeks": {
|
||||
|
||||
@@ -4,6 +4,6 @@ import TabularLayout from './tabular.vue';
|
||||
export default defineLayout(({ i18n }) => ({
|
||||
id: 'tabular',
|
||||
name: i18n.t('layouts.tabular.tabular'),
|
||||
icon: 'table',
|
||||
icon: 'reorder',
|
||||
component: TabularLayout,
|
||||
}));
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
</template>
|
||||
|
||||
<template #drawer>
|
||||
<layout-drawer-detail v-model="viewType" />
|
||||
<filter-drawer-detail v-model="filters" :collection="collection" />
|
||||
<portal-target name="drawer" />
|
||||
</template>
|
||||
@@ -53,9 +54,10 @@
|
||||
<collections-navigation />
|
||||
</template>
|
||||
|
||||
<layout-tabular
|
||||
<component
|
||||
class="layout"
|
||||
ref="layout"
|
||||
:is="`layout-${viewType}`"
|
||||
:collection="collection"
|
||||
:selection.sync="selection"
|
||||
:view-options.sync="viewOptions"
|
||||
@@ -78,6 +80,7 @@ import CollectionsNotFound from '../not-found/';
|
||||
import useCollection from '@/compositions/use-collection';
|
||||
import useCollectionPreset from '@/compositions/use-collection-preset';
|
||||
import FilterDrawerDetail from '@/views/private/components/filter-drawer-detail';
|
||||
import LayoutDrawerDetail from '@/views/private/components/layout-drawer-detail';
|
||||
|
||||
const redirectIfNeeded: NavigationGuard = async (to, from, next) => {
|
||||
const collectionsStore = useCollectionsStore();
|
||||
@@ -115,7 +118,12 @@ export default defineComponent({
|
||||
beforeRouteEnter: redirectIfNeeded,
|
||||
beforeRouteUpdate: redirectIfNeeded,
|
||||
name: 'collections-browse',
|
||||
components: { CollectionsNavigation, CollectionsNotFound, FilterDrawerDetail },
|
||||
components: {
|
||||
CollectionsNavigation,
|
||||
CollectionsNotFound,
|
||||
FilterDrawerDetail,
|
||||
LayoutDrawerDetail,
|
||||
},
|
||||
props: {
|
||||
collection: {
|
||||
type: String,
|
||||
@@ -132,22 +140,23 @@ export default defineComponent({
|
||||
const { selection } = useSelection();
|
||||
const { info: currentCollection, primaryKeyField } = useCollection(collection);
|
||||
const { addNewLink, batchLink, collectionsLink } = useLinks();
|
||||
const { viewOptions, viewQuery, filters } = useCollectionPreset(collection);
|
||||
const { viewType, viewOptions, viewQuery, filters } = useCollectionPreset(collection);
|
||||
const { confirmDelete, deleting, batchDelete } = useBatchDelete();
|
||||
|
||||
return {
|
||||
currentCollection,
|
||||
addNewLink,
|
||||
batchLink,
|
||||
selection,
|
||||
confirmDelete,
|
||||
batchDelete,
|
||||
batchLink,
|
||||
collectionsLink,
|
||||
confirmDelete,
|
||||
currentCollection,
|
||||
deleting,
|
||||
filters,
|
||||
layout,
|
||||
selection,
|
||||
viewOptions,
|
||||
viewQuery,
|
||||
collectionsLink,
|
||||
filters,
|
||||
viewType,
|
||||
};
|
||||
|
||||
function useSelection() {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</template>
|
||||
|
||||
<template #drawer>
|
||||
<layout-drawer-detail v-model="viewType" />
|
||||
<filter-drawer-detail v-model="filters" collection="directus_files" />
|
||||
<portal-target name="drawer" />
|
||||
</template>
|
||||
@@ -52,9 +53,10 @@
|
||||
<files-navigation />
|
||||
</template>
|
||||
|
||||
<layout-tabular
|
||||
<component
|
||||
class="layout"
|
||||
ref="layout"
|
||||
:is="`layout-${viewType}`"
|
||||
collection="directus_files"
|
||||
:selection.sync="selection"
|
||||
:view-options.sync="viewOptions"
|
||||
@@ -74,6 +76,7 @@ import api from '@/api';
|
||||
import { LayoutComponent } from '@/layouts/types';
|
||||
import useCollectionPreset from '@/compositions/use-collection-preset';
|
||||
import FilterDrawerDetail from '@/views/private/components/filter-drawer-detail';
|
||||
import LayoutDrawerDetail from '@/views/private/components/layout-drawer-detail';
|
||||
|
||||
type Item = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -82,7 +85,7 @@ type Item = {
|
||||
|
||||
export default defineComponent({
|
||||
name: 'files-browse',
|
||||
components: { FilesNavigation, FilterDrawerDetail },
|
||||
components: { FilesNavigation, FilterDrawerDetail, LayoutDrawerDetail },
|
||||
props: {},
|
||||
setup() {
|
||||
const layout = ref<LayoutComponent>(null);
|
||||
@@ -90,23 +93,26 @@ export default defineComponent({
|
||||
|
||||
const selection = ref<Item[]>([]);
|
||||
|
||||
const { viewOptions, viewQuery, filters } = useCollectionPreset(ref('directus_files'));
|
||||
const { viewType, viewOptions, viewQuery, filters } = useCollectionPreset(
|
||||
ref('directus_files')
|
||||
);
|
||||
const { addNewLink, batchLink } = useLinks();
|
||||
const { confirmDelete, deleting, batchDelete } = useBatchDelete();
|
||||
const { breadcrumb } = useBreadcrumb();
|
||||
|
||||
return {
|
||||
addNewLink,
|
||||
batchDelete,
|
||||
batchLink,
|
||||
selection,
|
||||
breadcrumb,
|
||||
confirmDelete,
|
||||
batchDelete,
|
||||
deleting,
|
||||
filters,
|
||||
layout,
|
||||
selection,
|
||||
viewOptions,
|
||||
viewQuery,
|
||||
filters,
|
||||
viewType,
|
||||
};
|
||||
|
||||
function useBatchDelete() {
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
</template>
|
||||
|
||||
<template #drawer>
|
||||
<layout-drawer-detail v-model="viewType" />
|
||||
<filter-drawer-detail v-model="filters" collection="directus_users" />
|
||||
<portal-target name="drawer" />
|
||||
</template>
|
||||
@@ -52,9 +53,10 @@
|
||||
<users-navigation />
|
||||
</template>
|
||||
|
||||
<layout-tabular
|
||||
<component
|
||||
class="layout"
|
||||
ref="layout"
|
||||
:is="`layout-${viewType}`"
|
||||
collection="directus_users"
|
||||
:selection.sync="selection"
|
||||
:view-options.sync="viewOptions"
|
||||
@@ -75,6 +77,7 @@ import api from '@/api';
|
||||
import { LayoutComponent } from '@/layouts/types';
|
||||
import useCollectionPreset from '@/compositions/use-collection-preset';
|
||||
import FilterDrawerDetail from '@/views/private/components/filter-drawer-detail';
|
||||
import LayoutDrawerDetail from '@/views/private/components/layout-drawer-detail';
|
||||
|
||||
type Item = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
||||
@@ -83,7 +86,7 @@ type Item = {
|
||||
|
||||
export default defineComponent({
|
||||
name: 'users-browse',
|
||||
components: { UsersNavigation, FilterDrawerDetail },
|
||||
components: { UsersNavigation, FilterDrawerDetail, LayoutDrawerDetail },
|
||||
props: {
|
||||
role: {
|
||||
type: String,
|
||||
@@ -96,7 +99,9 @@ export default defineComponent({
|
||||
|
||||
const selection = ref<Item[]>([]);
|
||||
|
||||
const { viewOptions, viewQuery, filters } = useCollectionPreset(ref('directus_users'));
|
||||
const { viewType, viewOptions, viewQuery, filters } = useCollectionPreset(
|
||||
ref('directus_users')
|
||||
);
|
||||
const { addNewLink, batchLink } = useLinks();
|
||||
const { confirmDelete, deleting, batchDelete } = useBatchDelete();
|
||||
const { breadcrumb } = useBreadcrumb();
|
||||
@@ -129,18 +134,19 @@ export default defineComponent({
|
||||
});
|
||||
|
||||
return {
|
||||
_filters,
|
||||
addNewLink,
|
||||
batchDelete,
|
||||
batchLink,
|
||||
selection,
|
||||
breadcrumb,
|
||||
confirmDelete,
|
||||
batchDelete,
|
||||
deleting,
|
||||
filters,
|
||||
layout,
|
||||
selection,
|
||||
viewOptions,
|
||||
viewQuery,
|
||||
_filters,
|
||||
filters,
|
||||
viewType,
|
||||
};
|
||||
|
||||
function useBatchDelete() {
|
||||
|
||||
@@ -0,0 +1,4 @@
|
||||
import LayoutDrawerDetail from './layout-drawer-detail.vue';
|
||||
|
||||
export { LayoutDrawerDetail };
|
||||
export default LayoutDrawerDetail;
|
||||
@@ -0,0 +1,39 @@
|
||||
<template>
|
||||
<drawer-detail :icon="currentLayout.icon" :title="$t('view_type')">
|
||||
<v-select :items="layouts" item-text="name" item-value="id" v-model="viewType" full-width />
|
||||
</drawer-detail>
|
||||
</template>
|
||||
|
||||
<script lang="ts">
|
||||
import { defineComponent, computed } from '@vue/composition-api';
|
||||
import layouts from '@/layouts';
|
||||
|
||||
export default defineComponent({
|
||||
props: {
|
||||
value: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
let currentLayout = layouts.find((layout) => layout.id === props.value);
|
||||
|
||||
// If for whatever reason the current layout doesn't exist, force reset it to tabular
|
||||
if (currentLayout === undefined) {
|
||||
currentLayout = layouts.find((layout) => layout.id === 'tabular');
|
||||
emit('input', 'tabular');
|
||||
}
|
||||
|
||||
const viewType = computed({
|
||||
get() {
|
||||
return props.value;
|
||||
},
|
||||
set(newType: string) {
|
||||
emit('input', newType);
|
||||
},
|
||||
});
|
||||
|
||||
return { currentLayout, layouts, viewType };
|
||||
},
|
||||
});
|
||||
</script>
|
||||
Reference in New Issue
Block a user