Skip to content

Commit e7fd906

Browse files
committed
[Feature] Script Lifecycle
1 parent 7f514c8 commit e7fd906

14 files changed

Lines changed: 931 additions & 44 deletions

File tree

docs.openc3.com/docs/tools/script-runner.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,32 @@ Right clicking a script brings up several options:
9494

9595
'Clear all breakpoints' allows you to quickly clear breakpoints set by clicking on the editor line number.
9696

97+
## Script Lifecycle
98+
99+
The Script Lifecycle feature tracks scripts through three states: **In Development**, **In Review**, and **Approved**. It is disabled by default and can be enabled in the Admin Console under Settings → Script Lifecycle Settings.
100+
101+
When enabled, a colored chip next to the Script State field shows the current lifecycle state of the open script (blue for In Development, orange for In Review, green for Approved). Clicking the chip, or selecting Script → Script Lifecycle, opens the lifecycle dialog. New scripts always begin **In Development**.
102+
103+
The dialog displays the current state, lets you move the script to another state with an optional comment (up to 1000 characters), and shows the complete audit history of every transition: who made the change, when it happened, the states involved, and the comment. Timestamps are displayed in the time zone configured in the Admin Console Settings.
104+
105+
![script-lifecycle](/img/script_runner/script_lifecycle.png)
106+
107+
### Lifecycle Transitions
108+
109+
| From | To (and back) | Required Role |
110+
| -------------- | --------------------- | ----------------- |
111+
| In Development | In Review | Operator or Admin |
112+
| In Review | Approved | Admin |
113+
| In Development | Approved | Admin |
114+
115+
Operators (or any user with the script_edit permission) can move scripts between In Development and In Review. Only admins can approve a script or move an approved script back to In Review or In Development. Role-based restrictions require COSMOS Enterprise; in COSMOS Core the user can perform all transitions.
116+
117+
### Approved Scripts
118+
119+
Once a script is Approved it cannot be modified or deleted. The editor becomes read-only and the Save and Delete menu items are disabled. This is also enforced by the server, so the script cannot be changed through the API. To edit an approved script, an admin must first move it back to In Review or In Development.
120+
121+
In addition, users with only the runner role (or the script_run permission) can only run Approved scripts. This ensures operators in a production environment only execute scripts that have completed the review process. Users who can edit scripts can run scripts in any lifecycle state.
122+
97123
## Script Environment Variables
98124

99125
Environment variables are used for storing information about the runtime environment of a running script. If your script depends on environment variables, you can access the "Script Environment Variables" dialog by clicking on the "(x)" icon next to the "Start" button.
364 KB
Loading

openc3-cosmos-init/plugins/packages/openc3-vue-common/src/components/TopBarMenu.vue

Lines changed: 42 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -77,39 +77,52 @@
7777
</v-list-item-action>
7878
</v-list-item>
7979
</v-radio-group>
80-
<v-list-item
80+
<v-tooltip
8181
v-else
8282
:key="j + '-list'"
83-
:disabled="option.disabled"
84-
:data-test="formatDT(`${title} ${menu.label} ${option.label}`)"
85-
@click="
86-
() => {
87-
option.command(option)
88-
if (!option.checkbox) closeMenu()
89-
}
90-
"
83+
:disabled="!option.tooltip"
84+
:text="option.tooltip"
85+
location="right"
9186
>
92-
<template v-if="option.icon" #prepend>
93-
<v-icon :icon="option.icon" :disabled="option.disabled"></v-icon>
87+
<template #activator="{ props }">
88+
<div v-bind="props">
89+
<v-list-item
90+
:disabled="option.disabled"
91+
:data-test="formatDT(`${title} ${menu.label} ${option.label}`)"
92+
@click="
93+
() => {
94+
option.command(option)
95+
if (!option.checkbox) closeMenu()
96+
}
97+
"
98+
>
99+
<template v-if="option.icon" #prepend>
100+
<v-icon
101+
:icon="option.icon"
102+
:disabled="option.disabled"
103+
></v-icon>
104+
</template>
105+
<v-list-item-action v-if="option.checkbox" class="list-action">
106+
<v-checkbox
107+
v-model="option.checked"
108+
:label="option.label"
109+
color="secondary"
110+
density="compact"
111+
hide-details
112+
/>
113+
</v-list-item-action>
114+
<v-list-item-title
115+
v-if="!option.radio && !option.checkbox"
116+
:style="
117+
'cursor: pointer;' + (option.disabled ? 'opacity: 0.2' : '')
118+
"
119+
>
120+
{{ option.label }}
121+
</v-list-item-title>
122+
</v-list-item>
123+
</div>
94124
</template>
95-
<v-list-item-action v-if="option.checkbox" class="list-action">
96-
<v-checkbox
97-
v-model="option.checked"
98-
:label="option.label"
99-
color="secondary"
100-
density="compact"
101-
hide-details
102-
/>
103-
</v-list-item-action>
104-
<v-list-item-title
105-
v-if="!option.radio && !option.checkbox"
106-
:style="
107-
'cursor: pointer;' + (option.disabled ? 'opacity: 0.2' : '')
108-
"
109-
>
110-
{{ option.label }}
111-
</v-list-item-title>
112-
</v-list-item>
125+
</v-tooltip>
113126
</template>
114127
</v-list>
115128
</v-menu>
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,15 @@
1+
/*
2+
# Copyright 2026 OpenC3, Inc.
3+
# All Rights Reserved.
4+
#
5+
# This program is distributed in the hope that it will be useful,
6+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
7+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8+
# See LICENSE.md for more details.
9+
10+
# This file may also be used under the terms of a commercial license
11+
# if purchased from OpenC3, Inc.
12+
*/
13+
114
export { useContainerHeight } from './useContainerHeight'
15+
export { useTimeFilters } from './useTimeFilters'
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/*
2+
# Copyright 2026 OpenC3, Inc.
3+
# All Rights Reserved.
4+
#
5+
# This program is distributed in the hope that it will be useful,
6+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
7+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8+
# See LICENSE.md for more details.
9+
10+
# This file may also be used under the terms of a commercial license
11+
# if purchased from OpenC3, Inc.
12+
*/
13+
14+
import TimeFilters from '@/util/timeFilters'
15+
16+
// Composition API access to the TimeFilters mixin methods.
17+
// Call methods on the returned object (don't destructure) since
18+
// they reference each other through `this`.
19+
export function useTimeFilters() {
20+
return TimeFilters.methods
21+
}

