diff --git a/ui/src/app/shared/components/error-panel.tsx b/ui/src/app/shared/components/error-panel.tsx index d1cb2f62db5f..b03e44f3234d 100644 --- a/ui/src/app/shared/components/error-panel.tsx +++ b/ui/src/app/shared/components/error-panel.tsx @@ -6,46 +6,40 @@ interface Props { errorInfo?: ErrorInfo; } -export class ErrorPanel extends React.Component { - constructor(props: Props) { - super(props); - } - - public render() { - return ( -
-

- {this.props.error.message} -

-

- Reload this page to try again. -

- {this.props.error.response && ( - <> - {this.props.error.response.req && ( - <> -
Request
-
-                                    {this.props.error.response.req.method} {this.props.error.response.req.url}
-                                
- - )} +export function ErrorPanel(props: Props) { + return ( +
+

+ {props.error.message} +

+

+ Reload this page to try again. +

+ {props.error.response && ( + <> + {props.error.response.req && ( <> -
Response
-
HTTP {this.props.error.response.status}
- {this.props.error.response.body &&
{JSON.stringify(this.props.error.response.body, null, 2)}
} +
Request
+
+                                {props.error.response.req.method} {props.error.response.req.url}
+                            
- - )} -
Stack Trace
-
{this.props.error.stack}
- {this.props.errorInfo && ( + )} <> -
Component Stack
-
{this.props.errorInfo.componentStack}
+
Response
+
HTTP {props.error.response.status}
+ {props.error.response.body &&
{JSON.stringify(props.error.response.body, null, 2)}
} - )} -
- ); - } + + )} +
Stack Trace
+
{props.error.stack}
+ {props.errorInfo && ( + <> +
Component Stack
+
{props.errorInfo.componentStack}
+ + )} +
+ ); } diff --git a/ui/src/app/shared/components/inline-table/inline-table.tsx b/ui/src/app/shared/components/inline-table/inline-table.tsx index be075827d453..b0da9340faa4 100644 --- a/ui/src/app/shared/components/inline-table/inline-table.tsx +++ b/ui/src/app/shared/components/inline-table/inline-table.tsx @@ -11,19 +11,17 @@ interface Row { right: ReactChild; } -export class InlineTable extends React.Component { - public render() { - return ( -
- {this.props.rows.map((row, i) => { - return ( -
-
{row.left}
-
{row.right}
-
- ); - })} -
- ); - } +export function InlineTable(props: TableProps) { + return ( +
+ {props.rows.map((row, i) => { + return ( +
+
{row.left}
+
{row.right}
+
+ ); + })} +
+ ); } diff --git a/ui/src/app/shared/components/nudge.tsx b/ui/src/app/shared/components/nudge.tsx index c40be0800e40..9ae47df31314 100644 --- a/ui/src/app/shared/components/nudge.tsx +++ b/ui/src/app/shared/components/nudge.tsx @@ -1,29 +1,24 @@ import * as React from 'react'; +import {useState} from 'react'; import {Notice} from './notice'; -export class Nudge extends React.Component<{key: string}, {closed: boolean}> { - constructor(props: Readonly<{key: string}>) { - super(props); - this.state = {closed: localStorage.getItem(props.key) !== null}; +export function Nudge(props: React.PropsWithChildren<{key: string}>) { + const [closed, setClosed] = useState(localStorage.getItem(props.key) !== null); + function close() { + setClosed(true); + localStorage.setItem(props.key, '{}'); } - public render() { - return ( - !this.state.closed && ( - - {this.props.children} - - this.close()}> - - {' '} - - - ) - ); - } - - private close() { - this.setState({closed: true}); - localStorage.setItem(this.props.key, '{}'); - } + return ( + !closed && ( + + {props.children} + + close()}> + + {' '} + + + ) + ); } diff --git a/ui/src/app/shared/components/pagination-panel.tsx b/ui/src/app/shared/components/pagination-panel.tsx index 552654ce3ae8..da1906a02b52 100644 --- a/ui/src/app/shared/components/pagination-panel.tsx +++ b/ui/src/app/shared/components/pagination-panel.tsx @@ -2,61 +2,56 @@ import * as React from 'react'; import {Pagination, parseLimit} from '../pagination'; import {WarningIcon} from './fa-icons'; -export class PaginationPanel extends React.Component<{pagination: Pagination; onChange: (pagination: Pagination) => void; numRecords: number}> { - public render() { - return ( -

- - - {this.props.pagination.limit > 0 && this.props.pagination.limit <= this.props.numRecords ? ( - <> - Workflows cannot be globally sorted when paginated - - ) : ( - - )} - - { + const limit = parseLimit(e.target.value); + const newValue: Pagination = {limit}; - // Only return the offset if we're actually going to be limiting - // the results we're requesting. If we're requesting all records, - // we should not skip any by setting an offset. - // The offset must be initialized whenever the pagination limit is changed. - if (limit) { - newValue.offset = ''; - } + // Only return the offset if we're actually going to be limiting + // the results we're requesting. If we're requesting all records, + // we should not skip any by setting an offset. + // The offset must be initialized whenever the pagination limit is changed. + if (limit) { + newValue.offset = ''; + } - this.props.onChange(newValue); - }} - value={this.props.pagination.limit || 0}> - {[5, 10, 20, 50, 100, 500, 0].map(limit => ( - - ))} - {' '} - results per page - -

- ); - } + props.onChange(newValue); + }} + value={props.pagination.limit || 0}> + {[5, 10, 20, 50, 100, 500, 0].map(limit => ( + + ))} + {' '} + results per page + +

+ ); } diff --git a/ui/src/app/shared/conditions-panel.tsx b/ui/src/app/shared/conditions-panel.tsx index 44b17f86819a..15689982e860 100644 --- a/ui/src/app/shared/conditions-panel.tsx +++ b/ui/src/app/shared/conditions-panel.tsx @@ -48,21 +48,19 @@ function getConditionIcon(condition: ConditionType): JSX.Element { } } -export class ConditionsPanel extends React.Component { - public render() { - return ( - <> - {this.props.conditions && - Object.entries(this.props.conditions).map(([_, condition]) => { - return ( -
- {getConditionIcon(condition.type)} - {condition.type} - {': ' + (condition.message || condition.status)} -
- ); - })} - - ); - } +export function ConditionsPanel(props: Props) { + return ( + <> + {props.conditions && + Object.entries(props.conditions).map(([_, condition]) => { + return ( +
+ {getConditionIcon(condition.type)} + {condition.type} + {': ' + (condition.message || condition.status)} +
+ ); + })} + + ); } diff --git a/ui/src/app/shared/resources-duration.tsx b/ui/src/app/shared/resources-duration.tsx index 152a742af6a6..b3ca1b73e7b6 100644 --- a/ui/src/app/shared/resources-duration.tsx +++ b/ui/src/app/shared/resources-duration.tsx @@ -5,18 +5,16 @@ interface Props { resourcesDuration: {[resource: string]: number}; } -export class ResourcesDuration extends React.Component { - public render() { - return ( - <> - {this.props.resourcesDuration && - Object.entries(this.props.resourcesDuration) - .map(([resource, duration]) => formatDuration(duration, 1) + '*(' + denominator(resource) + ' ' + resource + ')') - .join(',')}{' '} - - - - - ); - } +export function ResourcesDuration(props: Props) { + return ( + <> + {props.resourcesDuration && + Object.entries(props.resourcesDuration) + .map(([resource, duration]) => formatDuration(duration, 1) + '*(' + denominator(resource) + ' ' + resource + ')') + .join(',')}{' '} + + + + + ); } diff --git a/ui/src/app/workflow-templates/components/workflow-template-creator.tsx b/ui/src/app/workflow-templates/components/workflow-template-creator.tsx index 58e6982b85d9..5b768e217761 100644 --- a/ui/src/app/workflow-templates/components/workflow-template-creator.tsx +++ b/ui/src/app/workflow-templates/components/workflow-template-creator.tsx @@ -10,7 +10,7 @@ import {services} from '../../shared/services'; import {Utils} from '../../shared/utils'; import {WorkflowTemplateEditor} from './workflow-template-editor'; -export const WorkflowTemplateCreator = ({namespace, onCreate}: {namespace: string; onCreate: (workflow: WorkflowTemplate) => void}) => { +export function WorkflowTemplateCreator({namespace, onCreate}: {namespace: string; onCreate: (workflow: WorkflowTemplate) => void}) { const [template, setTemplate] = useState(exampleWorkflowTemplate(Utils.getNamespaceWithDefault(namespace))); const [error, setError] = useState(); return ( @@ -35,4 +35,4 @@ export const WorkflowTemplateCreator = ({namespace, onCreate}: {namespace: strin

); -}; +} diff --git a/ui/src/app/workflow-templates/components/workflow-template-details/workflow-template-details.tsx b/ui/src/app/workflow-templates/components/workflow-template-details/workflow-template-details.tsx index d2a6dd7dbeb7..dbcc104c2c45 100644 --- a/ui/src/app/workflow-templates/components/workflow-template-details/workflow-template-details.tsx +++ b/ui/src/app/workflow-templates/components/workflow-template-details/workflow-template-details.tsx @@ -16,7 +16,7 @@ import {WidgetGallery} from '../../../widgets/widget-gallery'; import {SubmitWorkflowPanel} from '../../../workflows/components/submit-workflow-panel'; import {WorkflowTemplateEditor} from '../workflow-template-editor'; -export const WorkflowTemplateDetails = ({history, location, match}: RouteComponentProps) => { +export function WorkflowTemplateDetails({history, location, match}: RouteComponentProps) { // boiler-plate const {notifications, navigation, popup} = useContext(Context); const queryParams = new URLSearchParams(location.search); @@ -139,4 +139,4 @@ export const WorkflowTemplateDetails = ({history, location, match}: RouteCompone )} ); -}; +} diff --git a/ui/src/app/workflow-templates/components/workflow-template-editor.tsx b/ui/src/app/workflow-templates/components/workflow-template-editor.tsx index 76059a783a22..5607c446e498 100644 --- a/ui/src/app/workflow-templates/components/workflow-template-editor.tsx +++ b/ui/src/app/workflow-templates/components/workflow-template-editor.tsx @@ -7,7 +7,7 @@ import {MetadataEditor} from '../../shared/components/editors/metadata-editor'; import {WorkflowParametersEditor} from '../../shared/components/editors/workflow-parameters-editor'; import {ObjectEditor} from '../../shared/components/object-editor/object-editor'; -export const WorkflowTemplateEditor = ({ +export function WorkflowTemplateEditor({ onChange, onError, onTabSelected, @@ -19,7 +19,7 @@ export const WorkflowTemplateEditor = ({ onError: (error: Error) => void; onTabSelected?: (tab: string) => void; selectedTabKey?: string; -}) => { +}) { return ( ); -}; +} diff --git a/ui/src/app/workflow-templates/components/workflow-template-filters/workflow-template-filters.tsx b/ui/src/app/workflow-templates/components/workflow-template-filters/workflow-template-filters.tsx index 602f6aa19e12..a4e5d484829c 100644 --- a/ui/src/app/workflow-templates/components/workflow-template-filters/workflow-template-filters.tsx +++ b/ui/src/app/workflow-templates/components/workflow-template-filters/workflow-template-filters.tsx @@ -13,7 +13,7 @@ interface WorkflowFilterProps { onChange: (namespace: string, labels: string[]) => void; } -export const WorkflowTemplateFilters = ({templates, namespace, labels, onChange}: WorkflowFilterProps) => { +export function WorkflowTemplateFilters({templates, namespace, labels, onChange}: WorkflowFilterProps) { const [labelSuggestion, setLabelSuggestion] = useState([]); useEffect(() => { @@ -58,4 +58,4 @@ export const WorkflowTemplateFilters = ({templates, namespace, labels, onChange} ); -}; +} diff --git a/ui/src/app/workflow-templates/components/workflow-template-list/workflow-template-list.tsx b/ui/src/app/workflow-templates/components/workflow-template-list/workflow-template-list.tsx index 950d5686c88a..201f3206435a 100644 --- a/ui/src/app/workflow-templates/components/workflow-template-list/workflow-template-list.tsx +++ b/ui/src/app/workflow-templates/components/workflow-template-list/workflow-template-list.tsx @@ -27,7 +27,7 @@ require('./workflow-template-list.scss'); const learnMore = Learn more; -export const WorkflowTemplateList = ({match, location, history}: RouteComponentProps) => { +export function WorkflowTemplateList({match, location, history}: RouteComponentProps) { // boiler-plate const queryParams = new URLSearchParams(location.search); const {navigation} = useContext(Context); @@ -163,4 +163,4 @@ export const WorkflowTemplateList = ({match, location, history}: RouteComponentP ); -}; +} diff --git a/ui/src/app/workflows/components/events-panel.tsx b/ui/src/app/workflows/components/events-panel.tsx index 9cb20b792c9c..b49027b7e951 100644 --- a/ui/src/app/workflows/components/events-panel.tsx +++ b/ui/src/app/workflows/components/events-panel.tsx @@ -10,7 +10,7 @@ import debounce from '../../shared/debounce'; import {ListWatch} from '../../shared/list-watch'; import {services} from '../../shared/services'; -export const EventsPanel = ({namespace, name, kind}: {namespace: string; name: string; kind: string}) => { +export function EventsPanel({namespace, name, kind}: {namespace: string; name: string; kind: string}) { const [showAll, setShowAll] = useState(false); const [hideNormal, setHideNormal] = useState(false); const [events, setEvents] = useState(); @@ -53,7 +53,7 @@ export const EventsPanel = ({namespace, name, kind}: {namespace: string; name: s const tableRef = useRef(null); useEffect(() => { - const calculateTooltips = () => { + function calculateTooltips() { const table = tableRef.current; if (table) { @@ -75,7 +75,7 @@ export const EventsPanel = ({namespace, name, kind}: {namespace: string; name: s } } } - }; + } const [debouncedCalculateTooltips, cleanup] = debounce(calculateTooltips, 1000); @@ -134,4 +134,4 @@ export const EventsPanel = ({namespace, name, kind}: {namespace: string; name: s )} ); -}; +} diff --git a/ui/src/app/workflows/components/workflow-artifacts.tsx b/ui/src/app/workflows/components/workflow-artifacts.tsx index 8ae8dbb67bc0..9b700ec8998b 100644 --- a/ui/src/app/workflows/components/workflow-artifacts.tsx +++ b/ui/src/app/workflows/components/workflow-artifacts.tsx @@ -9,7 +9,7 @@ interface Props { archived: boolean; } -export const WorkflowArtifacts = (props: Props) => { +export function WorkflowArtifacts(props: Props) { const workflowStatusNodes = (props.workflow.status && props.workflow.status.nodes) || {}; const artifacts = Object.keys(workflowStatusNodes) @@ -60,4 +60,4 @@ export const WorkflowArtifacts = (props: Props) => { ); -}; +} diff --git a/ui/src/app/workflows/components/workflow-creator-info/workflow-creator-info.tsx b/ui/src/app/workflows/components/workflow-creator-info/workflow-creator-info.tsx index 011750e5ed21..3edf8101d542 100644 --- a/ui/src/app/workflows/components/workflow-creator-info/workflow-creator-info.tsx +++ b/ui/src/app/workflows/components/workflow-creator-info/workflow-creator-info.tsx @@ -9,41 +9,35 @@ interface WorkflowCreatorInfoProps { onChange: (key: string, value: string) => void; } -export class WorkflowCreatorInfo extends React.Component { - constructor(props: WorkflowCreatorInfoProps) { - super(props); - } - - public render() { - const w = this.props.workflow; - const creatorLabels = []; - if (w.metadata.labels) { - const creatorInfoMap = new Map([ - ['Name', [labels.creator, w.metadata.labels[labels.creator]]], - ['Email', [labels.creatorEmail, w.metadata.labels[labels.creatorEmail]]], - ['Preferred username', [labels.creatorPreferredUsername, w.metadata.labels[labels.creatorPreferredUsername]]] - ]); - creatorInfoMap.forEach((value: [string, string], key: string) => { - const [searchKey, searchValue] = value; - if (searchValue !== '' && searchValue !== undefined) { - creatorLabels.push( -
{ - e.preventDefault(); - this.props.onChange(searchKey, searchValue); - }}> -
{key}
-
{searchValue}
-
- ); - } - }); - } else { - creatorLabels.push(
No creator information
); - } - return
{creatorLabels}
; +export function WorkflowCreatorInfo(props: WorkflowCreatorInfoProps) { + const w = props.workflow; + const creatorLabels = []; + if (w.metadata.labels) { + const creatorInfoMap = new Map([ + ['Name', [labels.creator, w.metadata.labels[labels.creator]]], + ['Email', [labels.creatorEmail, w.metadata.labels[labels.creatorEmail]]], + ['Preferred username', [labels.creatorPreferredUsername, w.metadata.labels[labels.creatorPreferredUsername]]] + ]); + creatorInfoMap.forEach((value: [string, string], key: string) => { + const [searchKey, searchValue] = value; + if (searchValue !== '' && searchValue !== undefined) { + creatorLabels.push( +
{ + e.preventDefault(); + props.onChange(searchKey, searchValue); + }}> +
{key}
+
{searchValue}
+
+ ); + } + }); + } else { + creatorLabels.push(
No creator information
); } + return
{creatorLabels}
; } diff --git a/ui/src/app/workflows/components/workflow-creator.tsx b/ui/src/app/workflows/components/workflow-creator.tsx index c423150cf0ec..0146abe15f45 100644 --- a/ui/src/app/workflows/components/workflow-creator.tsx +++ b/ui/src/app/workflows/components/workflow-creator.tsx @@ -14,7 +14,7 @@ import {WorkflowEditor} from './workflow-editor'; type Stage = 'choose-method' | 'submit-workflow' | 'full-editor'; -export const WorkflowCreator = ({namespace, onCreate}: {namespace: string; onCreate: (workflow: Workflow) => void}) => { +export function WorkflowCreator({namespace, onCreate}: {namespace: string; onCreate: (workflow: Workflow) => void}) { const [workflowTemplates, setWorkflowTemplates] = useState(); const [workflowTemplate, setWorkflowTemplate] = useState(); const [stage, setStage] = useState('choose-method'); @@ -123,4 +123,4 @@ export const WorkflowCreator = ({namespace, onCreate}: {namespace: string; onCre )} ); -}; +} diff --git a/ui/src/app/workflows/components/workflow-dag/workflow-dag-render-options-panel.tsx b/ui/src/app/workflows/components/workflow-dag/workflow-dag-render-options-panel.tsx index d577cce7dfeb..6607a3b058b1 100644 --- a/ui/src/app/workflows/components/workflow-dag/workflow-dag-render-options-panel.tsx +++ b/ui/src/app/workflows/components/workflow-dag/workflow-dag-render-options-panel.tsx @@ -1,46 +1,44 @@ import * as React from 'react'; import {WorkflowDagRenderOptions} from './workflow-dag'; -export class WorkflowDagRenderOptionsPanel extends React.Component void}> { - private get workflowDagRenderOptions() { - return this.props as WorkflowDagRenderOptions; +export function WorkflowDagRenderOptionsPanel(props: WorkflowDagRenderOptions & {onChange: (changed: WorkflowDagRenderOptions) => void}) { + function workflowDagRenderOptions() { + return props as WorkflowDagRenderOptions; } - public render() { - return ( - <> - - this.props.onChange({ - ...this.workflowDagRenderOptions, - showArtifacts: !this.workflowDagRenderOptions.showArtifacts - }) - } - className={this.workflowDagRenderOptions.showArtifacts ? 'active' : ''} - title='Toggle artifacts'> - - - - this.props.onChange({ - ...this.workflowDagRenderOptions, - expandNodes: new Set() - }) - } - title='Collapse all nodes'> - - - - this.props.onChange({ - ...this.workflowDagRenderOptions, - expandNodes: new Set(['*']) - }) - } - title='Expand all nodes'> - - - - ); - } + return ( + <> + + props.onChange({ + ...workflowDagRenderOptions(), + showArtifacts: !workflowDagRenderOptions().showArtifacts + }) + } + className={workflowDagRenderOptions().showArtifacts ? 'active' : ''} + title='Toggle artifacts'> + + + + props.onChange({ + ...workflowDagRenderOptions(), + expandNodes: new Set() + }) + } + title='Collapse all nodes'> + + + + props.onChange({ + ...workflowDagRenderOptions(), + expandNodes: new Set(['*']) + }) + } + title='Expand all nodes'> + + + + ); } diff --git a/ui/src/app/workflows/components/workflow-editor.tsx b/ui/src/app/workflows/components/workflow-editor.tsx index e0ed3cbd58a1..184fcbb249c3 100644 --- a/ui/src/app/workflows/components/workflow-editor.tsx +++ b/ui/src/app/workflows/components/workflow-editor.tsx @@ -6,7 +6,7 @@ import {MetadataEditor} from '../../shared/components/editors/metadata-editor'; import {WorkflowParametersEditor} from '../../shared/components/editors/workflow-parameters-editor'; import {ObjectEditor} from '../../shared/components/object-editor/object-editor'; -export const WorkflowEditor = ({ +export function WorkflowEditor({ selectedTabKey, onTabSelected, onError, @@ -18,7 +18,7 @@ export const WorkflowEditor = ({ onError: (error: Error) => void; onTabSelected?: (tab: string) => void; selectedTabKey?: string; -}) => { +}) { return ( ); -}; +} diff --git a/ui/src/app/workflows/components/workflow-from.tsx b/ui/src/app/workflows/components/workflow-from.tsx index 69e3e4a7a51f..c99f546f075b 100644 --- a/ui/src/app/workflows/components/workflow-from.tsx +++ b/ui/src/app/workflows/components/workflow-from.tsx @@ -4,7 +4,7 @@ import {ClusterWorkflowTemplateLink} from '../../cluster-workflow-templates/comp import {CronWorkflowLink} from '../../cron-workflows/components/cron-workflow-link'; import {WorkflowTemplateLink} from '../../workflow-templates/components/workflow-template-link'; -export const WorkflowFrom = (props: {namespace: string; labels: {[name: string]: string}}) => { +export function WorkflowFrom(props: {namespace: string; labels: {[name: string]: string}}) { const workflowTemplate = props.labels[labels.workflowTemplate]; const clusterWorkflowTemplate = props.labels[labels.clusterWorkflowTemplate]; const cronWorkflow = props.labels[labels.cronWorkflow]; @@ -16,4 +16,4 @@ export const WorkflowFrom = (props: {namespace: string; labels: {[name: string]: {!workflowTemplate && !clusterWorkflowTemplate && !cronWorkflow && '-'} ); -}; +} diff --git a/ui/src/app/workflows/components/workflow-labels/workflow-labels.tsx b/ui/src/app/workflows/components/workflow-labels/workflow-labels.tsx index 2b064cb5f539..f98c067ecaa6 100644 --- a/ui/src/app/workflows/components/workflow-labels/workflow-labels.tsx +++ b/ui/src/app/workflows/components/workflow-labels/workflow-labels.tsx @@ -8,34 +8,28 @@ interface WorkflowLabelsProps { onChange: (key: string, value: string) => void; } -export class WorkflowLabels extends React.Component { - constructor(props: WorkflowLabelsProps) { - super(props); +export function WorkflowLabels(props: WorkflowLabelsProps) { + const labels = []; + const w = props.workflow; + if (w.metadata.labels) { + labels.push( + Object.entries(w.metadata.labels).map(([key, value]) => ( +
{ + e.preventDefault(); + props.onChange(key, value); + }}> +
{key}
+
{value}
+
+ )) + ); + } else { + labels.push(
No labels
); } - public render() { - const labels = []; - const w = this.props.workflow; - if (w.metadata.labels) { - labels.push( - Object.entries(w.metadata.labels).map(([key, value]) => ( -
{ - e.preventDefault(); - this.props.onChange(key, value); - }}> -
{key}
-
{value}
-
- )) - ); - } else { - labels.push(
No labels
); - } - - return
{labels}
; - } + return
{labels}
; } diff --git a/ui/src/app/workflows/components/workflow-logs-viewer/full-height-logs-viewer.tsx b/ui/src/app/workflows/components/workflow-logs-viewer/full-height-logs-viewer.tsx index 4e351237122d..a7b5d14394c2 100644 --- a/ui/src/app/workflows/components/workflow-logs-viewer/full-height-logs-viewer.tsx +++ b/ui/src/app/workflows/components/workflow-logs-viewer/full-height-logs-viewer.tsx @@ -5,7 +5,7 @@ import {LogsViewerProps} from 'argo-ui/src/components/logs-viewer/logs-viewer'; require('./workflow-logs-viewer.scss'); -export const FullHeightLogsViewer = (props: LogsViewerProps) => { +export function FullHeightLogsViewer(props: LogsViewerProps) { const ref = React.useRef(null); const [height, setHeight] = React.useState(null); const {source} = props; @@ -20,4 +20,4 @@ export const FullHeightLogsViewer = (props: LogsViewerProps) => { {height && } ); -}; +} diff --git a/ui/src/app/workflows/components/workflow-logs-viewer/json-logs-field-selector.tsx b/ui/src/app/workflows/components/workflow-logs-viewer/json-logs-field-selector.tsx index 0079f7663b12..07a3898e1889 100644 --- a/ui/src/app/workflows/components/workflow-logs-viewer/json-logs-field-selector.tsx +++ b/ui/src/app/workflows/components/workflow-logs-viewer/json-logs-field-selector.tsx @@ -5,7 +5,7 @@ export interface SelectedJsonFields { values: string[]; } -export const JsonLogsFieldSelector = ({fields, onChange}: {fields: SelectedJsonFields; onChange: (v: string[]) => void}) => { +export function JsonLogsFieldSelector({fields, onChange}: {fields: SelectedJsonFields; onChange: (v: string[]) => void}) { const [inputFields, setInputFields] = React.useState(fields); const [key, setKey] = React.useState(''); const deleteItem = (k: string) => { @@ -61,7 +61,7 @@ export const JsonLogsFieldSelector = ({fields, onChange}: {fields: SelectedJsonF ); -}; +} export const extractJsonValue = (obj: any, jsonpath: string): string | null => { const fields = jsonpath.split('.'); diff --git a/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx b/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx index 14579c606170..b2c94abd83ff 100644 --- a/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx +++ b/ui/src/app/workflows/components/workflow-logs-viewer/workflow-logs-viewer.tsx @@ -48,16 +48,16 @@ interface ParsedTime { fullstring: string; } // extract the time field from a string -const parseTime = (formattedString: string): undefined | ParsedTime => { +function parseTime(formattedString: string): undefined | ParsedTime { const re = new RegExp('time="(.*?)"'); const table = re.exec(formattedString); if (table === null || table.length !== 2) { return undefined; } return {quoted: table[1], fullstring: table[0]}; -}; +} -const parseAndTransform = (formattedString: string, timezone: string) => { +function parseAndTransform(formattedString: string, timezone: string) { const maybeTime = parseTime(formattedString); if (maybeTime === undefined) { return formattedString; @@ -71,9 +71,9 @@ const parseAndTransform = (formattedString: string, timezone: string) => { } catch { return formattedString; } -}; +} -export const WorkflowLogsViewer = ({workflow, nodeId, initialPodName, container, archived}: WorkflowLogsViewerProps) => { +export function WorkflowLogsViewer({workflow, nodeId, initialPodName, container, archived}: WorkflowLogsViewerProps) { const storage = new ScopedLocalStorage('workflow-logs-viewer'); const storedJsonFields = storage.getItem('jsonFields', { values: [] @@ -202,7 +202,7 @@ export const WorkflowLogsViewer = ({workflow, nodeId, initialPodName, container, const [candidateContainer, setCandidateContainer] = useState(container); const filteredTimezones = timezones.filter(tz => tz.startsWith(uiTimezone) || uiTimezone === ''); - const popupJsonFieldSelector = async () => { + async function popupJsonFieldSelector() { const fields = {...selectedJsonFields}; const updated = await popup.confirm('Select Json Fields', () => ( @@ -333,4 +333,4 @@ export const WorkflowLogsViewer = ({workflow, nodeId, initialPodName, container,

); -}; +} diff --git a/ui/src/app/workflows/components/workflow-node-info/workflow-node-info.tsx b/ui/src/app/workflows/components/workflow-node-info/workflow-node-info.tsx index 6a4fd98af42d..87b505991d2a 100644 --- a/ui/src/app/workflows/components/workflow-node-info/workflow-node-info.tsx +++ b/ui/src/app/workflows/components/workflow-node-info/workflow-node-info.tsx @@ -1,6 +1,7 @@ import {Tabs, Ticker, Tooltip} from 'argo-ui'; import moment from 'moment'; import * as React from 'react'; +import {useState} from 'react'; import * as models from '../../../../models'; import {Artifact, NodeStatus, Workflow} from '../../../../models'; @@ -377,49 +378,39 @@ const WorkflowNodeContainer = (props: { ); }; -class WorkflowNodeContainers extends React.Component { - constructor(props: Props) { - super(props); - this.state = {selectedSidecar: null}; - } - - public render() { - const template = getResolvedTemplates(this.props.workflow, this.props.node); - if (!template || (!template.container && !template.containerSet && !template.script)) { - return ( -
-
-
No data to display
-
-
- ); - } - const containers = (template.containerSet ? template.containerSet.containers : []).concat(template.sidecars || []); - - const container = (this.state.selectedSidecar && containers.find(item => item.name === this.state.selectedSidecar)) || template.container || template.script; +function WorkflowNodeContainers(props: Props) { + const [selectedSidecar, setSelectedSidecar] = useState(null); + const template = getResolvedTemplates(props.workflow, props.node); + if (!template || (!template.container && !template.containerSet && !template.script)) { return ( -
- {this.state.selectedSidecar && this.setState({selectedSidecar: null})} />} - - {!this.state.selectedSidecar && ( -
-

SIDECARS:

- {containers.map(sidecar => ( -
this.setState({selectedSidecar: sidecar.name})}> - {sidecar.name} -
- ))} -
- )} +
+
+
No data to display
+
); } + + const containers = (template.containerSet ? template.containerSet.containers : []).concat(template.sidecars || []); + const container = (selectedSidecar && containers.find(item => item.name === selectedSidecar)) || template.container || template.script; + + return ( +
+ {selectedSidecar && setSelectedSidecar(null)} />} + + {!selectedSidecar && ( +
+

SIDECARS:

+ {containers.map(sidecar => ( +
setSelectedSidecar(sidecar.name)}> + {sidecar.name} +
+ ))} +
+ )} +
+ ); } const WorkflowNodeArtifacts = (props: {workflow: Workflow; node: NodeStatus; archived: boolean; isInput: boolean; artifacts: Artifact[]}) => { diff --git a/ui/src/app/workflows/components/workflow-panel/workflow-panel.tsx b/ui/src/app/workflows/components/workflow-panel/workflow-panel.tsx index 523163e7b90c..a84df7d13766 100644 --- a/ui/src/app/workflows/components/workflow-panel/workflow-panel.tsx +++ b/ui/src/app/workflows/components/workflow-panel/workflow-panel.tsx @@ -12,26 +12,24 @@ interface Props { nodeClicked: (nodeId: string) => void; } -export class WorkflowPanel extends React.Component { - public render() { - if (!this.props.workflowStatus.nodes && this.props.workflowStatus.phase) { - return ( -
- - : {this.props.workflowStatus.message} - -
- ); - } - +export function WorkflowPanel(props: Props) { + if (!props.workflowStatus.nodes && props.workflowStatus.phase) { return ( - +
+ + : {props.workflowStatus.message} + +
); } + + return ( + + ); } diff --git a/ui/src/app/workflows/components/workflow-yaml-viewer/workflow-yaml-viewer.tsx b/ui/src/app/workflows/components/workflow-yaml-viewer/workflow-yaml-viewer.tsx index 1202f5cc369f..d4376c58e068 100644 --- a/ui/src/app/workflows/components/workflow-yaml-viewer/workflow-yaml-viewer.tsx +++ b/ui/src/app/workflows/components/workflow-yaml-viewer/workflow-yaml-viewer.tsx @@ -10,59 +10,60 @@ interface WorkflowYamlViewerProps { selectedNode: models.NodeStatus; } -export class WorkflowYamlViewer extends React.Component { - public render() { - const contents: JSX.Element[] = []; - contents.push(

Node

); - if (this.props.selectedNode) { - const parentNode = this.props.workflow.status.nodes[this.props.selectedNode.boundaryID]; - if (parentNode) { - contents.push( -
-

{this.normalizeNodeName(this.props.selectedNode.displayName || this.props.selectedNode.name)}

- -
- ); - } +function normalizeNodeName(name: string) { + const parts = name.replace(/([(][^)]*[)])/g, '').split('.'); + return parts[parts.length - 1]; +} - const currentNodeTemplate = getResolvedTemplates(this.props.workflow, this.props.selectedNode); - if (currentNodeTemplate) { - contents.push( -
-

{this.props.selectedNode.name}

- -
- ); - } - } - const templates = this.props.workflow.spec.templates; - if (templates && Object.keys(templates).length) { +export function WorkflowYamlViewer(props: WorkflowYamlViewerProps) { + const contents: JSX.Element[] = []; + contents.push(

Node

); + + if (props.selectedNode) { + const parentNode = props.workflow.status.nodes[props.selectedNode.boundaryID]; + if (parentNode) { contents.push( - } - className='workflow-yaml-section' - /> +
+

{normalizeNodeName(props.selectedNode.displayName || props.selectedNode.name)}

+ +
); } - const storedTemplates = this.props.workflow.status.storedTemplates; - if (storedTemplates && Object.keys(storedTemplates).length) { + + const currentNodeTemplate = getResolvedTemplates(props.workflow, props.selectedNode); + if (currentNodeTemplate) { contents.push( - } - className='workflow-yaml-section' - /> +
+

{props.selectedNode.name}

+ +
); } + } - return
{contents}
; + const templates = props.workflow.spec.templates; + if (templates && Object.keys(templates).length) { + contents.push( + } + className='workflow-yaml-section' + /> + ); } - private normalizeNodeName(name: string) { - const parts = name.replace(/([(][^)]*[)])/g, '').split('.'); - return parts[parts.length - 1]; + const storedTemplates = props.workflow.status.storedTemplates; + if (storedTemplates && Object.keys(storedTemplates).length) { + contents.push( + } + className='workflow-yaml-section' + /> + ); } + + return
{contents}
; } diff --git a/ui/src/app/workflows/components/workflows-row/workflows-row.tsx b/ui/src/app/workflows/components/workflows-row/workflows-row.tsx index 9b428205d38c..6a3f3dad2d16 100644 --- a/ui/src/app/workflows/components/workflows-row/workflows-row.tsx +++ b/ui/src/app/workflows/components/workflows-row/workflows-row.tsx @@ -1,5 +1,6 @@ import {Ticker} from 'argo-ui/src/index'; import * as React from 'react'; +import {useState} from 'react'; import {Link} from 'react-router-dom'; import * as models from '../../../../models'; import {isArchivedWorkflow, Workflow} from '../../../../models'; @@ -19,103 +20,92 @@ interface WorkflowsRowProps { columns: models.Column[]; } -interface WorkflowRowState { - hideDrawer: boolean; -} - -export class WorkflowsRow extends React.Component { - constructor(props: WorkflowsRowProps) { - super(props); - this.state = { - hideDrawer: true - }; - } +export function WorkflowsRow(props: WorkflowsRowProps) { + const [hideDrawer, setHideDrawer] = useState(true); + const wf = props.workflow; - public render() { - const wf = this.props.workflow; - return ( -
-
-
- { - e.stopPropagation(); - }} - onChange={e => { - this.props.select(this.props.workflow); - }} - /> - -
- +
+
+ { + e.stopPropagation(); }} - className='small-11 row'> -
- {(wf.metadata.annotations && wf.metadata.annotations[ANNOTATION_TITLE]) || wf.metadata.name} - {wf.metadata.annotations && wf.metadata.annotations[ANNOTATION_DESCRIPTION] ?

{wf.metadata.annotations[ANNOTATION_DESCRIPTION]}

: null} -
-
{wf.metadata.namespace}
-
- -
-
- -
-
- {() => } -
-
{wf.status.progress || '-'}
-
{wf.status.message || '-'}
-
-
-
{ - e.preventDefault(); - this.setState({hideDrawer: !this.state.hideDrawer}); - }} - className={`workflows-row__action workflows-row__action--${this.state.hideDrawer ? 'show' : 'hide'}`}> - {this.state.hideDrawer ? ( - - SHOW {' '} - - ) : ( - - HIDE - - )} -
+ onChange={e => { + props.select(props.workflow); + }} + /> + +
+ +
+ {(wf.metadata.annotations && wf.metadata.annotations[ANNOTATION_TITLE]) || wf.metadata.name} + {wf.metadata.annotations && wf.metadata.annotations[ANNOTATION_DESCRIPTION] ?

{wf.metadata.annotations[ANNOTATION_DESCRIPTION]}

: null} +
+
{wf.metadata.namespace}
+
+ +
+
+ +
+
+ {() => } +
+
{wf.status.progress || '-'}
+
{wf.status.message || '-'}
+
+
+
{ + e.preventDefault(); + setHideDrawer(!hideDrawer); + }} + className={`workflows-row__action workflows-row__action--${hideDrawer ? 'show' : 'hide'}`}> + {hideDrawer ? ( + + SHOW {' '} + + ) : ( + + HIDE + + )}
-
{isArchivedWorkflow(wf) ? 'true' : 'false'}
- {(this.props.columns || []).map(column => { - // best not to make any assumptions and wait until this data is filled - const value = wf?.metadata?.labels?.[column.key] ?? 'unknown'; - return ( -
- {value} -
- ); - })} - {this.state.hideDrawer ? ( - - ) : ( - { - this.props.onChange(key); - }} - /> - )} - -
+
+
{isArchivedWorkflow(wf) ? 'true' : 'false'}
+ {(props.columns || []).map(column => { + // best not to make any assumptions and wait until this data is filled + const value = wf?.metadata?.labels?.[column.key] ?? 'unknown'; + return ( +
+ {value} +
+ ); + })} + {hideDrawer ? ( + + ) : ( + { + props.onChange(key); + }} + /> + )} +
- ); - } +
+ ); } diff --git a/ui/src/app/workflows/components/workflows-summary-container/workflows-summary-container.tsx b/ui/src/app/workflows/components/workflows-summary-container/workflows-summary-container.tsx index 03d5fdeea115..c47796f2899c 100644 --- a/ui/src/app/workflows/components/workflows-summary-container/workflows-summary-container.tsx +++ b/ui/src/app/workflows/components/workflows-summary-container/workflows-summary-container.tsx @@ -7,7 +7,7 @@ require('./workflows-summary-container.scss'); type ReduceReturnType = Record; -export const WorkflowsSummaryContainer = (props: {workflows: Workflow[]}) => { +export function WorkflowsSummaryContainer(props: {workflows: Workflow[]}) { const [wfSummary, setWfSummary] = useState(null); useEffect(() => { if (props.workflows) { @@ -54,4 +54,4 @@ export const WorkflowsSummaryContainer = (props: {workflows: Workflow[]}) => {
); -}; +}