2025-02-03 22:27:44 +00:00
|
|
|
import React, { useContext, useState } from "react";
|
|
|
|
|
import { useQuery } from "react-query";
|
|
|
|
|
|
2025-05-12 20:51:38 +00:00
|
|
|
import classnames from "classnames";
|
|
|
|
|
|
2025-02-03 22:27:44 +00:00
|
|
|
import { NotificationContext } from "context/notification";
|
2025-02-27 15:53:34 +00:00
|
|
|
import { AppContext } from "context/app";
|
Technician role FE changes (#39494)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #38630
## Testing
- [x] QA'd all new/changed functionality manually
Screenshots below were taken with a **Team Technician** user. Same
changes apply for a **Global Technician**.
#### Controls > OS settings > Disk encryption
- Shows table without controls below.
- Shows empty state (doesn't allow to turn it on).
<img width="1915" height="886" alt="Screenshot 2026-02-10 at 12 24
25 PM"
src="https://github.com/user-attachments/assets/3f44d338-e728-4eb2-ad93-e30844201b52"
/>
<img width="1913" height="907" alt="Screenshot 2026-02-10 at 12 31
38 PM"
src="https://github.com/user-attachments/assets/71706e9e-0540-4c25-b5c0-3f7ccff3ba5a"
/>
#### Controls > OS settings > Custom settings
- Changed description to say **View configuration profiles that apply
custom settings.** instead of **Create and upload configuration profiles
to apply custom settings.**.
- **Add profile** not shown within table header.
- Trash can icon not shown when hovering over a row within the table.
- **Add profile** card not shown on empty state. Instead, "No
configuration profiles have been added." is shown.
<img width="1911" height="729" alt="Screenshot 2026-02-10 at 12 24
39 PM"
src="https://github.com/user-attachments/assets/aa68cbaf-4772-402d-9288-b4be2ddd3250"
/>
<img width="1912" height="650" alt="Screenshot 2026-02-10 at 12 28
48 PM"
src="https://github.com/user-attachments/assets/6a186172-b01f-4314-bb50-4cb533e13bce"
/>
#### Controls > Scripts > Library
- **Add script** not shown within table header.
- No actions shown when hovering over a table row.
- Can view script by clicking on a table row.
- Removed **To run the script across multiple hosts, add a policy
automation on the Policies page** line below **To run this script on a
host, go to the Hosts page and select a host.**.
- Updated copy to `To run this script on a host, go to the Hosts page
and select a host. Then, click Actions > Run script.`
<img width="1912" height="772" alt="Screenshot 2026-02-10 at 12 25
46 PM"
src="https://github.com/user-attachments/assets/83fbc1ec-3a6e-4bb5-865e-b5e7faef1e37"
/>
<img width="1732" height="761" alt="Screenshot 2026-02-11 at 3 50 33 PM"
src="https://github.com/user-attachments/assets/6dda97d7-fde2-4bcd-94b3-fa7368c65528"
/>
#### Labels
Can add label and filter by label
<img width="160" height="247" alt="Screenshot 2026-02-10 at 12 51 24 PM"
src="https://github.com/user-attachments/assets/ed63b708-27f8-4363-9d4f-9a7b0bf82b21"
/>
<img width="1901" height="856" alt="Screenshot 2026-02-10 at 12 35
07 PM"
src="https://github.com/user-attachments/assets/c2ef5e21-03ab-4955-a22f-cd6ca32f3179"
/>
<img width="1903" height="937" alt="Screenshot 2026-02-10 at 12 36
11 PM"
src="https://github.com/user-attachments/assets/d9d9f3bc-4d71-4c4b-902a-455eec9e057c"
/>
Can edit/delete labels created by themselves.
NOTE: my technician user ID is 37 - note that the **x** label belongs to
a different user id, while the second label belongs to ID 37, therefore
it can be edited and deleted.
<img width="1915" height="1152" alt="Screenshot 2026-02-10 at 12 38
29 PM"
src="https://github.com/user-attachments/assets/21f44c11-4e2d-456b-8547-90936b5d7602"
/>
<img width="1911" height="1154" alt="Screenshot 2026-02-10 at 12 38
42 PM"
src="https://github.com/user-attachments/assets/f9f7ea30-11b2-4d2d-9d71-de7299e4b451"
/>
Can delete manual label from host
https://github.com/user-attachments/assets/b64ba6dd-3f54-4dcd-9c57-7bede65122da
#### Host details
Can run scripts and view their results
<img width="1908" height="472" alt="Screenshot 2026-02-10 at 12 52
33 PM"
src="https://github.com/user-attachments/assets/d1e40339-ec52-47ff-bc53-c311498ffe80"
/>
<img width="1882" height="716" alt="Screenshot 2026-02-10 at 12 52
40 PM"
src="https://github.com/user-attachments/assets/dd0c2ec3-8cb8-4835-9c6d-f731a7434637"
/>
<img width="1915" height="718" alt="Screenshot 2026-02-10 at 12 52
48 PM"
src="https://github.com/user-attachments/assets/5e7a73e0-ac5b-4d38-b635-770f53dea9e3"
/>
<img width="1914" height="718" alt="Screenshot 2026-02-10 at 12 52
55 PM"
src="https://github.com/user-attachments/assets/b199c796-66b1-46bc-b2b5-fd35e8aa7a7c"
/>
Can run query associated to host as a live query
https://github.com/user-attachments/assets/7aea6f63-e443-4fa0-87dc-48bef84efa2f
#### Software
Doesn't show trash can icon on software installer card, just the
download one.
<img width="1423" height="838" alt="Screenshot 2026-02-10 at 1 33 53 PM"
src="https://github.com/user-attachments/assets/3a55c226-0bba-43ac-8594-7b5ac0a3684a"
/>
Can install/uninstall software on a host. Note that **Add software**
button is hidden (technicians can't add software).
<img width="1378" height="277" alt="Screenshot 2026-02-10 at 3 08 55 PM"
src="https://github.com/user-attachments/assets/bf413467-2071-48b6-b62b-f3a721b6057c"
/>
#### Queries
- Can run inherited queries on all hosts
https://github.com/user-attachments/assets/09f07e6b-a8c1-453e-81fd-4deb16005836
- Can run team queries on all hosts
https://github.com/user-attachments/assets/18b62dea-e159-40ea-b0ed-1d96b6bd40e7
- Can't manage automations or add queries (buttons are not shown at the
top-right corner)
#### Policies
Same as Queries
https://github.com/user-attachments/assets/2c24514a-2ae0-47a6-b631-6f9e48fc7b9c
#### Protected routes
Tested that I can't access routes that have restricted functionality for
this role, such as:
- **/controls/os-updates**, **/controls/setup-experience** and
**/controls/os-settings/certificates** => redirects to
**/controls/os-settings** ✅
- **/controls/scripts/progress** => redirects to
**/controls/scripts/library** ✅
- **/queries/new** and **/software/add/*** => renders access denied page
✅
---------
Co-authored-by: Lucas Manuel Rodriguez <lucas@fleetdm.com>
2026-02-11 21:38:41 +00:00
|
|
|
import RunScriptHelpText from "pages/hosts/components/ScriptDetailsModal/RunScriptHelpText";
|
2025-02-03 22:27:44 +00:00
|
|
|
import scriptAPI from "services/entities/scripts";
|
|
|
|
|
|
|
|
|
|
import Button from "components/buttons/Button";
|
|
|
|
|
import DataError from "components/DataError";
|
|
|
|
|
import Editor from "components/Editor";
|
|
|
|
|
import Modal from "components/Modal";
|
|
|
|
|
import ModalFooter from "components/ModalFooter";
|
|
|
|
|
import Spinner from "components/Spinner";
|
|
|
|
|
|
|
|
|
|
import { ScriptContent } from "interfaces/script";
|
|
|
|
|
import { DEFAULT_USE_QUERY_OPTIONS } from "utilities/constants";
|
2025-10-17 15:49:59 +00:00
|
|
|
import { getErrorMessage } from "../ScriptUploadModal/helpers";
|
2025-02-03 22:27:44 +00:00
|
|
|
|
|
|
|
|
const baseClass = "edit-script-modal";
|
|
|
|
|
|
2025-05-12 20:51:38 +00:00
|
|
|
interface IWarningModal {
|
|
|
|
|
onExit: () => void;
|
|
|
|
|
onSave: () => void;
|
|
|
|
|
scriptName: string;
|
|
|
|
|
isSubmitting: boolean;
|
|
|
|
|
}
|
|
|
|
|
const WarningModal = ({
|
|
|
|
|
onExit,
|
|
|
|
|
onSave,
|
|
|
|
|
scriptName,
|
|
|
|
|
isSubmitting,
|
|
|
|
|
}: IWarningModal) => {
|
|
|
|
|
return (
|
|
|
|
|
<Modal
|
|
|
|
|
className={`${baseClass}__warning`}
|
|
|
|
|
title="Save changes?"
|
|
|
|
|
onExit={onExit}
|
|
|
|
|
>
|
2026-03-10 22:30:55 +00:00
|
|
|
<p>
|
|
|
|
|
The changes you are making will cancel any pending script runs for{" "}
|
|
|
|
|
<b>{scriptName}</b>.<br />
|
|
|
|
|
<br />
|
|
|
|
|
If this script is currently running on a host, it will complete, but
|
|
|
|
|
results won't appear in Fleet. <br />
|
|
|
|
|
<br />
|
|
|
|
|
You cannot undo this action.
|
|
|
|
|
</p>
|
|
|
|
|
<div className="modal-cta-wrap">
|
|
|
|
|
<Button
|
|
|
|
|
type="button"
|
|
|
|
|
onClick={onSave}
|
|
|
|
|
className="save-loading"
|
|
|
|
|
isLoading={isSubmitting}
|
|
|
|
|
>
|
|
|
|
|
Save
|
|
|
|
|
</Button>
|
|
|
|
|
<Button onClick={onExit} variant="inverse">
|
|
|
|
|
Cancel
|
|
|
|
|
</Button>
|
|
|
|
|
</div>
|
2025-05-12 20:51:38 +00:00
|
|
|
</Modal>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2025-02-03 22:27:44 +00:00
|
|
|
interface IEditScriptModal {
|
|
|
|
|
onExit: () => void;
|
|
|
|
|
scriptId: number;
|
|
|
|
|
scriptName: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const validate = (scriptContent: string) => {
|
|
|
|
|
if (scriptContent.trim() === "") {
|
|
|
|
|
return "Script cannot be empty";
|
|
|
|
|
}
|
|
|
|
|
return null;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const EditScriptModal = ({
|
|
|
|
|
scriptId,
|
|
|
|
|
scriptName,
|
|
|
|
|
onExit,
|
|
|
|
|
}: IEditScriptModal) => {
|
|
|
|
|
const { renderFlash } = useContext(NotificationContext);
|
Technician role FE changes (#39494)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #38630
## Testing
- [x] QA'd all new/changed functionality manually
Screenshots below were taken with a **Team Technician** user. Same
changes apply for a **Global Technician**.
#### Controls > OS settings > Disk encryption
- Shows table without controls below.
- Shows empty state (doesn't allow to turn it on).
<img width="1915" height="886" alt="Screenshot 2026-02-10 at 12 24
25 PM"
src="https://github.com/user-attachments/assets/3f44d338-e728-4eb2-ad93-e30844201b52"
/>
<img width="1913" height="907" alt="Screenshot 2026-02-10 at 12 31
38 PM"
src="https://github.com/user-attachments/assets/71706e9e-0540-4c25-b5c0-3f7ccff3ba5a"
/>
#### Controls > OS settings > Custom settings
- Changed description to say **View configuration profiles that apply
custom settings.** instead of **Create and upload configuration profiles
to apply custom settings.**.
- **Add profile** not shown within table header.
- Trash can icon not shown when hovering over a row within the table.
- **Add profile** card not shown on empty state. Instead, "No
configuration profiles have been added." is shown.
<img width="1911" height="729" alt="Screenshot 2026-02-10 at 12 24
39 PM"
src="https://github.com/user-attachments/assets/aa68cbaf-4772-402d-9288-b4be2ddd3250"
/>
<img width="1912" height="650" alt="Screenshot 2026-02-10 at 12 28
48 PM"
src="https://github.com/user-attachments/assets/6a186172-b01f-4314-bb50-4cb533e13bce"
/>
#### Controls > Scripts > Library
- **Add script** not shown within table header.
- No actions shown when hovering over a table row.
- Can view script by clicking on a table row.
- Removed **To run the script across multiple hosts, add a policy
automation on the Policies page** line below **To run this script on a
host, go to the Hosts page and select a host.**.
- Updated copy to `To run this script on a host, go to the Hosts page
and select a host. Then, click Actions > Run script.`
<img width="1912" height="772" alt="Screenshot 2026-02-10 at 12 25
46 PM"
src="https://github.com/user-attachments/assets/83fbc1ec-3a6e-4bb5-865e-b5e7faef1e37"
/>
<img width="1732" height="761" alt="Screenshot 2026-02-11 at 3 50 33 PM"
src="https://github.com/user-attachments/assets/6dda97d7-fde2-4bcd-94b3-fa7368c65528"
/>
#### Labels
Can add label and filter by label
<img width="160" height="247" alt="Screenshot 2026-02-10 at 12 51 24 PM"
src="https://github.com/user-attachments/assets/ed63b708-27f8-4363-9d4f-9a7b0bf82b21"
/>
<img width="1901" height="856" alt="Screenshot 2026-02-10 at 12 35
07 PM"
src="https://github.com/user-attachments/assets/c2ef5e21-03ab-4955-a22f-cd6ca32f3179"
/>
<img width="1903" height="937" alt="Screenshot 2026-02-10 at 12 36
11 PM"
src="https://github.com/user-attachments/assets/d9d9f3bc-4d71-4c4b-902a-455eec9e057c"
/>
Can edit/delete labels created by themselves.
NOTE: my technician user ID is 37 - note that the **x** label belongs to
a different user id, while the second label belongs to ID 37, therefore
it can be edited and deleted.
<img width="1915" height="1152" alt="Screenshot 2026-02-10 at 12 38
29 PM"
src="https://github.com/user-attachments/assets/21f44c11-4e2d-456b-8547-90936b5d7602"
/>
<img width="1911" height="1154" alt="Screenshot 2026-02-10 at 12 38
42 PM"
src="https://github.com/user-attachments/assets/f9f7ea30-11b2-4d2d-9d71-de7299e4b451"
/>
Can delete manual label from host
https://github.com/user-attachments/assets/b64ba6dd-3f54-4dcd-9c57-7bede65122da
#### Host details
Can run scripts and view their results
<img width="1908" height="472" alt="Screenshot 2026-02-10 at 12 52
33 PM"
src="https://github.com/user-attachments/assets/d1e40339-ec52-47ff-bc53-c311498ffe80"
/>
<img width="1882" height="716" alt="Screenshot 2026-02-10 at 12 52
40 PM"
src="https://github.com/user-attachments/assets/dd0c2ec3-8cb8-4835-9c6d-f731a7434637"
/>
<img width="1915" height="718" alt="Screenshot 2026-02-10 at 12 52
48 PM"
src="https://github.com/user-attachments/assets/5e7a73e0-ac5b-4d38-b635-770f53dea9e3"
/>
<img width="1914" height="718" alt="Screenshot 2026-02-10 at 12 52
55 PM"
src="https://github.com/user-attachments/assets/b199c796-66b1-46bc-b2b5-fd35e8aa7a7c"
/>
Can run query associated to host as a live query
https://github.com/user-attachments/assets/7aea6f63-e443-4fa0-87dc-48bef84efa2f
#### Software
Doesn't show trash can icon on software installer card, just the
download one.
<img width="1423" height="838" alt="Screenshot 2026-02-10 at 1 33 53 PM"
src="https://github.com/user-attachments/assets/3a55c226-0bba-43ac-8594-7b5ac0a3684a"
/>
Can install/uninstall software on a host. Note that **Add software**
button is hidden (technicians can't add software).
<img width="1378" height="277" alt="Screenshot 2026-02-10 at 3 08 55 PM"
src="https://github.com/user-attachments/assets/bf413467-2071-48b6-b62b-f3a721b6057c"
/>
#### Queries
- Can run inherited queries on all hosts
https://github.com/user-attachments/assets/09f07e6b-a8c1-453e-81fd-4deb16005836
- Can run team queries on all hosts
https://github.com/user-attachments/assets/18b62dea-e159-40ea-b0ed-1d96b6bd40e7
- Can't manage automations or add queries (buttons are not shown at the
top-right corner)
#### Policies
Same as Queries
https://github.com/user-attachments/assets/2c24514a-2ae0-47a6-b631-6f9e48fc7b9c
#### Protected routes
Tested that I can't access routes that have restricted functionality for
this role, such as:
- **/controls/os-updates**, **/controls/setup-experience** and
**/controls/os-settings/certificates** => redirects to
**/controls/os-settings** ✅
- **/controls/scripts/progress** => redirects to
**/controls/scripts/library** ✅
- **/queries/new** and **/software/add/*** => renders access denied page
✅
---------
Co-authored-by: Lucas Manuel Rodriguez <lucas@fleetdm.com>
2026-02-11 21:38:41 +00:00
|
|
|
const {
|
|
|
|
|
currentTeam,
|
|
|
|
|
isGlobalAdmin,
|
|
|
|
|
isAnyTeamAdmin,
|
|
|
|
|
isGlobalMaintainer,
|
|
|
|
|
isAnyTeamMaintainer,
|
|
|
|
|
isTeamTechnician,
|
|
|
|
|
isGlobalTechnician,
|
|
|
|
|
} = useContext(AppContext);
|
|
|
|
|
|
|
|
|
|
const isTechnician = !!isTeamTechnician || !!isGlobalTechnician;
|
|
|
|
|
|
|
|
|
|
const canRunScripts = !!(
|
|
|
|
|
isGlobalAdmin ||
|
|
|
|
|
isAnyTeamAdmin ||
|
|
|
|
|
isGlobalMaintainer ||
|
|
|
|
|
isAnyTeamMaintainer
|
|
|
|
|
);
|
2025-02-03 22:27:44 +00:00
|
|
|
|
|
|
|
|
// Editable script content
|
|
|
|
|
const [scriptFormData, setScriptFormData] = useState("");
|
|
|
|
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
|
|
|
const [formError, setFormError] = useState<string | null>(null);
|
|
|
|
|
|
2025-05-12 20:51:38 +00:00
|
|
|
const [showConfirmChanges, setShowConfirmChanges] = useState(false);
|
|
|
|
|
|
2025-02-03 22:27:44 +00:00
|
|
|
const {
|
2025-05-12 20:51:38 +00:00
|
|
|
data: curScriptContent,
|
2025-02-03 22:27:44 +00:00
|
|
|
error: isSelectedScriptContentError,
|
|
|
|
|
isLoading: isLoadingSelectedScriptContent,
|
|
|
|
|
} = useQuery<ScriptContent, Error>(
|
|
|
|
|
[scriptId],
|
|
|
|
|
() => scriptAPI.downloadScript(scriptId),
|
|
|
|
|
{
|
|
|
|
|
...DEFAULT_USE_QUERY_OPTIONS,
|
2025-05-12 20:51:38 +00:00
|
|
|
onSuccess: (curScriptContent_) => {
|
|
|
|
|
setScriptFormData(curScriptContent_);
|
2025-02-03 22:27:44 +00:00
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
const onChange = (value: string) => {
|
|
|
|
|
setScriptFormData(value);
|
2025-02-04 17:27:52 +00:00
|
|
|
const err = validate(value);
|
|
|
|
|
if (!err && !!formError) {
|
|
|
|
|
setFormError(validate(value));
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onBlur = () => {
|
|
|
|
|
setFormError(validate(scriptFormData));
|
2025-02-03 22:27:44 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onSave = async () => {
|
2025-02-04 17:27:52 +00:00
|
|
|
const err = validate(scriptFormData);
|
|
|
|
|
setFormError(err);
|
|
|
|
|
if (err || isSubmitting) {
|
2025-02-03 22:27:44 +00:00
|
|
|
return;
|
|
|
|
|
}
|
2025-05-12 20:51:38 +00:00
|
|
|
// if contents have changed and not already showing the warning modal
|
|
|
|
|
if (curScriptContent !== scriptFormData && !showConfirmChanges) {
|
|
|
|
|
setShowConfirmChanges(true);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
// show warning modal and abort this call
|
2025-02-03 22:27:44 +00:00
|
|
|
try {
|
|
|
|
|
setIsSubmitting(true);
|
|
|
|
|
await scriptAPI.updateScript(scriptId, scriptFormData, scriptName);
|
|
|
|
|
renderFlash("success", "Successfully saved script.");
|
|
|
|
|
onExit();
|
|
|
|
|
} catch (e) {
|
|
|
|
|
renderFlash("error", getErrorMessage(e));
|
|
|
|
|
} finally {
|
|
|
|
|
setIsSubmitting(false);
|
2025-05-12 20:51:38 +00:00
|
|
|
setShowConfirmChanges(false);
|
2025-02-03 22:27:44 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const onSubmit = async (e: React.FormEvent<HTMLFormElement>) => {
|
|
|
|
|
e.preventDefault();
|
|
|
|
|
onSave();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
const renderContent = () => {
|
|
|
|
|
if (isLoadingSelectedScriptContent) {
|
|
|
|
|
return <Spinner />;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (isSelectedScriptContentError) {
|
|
|
|
|
return <DataError description="Close this modal and try again." />;
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-29 15:24:05 +00:00
|
|
|
// Set editing mode based on the file extension.
|
|
|
|
|
const mode = scriptName.match(/\.sh$/) ? "sh" : "powershell";
|
|
|
|
|
|
2025-02-03 22:27:44 +00:00
|
|
|
return (
|
|
|
|
|
<>
|
|
|
|
|
<form onSubmit={onSubmit}>
|
|
|
|
|
<Editor
|
2025-04-29 15:24:05 +00:00
|
|
|
mode={mode}
|
2025-02-03 22:27:44 +00:00
|
|
|
error={formError}
|
2025-02-14 14:31:21 +00:00
|
|
|
label="Script"
|
2025-02-04 17:27:52 +00:00
|
|
|
onBlur={onBlur}
|
2025-02-14 14:31:21 +00:00
|
|
|
onChange={onChange}
|
|
|
|
|
value={scriptFormData}
|
2025-02-03 22:27:44 +00:00
|
|
|
/>
|
Technician role FE changes (#39494)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #38630
## Testing
- [x] QA'd all new/changed functionality manually
Screenshots below were taken with a **Team Technician** user. Same
changes apply for a **Global Technician**.
#### Controls > OS settings > Disk encryption
- Shows table without controls below.
- Shows empty state (doesn't allow to turn it on).
<img width="1915" height="886" alt="Screenshot 2026-02-10 at 12 24
25 PM"
src="https://github.com/user-attachments/assets/3f44d338-e728-4eb2-ad93-e30844201b52"
/>
<img width="1913" height="907" alt="Screenshot 2026-02-10 at 12 31
38 PM"
src="https://github.com/user-attachments/assets/71706e9e-0540-4c25-b5c0-3f7ccff3ba5a"
/>
#### Controls > OS settings > Custom settings
- Changed description to say **View configuration profiles that apply
custom settings.** instead of **Create and upload configuration profiles
to apply custom settings.**.
- **Add profile** not shown within table header.
- Trash can icon not shown when hovering over a row within the table.
- **Add profile** card not shown on empty state. Instead, "No
configuration profiles have been added." is shown.
<img width="1911" height="729" alt="Screenshot 2026-02-10 at 12 24
39 PM"
src="https://github.com/user-attachments/assets/aa68cbaf-4772-402d-9288-b4be2ddd3250"
/>
<img width="1912" height="650" alt="Screenshot 2026-02-10 at 12 28
48 PM"
src="https://github.com/user-attachments/assets/6a186172-b01f-4314-bb50-4cb533e13bce"
/>
#### Controls > Scripts > Library
- **Add script** not shown within table header.
- No actions shown when hovering over a table row.
- Can view script by clicking on a table row.
- Removed **To run the script across multiple hosts, add a policy
automation on the Policies page** line below **To run this script on a
host, go to the Hosts page and select a host.**.
- Updated copy to `To run this script on a host, go to the Hosts page
and select a host. Then, click Actions > Run script.`
<img width="1912" height="772" alt="Screenshot 2026-02-10 at 12 25
46 PM"
src="https://github.com/user-attachments/assets/83fbc1ec-3a6e-4bb5-865e-b5e7faef1e37"
/>
<img width="1732" height="761" alt="Screenshot 2026-02-11 at 3 50 33 PM"
src="https://github.com/user-attachments/assets/6dda97d7-fde2-4bcd-94b3-fa7368c65528"
/>
#### Labels
Can add label and filter by label
<img width="160" height="247" alt="Screenshot 2026-02-10 at 12 51 24 PM"
src="https://github.com/user-attachments/assets/ed63b708-27f8-4363-9d4f-9a7b0bf82b21"
/>
<img width="1901" height="856" alt="Screenshot 2026-02-10 at 12 35
07 PM"
src="https://github.com/user-attachments/assets/c2ef5e21-03ab-4955-a22f-cd6ca32f3179"
/>
<img width="1903" height="937" alt="Screenshot 2026-02-10 at 12 36
11 PM"
src="https://github.com/user-attachments/assets/d9d9f3bc-4d71-4c4b-902a-455eec9e057c"
/>
Can edit/delete labels created by themselves.
NOTE: my technician user ID is 37 - note that the **x** label belongs to
a different user id, while the second label belongs to ID 37, therefore
it can be edited and deleted.
<img width="1915" height="1152" alt="Screenshot 2026-02-10 at 12 38
29 PM"
src="https://github.com/user-attachments/assets/21f44c11-4e2d-456b-8547-90936b5d7602"
/>
<img width="1911" height="1154" alt="Screenshot 2026-02-10 at 12 38
42 PM"
src="https://github.com/user-attachments/assets/f9f7ea30-11b2-4d2d-9d71-de7299e4b451"
/>
Can delete manual label from host
https://github.com/user-attachments/assets/b64ba6dd-3f54-4dcd-9c57-7bede65122da
#### Host details
Can run scripts and view their results
<img width="1908" height="472" alt="Screenshot 2026-02-10 at 12 52
33 PM"
src="https://github.com/user-attachments/assets/d1e40339-ec52-47ff-bc53-c311498ffe80"
/>
<img width="1882" height="716" alt="Screenshot 2026-02-10 at 12 52
40 PM"
src="https://github.com/user-attachments/assets/dd0c2ec3-8cb8-4835-9c6d-f731a7434637"
/>
<img width="1915" height="718" alt="Screenshot 2026-02-10 at 12 52
48 PM"
src="https://github.com/user-attachments/assets/5e7a73e0-ac5b-4d38-b635-770f53dea9e3"
/>
<img width="1914" height="718" alt="Screenshot 2026-02-10 at 12 52
55 PM"
src="https://github.com/user-attachments/assets/b199c796-66b1-46bc-b2b5-fd35e8aa7a7c"
/>
Can run query associated to host as a live query
https://github.com/user-attachments/assets/7aea6f63-e443-4fa0-87dc-48bef84efa2f
#### Software
Doesn't show trash can icon on software installer card, just the
download one.
<img width="1423" height="838" alt="Screenshot 2026-02-10 at 1 33 53 PM"
src="https://github.com/user-attachments/assets/3a55c226-0bba-43ac-8594-7b5ac0a3684a"
/>
Can install/uninstall software on a host. Note that **Add software**
button is hidden (technicians can't add software).
<img width="1378" height="277" alt="Screenshot 2026-02-10 at 3 08 55 PM"
src="https://github.com/user-attachments/assets/bf413467-2071-48b6-b62b-f3a721b6057c"
/>
#### Queries
- Can run inherited queries on all hosts
https://github.com/user-attachments/assets/09f07e6b-a8c1-453e-81fd-4deb16005836
- Can run team queries on all hosts
https://github.com/user-attachments/assets/18b62dea-e159-40ea-b0ed-1d96b6bd40e7
- Can't manage automations or add queries (buttons are not shown at the
top-right corner)
#### Policies
Same as Queries
https://github.com/user-attachments/assets/2c24514a-2ae0-47a6-b631-6f9e48fc7b9c
#### Protected routes
Tested that I can't access routes that have restricted functionality for
this role, such as:
- **/controls/os-updates**, **/controls/setup-experience** and
**/controls/os-settings/certificates** => redirects to
**/controls/os-settings** ✅
- **/controls/scripts/progress** => redirects to
**/controls/scripts/library** ✅
- **/queries/new** and **/software/add/*** => renders access denied page
✅
---------
Co-authored-by: Lucas Manuel Rodriguez <lucas@fleetdm.com>
2026-02-11 21:38:41 +00:00
|
|
|
<RunScriptHelpText
|
|
|
|
|
className="form-field__help-text"
|
|
|
|
|
isTechnician={isTechnician}
|
|
|
|
|
canRunScripts={canRunScripts}
|
|
|
|
|
teamId={currentTeam?.id}
|
|
|
|
|
/>
|
2025-02-03 22:27:44 +00:00
|
|
|
</form>
|
Technician role FE changes (#39494)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or
remove if NA -->
**Related issue:** Resolves #38630
## Testing
- [x] QA'd all new/changed functionality manually
Screenshots below were taken with a **Team Technician** user. Same
changes apply for a **Global Technician**.
#### Controls > OS settings > Disk encryption
- Shows table without controls below.
- Shows empty state (doesn't allow to turn it on).
<img width="1915" height="886" alt="Screenshot 2026-02-10 at 12 24
25 PM"
src="https://github.com/user-attachments/assets/3f44d338-e728-4eb2-ad93-e30844201b52"
/>
<img width="1913" height="907" alt="Screenshot 2026-02-10 at 12 31
38 PM"
src="https://github.com/user-attachments/assets/71706e9e-0540-4c25-b5c0-3f7ccff3ba5a"
/>
#### Controls > OS settings > Custom settings
- Changed description to say **View configuration profiles that apply
custom settings.** instead of **Create and upload configuration profiles
to apply custom settings.**.
- **Add profile** not shown within table header.
- Trash can icon not shown when hovering over a row within the table.
- **Add profile** card not shown on empty state. Instead, "No
configuration profiles have been added." is shown.
<img width="1911" height="729" alt="Screenshot 2026-02-10 at 12 24
39 PM"
src="https://github.com/user-attachments/assets/aa68cbaf-4772-402d-9288-b4be2ddd3250"
/>
<img width="1912" height="650" alt="Screenshot 2026-02-10 at 12 28
48 PM"
src="https://github.com/user-attachments/assets/6a186172-b01f-4314-bb50-4cb533e13bce"
/>
#### Controls > Scripts > Library
- **Add script** not shown within table header.
- No actions shown when hovering over a table row.
- Can view script by clicking on a table row.
- Removed **To run the script across multiple hosts, add a policy
automation on the Policies page** line below **To run this script on a
host, go to the Hosts page and select a host.**.
- Updated copy to `To run this script on a host, go to the Hosts page
and select a host. Then, click Actions > Run script.`
<img width="1912" height="772" alt="Screenshot 2026-02-10 at 12 25
46 PM"
src="https://github.com/user-attachments/assets/83fbc1ec-3a6e-4bb5-865e-b5e7faef1e37"
/>
<img width="1732" height="761" alt="Screenshot 2026-02-11 at 3 50 33 PM"
src="https://github.com/user-attachments/assets/6dda97d7-fde2-4bcd-94b3-fa7368c65528"
/>
#### Labels
Can add label and filter by label
<img width="160" height="247" alt="Screenshot 2026-02-10 at 12 51 24 PM"
src="https://github.com/user-attachments/assets/ed63b708-27f8-4363-9d4f-9a7b0bf82b21"
/>
<img width="1901" height="856" alt="Screenshot 2026-02-10 at 12 35
07 PM"
src="https://github.com/user-attachments/assets/c2ef5e21-03ab-4955-a22f-cd6ca32f3179"
/>
<img width="1903" height="937" alt="Screenshot 2026-02-10 at 12 36
11 PM"
src="https://github.com/user-attachments/assets/d9d9f3bc-4d71-4c4b-902a-455eec9e057c"
/>
Can edit/delete labels created by themselves.
NOTE: my technician user ID is 37 - note that the **x** label belongs to
a different user id, while the second label belongs to ID 37, therefore
it can be edited and deleted.
<img width="1915" height="1152" alt="Screenshot 2026-02-10 at 12 38
29 PM"
src="https://github.com/user-attachments/assets/21f44c11-4e2d-456b-8547-90936b5d7602"
/>
<img width="1911" height="1154" alt="Screenshot 2026-02-10 at 12 38
42 PM"
src="https://github.com/user-attachments/assets/f9f7ea30-11b2-4d2d-9d71-de7299e4b451"
/>
Can delete manual label from host
https://github.com/user-attachments/assets/b64ba6dd-3f54-4dcd-9c57-7bede65122da
#### Host details
Can run scripts and view their results
<img width="1908" height="472" alt="Screenshot 2026-02-10 at 12 52
33 PM"
src="https://github.com/user-attachments/assets/d1e40339-ec52-47ff-bc53-c311498ffe80"
/>
<img width="1882" height="716" alt="Screenshot 2026-02-10 at 12 52
40 PM"
src="https://github.com/user-attachments/assets/dd0c2ec3-8cb8-4835-9c6d-f731a7434637"
/>
<img width="1915" height="718" alt="Screenshot 2026-02-10 at 12 52
48 PM"
src="https://github.com/user-attachments/assets/5e7a73e0-ac5b-4d38-b635-770f53dea9e3"
/>
<img width="1914" height="718" alt="Screenshot 2026-02-10 at 12 52
55 PM"
src="https://github.com/user-attachments/assets/b199c796-66b1-46bc-b2b5-fd35e8aa7a7c"
/>
Can run query associated to host as a live query
https://github.com/user-attachments/assets/7aea6f63-e443-4fa0-87dc-48bef84efa2f
#### Software
Doesn't show trash can icon on software installer card, just the
download one.
<img width="1423" height="838" alt="Screenshot 2026-02-10 at 1 33 53 PM"
src="https://github.com/user-attachments/assets/3a55c226-0bba-43ac-8594-7b5ac0a3684a"
/>
Can install/uninstall software on a host. Note that **Add software**
button is hidden (technicians can't add software).
<img width="1378" height="277" alt="Screenshot 2026-02-10 at 3 08 55 PM"
src="https://github.com/user-attachments/assets/bf413467-2071-48b6-b62b-f3a721b6057c"
/>
#### Queries
- Can run inherited queries on all hosts
https://github.com/user-attachments/assets/09f07e6b-a8c1-453e-81fd-4deb16005836
- Can run team queries on all hosts
https://github.com/user-attachments/assets/18b62dea-e159-40ea-b0ed-1d96b6bd40e7
- Can't manage automations or add queries (buttons are not shown at the
top-right corner)
#### Policies
Same as Queries
https://github.com/user-attachments/assets/2c24514a-2ae0-47a6-b631-6f9e48fc7b9c
#### Protected routes
Tested that I can't access routes that have restricted functionality for
this role, such as:
- **/controls/os-updates**, **/controls/setup-experience** and
**/controls/os-settings/certificates** => redirects to
**/controls/os-settings** ✅
- **/controls/scripts/progress** => redirects to
**/controls/scripts/library** ✅
- **/queries/new** and **/software/add/*** => renders access denied page
✅
---------
Co-authored-by: Lucas Manuel Rodriguez <lucas@fleetdm.com>
2026-02-11 21:38:41 +00:00
|
|
|
{canRunScripts && (
|
|
|
|
|
<ModalFooter
|
|
|
|
|
primaryButtons={
|
|
|
|
|
<>
|
|
|
|
|
<Button onClick={onExit} variant="inverse">
|
|
|
|
|
Cancel
|
|
|
|
|
</Button>
|
|
|
|
|
<Button
|
|
|
|
|
onClick={onSave}
|
|
|
|
|
isLoading={isSubmitting}
|
|
|
|
|
disabled={!!formError}
|
|
|
|
|
>
|
|
|
|
|
Save
|
|
|
|
|
</Button>
|
|
|
|
|
</>
|
|
|
|
|
}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
2025-02-03 22:27:44 +00:00
|
|
|
</>
|
|
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
2025-05-12 20:51:38 +00:00
|
|
|
const classes = classnames(baseClass, {
|
|
|
|
|
[`${baseClass}__hide-main`]: !!showConfirmChanges,
|
|
|
|
|
});
|
2025-02-03 22:27:44 +00:00
|
|
|
return (
|
2025-05-12 20:51:38 +00:00
|
|
|
<>
|
|
|
|
|
<Modal
|
|
|
|
|
className={classes}
|
|
|
|
|
title={scriptName}
|
|
|
|
|
width="large"
|
|
|
|
|
onExit={onExit}
|
|
|
|
|
>
|
|
|
|
|
{renderContent()}
|
|
|
|
|
</Modal>
|
|
|
|
|
{!!showConfirmChanges && (
|
|
|
|
|
<WarningModal
|
|
|
|
|
onExit={() => setShowConfirmChanges(false)}
|
|
|
|
|
onSave={onSave}
|
|
|
|
|
scriptName={scriptName}
|
|
|
|
|
isSubmitting={isSubmitting}
|
|
|
|
|
/>
|
|
|
|
|
)}
|
|
|
|
|
</>
|
2025-02-03 22:27:44 +00:00
|
|
|
);
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export default EditScriptModal;
|