Fleet UI: Add textarea variant 'code' and apply to various modals (#27930)
This commit is contained in:
+7
-4
@@ -1,3 +1,5 @@
|
||||
// Used on: Dashboard > activity, Host details > past activity
|
||||
|
||||
import React from "react";
|
||||
import { useQuery } from "react-query";
|
||||
|
||||
@@ -115,16 +117,17 @@ export const AppInstallDetails = ({
|
||||
</div>
|
||||
{showCommandPayload && (
|
||||
<div className={`${baseClass}__script-output`}>
|
||||
Request payload:
|
||||
<Textarea className={`${baseClass}__output-textarea`}>
|
||||
<Textarea label="Request payload:" variant="code">
|
||||
{result.payload}
|
||||
</Textarea>
|
||||
</div>
|
||||
)}
|
||||
{showCommandResponse && (
|
||||
<div className={`${baseClass}__script-output`}>
|
||||
The response from {formattedHost}:
|
||||
<Textarea className={`${baseClass}__output-textarea`}>
|
||||
<Textarea
|
||||
label={`The response from ${formattedHost}:`}
|
||||
variant="code"
|
||||
>
|
||||
{result.result}
|
||||
</Textarea>
|
||||
</div>
|
||||
|
||||
@@ -10,20 +10,7 @@
|
||||
gap: $pad-small;
|
||||
margin: 0;
|
||||
.icon {
|
||||
padding-top: 3px;
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
&__script-output {
|
||||
padding-top: $pad-xlarge;
|
||||
.textarea {
|
||||
margin-top: $pad-medium;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
}
|
||||
|
||||
&__output-textarea {
|
||||
max-height: 300px;
|
||||
overflow-y: auto;
|
||||
}
|
||||
}
|
||||
|
||||
+22
-20
@@ -1,3 +1,5 @@
|
||||
// Used on: Dashboard > activity, Host details > past activity
|
||||
|
||||
import React from "react";
|
||||
import { useQuery } from "react-query";
|
||||
import { formatDistanceToNow } from "date-fns";
|
||||
@@ -79,8 +81,10 @@ const Output = ({
|
||||
}) => {
|
||||
return (
|
||||
<div className={`${baseClass}__script-output`}>
|
||||
{SOFTWARE_INSTALL_OUTPUT_DISPLAY_LABELS[displayKey]}:
|
||||
<Textarea className={`${baseClass}__output-textarea`}>
|
||||
<Textarea
|
||||
label={`${SOFTWARE_INSTALL_OUTPUT_DISPLAY_LABELS[displayKey]}:`}
|
||||
variant="code"
|
||||
>
|
||||
{result[displayKey]}
|
||||
</Textarea>
|
||||
</div>
|
||||
@@ -126,24 +130,22 @@ export const SoftwareInstallDetails = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<div className={`${baseClass}__software-install-details`}>
|
||||
<StatusMessage
|
||||
result={
|
||||
result.host_display_name ? result : { ...result, host_display_name } // prefer result.host_display_name (it may be empty if the host was deleted) otherwise default to whatever we received via props
|
||||
}
|
||||
/>
|
||||
{result.status !== "pending_install" && (
|
||||
<>
|
||||
{result.pre_install_query_output && (
|
||||
<Output displayKey="pre_install_query_output" result={result} />
|
||||
)}
|
||||
{result.output && <Output displayKey="output" result={result} />}
|
||||
{result.post_install_script_output && (
|
||||
<Output displayKey="post_install_script_output" result={result} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
<StatusMessage
|
||||
result={
|
||||
result.host_display_name ? result : { ...result, host_display_name } // prefer result.host_display_name (it may be empty if the host was deleted) otherwise default to whatever we received via props
|
||||
}
|
||||
/>
|
||||
{result.status !== "pending_install" && (
|
||||
<>
|
||||
{result.pre_install_query_output && (
|
||||
<Output displayKey="pre_install_query_output" result={result} />
|
||||
)}
|
||||
{result.output && <Output displayKey="output" result={result} />}
|
||||
{result.post_install_script_output && (
|
||||
<Output displayKey="post_install_script_output" result={result} />
|
||||
)}
|
||||
</>
|
||||
)}
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
+6
-8
@@ -1,21 +1,19 @@
|
||||
.software-install-details {
|
||||
overflow-wrap: anywhere; // Prevent long software name overflow
|
||||
|
||||
&__modal-content {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $pad-medium;
|
||||
}
|
||||
|
||||
&__status-message {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: $pad-small;
|
||||
margin: 0;
|
||||
.icon {
|
||||
padding-top: 3px;
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
&__script-output {
|
||||
padding-top: $pad-xlarge;
|
||||
.textarea {
|
||||
margin-top: $pad-medium;
|
||||
overflow-wrap: break-word;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,3 +1,5 @@
|
||||
// Used on: Dashboard > activity, Host details > past activity
|
||||
|
||||
import Button from "components/buttons/Button";
|
||||
import DataError from "components/DataError";
|
||||
import Icon from "components/Icon";
|
||||
@@ -127,15 +129,13 @@ const SoftwareUninstallDetailsModal = ({
|
||||
{!isPendingStatus(status) && scriptResult && (
|
||||
<>
|
||||
<div className={`${baseClass}__script-output`}>
|
||||
Uninstall script content:
|
||||
<Textarea className={`${baseClass}__output-textarea`}>
|
||||
<Textarea label="Uninstall script content:" variant="code">
|
||||
{scriptResult.script_contents}
|
||||
</Textarea>
|
||||
</div>
|
||||
|
||||
<div className={`${baseClass}__script-output`}>
|
||||
Uninstall script output:
|
||||
<Textarea className={`${baseClass}__output-textarea`}>
|
||||
<Textarea label="Uninstall script output:" variant="code">
|
||||
{scriptResult.output}
|
||||
</Textarea>
|
||||
</div>
|
||||
|
||||
-7
@@ -13,11 +13,4 @@
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
&__script-output {
|
||||
.textarea {
|
||||
margin-top: $pad-medium;
|
||||
overflow-wrap: break-word;
|
||||
font-family: "SourceCodePro", $monospace;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
import { Meta, StoryObj } from "@storybook/react";
|
||||
import Textarea from ".";
|
||||
import "../../index.scss";
|
||||
|
||||
const meta: Meta<typeof Textarea> = {
|
||||
component: Textarea,
|
||||
title: "Components/Textarea",
|
||||
args: {
|
||||
children: "Default textarea content",
|
||||
},
|
||||
};
|
||||
|
||||
export default meta;
|
||||
|
||||
type Story = StoryObj<typeof Textarea>;
|
||||
|
||||
export const ExampleWithLabelAndCodeVariant: Story = {
|
||||
args: {
|
||||
variant: "code",
|
||||
label: "Textarea label:",
|
||||
children:
|
||||
"const example = 'This is code styled text';\n// With line breaks preserved.\n\n Text with\r\ncarriage returns\r\nconverted to\nline breaks",
|
||||
},
|
||||
};
|
||||
@@ -6,10 +6,13 @@ const baseClass = "textarea";
|
||||
interface ITextareaProps {
|
||||
children: React.ReactNode;
|
||||
className?: string;
|
||||
label?: React.ReactNode;
|
||||
/** code - code font, max height 300px */
|
||||
variant?: "code" | "default";
|
||||
}
|
||||
|
||||
// A textarea component that encapsulates common styles and functionality.
|
||||
const Textarea = ({ children, className }: ITextareaProps) => {
|
||||
const Textarea = ({ children, className, label, variant }: ITextareaProps) => {
|
||||
// this is to preserve line breaks when we encounter a carriage return character.
|
||||
// We could not find a way to preserve line breaks in the CSS alone for this
|
||||
// character.
|
||||
@@ -17,8 +20,17 @@ const Textarea = ({ children, className }: ITextareaProps) => {
|
||||
children = children.replace(/\r/g, "\n");
|
||||
}
|
||||
|
||||
const classNames = classnames(baseClass, className);
|
||||
return <div className={classNames}>{children}</div>;
|
||||
const wrapperClasses = classnames(`${baseClass}-wrapper`, className);
|
||||
const textareaClasses = classnames(baseClass, {
|
||||
[`${baseClass}--code`]: variant === "code",
|
||||
});
|
||||
|
||||
return (
|
||||
<div className={wrapperClasses}>
|
||||
{label && <div className={`${baseClass}__label`}>{label}</div>}
|
||||
<div className={textareaClasses}>{children}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default Textarea;
|
||||
|
||||
@@ -4,4 +4,17 @@
|
||||
border: 1px solid $ui-fleet-black-10;
|
||||
background-color: $ui-off-white;
|
||||
white-space: pre-wrap;
|
||||
|
||||
&-wrapper {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: $pad-medium;
|
||||
}
|
||||
|
||||
&--code {
|
||||
overflow-wrap: break-word;
|
||||
overflow-y: auto;
|
||||
font-family: "SourceCodePro", $monospace;
|
||||
max-height: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -268,8 +268,7 @@ const ScriptDetailsModal = ({
|
||||
className={`${baseClass}__script-content modal-scrollable-content`}
|
||||
ref={topDivRef}
|
||||
>
|
||||
<span>Script content:</span>
|
||||
<Textarea className={`${baseClass}__script-content-textarea`}>
|
||||
<Textarea label="Script content" variant="code">
|
||||
{scriptContent}
|
||||
</Textarea>
|
||||
{runScriptHelpText && (
|
||||
|
||||
Reference in New Issue
Block a user