Skip to content

Commit

Permalink
refactor(ui): migrate several components from class to functional (#1…
Browse files Browse the repository at this point in the history
…1791)

Signed-off-by: Anton Gilgur <agilgur5@gmail.com>
  • Loading branch information
agilgur5 authored Sep 16, 2023
1 parent d33f267 commit 56d1333
Show file tree
Hide file tree
Showing 27 changed files with 443 additions and 499 deletions.
70 changes: 32 additions & 38 deletions ui/src/app/shared/components/error-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,46 +6,40 @@ interface Props {
errorInfo?: ErrorInfo;
}

export class ErrorPanel extends React.Component<Props> {
constructor(props: Props) {
super(props);
}

public render() {
return (
<div className='white-box'>
<h3>
<i className='fa fa-skull status-icon--failed' /> {this.props.error.message}
</h3>
<p>
<i className='fa fa-redo' /> <a href='javascript:document.location.reload();'>Reload this page</a> to try again.
</p>
{this.props.error.response && (
<>
{this.props.error.response.req && (
<>
<h5>Request</h5>
<pre>
{this.props.error.response.req.method} {this.props.error.response.req.url}
</pre>
</>
)}
export function ErrorPanel(props: Props) {
return (
<div className='white-box'>
<h3>
<i className='fa fa-skull status-icon--failed' /> {props.error.message}
</h3>
<p>
<i className='fa fa-redo' /> <a href='javascript:document.location.reload();'>Reload this page</a> to try again.
</p>
{props.error.response && (
<>
{props.error.response.req && (
<>
<h5>Response</h5>
<pre>HTTP {this.props.error.response.status}</pre>
{this.props.error.response.body && <pre>{JSON.stringify(this.props.error.response.body, null, 2)}</pre>}
<h5>Request</h5>
<pre>
{props.error.response.req.method} {props.error.response.req.url}
</pre>
</>
</>
)}
<h5>Stack Trace</h5>
<pre>{this.props.error.stack}</pre>
{this.props.errorInfo && (
)}
<>
<h5>Component Stack</h5>
<pre>{this.props.errorInfo.componentStack}</pre>
<h5>Response</h5>
<pre>HTTP {props.error.response.status}</pre>
{props.error.response.body && <pre>{JSON.stringify(props.error.response.body, null, 2)}</pre>}
</>
)}
</div>
);
}
</>
)}
<h5>Stack Trace</h5>
<pre>{props.error.stack}</pre>
{props.errorInfo && (
<>
<h5>Component Stack</h5>
<pre>{props.errorInfo.componentStack}</pre>
</>
)}
</div>
);
}
28 changes: 13 additions & 15 deletions ui/src/app/shared/components/inline-table/inline-table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,17 @@ interface Row {
right: ReactChild;
}

export class InlineTable extends React.Component<TableProps> {
public render() {
return (
<div className='it'>
{this.props.rows.map((row, i) => {
return (
<div key={i} className='it--row'>
<div className='it--col it--key'>{row.left}</div>
<div className='it--col'>{row.right}</div>
</div>
);
})}
</div>
);
}
export function InlineTable(props: TableProps) {
return (
<div className='it'>
{props.rows.map((row, i) => {
return (
<div key={i} className='it--row'>
<div className='it--col it--key'>{row.left}</div>
<div className='it--col'>{row.right}</div>
</div>
);
})}
</div>
);
}
41 changes: 18 additions & 23 deletions ui/src/app/shared/components/nudge.tsx
Original file line number Diff line number Diff line change
@@ -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 && (
<Notice style={{marginLeft: 0, marginRight: 0}}>
{this.props.children}
<span className='fa-pull-right'>
<a onClick={() => this.close()}>
<i className='fa fa-times' />
</a>{' '}
</span>
</Notice>
)
);
}

