Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions ui/src/components/RowActionsCog.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<!--
RowActionsCog — shared row-action menu used by every plugin-ui table.

A cog icon button (`.lj-iconbtn`) that opens a popmenu (`.lj-popmenu`); the
caller supplies the action items through the default slot as plain <button>
elements (with `class="danger"` for destructive ones and `<div class="sep" />`
separators), exactly like the host's global popmenu pattern. Both classes are
the host's GLOBAL classes (defined in vuetify-overrides.css), so the menu —
which `v-menu` teleports outside the view's scope — is styled consistently
with no scoped CSS here. The trigger stops row-click propagation so opening
the menu never also opens the row. Vuetify's `close-on-content-click` (on by
default) closes the menu after an item is clicked.
-->
<template>
<v-menu location="bottom end">
<template #activator="{ props }">
<button class="lj-iconbtn" v-bind="props" :aria-label="label || t('common.actions')" @click.stop>
<v-icon size="18">{{ icon }}</v-icon>
</button>
</template>
<div class="lj-popmenu">
<slot />
</div>
</v-menu>
</template>

<script setup>
import { useI18nStore } from '@ligoj/host'

defineProps({
icon: { type: String, default: 'mdi-cog' },
label: { type: String, default: '' },
})

const t = useI18nStore().t
</script>
21 changes: 7 additions & 14 deletions ui/src/views/ApiTokenView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -39,18 +39,12 @@
</div>
</template>
<template #actions="{ item }">
<button class="lj-iconbtn" @click.stop="openShow(item.name, 'load')">
<v-icon size="18">mdi-eye-outline</v-icon>
<v-tooltip activator="parent" :text="t('system.apiToken.show')" location="top" />
</button>
<button class="lj-iconbtn" @click.stop="openShow(item.name, 'regen')">
<v-icon size="18">mdi-refresh</v-icon>
<v-tooltip activator="parent" :text="t('system.apiToken.regenerate')" location="top" />
</button>
<button class="lj-iconbtn danger" @click.stop="startDelete(item.name)">
<v-icon size="18">mdi-delete-outline</v-icon>
<v-tooltip activator="parent" :text="t('system.apiToken.revoke')" location="top" />
</button>
<RowActionsCog>
<button @click="openShow(item.name, 'load')"><v-icon size="18">mdi-eye-outline</v-icon>{{ t('system.apiToken.show') }}</button>
<button @click="openShow(item.name, 'regen')"><v-icon size="18">mdi-refresh</v-icon>{{ t('system.apiToken.regenerate') }}</button>
<div class="sep" />
<button class="danger" @click="startDelete(item.name)"><v-icon size="18">mdi-delete-outline</v-icon>{{ t('system.apiToken.revoke') }}</button>
</RowActionsCog>
</template>
</VibrantDataTable>

Expand Down Expand Up @@ -97,6 +91,7 @@
import { ref, computed, onMounted } from 'vue'
import { useApi, useAppStore, useAuthStore, useI18nStore, useClipboard, APP_BASE } from '@ligoj/host'
import { VibrantDataTable, VibrantConfirmDialog as LigojConfirmDialog, LjPageHeader, LjButton, LjSearch, LjDialog } from '@ligoj/host'
import RowActionsCog from '../components/RowActionsCog.vue'

