<template>
<div class="area-grid">
<div
v-for="script in scripts"
:key="script.alias"
class="action-card-item"
:class="cardClass(script)"
@click="goToDetail(script.alias)"
>
<GnActionCard :title="script.name">
<template #default>
<div v-if="script.icon" v-html="script.icon" class="script-icon" />
<p v-if="script.description">{{ script.description }}</p>
<div class="script-meta">
<GnBadge :variant="script.state === 'enabled' ? 'success' : 'secondary'"
>{{ script.state }}</GnBadge>
<GnBadge v-if="script.scope" variant="primary">{{ script.scope }}</GnBadge>
<GnBadge v-if="showAreaBadge && areaFor(script)" variant="primary">{{ areaFor(script).display_name }}</GnBadge>
<GnBadge
v-for="(ind, i) in script.indicators"
:key="i"
:variant="ind.variant"
>{{ ind.label }}</GnBadge>
</div>
<small v-if="script.created_by || script.author">{{ script.created_by || script.author }}</small>
</template>
<template #actions>
<GnButton
v-if="perm.has('scripts.run')"
variant="primary"
icon="ph-play"
:loading="scriptsStore.isRunning(script.alias)"
:disabled="script.state !== 'enabled'"
@click.stop="run(script)"
>
Run
</GnButton>
</template>
</GnActionCard>
</div>
</div>
<ScriptRunModal
v-if="activeScript"
:open="showRunModal"
:script="activeScript"
@update:open="showRunModal = $event"
@run="executeRun($event.alias, $event.params)"
/>
<GnConfirmDialog
:open="confirmOpen"
:title="confirmTitle"
:message="confirmMessage"
:confirm-variant="confirmVariant"
@update:open="confirmOpen = $event"
@confirm="onConfirmRun"
@cancel="onCancelConfirm"
/>
</template>
<script setup>
import { ref } from "vue";
import { useRouter } from "vue-router";
import { useScriptsStore } from "../../stores/scripts";
import { useAreasStore } from "../../stores/areas";
import { usePermission } from "../../composables/usePermission.js";
import ScriptRunModal from "./ScriptRunModal.vue";
import {
GnBadge,
GnActionCard,
GnButton,
GnConfirmDialog,
useToast,
} from "gnexus-ui-kit/vue";
const props = defineProps({
scripts: {
type: Array,
required: true,
},
showAreaBadge: {
type: Boolean,
default: false,
},
});
const emit = defineEmits(["run-success"]);
const router = useRouter();
const scriptsStore = useScriptsStore();
const areasStore = useAreasStore();
const toast = useToast();
const perm = usePermission();
const showRunModal = ref(false);
const activeScript = ref(null);
const confirmOpen = ref(false);
const confirmScript = ref(null);
const confirmTitle = ref("");
const confirmMessage = ref("");
const confirmVariant = ref("warning");
function areaFor(script) {
if (!script.area_id || !props.showAreaBadge) return null;
return areasStore.areas.find((a) => a.id === script.area_id) || null;
}
function cardClass(script) {
if (script.danger_level === "dangerous") return "card-dangerous";
if (script.danger_level === "cautious") return "card-cautious";
return "";
}
function run(script) {
if (script.danger_level === "cautious" || script.danger_level === "dangerous") {
confirmScript.value = script;
confirmTitle.value = `Run: ${script.name || script.alias}`;
confirmMessage.value =
script.danger_level === "dangerous"
? "This action is marked as dangerous. Are you sure you want to proceed?"
: "This action requires caution. Proceed?";
confirmVariant.value = script.danger_level === "dangerous" ? "danger" : "warning";
confirmOpen.value = true;
return;
}
const schema = script.params_schema;
if (schema && Object.keys(schema).length > 0) {
activeScript.value = script;
showRunModal.value = true;
return;
}
executeRun(script.alias, {});
}
function onConfirmRun() {
if (confirmScript.value) {
const schema = confirmScript.value.params_schema;
if (schema && Object.keys(schema).length > 0) {
activeScript.value = confirmScript.value;
showRunModal.value = true;
} else {
executeRun(confirmScript.value.alias, {});
}
confirmScript.value = null;
}
}
function onCancelConfirm() {
confirmScript.value = null;
}
async function executeRun(alias, params) {
const result = await scriptsStore.runScript(alias, params);
if (result?.ok) {
toast.success({
title: `Ran ${alias}`,
text: scriptsStore.lastRunResult?.execTime ? `Exec time: ${scriptsStore.lastRunResult.execTime}` : undefined,
});
emit("run-success", { alias });
} else {
toast.error({ title: `Failed ${alias}`, text: result?.error?.message || "Unknown error" });
}
}
function goToDetail(alias) {
router.push({ name: "script-detail", params: { type: "actions", id: alias } });
}
</script>
<style scoped>
.script-icon {
font-size: 32px;
}
.script-meta {
display: flex;
flex-wrap: wrap;
gap: 8px;
align-items: center;
}
.action-card-item.card-cautious :deep(.action-card) {
border-color: #e0af68;
}
.action-card-item.card-dangerous :deep(.action-card) {
border-color: #f7768e;
}
</style>