SlaveLogs.tsx 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180
  1. import * as React from "react";
  2. import { ContextualMenu, Dropdown, IconButton, IDragOptions, mergeStyleSets, Modal, PrimaryButton, Stack, TextField, } from "@fluentui/react";
  3. import { useId } from "@fluentui/react-hooks";
  4. import { scopedLogger } from "@hpcc-js/util";
  5. import { useForm, Controller } from "react-hook-form";
  6. import nlsHPCC from "src/nlsHPCC";
  7. import * as FormStyles from "./landing-zone/styles";
  8. import { useWorkunit } from "../../hooks/Workunit";
  9. const logger = scopedLogger("src-react/components/forms/SlaveLogs.tsx");
  10. interface SlaveLogsValues {
  11. ThorProcess: string;
  12. SlaveNumber: string;
  13. FileFormat: string;
  14. }
  15. const defaultValues: SlaveLogsValues = {
  16. ThorProcess: "",
  17. SlaveNumber: "1",
  18. FileFormat: "1"
  19. };
  20. interface SlaveLogsProps {
  21. wuid?: string;
  22. showForm: boolean;
  23. setShowForm: (_: boolean) => void;
  24. }
  25. export const SlaveLogs: React.FunctionComponent<SlaveLogsProps> = ({
  26. wuid,
  27. showForm,
  28. setShowForm
  29. }) => {
  30. const [workunit] = useWorkunit(wuid);
  31. const [thorProcesses, setThorProcesses] = React.useState([]);
  32. const [maxThorSlaves, setMaxThorSlaves] = React.useState(1);
  33. const [thorLogDate, setThorLogDate] = React.useState("");
  34. const [clusterGroup, setClusterGroup] = React.useState("");
  35. const { handleSubmit, control, reset } = useForm<SlaveLogsValues>({ defaultValues });
  36. const closeForm = React.useCallback(() => {
  37. setShowForm(false);
  38. }, [setShowForm]);
  39. const onSubmit = React.useCallback(() => {
  40. handleSubmit(
  41. (data, evt) => {
  42. const url = `/WsWorkunits/WUFile?Wuid=${wuid}&Type=ThorSlaveLog&Process=${data.ThorProcess}` +
  43. `&ClusterGroup=${clusterGroup}&LogDate=${thorLogDate}&SlaveNumber=${data.SlaveNumber}&Option=${data.FileFormat}`;
  44. window.open(url);
  45. closeForm();
  46. reset(defaultValues);
  47. },
  48. logger.info
  49. )();
  50. }, [closeForm, clusterGroup, handleSubmit, reset, thorLogDate, wuid]);
  51. const titleId = useId("title");
  52. const dragOptions: IDragOptions = {
  53. moveMenuItemText: nlsHPCC.Move,
  54. closeMenuItemText: nlsHPCC.Close,
  55. menu: ContextualMenu,
  56. };
  57. const componentStyles = mergeStyleSets(
  58. FormStyles.componentStyles,
  59. {
  60. container: {
  61. minWidth: 440,
  62. }
  63. }
  64. );
  65. React.useEffect(() => {
  66. if (!workunit?.ThorLogList) return;
  67. setThorProcesses(workunit?.ThorLogList?.ThorLogInfo.map(process => {
  68. return { key: process.ProcessName, text: process.ProcessName };
  69. }));
  70. setMaxThorSlaves(workunit?.ThorLogList?.ThorLogInfo[0].NumberSlaves || 1);
  71. setThorLogDate(workunit?.ThorLogList?.ThorLogInfo[0].LogDate);
  72. setClusterGroup(workunit?.ThorLogList?.ThorLogInfo[0].ProcessName);
  73. }, [workunit]);
  74. return <Modal
  75. titleAriaId={titleId}
  76. isOpen={showForm}
  77. onDismiss={closeForm}
  78. isBlocking={false}
  79. containerClassName={componentStyles.container}
  80. dragOptions={dragOptions}
  81. >
  82. <div className={componentStyles.header}>
  83. <span id={titleId}>{nlsHPCC.SlaveLogs}</span>
  84. <IconButton
  85. styles={FormStyles.iconButtonStyles}
  86. iconProps={FormStyles.cancelIcon}
  87. ariaLabel={nlsHPCC.CloseModal}
  88. onClick={closeForm}
  89. />
  90. </div>
  91. <div className={componentStyles.body}>
  92. <Stack>
  93. <Controller
  94. control={control} name="ThorProcess"
  95. render={({
  96. field: { onChange, name: fieldName, value },
  97. fieldState: { error }
  98. }) => <Dropdown
  99. key={fieldName}
  100. label={nlsHPCC.ThorProcess}
  101. options={thorProcesses}
  102. required={true}
  103. onChange={(evt, option) => {
  104. onChange(option.key);
  105. }}
  106. errorMessage={error && error.message}
  107. />}
  108. rules={{
  109. required: nlsHPCC.ValidationErrorRequired
  110. }}
  111. />
  112. <Controller
  113. control={control} name="SlaveNumber"
  114. render={({
  115. field: { onChange, name: fieldName, value },
  116. fieldState: { error }
  117. }) => <TextField
  118. name={fieldName}
  119. onChange={onChange}
  120. label={nlsHPCC.SlaveNumber}
  121. value={value}
  122. errorMessage={error && error.message}
  123. />}
  124. rules={{
  125. pattern: {
  126. value: /^[1-9]+$/i,
  127. message: nlsHPCC.ValidationErrorEnterNumber
  128. },
  129. min: {
  130. value: 1,
  131. message: `${nlsHPCC.ValidationErrorNumberLess} 1`
  132. },
  133. max: {
  134. value: maxThorSlaves,
  135. message: `${nlsHPCC.ValidationErrorNumberGreater} ${maxThorSlaves}`
  136. }
  137. }}
  138. />
  139. <Controller
  140. control={control} name="FileFormat"
  141. render={({
  142. field: { onChange, name: fieldName, value },
  143. fieldState: { error }
  144. }) => <Dropdown
  145. key={fieldName}
  146. label={nlsHPCC.File}
  147. options={[
  148. { key: "1", text: nlsHPCC.OriginalFile },
  149. { key: "2", text: nlsHPCC.Zip },
  150. { key: "3", text: nlsHPCC.GZip },
  151. ]}
  152. defaultSelectedKey="1"
  153. onChange={(evt, option) => {
  154. onChange(option.key);
  155. }}
  156. />}
  157. />
  158. </Stack>
  159. <Stack horizontal horizontalAlign="space-between" verticalAlign="end" styles={FormStyles.buttonStackStyles}>
  160. <PrimaryButton text={nlsHPCC.Download} onClick={handleSubmit(onSubmit)} />
  161. </Stack>
  162. </div>
  163. </Modal>;
  164. };