const api = useApi()
const app = useAppStore()
Expand Down Expand Up @@ -222,8 +217,6 @@ onMounted(() => {
.avatar-cell { display: flex; align-items: center; gap: 12px; }
.kglyph { width: 34px; height: 34px; border-radius: var(--radius-sm); flex: none; display: grid; place-items: center; background: rgba(139, 92, 246, .13); color: #8b5cf6; }
.kname { font-family: var(--mono); font-size: 13px; font-weight: 600; color: var(--ink); }
/* Danger accent for the inline revoke trigger (base `.lj-iconbtn` is global). */
.lj-iconbtn.danger:hover { background: rgba(var(--v-theme-error), .1); color: rgb(var(--v-theme-error)); }

/* Dialog body bits (slotted into LjDialog; --pill/--mono/--accent come from
the dialog card's `.lj-surface`). */
Expand Down
19 changes: 6 additions & 13 deletions ui/src/views/ProjectListView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,14 +44,11 @@
<span class="subs-chip">{{ item.subs }}</span>
</template>
<template #cell.actions="{ item }">
<button class="lj-iconbtn" @click.stop="openEdit(item)">
<v-icon size="18">mdi-pencil-outline</v-icon>
<v-tooltip activator="parent" :text="t('common.edit')" location="top" />
</button>
<button class="lj-iconbtn danger" @click.stop="startDelete(item)">
<v-icon size="18">mdi-delete-outline</v-icon>
<v-tooltip activator="parent" :text="t('common.delete')" location="top" />
</button>
<RowActionsCog>
<button @click="openEdit(item)"><v-icon size="18">mdi-pencil-outline</v-icon>{{ t('common.edit') }}</button>
<div class="sep" />
<button class="danger" @click="startDelete(item)"><v-icon size="18">mdi-delete-outline</v-icon>{{ t('common.delete') }}</button>
</RowActionsCog>
</template>
</VibrantDataTable>

Expand All @@ -71,6 +68,7 @@ import { ref, computed, onMounted } from 'vue'
import { useRouter } from 'vue-router'
import { useApi, useAppStore, useI18nStore } from '@ligoj/host'
import ProjectEditDialog from './ProjectEditDialog.vue'
import RowActionsCog from '../components/RowActionsCog.vue'
import { VibrantDataTable, VibrantConfirmDialog, LjPageHeader, LjButton, LjSearch } from '@ligoj/host'

const router = useRouter()
Expand Down Expand Up @@ -284,11 +282,6 @@ onMounted(() => {
color: var(--ink-2);
}

/* Danger accent for the inline delete trigger (base `.lj-iconbtn` is global). */
.lj-iconbtn.danger:hover {
color: rgb(var(--v-theme-error));
}

.toast {
position: fixed;
bottom: 24px;
Expand Down
16 changes: 6 additions & 10 deletions ui/src/views/SystemConfigurationView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,11 @@
<span v-if="item.overridden" class="ovr" :title="t('system.config.tipOverridden')"><v-icon size="13">mdi-alert</v-icon></span>
</template>
<template #actions="{ item }">
<button class="lj-iconbtn" @click.stop="openEdit(item)">
<v-icon size="18">mdi-pencil-outline</v-icon>
<v-tooltip activator="parent" :text="t('common.edit')" location="top" />
</button>
<button class="lj-iconbtn danger" @click.stop="startDelete(item)">
<v-icon size="18">mdi-delete-outline</v-icon>
<v-tooltip activator="parent" :text="t('common.delete')" location="top" />
</button>
<RowActionsCog>
<button @click="openEdit(item)"><v-icon size="18">mdi-pencil-outline</v-icon>{{ t('common.edit') }}</button>
<div class="sep" />
<button class="danger" @click="startDelete(item)"><v-icon size="18">mdi-delete-outline</v-icon>{{ t('common.delete') }}</button>
</RowActionsCog>
</template>
</VibrantDataTable>

Expand Down Expand Up @@ -106,6 +103,7 @@
import { ref, computed, onMounted } from 'vue'
import { useApi, useAppStore, useI18nStore, useClipboard, APP_BASE } from '@ligoj/host'
import { VibrantDataTable, VibrantConfirmDialog as LigojConfirmDialog, LjPageHeader, LjButton, LjSearch, LjDialog, LjAvailabilityField } from '@ligoj/host'
import RowActionsCog from '../components/RowActionsCog.vue'

const api = useApi()
const app = useAppStore()
Expand Down Expand Up @@ -342,8 +340,6 @@ onMounted(() => {
.srcpill :deep(.v-icon) { flex: none; }
.src-txt { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.ovr { color: #d9701a; margin-left: 5px; vertical-align: middle; }
/* Danger accent for the inline delete trigger (base `.lj-iconbtn` is global). */
.lj-iconbtn.danger:hover { background: rgba(var(--v-theme-error), .1); color: rgb(var(--v-theme-error)); }

/* Custom checkboxes inside the edit dialog (slotted content keeps this
component's scope id; --accent/--border-2 come from the LjDialog card's
Expand Down
16 changes: 6 additions & 10 deletions ui/src/views/SystemNodeView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -64,16 +64,11 @@
<template #actions="{ item }">
<!-- Only instances can be edited/deleted; service/tool/feature nodes
have no actions, so the cog menu is omitted for them. -->
<v-menu v-if="isInstance(item)" location="bottom end">
<template #activator="{ props }">
<button class="lj-iconbtn" v-bind="props" :aria-label="t('common.actions')" @click.stop><v-icon size="18">mdi-cog</v-icon></button>
</template>
<div class="lj-popmenu">
<button @click="startEdit(item)"><v-icon size="18">mdi-pencil-outline</v-icon>{{ t('common.edit') }}</button>
<div class="sep" />
<button class="danger" @click="startDelete(item)"><v-icon size="18">mdi-delete-outline</v-icon>{{ t('common.delete') }}</button>
</div>
</v-menu>
<RowActionsCog v-if="isInstance(item)">
<button @click="startEdit(item)"><v-icon size="18">mdi-pencil-outline</v-icon>{{ t('common.edit') }}</button>
<div class="sep" />
<button class="danger" @click="startDelete(item)"><v-icon size="18">mdi-delete-outline</v-icon>{{ t('common.delete') }}</button>
</RowActionsCog>
</template>
</VibrantDataTable>

Expand All @@ -91,6 +86,7 @@ import { ref, computed, onMounted, onBeforeUnmount } from 'vue'
import { useApi, useAppStore, useI18nStore, NodeIcon, NodeModeChip, isInstance, nodeType } from '@ligoj/host'
import { VibrantDataTable, VibrantConfirmDialog as LigojConfirmDialog, LjPageHeader, LjButton } from '@ligoj/host'
import NodeEditDialog from './NodeEditDialog.vue'
import RowActionsCog from '../components/RowActionsCog.vue'

const api = useApi()
const app = useAppStore()
Expand Down
16 changes: 6 additions & 10 deletions ui/src/views/SystemRoleView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -49,14 +49,11 @@
</span>
</template>
<template #actions="{ item }">
<button class="lj-iconbtn" @click.stop="openEdit(item)">
<v-icon size="18">mdi-pencil-outline</v-icon>
<v-tooltip activator="parent" :text="t('common.edit')" location="top" />
</button>
<button class="lj-iconbtn danger" @click.stop="startDelete(item)">
<v-icon size="18">mdi-delete-outline</v-icon>
<v-tooltip activator="parent" :text="t('common.delete')" location="top" />
</button>
<RowActionsCog>
<button @click="openEdit(item)"><v-icon size="18">mdi-pencil-outline</v-icon>{{ t('common.edit') }}</button>
<div class="sep" />
<button class="danger" @click="startDelete(item)"><v-icon size="18">mdi-delete-outline</v-icon>{{ t('common.delete') }}</button>
</RowActionsCog>
</template>
</VibrantDataTable>

Expand Down Expand Up @@ -84,6 +81,7 @@
import { ref, computed, onMounted } from 'vue'
import { useApi, useAppStore, useI18nStore } from '@ligoj/host'
import { VibrantDataTable, VibrantConfirmDialog as LigojConfirmDialog, LjPageHeader, LjButton, LjSearch, LjDialog, LjAvailabilityField } from '@ligoj/host'
import RowActionsCog from '../components/RowActionsCog.vue'

const api = useApi()
const app = useAppStore()
Expand Down Expand Up @@ -272,6 +270,4 @@ onMounted(() => {
.tok.api { color: #2f6df6; background: rgba(47, 109, 246, .12); }
.tok.ui { color: #1d9d63; background: rgba(29, 157, 99, .13); }
.dash { color: var(--ink-3); }
/* Danger accent for the inline delete trigger (base `.lj-iconbtn` is global). */
.lj-iconbtn.danger:hover { background: rgba(var(--v-theme-error), .1); color: rgb(var(--v-theme-error)); }
</style>
16 changes: 6 additions & 10 deletions ui/src/views/SystemUserView.vue
Original file line number Diff line number Diff line change
Expand Up @@ -53,14 +53,11 @@
</span>
</template>
<template #actions="{ item }">
<button class="lj-iconbtn" @click.stop="openEdit(item)">
<v-icon size="18">mdi-pencil-outline</v-icon>
<v-tooltip activator="parent" :text="t('common.edit')" location="top" />
</button>
<button class="lj-iconbtn danger" @click.stop="startDelete(item)">
<v-icon size="18">mdi-delete-outline</v-icon>
<v-tooltip activator="parent" :text="t('common.delete')" location="top" />
</button>
<RowActionsCog>
<button @click="openEdit(item)"><v-icon size="18">mdi-pencil-outline</v-icon>{{ t('common.edit') }}</button>
<div class="sep" />
<button class="danger" @click="startDelete(item)"><v-icon size="18">mdi-delete-outline</v-icon>{{ t('common.delete') }}</button>
</RowActionsCog>
</template>
</VibrantDataTable>

Expand Down Expand Up @@ -99,6 +96,7 @@
import { ref, computed, onMounted } from 'vue'
import { useApi, useAppStore, useDataTable, useI18nStore } from '@ligoj/host'
import { VibrantDataTable, VibrantConfirmDialog as LigojConfirmDialog, LjPageHeader, LjButton, LjSearch, LjDialog, LjAvailabilityField } from '@ligoj/host'
import RowActionsCog from '../components/RowActionsCog.vue'

const api = useApi()
const app = useAppStore()
Expand Down Expand Up @@ -239,6 +237,4 @@ onMounted(() => {
.chips { display: inline-flex; flex-wrap: wrap; gap: 6px; }
.rchip { display: inline-flex; align-items: center; gap: 5px; font-family: var(--font); font-weight: 700; font-size: 11.5px; padding: 3px 10px; border-radius: 999px; color: #8b5cf6; background: rgba(139, 92, 246, .13); }
.dash { color: var(--ink-3); font-size: 13px; }
/* Danger accent for the inline delete trigger (base `.lj-iconbtn` is global). */
.lj-iconbtn.danger:hover { background: rgba(var(--v-theme-error), .1); color: rgb(var(--v-theme-error)); }
</style>
Loading