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
Original file line number Diff line number Diff line change
Expand Up @@ -131,8 +131,10 @@ export const VEX_MANAGEMENT_TABLE = [
{
name: "createdBy",
labelKey: "imageScanner.vexManagement.table.headers.createdBy",
value: (row: any) =>
row?.metadata?.generation === 1 ? "Rancher" : "Manual entry",
value: (row: any) => {
const gen = Number(row?.metadata?.generation);
return (gen === 1) ? 'Rancher' : 'Manual entry';
},
sort: "metadata.generation",
},
{
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
import SteveModel from '@shell/plugins/steve/steve-class';
import { insertAt } from '@shell/utils/array';

export default class SbombasticRancherIoVexhub extends SteveModel {
get _availableActions() {
let out = super._availableActions || [];

// Remove download actions and View in API, keep edit YAML and clone
const remove = new Set([
'download',
'downloadYaml',
'downloadyaml',
'viewYaml',
'goToViewYaml',
'viewInApi'
]);
out = out.filter((a) => !a?.action || !remove.has(a.action));

const isEnabled = !!this.spec?.enabled;

const toggle = isEnabled
? {
action: 'disable',
label: this.t('imageScanner.vexManagement.buttons.disable') || 'Disable',
icon: 'icon-pause',
enabled: true,
bulkable: true,
invoke: async() => {
this.spec = { ...(this.spec || {}), enabled: false };
await this.save();
}
}
: {
action: 'enable',
label: this.t('imageScanner.vexManagement.buttons.enable') || 'Enable',
icon: 'icon-play',
enabled: true,
bulkable: true,
invoke: async() => {
this.spec = { ...(this.spec || {}), enabled: true };
await this.save();
}
};

if (isEnabled) {
// For enabled items: Disable, then other actions
const reordered = [toggle]; // Only the disable action

// Add other actions except delete (which goes last)
const otherActions = out.filter(a => a && a.action !== 'promptRemove');
reordered.push(...otherActions);

// Add delete at the end
const deleteAction = out.find((a) => a?.action === 'promptRemove');
if (deleteAction) {
reordered.push(deleteAction);
}

// Ensure all actions are enabled
return reordered.map(action => {
if (action && action.enabled === false) {
return { ...action, enabled: true };
}
return action;
});
}

// When disabled: Enable, then Delete
const deleteAction = out.find((a) => a?.action === 'promptRemove');
return [toggle, ...(deleteAction ? [deleteAction] : [])];
}

get canDelete() {
return !this.spec?.enabled;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,48 +64,15 @@ export default {
},
async fetch() {
await this.$store.dispatch('cluster/findAll', { type: RESOURCE.VEX_HUB });
let vexhubsCRD = this.$store.getters['cluster/all']?.(RESOURCE.VEX_HUB);
this.rows = (vexhubsCRD || []).map((r) => this.rowWithActions(r));
const vexhubsCRD = this.$store.getters['cluster/all']?.(RESOURCE.VEX_HUB);
this.rows = vexhubsCRD || [];
},
methods: {
rowWithActions(r) {
const isEnabled = !!r?.spec?.enabled;
const toggleAction = isEnabled
? { action: 'disable', label: this.t('imageScanner.vexManagement.buttons.disable') || 'Disable', icon: 'icon-pause', enabled: true, bulkable: true, invoke: ({}, resources) => this.switchStatus(false, resources) }
: { action: 'enable', label: this.t('imageScanner.vexManagement.buttons.enable') || 'Enable', icon: 'icon-play', enabled: true, bulkable: true, invoke: ({}, resources) => this.switchStatus(true, resources) };

const actions = Array.isArray(r.availableActions) ? r.availableActions.filter(a => !['download','downloadYaml'].includes(a.action)): [];

if (isEnabled && !actions.find(a => a && (a.action === 'edit' || a.action === 'goToEdit'))) {
const editAction = {
action: 'goToEdit',
label: this.t('imageScanner.vexManagement.actions.editConfig') || 'Edit configuration',
icon: 'icon-edit',
enabled: true,
bulkable: false,
invoke: ({}, res = []) => {
const target = (res && res.length ? res[0] : r);
const model = target._model || target;
if (model && typeof model.goToEdit === 'function') {
model.goToEdit();
}
}
};
actions.unshift(editAction);
}
const deleteAction = actions.find(a => a.action === 'promptRemove');

const availableActions = isEnabled
? [toggleAction, ...actions]
: [toggleAction, deleteAction]; // when disabled show only Enable + Delete

return { ...r, _model: r, availableActions };
},
rowWithActions(r) { return r; },
async switchStatus(desired, selected) {
const resources = selected && selected.length ? selected : (this.selectedRows || []);
if (!resources.length) return;
const models = resources.map((r) => r._model || r).filter(Boolean);
await Promise.all(models.map(async (m) => {
await Promise.all(resources.map(async (m) => {
m.spec = { ...(m.spec || {}), enabled: desired };
await m.save();
}));
Expand Down