openc3-cosmos-init/plugins/packages/openc3-vue-common/src/tools/admin/tabs/SettingsTab.vue

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
<v-divider />
2020
<editor-settings />
2121
<v-divider />
22+
<script-lifecycle-settings />
23+
<v-divider />
2224
<astro-settings />
2325
<v-divider />
2426
<theme-settings />
@@ -47,6 +49,7 @@
4749
import SuppressedSettings from './settings/SuppressedSettings.vue'
4850
import DefaultConfigSettings from './settings/DefaultConfigSettings.vue'
4951
import EditorSettings from './settings/EditorSettings.vue'
52+
import ScriptLifecycleSettings from './settings/ScriptLifecycleSettings.vue'
5053
import AstroSettings from './settings/AstroSettings.vue'
5154
import ThemeSettings from './settings/ThemeSettings.vue'
5255
import ClassificationBannerSettings from './settings/ClassificationBannerSettings.vue'
@@ -64,6 +67,7 @@ export default {
6467
SuppressedSettings,
6568
DefaultConfigSettings,
6669
EditorSettings,
70+
ScriptLifecycleSettings,
6771
AstroSettings,
6872
ThemeSettings,
6973
ClassificationBannerSettings,
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
<!--
2+
# Copyright 2026 OpenC3, Inc.
3+
# All Rights Reserved.
4+
#
5+
# This program is distributed in the hope that it will be useful,
6+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
7+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
8+
# See LICENSE.md for more details.
9+
10+
# This file may also be used under the terms of a commercial license
11+
# if purchased from OpenC3, Inc.
12+
-->
13+
14+
<template>
15+
<v-card>
16+
<v-card-title> Script Lifecycle Settings </v-card-title>
17+
<v-card-subtitle>
18+
Track scripts through In Development, In Review, and Approved lifecycle
19+
states in Script Runner.
20+
</v-card-subtitle>
21+
<v-alert v-model="errorLoading" type="error" closable density="compact">
22+
Error loading previous configuration due to {{ errorText }}
23+
</v-alert>
24+
<v-alert v-model="errorSaving" type="error" closable density="compact">
25+
Error saving due to {{ errorText }}
26+
</v-alert>
27+
<v-alert v-model="successSaving" type="success" closable density="compact">
28+
Saved! (Refresh the page to see changes)
29+
</v-alert>
30+
<v-card-text class="pb-0">
31+
<v-switch
32+
v-model="lifecycleEnabled"
33+
label="Script Lifecycle - When enabled, scripts are tracked through
34+
In Development, In Review, and Approved states. Operators can move
35+
scripts between development and review, but only admins can approve
36+
scripts or move approved scripts back to review. Approved scripts
37+
cannot be modified or deleted, and users with only the runner
38+
permission can only run approved scripts."
39+
color="primary"
40+
data-test="script-lifecycle-enabled"
41+
/>
42+
</v-card-text>
43+
<v-card-actions>
44+
<v-btn
45+
color="success"
46+
variant="text"
47+
data-test="save-script-lifecycle-settings"
48+
@click="save"
49+
>
50+
Save
51+
</v-btn>
52+
</v-card-actions>
53+
</v-card>
54+
</template>
55+
56+
<script>
57+
import Settings from './settings.js'
58+
59+
const SCRIPT_LIFECYCLE_SETTING = 'script_runner_lifecycle'
60+
61+
export default {
62+
mixins: [Settings],
63+
data() {
64+
return {
65+
lifecycleEnabled: false,
66+
}
67+
},
68+
created() {
69+
this.loadSetting(SCRIPT_LIFECYCLE_SETTING)
70+
},
71+
methods: {
72+
save: function () {
73+
this.saveSetting(SCRIPT_LIFECYCLE_SETTING, this.lifecycleEnabled)
74+
},
75+
parseSetting: function (response) {
76+
if (response !== null && response !== undefined) {
77+
this.lifecycleEnabled = response
78+
}
79+
},
80+
},
81+
}
82+
</script>

0 commit comments

Comments
 (0)