This commit is contained in:
2026-06-25 16:51:56 -05:00
parent 94f4d8959d
commit 402bf6782a
25 changed files with 1323 additions and 103 deletions

View File

@@ -331,6 +331,7 @@
>
<template #cell-name="{ row }"><strong>{{ row.name }}</strong></template>
<template #cell-address="{ row }"><code>{{ row.address }}</code></template>
<template #cell-osFamily="{ row }"><span :class="['status-pill', row.osFamily || 'other']">{{ osFamilyLabel(row.osFamily) }}</span></template>
<template #cell-transport="{ row }"><span :class="['status-pill', row.transport]">{{ row.transport }}</span></template>
<template #cell-sourceType="{ row }"><span :class="['status-pill', row.sourceType]">{{ row.sourceType === 'vmware' ? 'VMware' : 'Manual' }}</span></template>
<template #cell-credentialName="{ row }">{{ row.credentialName || 'No credential' }}</template>
@@ -462,7 +463,7 @@
<form @submit.prevent="saveHost" class="form-grid">
<label><span>Display name</span><input v-model="hostForm.name" required placeholder="SQL-PROD-01" /></label>
<label><span>Address / FQDN</span><input v-model="hostForm.address" required placeholder="sql-prod-01.contoso.local" /></label>
<label><span>OS family</span><select v-model="hostForm.osFamily"><option value="windows">Windows</option><option value="linux">Linux</option><option value="network">Network</option><option value="api">API</option></select></label>
<label><span>Operating system type</span><select v-model="hostForm.osFamily"><option value="windows">Windows</option><option value="linux">Linux</option><option value="other">Other / unknown</option></select></label>
<label><span>Transport</span><select v-model="hostForm.transport"><option value="winrm">WinRM</option><option value="ssh">SSH</option><option value="local">Local</option><option value="api">API</option></select></label>
<label class="full"><span>Credential</span><select v-model="hostForm.credentialId"><option :value="null">No credential</option><option v-for="credential in credentials" :key="credential.id" :value="credential.id">{{ credential.name }}</option></select></label>
<label class="full"><span>Tags</span><input v-model="hostForm.tagsText" placeholder="production, database, east" /></label>
@@ -1326,6 +1327,7 @@ const availableThemes = [
const hostColumns = [
{ key: 'name', label: 'Name' },
{ key: 'address', label: 'Address' },
{ key: 'osFamily', label: 'OS' },
{ key: 'transport', label: 'Transport' },
{ key: 'sourceType', label: 'Source' },
{ key: 'credentialName', label: 'Credential' },
@@ -1469,6 +1471,7 @@ const filteredHosts = computed(() => filterRows(hosts.value, hostFilters, (host)
host.name,
host.address,
host.fqdn,
host.osFamily,
host.transport,
host.sourceType,
host.sourceConnectionName,
@@ -1945,6 +1948,10 @@ async function executeScriptTestRun(payload) {
scriptTestPollFailures = 0;
stopScriptTestPolling();
try {
if (!(await confirmLinuxCompatibility(`/api/scripts/${scriptTestTarget.value.id}/compatibility`, payload))) {
scriptTestRunning.value = false;
return;
}
const job = await api.post(`/api/scripts/${scriptTestTarget.value.id}/test-run`, payload);
scriptTestJob.value = await api.get(`/api/jobs/${job.id}`).catch(() => job);
startScriptTestPolling(job.id);
@@ -2471,6 +2478,12 @@ async function saveHost() {
notify('Host saved');
}
function osFamilyLabel(value) {
if (value === 'windows') return 'Windows';
if (value === 'linux') return 'Linux';
return 'Other';
}
async function saveHostGroup(payload) {
const body = { ...payload };
const groupId = body.id;
@@ -2669,6 +2682,7 @@ function openRunPlanModal(runplan = null) {
}
async function executeRunPlan(id) {
if (!(await confirmLinuxCompatibility(`/api/runplans/${id}/compatibility`))) return;
const job = await api.post(`/api/runplans/${id}/execute`, {});
await refreshAll();
await openJob(job.id);
@@ -2676,6 +2690,20 @@ async function executeRunPlan(id) {
notify('RunPlan queued');
}
async function confirmLinuxCompatibility(path, payload = null) {
const result = payload ? await api.post(path, payload) : await api.get(path);
const warnings = (result.findings || []).filter((finding) => finding.level === 'warning');
if (!result.hasLinuxTargets || !warnings.length) return true;
const lines = warnings.slice(0, 5).map((finding) => `- ${finding.title}${finding.line ? ` line ${finding.line}` : ''}: ${finding.message}`);
return window.confirm([
'This script is targeting one or more Linux hosts and POSHManager found possible compatibility issues.',
'',
...lines,
'',
'Continue anyway? The same warnings will be written to the job logs.'
].join('\n'));
}
async function openJob(id) {
selectedJob.value = await api.get(`/api/jobs/${id}`);
view.value = 'logs';