mirror of
https://github.com/directus/directus.git
synced 2026-02-02 06:45:36 -05:00
Add updating dashboard
This commit is contained in:
@@ -548,6 +548,9 @@ dashboard: Dashboard
|
||||
panel: Panel
|
||||
panel_header: Panel Header
|
||||
panel_delete_confirm: Are you sure you want to delete this panel? This action can not be undone.
|
||||
dashboard_delete_confirm: Are you sure you want to delete this dashboard? This action can not be undone.
|
||||
edit_dashboard: Edit Dashboard
|
||||
delete_dashboard: Delete Dashboard
|
||||
visible: Visible
|
||||
no_dashboards: No Dashboards
|
||||
no_dashboards_copy: You don’t have any Dashboards yet.
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
</template>
|
||||
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('create_dashboard') }}</v-card-title>
|
||||
<v-card-title v-if="!dashboard">{{ $t('create_dashboard') }}</v-card-title>
|
||||
<v-card-title v-else>{{ $t('edit_dashboard') }}</v-card-title>
|
||||
|
||||
<v-card-text>
|
||||
<div class="fields">
|
||||
<v-input @keyup.enter="save" autofocus v-model="dashboardName" :placeholder="$t('dashboard_name')" />
|
||||
<interface-select-icon v-model="dashboardIcon" />
|
||||
<v-input autofocus v-model="values.name" :placeholder="$t('dashboard_name')" />
|
||||
<interface-select-icon v-model="values.icon" />
|
||||
<v-input class="full" v-model="values.note" :placeholder="$t('note')" />
|
||||
</div>
|
||||
</v-card-text>
|
||||
|
||||
@@ -18,7 +20,7 @@
|
||||
<v-button @click="cancel" secondary>
|
||||
{{ $t('cancel') }}
|
||||
</v-button>
|
||||
<v-button :disabled="dashboardName === null || dashboardName.length === 0" @click="save" :loading="saving">
|
||||
<v-button :disabled="!values.name" @click="save" :loading="saving">
|
||||
{{ $t('save') }}
|
||||
</v-button>
|
||||
</v-card-actions>
|
||||
@@ -29,11 +31,13 @@
|
||||
<script lang="ts">
|
||||
import api from '@/api';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
import { defineComponent, ref } from '@vue/composition-api';
|
||||
import { defineComponent, ref, reactive, PropType } from '@vue/composition-api';
|
||||
import { useInsightsStore } from '@/stores';
|
||||
import router from '@/router';
|
||||
import { Dashboard } from '@/types';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'DashboardDialog',
|
||||
model: {
|
||||
prop: 'active',
|
||||
event: 'toggle',
|
||||
@@ -43,18 +47,25 @@ export default defineComponent({
|
||||
type: Boolean,
|
||||
default: false,
|
||||
},
|
||||
dashboard: {
|
||||
type: Object as PropType<Dashboard>,
|
||||
default: null,
|
||||
},
|
||||
},
|
||||
setup(props, { emit }) {
|
||||
const insightsStore = useInsightsStore();
|
||||
|
||||
const dashboardName = ref(null);
|
||||
const dashboardIcon = ref(null);
|
||||
const values = reactive({
|
||||
name: props.dashboard?.name ?? null,
|
||||
icon: props.dashboard?.icon ?? null,
|
||||
note: props.dashboard?.note ?? null,
|
||||
});
|
||||
|
||||
const saving = ref(false);
|
||||
|
||||
return { dashboardName, cancel, saving, save, dashboardIcon };
|
||||
return { values, cancel, saving, save };
|
||||
|
||||
function cancel() {
|
||||
dashboardName.value = null;
|
||||
emit('toggle', false);
|
||||
}
|
||||
|
||||
@@ -62,13 +73,14 @@ export default defineComponent({
|
||||
saving.value = true;
|
||||
|
||||
try {
|
||||
const response = await api.post(
|
||||
'/dashboards',
|
||||
{ name: dashboardName.value, icon: dashboardIcon.value },
|
||||
{ params: { fields: ['id'] } }
|
||||
);
|
||||
await insightsStore.hydrate();
|
||||
router.push(`/insights/${response.data.data.id}`);
|
||||
if (props.dashboard) {
|
||||
await api.patch(`/dashboards/${props.dashboard.id}`, values, { params: { fields: ['id'] } });
|
||||
await insightsStore.hydrate();
|
||||
} else {
|
||||
const response = await api.post('/dashboards', values, { params: { fields: ['id'] } });
|
||||
await insightsStore.hydrate();
|
||||
router.push(`/insights/${response.data.data.id}`);
|
||||
}
|
||||
emit('toggle', false);
|
||||
} catch (err) {
|
||||
unexpectedError(err);
|
||||
@@ -86,4 +98,8 @@ export default defineComponent({
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.full {
|
||||
grid-column: 1 / span 2;
|
||||
}
|
||||
</style>
|
||||
@@ -11,7 +11,7 @@
|
||||
</template>
|
||||
|
||||
<template #actions>
|
||||
<create-dashboard-dialog v-model="createDialogActive">
|
||||
<dashboard-dialog v-model="createDialogActive">
|
||||
<template #activator="{ on }">
|
||||
<v-button
|
||||
@click="on"
|
||||
@@ -23,7 +23,7 @@
|
||||
<v-icon name="add" />
|
||||
</v-button>
|
||||
</template>
|
||||
</create-dashboard-dialog>
|
||||
</dashboard-dialog>
|
||||
</template>
|
||||
|
||||
<v-table
|
||||
@@ -37,11 +37,56 @@
|
||||
<template #item.icon="{ item }">
|
||||
<v-icon class="icon" :name="item.icon" />
|
||||
</template>
|
||||
|
||||
<template #item-append="{ item }">
|
||||
<v-menu placement="left-start" show-arrow>
|
||||
<template #activator="{ toggle }">
|
||||
<v-icon name="more_vert" @click="toggle" class="ctx-toggle" />
|
||||
</template>
|
||||
|
||||
<v-list>
|
||||
<v-list-item @click="editDashboard = item" class="warning">
|
||||
<v-list-item-icon>
|
||||
<v-icon name="edit" outline />
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
{{ $t('edit_dashboard') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
|
||||
<v-list-item @click="confirmDelete = item.id" class="danger">
|
||||
<v-list-item-icon>
|
||||
<v-icon name="delete" outline />
|
||||
</v-list-item-icon>
|
||||
<v-list-item-content>
|
||||
{{ $t('delete_dashboard') }}
|
||||
</v-list-item-content>
|
||||
</v-list-item>
|
||||
</v-list>
|
||||
</v-menu>
|
||||
</template>
|
||||
</v-table>
|
||||
|
||||
<v-info icon="dashboard" :title="$t('no_dashboards')" v-else center>
|
||||
{{ $t('no_dashboards_copy') }}
|
||||
</v-info>
|
||||
|
||||
<v-dialog :active="!!confirmDelete" @esc="confirmDelete = null">
|
||||
<v-card>
|
||||
<v-card-title>{{ $t('dashboard_delete_confirm') }}</v-card-title>
|
||||
|
||||
<v-card-actions>
|
||||
<v-button @click="confirmDelete = null" secondary>
|
||||
{{ $t('cancel') }}
|
||||
</v-button>
|
||||
<v-button class="action-delete" @click="deleteDashboard" :loading="deletingDashboard">
|
||||
{{ $t('delete') }}
|
||||
</v-button>
|
||||
</v-card-actions>
|
||||
</v-card>
|
||||
</v-dialog>
|
||||
|
||||
<dashboard-dialog v-if="editDashboard" active @toggle="editDashboard = null" :dashboard="editDashboard" />
|
||||
</private-view>
|
||||
</template>
|
||||
|
||||
@@ -52,15 +97,21 @@ import i18n from '@/lang';
|
||||
import { Dashboard } from '@/types';
|
||||
import router from '@/router';
|
||||
import InsightsNavigation from '../components/navigation.vue';
|
||||
import CreateDashboardDialog from '../components/create-dashboard-dialog.vue';
|
||||
import DashboardDialog from '../components/dashboard-dialog.vue';
|
||||
import api from '@/api';
|
||||
import { unexpectedError } from '@/utils/unexpected-error';
|
||||
|
||||
export default defineComponent({
|
||||
name: 'InsightsOverview',
|
||||
components: { InsightsNavigation, CreateDashboardDialog },
|
||||
components: { InsightsNavigation, DashboardDialog },
|
||||
setup() {
|
||||
const insightsStore = useInsightsStore();
|
||||
const permissionsStore = usePermissionsStore();
|
||||
|
||||
const confirmDelete = ref<string | null>(null);
|
||||
const deletingDashboard = ref(false);
|
||||
const editDashboard = ref<Dashboard | null>(null);
|
||||
|
||||
const createDialogActive = ref(false);
|
||||
|
||||
const createAllowed = computed<boolean>(() => {
|
||||
@@ -86,17 +137,39 @@ export default defineComponent({
|
||||
},
|
||||
];
|
||||
|
||||
const dashboards = computed(() => insightsStore.state.dashboards);
|
||||
|
||||
return {
|
||||
dashboards: insightsStore.state.dashboards,
|
||||
dashboards,
|
||||
createAllowed,
|
||||
tableHeaders,
|
||||
navigateToDashboard,
|
||||
createDialogActive,
|
||||
confirmDelete,
|
||||
deletingDashboard,
|
||||
deleteDashboard,
|
||||
editDashboard,
|
||||
};
|
||||
|
||||
function navigateToDashboard(dashboard: Dashboard) {
|
||||
router.push(`/insights/${dashboard.id}`);
|
||||
}
|
||||
|
||||
async function deleteDashboard() {
|
||||
if (!confirmDelete.value) return;
|
||||
|
||||
deletingDashboard.value = true;
|
||||
|
||||
try {
|
||||
await api.delete(`/dashboards/${confirmDelete.value}`);
|
||||
await insightsStore.hydrate();
|
||||
confirmDelete.value = null;
|
||||
} catch (err) {
|
||||
unexpectedError(err);
|
||||
} finally {
|
||||
deletingDashboard.value = false;
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
</script>
|
||||
@@ -106,4 +179,28 @@ export default defineComponent({
|
||||
padding: var(--content-padding);
|
||||
padding-top: 0;
|
||||
}
|
||||
|
||||
.action-delete {
|
||||
--v-button-background-color: var(--danger-10);
|
||||
--v-button-color: var(--danger);
|
||||
--v-button-background-color-hover: var(--danger-25);
|
||||
--v-button-color-hover: var(--danger);
|
||||
}
|
||||
|
||||
.ctx-toggle {
|
||||
--v-icon-color: var(--foreground-subdued);
|
||||
--v-icon-color-hover: var(--foreground-normal);
|
||||
}
|
||||
|
||||
.v-list-item.danger {
|
||||
--v-list-item-color: var(--danger);
|
||||
--v-list-item-color-hover: var(--danger);
|
||||
--v-list-item-icon-color: var(--danger);
|
||||
}
|
||||
|
||||
.v-list-item.warning {
|
||||
--v-list-item-color: var(--warning);
|
||||
--v-list-item-color-hover: var(--warning);
|
||||
--v-list-item-icon-color: var(--warning);
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
export type Dashboard = {
|
||||
id: string;
|
||||
name: string;
|
||||
note: string;
|
||||
icon: string;
|
||||
panels: Panel[];
|
||||
date_created: string;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
<template functional>
|
||||
<template>
|
||||
<span class="null">--</span>
|
||||
</template>
|
||||
|
||||
<style lang="scss" scoped>
|
||||
<style scoped>
|
||||
.null {
|
||||
color: var(--border-normal); // Don't confuse NULL with subdued value
|
||||
color: var(--border-normal); /* Don't confuse NULL with subdued value */
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user