private close() {
this.setState({closed: true});
localStorage.setItem(this.props.key, '{}');
}
return (
!closed && (
<Notice style={{marginLeft: 0, marginRight: 0}}>
{props.children}
<span className='fa-pull-right'>
<a onClick={() => close()}>
<i className='fa fa-times' />
</a>{' '}
</span>
</Notice>
)
);
}
105 changes: 50 additions & 55 deletions ui/src/app/shared/components/pagination-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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 (
<p style={{paddingBottom: '45px'}}>
<button
disabled={!this.props.pagination.offset}
className='argo-button argo-button--base-o'
onClick={() => this.props.onChange({limit: this.props.pagination.limit})}>
First page
</button>
<button
disabled={!this.props.pagination.nextOffset}
className='argo-button argo-button--base-o'
onClick={() =>
this.props.onChange({
limit: this.props.pagination.limit,
offset: this.props.pagination.nextOffset
})
}>
Next page <i className='fa fa-chevron-right' />
</button>
{this.props.pagination.limit > 0 && this.props.pagination.limit <= this.props.numRecords ? (
<>
<WarningIcon /> Workflows cannot be globally sorted when paginated
</>
) : (
<span />
)}
<small className='fa-pull-right'>
<select
className='small'
onChange={e => {
const limit = parseLimit(e.target.value);
const newValue: Pagination = {limit};
export function PaginationPanel(props: {pagination: Pagination; onChange: (pagination: Pagination) => void; numRecords: number}) {
return (
<p style={{paddingBottom: '45px'}}>
<button disabled={!props.pagination.offset} className='argo-button argo-button--base-o' onClick={() => props.onChange({limit: props.pagination.limit})}>
First page
</button>
<button
disabled={!props.pagination.nextOffset}
className='argo-button argo-button--base-o'
onClick={() =>
props.onChange({
limit: props.pagination.limit,
offset: props.pagination.nextOffset
})
}>
Next page <i className='fa fa-chevron-right' />
</button>
{props.pagination.limit > 0 && props.pagination.limit <= props.numRecords ? (
<>
<WarningIcon /> Workflows cannot be globally sorted when paginated
</>
) : (
<span />
)}
<small className='fa-pull-right'>
<select
className='small'
onChange={e => {
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 => (
<option key={limit} value={limit}>
{limit === 0 ? 'all' : limit}
</option>
))}
</select>{' '}
results per page
</small>
</p>
);
}
props.onChange(newValue);
}}
value={props.pagination.limit || 0}>
{[5, 10, 20, 50, 100, 500, 0].map(limit => (
<option key={limit} value={limit}>
{limit === 0 ? 'all' : limit}
</option>
))}
</select>{' '}
results per page
</small>
</p>
);
}
32 changes: 15 additions & 17 deletions ui/src/app/shared/conditions-panel.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -48,21 +48,19 @@ function getConditionIcon(condition: ConditionType): JSX.Element {
}
}

export class ConditionsPanel extends React.Component<Props> {
public render() {
return (
<>
{this.props.conditions &&
Object.entries(this.props.conditions).map(([_, condition]) => {
return (
<div key={condition.type} style={{lineHeight: '120%', marginTop: '16px'}}>
{getConditionIcon(condition.type)}
<span className='condition-panel__type'>{condition.type}</span>
{': ' + (condition.message || condition.status)}
</div>
);
})}
</>
);
}
export function ConditionsPanel(props: Props) {
return (
<>
{props.conditions &&
Object.entries(props.conditions).map(([_, condition]) => {
return (
<div key={condition.type} style={{lineHeight: '120%', marginTop: '16px'}}>
{getConditionIcon(condition.type)}
<span className='condition-panel__type'>{condition.type}</span>
{': ' + (condition.message || condition.status)}
</div>
);
})}
</>
);
}
26 changes: 12 additions & 14 deletions ui/src/app/shared/resources-duration.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,18 +5,16 @@ interface Props {
resourcesDuration: {[resource: string]: number};
}

export class ResourcesDuration extends React.Component<Props> {
public render() {
return (
<>
{this.props.resourcesDuration &&
Object.entries(this.props.resourcesDuration)
.map(([resource, duration]) => formatDuration(duration, 1) + '*(' + denominator(resource) + ' ' + resource + ')')
.join(',')}{' '}
<a href='https://argoproj.github.io/argo-workflows/resource-duration/'>
<i className='fa fa-info-circle' />
</a>
</>
);
}
export function ResourcesDuration(props: Props) {
return (
<>
{props.resourcesDuration &&
Object.entries(props.resourcesDuration)
.map(([resource, duration]) => formatDuration(duration, 1) + '*(' + denominator(resource) + ' ' + resource + ')')
.join(',')}{' '}
<a href='https://argoproj.github.io/argo-workflows/resource-duration/'>
<i className='fa fa-info-circle' />
</a>
</>
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<WorkflowTemplate>(exampleWorkflowTemplate(Utils.getNamespaceWithDefault(namespace)));
const [error, setError] = useState<Error>();
return (
Expand All @@ -35,4 +35,4 @@ export const WorkflowTemplateCreator = ({namespace, onCreate}: {namespace: strin
</p>
</>
);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<any>) => {
export function WorkflowTemplateDetails({history, location, match}: RouteComponentProps<any>) {
// boiler-plate
const {notifications, navigation, popup} = useContext(Context);
const queryParams = new URLSearchParams(location.search);
Expand Down Expand Up @@ -139,4 +139,4 @@ export const WorkflowTemplateDetails = ({history, location, match}: RouteCompone
)}
</Page>
);
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -19,7 +19,7 @@ export const WorkflowTemplateEditor = ({
onError: (error: Error) => void;
onTabSelected?: (tab: string) => void;
selectedTabKey?: string;
}) => {
}) {
return (
<Tabs
key='tabs'
Expand Down Expand Up @@ -55,4 +55,4 @@ export const WorkflowTemplateEditor = ({
]}
/>
);
};
}
Loading

0 comments on commit 56d1333

Please sign in to comment.