setShowShowQueryModal(false)} />
+ )}
);
};
diff --git a/frontend/pages/DashboardPage/cards/ActivityFeed/ActivityItem/ActivityItem.tsx b/frontend/pages/DashboardPage/cards/ActivityFeed/ActivityItem/ActivityItem.tsx
index 418a71fa38..123ef6ffcd 100644
--- a/frontend/pages/DashboardPage/cards/ActivityFeed/ActivityItem/ActivityItem.tsx
+++ b/frontend/pages/DashboardPage/cards/ActivityFeed/ActivityItem/ActivityItem.tsx
@@ -488,6 +488,25 @@ const TAGGED_TEMPLATES = {
disabledWindowsMdm: (activity: IActivity) => {
return <> told Fleet to turn off Windows MDM features.>;
},
+ ranScript: (
+ activity: IActivity,
+ onDetailsClick?: (details: IActivityDetails) => void
+ ) => {
+ return (
+ <>
+ {" "}
+ ran a script on {activity.details?.host_display_name}.{" "}
+
+ >
+ );
+ },
};
const getDetail = (
@@ -598,6 +617,9 @@ const getDetail = (
case ActivityType.DisabledWindowsMdm: {
return TAGGED_TEMPLATES.disabledWindowsMdm(activity);
}
+ case ActivityType.RanScript: {
+ return TAGGED_TEMPLATES.ranScript(activity, onDetailsClick);
+ }
default: {
return TAGGED_TEMPLATES.defaultActivityTemplate(activity);
}
diff --git a/frontend/pages/DashboardPage/cards/ActivityFeed/components/ScriptDetailsModal/ScriptDetailsModal.tsx b/frontend/pages/DashboardPage/cards/ActivityFeed/components/ScriptDetailsModal/ScriptDetailsModal.tsx
new file mode 100644
index 0000000000..621754485b
--- /dev/null
+++ b/frontend/pages/DashboardPage/cards/ActivityFeed/components/ScriptDetailsModal/ScriptDetailsModal.tsx
@@ -0,0 +1,193 @@
+import React from "react";
+import { useQuery } from "react-query";
+
+import Modal from "components/Modal";
+import Button from "components/buttons/Button";
+import TooltipWrapper from "components/TooltipWrapper";
+import Icon from "components/Icon";
+import Textarea from "components/Textarea";
+import DataError from "components/DataError/DataError";
+import Spinner from "components/Spinner/Spinner";
+
+const baseClass = "script-details-modal";
+
+const SCRIPT_RUNNING_CODE = -999;
+const HOST_NOT_REACHED_CODE = -998;
+
+interface IScriptContentProps {
+ content: string;
+}
+
+const ScriptContent = ({ content }: IScriptContentProps) => {
+ return (
+
+ Script content:
+
+
+ );
+};
+
+interface IStatusMessageProps {
+ exitCode: number;
+ message: string;
+ runtime: number;
+}
+
+const StatusMessage = ({ exitCode, message, runtime }: IStatusMessageProps) => {
+ let statusMessage: JSX.Element;
+
+ // script timed out error
+ if (runtime > 30) {
+ statusMessage = (
+
+
+ Timeout error: Fleet stopped the script after 30 seconds to protect host
+ performance.
+
+ );
+ // host could not be reached
+ } else if (exitCode === HOST_NOT_REACHED_CODE) {
+ statusMessage = (
+
+
+ The script ran but Fleet couldn't get its output because Fleet
+ didn't hear back from the host.
+
+ );
+ // script still running
+ } else if (exitCode === SCRIPT_RUNNING_CODE) {
+ statusMessage = (
+
+
+ Script is running. To see if the script finished, close this modal and
+ open it again.
+
+ );
+ } else {
+ // 0 or 1 exit code with message
+ statusMessage = (
+
+
+ {`Exit code: ${exitCode} (${message})`}
+
+ );
+ }
+
+ return {statusMessage}
;
+};
+
+interface IScriptOutputProps {
+ output: string;
+}
+
+const ScriptOutput = ({ output }: IScriptOutputProps) => {
+ return (
+
+
+ The{" "}
+
+ output recorded
+ {" "}
+ when Marko's MacBook Pro ran the script above:
+
+
+
+ );
+};
+
+interface IScriptResultProps {
+ exitCode: number;
+ message: string;
+ output: string;
+ runtime: number;
+}
+
+const ScriptResult = ({
+ exitCode,
+ message,
+ output,
+ runtime,
+}: IScriptResultProps) => {
+ const showOutputText = exitCode !== -998 && exitCode !== -999 && runtime < 30;
+
+ return (
+
+
+ {showOutputText && }
+
+ );
+};
+
+interface IScriptDetailsModalProps {
+ onCancel: () => void;
+}
+
+const ScriptDetailsModal = ({ onCancel }: IScriptDetailsModalProps) => {
+ const TEST_DATA = {
+ script_contents: "test contentsss",
+ exit_code: 0,
+ output: "test output",
+ message: "test message",
+ runtime: 20,
+ };
+
+ const { data, isLoading, isError } = useQuery(
+ ["scriptDetailsModal"],
+ () => {
+ return new Promise((resolve) => resolve(TEST_DATA));
+ },
+ { refetchOnWindowFocus: false }
+ );
+
+ const renderContent = () => {
+ let content: JSX.Element;
+
+ if (isLoading) {
+ content = ;
+ } else if (isError) {
+ content = ;
+ } else {
+ content = (
+ <>
+
+
+ >
+ );
+ }
+
+ return (
+ <>
+ {content}
+
+
+
+ >
+ );
+ };
+
+ return (
+
+ {renderContent()}
+
+ );
+};
+
+export default ScriptDetailsModal;
diff --git a/frontend/pages/DashboardPage/cards/ActivityFeed/components/ScriptDetailsModal/_styles.scss b/frontend/pages/DashboardPage/cards/ActivityFeed/components/ScriptDetailsModal/_styles.scss
new file mode 100644
index 0000000000..1158ba1f96
--- /dev/null
+++ b/frontend/pages/DashboardPage/cards/ActivityFeed/components/ScriptDetailsModal/_styles.scss
@@ -0,0 +1,55 @@
+.script-details-modal {
+ box-sizing: border-box;
+ width: 811px;
+
+ &__modal-content {
+ display: flex;
+ flex-direction: column;
+ gap: $pad-xlarge;
+ }
+
+ &__script-content {
+ display: flex;
+ flex-direction: column;
+ gap: $pad-medium;
+ }
+
+ &__script-content-textarea {
+ box-sizing: border-box;
+ min-height: 300px;
+ font-family: "SourceCodePro";
+ }
+
+ &__status-message {
+ p {
+ display: flex;
+ align-items: center;
+ gap: $pad-small;
+ margin: 0;
+ }
+ }
+
+ &__script-result {
+ display: flex;
+ flex-direction: column;
+ gap: $pad-xlarge;
+ }
+
+ &__script-output {
+ display: flex;
+ flex-direction: column;
+ gap: $pad-medium;
+
+ p {
+ margin: 0;
+ }
+ }
+
+ &__output-tooltip {
+ width: 300px;
+ }
+
+ &__output-textarea {
+ font-family: "SourceCodePro";
+ }
+}
diff --git a/frontend/pages/DashboardPage/cards/ActivityFeed/components/ScriptDetailsModal/index.ts b/frontend/pages/DashboardPage/cards/ActivityFeed/components/ScriptDetailsModal/index.ts
new file mode 100644
index 0000000000..70b0475d96
--- /dev/null
+++ b/frontend/pages/DashboardPage/cards/ActivityFeed/components/ScriptDetailsModal/index.ts
@@ -0,0 +1 @@
+export { default } from "./ScriptDetailsModal";
diff --git a/frontend/styles/var/_global.scss b/frontend/styles/var/_global.scss
index 9dcced88e2..0c772c21e8 100644
--- a/frontend/styles/var/_global.scss
+++ b/frontend/styles/var/_global.scss
@@ -1 +1,2 @@
$border-radius: 4px;
+$border-radius-large: 6px;