WorkunitDetails.tsx 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. import * as React from "react";
  2. import { CommandBar, ContextualMenuItemType, ICommandBarItemProps, mergeStyleSets, Pivot, PivotItem, ScrollablePane, ScrollbarVisibility, Sticky, StickyPositionType } from "@fluentui/react";
  3. import { SizeMe } from "react-sizeme";
  4. import { ReflexContainer, ReflexSplitter, ReflexElement } from "react-reflex";
  5. import nlsHPCC from "src/nlsHPCC";
  6. import { getImageURL } from "src/Utility";
  7. import { getStateIconClass } from "src/ESPWorkunit";
  8. import { WUStatus } from "src/react/index";
  9. import { useWorkunit } from "../hooks/Workunit";
  10. import { DojoAdapter } from "../layouts/DojoAdapter";
  11. import { pushUrl } from "../util/history";
  12. import { ShortVerticalDivider } from "./Common";
  13. import { Results } from "./Results";
  14. import { Variables } from "./Variables";
  15. import { SourceFiles } from "./SourceFiles";
  16. import { Details } from "./Details";
  17. import { WUXMLSourceEditor } from "./SourceEditor";
  18. import { Workflows } from "./Workflows";
  19. import "react-reflex/styles.css";
  20. const classNames = mergeStyleSets({
  21. reflexScrollPane: {
  22. borderWidth: 1,
  23. borderStyle: "solid",
  24. borderColor: "darkgray"
  25. },
  26. reflexPane: {
  27. borderWidth: 1,
  28. borderStyle: "solid",
  29. borderColor: "darkgray",
  30. overflow: "hidden"
  31. },
  32. reflexSplitter: {
  33. position: "relative",
  34. height: "5px",
  35. backgroundColor: "transparent",
  36. borderStyle: "none"
  37. },
  38. reflexSplitterDiv: {
  39. fontFamily: "Lucida Sans,Lucida Grande,Arial !important",
  40. fontSize: "13px !important",
  41. cursor: "row-resize",
  42. position: "absolute",
  43. left: "49%",
  44. background: "#9e9e9e",
  45. height: "1px",
  46. top: "2px",
  47. width: "19px"
  48. }
  49. });
  50. const pivotItemStyle = (size, padding: number = 4) => {
  51. if (isNaN(size.width)) {
  52. return { position: "absolute", padding: `${padding}px`, overflow: "auto", zIndex: 0 } as React.CSSProperties;
  53. }
  54. return { position: "absolute", padding: `${padding}px`, overflow: "auto", zIndex: 0, width: size.width - padding * 2, height: size.height - 45 - padding * 2 } as React.CSSProperties;
  55. };
  56. interface InfoGridProps {
  57. wuid: string;
  58. dimensions?: any;
  59. }
  60. const InfoGrid: React.FunctionComponent<InfoGridProps> = ({
  61. wuid,
  62. dimensions
  63. }) => {
  64. return <div className="pane-content" style={{ height: dimensions.height }}>
  65. <DojoAdapter widgetClassID="InfoGridWidget" params={{ Wuid: wuid }} delayProps={{ showToolbar: true }} />
  66. </div>;
  67. };
  68. interface WorkunitDetailsProps {
  69. wuid: string;
  70. tab?: string;
  71. }
  72. export const WorkunitDetails: React.FunctionComponent<WorkunitDetailsProps> = ({
  73. wuid,
  74. tab = "summary"
  75. }) => {
  76. const [workunit] = useWorkunit(wuid, true);
  77. const [jobname, setJobname] = React.useState("");
  78. const [description, setDescription] = React.useState("");
  79. const [_protected, setProtected] = React.useState(false);
  80. React.useEffect(() => {
  81. setJobname(jobname || workunit?.Jobname);
  82. setDescription(description || workunit?.Description);
  83. setProtected(_protected || workunit?.Protected);
  84. // eslint-disable-next-line react-hooks/exhaustive-deps
  85. }, [workunit?.Jobname, workunit?.Jobname, workunit?.Jobname]);
  86. const canSave = workunit && (
  87. jobname !== workunit.Jobname ||
  88. description !== workunit.Description ||
  89. _protected !== workunit.Protected
  90. );
  91. const buttons: ICommandBarItemProps[] = [
  92. {
  93. key: "refresh", text: nlsHPCC.Refresh, iconProps: { iconName: "Refresh" },
  94. onClick: () => {
  95. workunit.refresh();
  96. }
  97. },
  98. { key: "divider_1", itemType: ContextualMenuItemType.Divider, onRender: () => <ShortVerticalDivider /> },
  99. {
  100. key: "save", text: nlsHPCC.Save, iconProps: { iconName: "Save" }, disabled: !canSave,
  101. onClick: () => {
  102. workunit?.update({
  103. Jobname: jobname,
  104. Description: description,
  105. Protected: _protected
  106. });
  107. }
  108. },
  109. {
  110. key: "copy", text: nlsHPCC.CopyWUID, iconProps: { iconName: "Copy" },
  111. onClick: () => {
  112. navigator?.clipboard?.writeText(wuid);
  113. }
  114. },
  115. { key: "divider_2", itemType: ContextualMenuItemType.Divider, onRender: () => <ShortVerticalDivider /> },
  116. ];
  117. const protectedImage = getImageURL(workunit?.Protected ? "locked.png" : "unlocked.png");
  118. const stateIconClass = getStateIconClass(workunit?.StateID, workunit?.isComplete(), workunit?.Archived);
  119. const serviceNames = workunit?.ServiceNames?.Item?.join("\n") || "";
  120. return <SizeMe monitorHeight>{({ size }) =>
  121. <Pivot overflowBehavior="menu" style={{ height: "100%" }} defaultSelectedKey={tab} onLinkClick={evt => pushUrl(`/workunits/${wuid}/${evt.props.itemKey}`)}>
  122. <PivotItem headerText={wuid} itemKey="summary" style={pivotItemStyle(size)}>
  123. <div style={{ height: "100%", position: "relative" }}>
  124. <ReflexContainer orientation="horizontal">
  125. <ReflexElement className={classNames.reflexScrollPane}>
  126. <div className="pane-content">
  127. <ScrollablePane scrollbarVisibility={ScrollbarVisibility.auto}>
  128. <Sticky stickyPosition={StickyPositionType.Header}>
  129. <CommandBar items={buttons} />
  130. </Sticky>
  131. <Sticky stickyPosition={StickyPositionType.Header}>
  132. <div style={{ display: "inline-block" }}>
  133. <h2>
  134. <img src={protectedImage} />&nbsp;<div className={stateIconClass}></div>&nbsp;<span className="bold">{wuid}</span>
  135. </h2>
  136. </div>
  137. <div style={{ width: "512px", height: "64px", float: "right" }}>
  138. <WUStatus wuid={wuid}></WUStatus>
  139. </div>
  140. </Sticky>
  141. <Details fields={{
  142. "wuid": { label: nlsHPCC.WUID, type: "string", value: wuid, readonly: true },
  143. "action": { label: nlsHPCC.Action, type: "string", value: workunit?.ActionEx, readonly: true },
  144. "state": { label: nlsHPCC.State, type: "string", value: workunit?.State, readonly: true },
  145. "owner": { label: nlsHPCC.Owner, type: "string", value: workunit?.Owner, readonly: true },
  146. "jobname": { label: nlsHPCC.JobName, type: "string", value: jobname },
  147. "description": { label: nlsHPCC.Description, type: "string", value: description },
  148. "protected": { label: nlsHPCC.Protected, type: "checkbox", value: _protected },
  149. "cluster": { label: nlsHPCC.Cluster, type: "string", value: workunit?.Cluster, readonly: true },
  150. "totalClusterTime": { label: nlsHPCC.TotalClusterTime, type: "string", value: workunit?.TotalClusterTime, readonly: true },
  151. "abortedBy": { label: nlsHPCC.AbortedBy, type: "string", value: workunit?.AbortBy, readonly: true },
  152. "abortedTime": { label: nlsHPCC.AbortedTime, type: "string", value: workunit?.AbortTime, readonly: true },
  153. "ServiceNamesCustom": { label: nlsHPCC.Services, type: "string", value: serviceNames, readonly: true, multiline: true },
  154. }} onChange={(id, value) => {
  155. switch (id) {
  156. case "jobname":
  157. setJobname(value);
  158. break;
  159. case "description":
  160. setDescription(value);
  161. break;
  162. case "protected":
  163. setProtected(value);
  164. break;
  165. default:
  166. console.log(id, value);
  167. }
  168. }} />
  169. </ScrollablePane>
  170. </div>
  171. </ReflexElement>
  172. <ReflexSplitter style={{ position: "relative", height: "5px", backgroundColor: "transparent", borderStyle: "none" }}>
  173. <div className={classNames.reflexSplitterDiv}></div>
  174. </ReflexSplitter>
  175. <ReflexElement propagateDimensions={true} className={classNames.reflexPane}>
  176. <InfoGrid wuid={wuid} />
  177. </ReflexElement>
  178. </ReflexContainer>
  179. </div>
  180. </PivotItem>
  181. <PivotItem headerText={nlsHPCC.Variables} itemCount={(workunit?.VariableCount || 0) + (workunit?.ApplicationValueCount || 0) + (workunit?.DebugValueCount || 0)} itemKey="variables" style={pivotItemStyle(size, 0)}>
  182. <Variables wuid={wuid} />
  183. </PivotItem>
  184. <PivotItem headerText={nlsHPCC.Outputs} itemKey="outputs" itemCount={workunit?.ResultCount} style={pivotItemStyle(size, 0)}>
  185. <Results wuid={wuid} />
  186. </PivotItem>
  187. <PivotItem headerText={nlsHPCC.Inputs} itemKey="inputs" itemCount={workunit?.SourceFileCount} style={pivotItemStyle(size, 0)}>
  188. <SourceFiles wuid={wuid} />
  189. </PivotItem>
  190. <PivotItem headerText={nlsHPCC.Timers} itemKey="timers" itemCount={workunit?.TimerCount} style={pivotItemStyle(size, 0)}>
  191. <DojoAdapter widgetClassID="TimingPageWidget" params={{ Wuid: wuid }} />
  192. </PivotItem>
  193. <PivotItem headerText={nlsHPCC.Graphs} itemKey="graphs" itemCount={workunit?.GraphCount} style={pivotItemStyle(size, 0)}>
  194. <DojoAdapter widgetClassID="GraphsWUWidget" params={{ Wuid: wuid }} />
  195. </PivotItem>
  196. <PivotItem headerText={nlsHPCC.Workflows} itemKey="workflows" itemCount={workunit?.WorkflowCount} style={pivotItemStyle(size, 0)}>
  197. <Workflows wuid={wuid} />
  198. </PivotItem>
  199. <PivotItem headerText={nlsHPCC.Queries} itemIcon="Search" itemKey="queries" style={pivotItemStyle(size, 0)}>
  200. <DojoAdapter widgetClassID="QuerySetQueryWidget" params={{ Wuid: wuid }} />
  201. </PivotItem>
  202. <PivotItem headerText={nlsHPCC.Resources} itemKey="resources" style={pivotItemStyle(size, 0)}>
  203. <DojoAdapter widgetClassID="ResourcesWidget" params={{ Wuid: wuid }} />
  204. </PivotItem>
  205. <PivotItem headerText={nlsHPCC.Helpers} itemKey="helpers" itemCount={workunit?.HelpersCount} style={pivotItemStyle(size, 0)}>
  206. <DojoAdapter widgetClassID="HelpersWidget" params={{ Wuid: wuid }} />
  207. </PivotItem>
  208. <PivotItem headerText={nlsHPCC.ECL} itemKey="eclsummary" style={pivotItemStyle(size, 0)}>
  209. <DojoAdapter widgetClassID="ECLArchiveWidget" params={{ Wuid: wuid }} />
  210. </PivotItem>
  211. <PivotItem headerText={nlsHPCC.XML} itemKey="xml" style={pivotItemStyle(size, 0)}>
  212. <WUXMLSourceEditor wuid={wuid} />
  213. </PivotItem>
  214. </Pivot>
  215. }</SizeMe>;
  216. };