Add an All PCs policy scope that excludes servers
The policy builder only offered "Matches everything" (the `true` scope node), which also targets servers. Authoring an estate-wide policy almost always means "every PC an operator sits at", and a reboot or script push against a server is a materially different event. Adds an `allpcs` scope node that matches every endpoint except those whose computer type is server-designated. Server designation reads the computer type's ICON slug, which is nominally a UI hint and is now load-bearing; it was chosen over matching the type NAME (a site can rename "Server") and over a new isserver column (needs a migration). It is isolated behind SERVER_ICON so promoting it to a real flag later is a one-place change. The `true` node is retained and still matches servers, so existing policies keep their exact meaning rather than silently re-scoping. It stays visible in the dropdown only when editing a policy that already uses it; new policies default to `allpcs`. Covered by tests/test_plugins/test_computers_policy_allpcs.py, verified against a planted canary so the server-exclusion assertions are known to bite.
This commit is contained in:
@@ -140,7 +140,7 @@ const error = ref('')
|
||||
const form = ref(emptyForm())
|
||||
|
||||
function emptyForm() {
|
||||
return { name: '', description: '', scopejson: { type: 'true' }, actions: [] }
|
||||
return { name: '', description: '', scopejson: { type: 'allpcs' }, actions: [] }
|
||||
}
|
||||
|
||||
onMounted(() => loadData())
|
||||
@@ -221,7 +221,7 @@ function openModal(item = null) {
|
||||
form.value = {
|
||||
name: item.name || '',
|
||||
description: item.description || '',
|
||||
scopejson: item.scopejson ? JSON.parse(JSON.stringify(item.scopejson)) : { type: 'true' },
|
||||
scopejson: item.scopejson ? JSON.parse(JSON.stringify(item.scopejson)) : { type: 'allpcs' },
|
||||
actions: (item.actions || []).map(a => ({
|
||||
action: a.action, mode: a.mode || 'gate',
|
||||
desiredstate: a.desiredstate, params: a.params, intervalminutes: a.intervalminutes
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
<div class="scope-node">
|
||||
<div class="scope-node-row">
|
||||
<select v-model="node.type" class="form-control scope-type" @change="onTypeChange">
|
||||
<option value="true">Matches everything</option>
|
||||
<option value="allpcs">All PCs (excludes servers)</option>
|
||||
<option v-if="node.type === 'true'" value="true">Matches everything (incl. servers)</option>
|
||||
<option value="pctype">PC type is</option>
|
||||
<option value="app">App is installed</option>
|
||||
<option value="and">ALL of (AND)</option>
|
||||
@@ -71,20 +72,20 @@ function onTypeChange() {
|
||||
delete node.nodes
|
||||
delete node.node
|
||||
if (node.type === 'and' || node.type === 'or') {
|
||||
node.nodes = [{ type: 'true' }]
|
||||
node.nodes = [{ type: 'allpcs' }]
|
||||
} else if (node.type === 'not') {
|
||||
node.node = { type: 'true' }
|
||||
node.node = { type: 'allpcs' }
|
||||
}
|
||||
}
|
||||
|
||||
function addChild() {
|
||||
props.node.nodes.push({ type: 'true' })
|
||||
props.node.nodes.push({ type: 'allpcs' })
|
||||
}
|
||||
|
||||
function removeChild(index) {
|
||||
props.node.nodes.splice(index, 1)
|
||||
if (props.node.nodes.length === 0) {
|
||||
props.node.nodes.push({ type: 'true' })
|
||||
props.node.nodes.push({ type: 'allpcs' })
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user