Skip to content

Commit

Permalink
ADDON-34750: feat: ucc_ui_lib: add dynamic data loading and error bou…
Browse files Browse the repository at this point in the history
…ndary
  • Loading branch information
harshpatel-crest committed Mar 12, 2021
1 parent 200792a commit b30ea13
Show file tree
Hide file tree
Showing 7 changed files with 266 additions and 602 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import React from 'react';
import Heading from '@splunk/react-ui/Heading';
import Message from '@splunk/react-ui/Message';

import errorCodes from '../constants/errorCodes';

class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { errorCode: null, error: null, errorInfo: null };
}

static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { errorCode: error.ucc_err_code };
}

componentDidCatch(error, errorInfo) {
// Catch errors in any components below and re-render with error message
this.setState({
error: error,
errorInfo: errorInfo,
});
// You can also log error messages to an error reporting service here
}

render() {
if (this.state.errorCode) {
// Error path
return (
<>
<Heading level={2}>
Something went wrong! (ERROR_CODE: {this.state.errorCode})
</Heading>
<Message type="info">{errorCodes[this.state.errorCode]}</Message>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.toString()}
<br />
{this.state.errorInfo && this.state.errorInfo.componentStack}
</details>
</>
);
} else if (this.state.error) {
return (
<>
<Heading level={2}>Something went wrong!</Heading>
<details style={{ whiteSpace: 'pre-wrap' }}>
{this.state.error && this.state.error.toString()}
<br />
{this.state.errorInfo && this.state.errorInfo.componentStack}
</details>
</>
);
}
// Normally, just render children
return this.props.children;
}
}

export default ErrorBoundary;
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,13 @@ import Trash from '@splunk/react-icons/Trash';
import Tooltip from '@splunk/react-ui/Tooltip';
import { _ } from '@splunk/ui-utils/i18n';
import PropTypes from 'prop-types';
import WaitSpinner from '@splunk/react-ui/WaitSpinner';

import { ActionButtonComponent } from './CustomTableStyle';
import { getUnifiedConfigs } from '../../util/util';
import { getExpansionRow } from './TableExpansionRow';

function CustomTable({ isInput, serviceName, data, handleToggleActionClick }) {

const [sortKey, setSortKey] = useState('name');
const [sortDir, setSortDir] = useState('asc');

Expand All @@ -27,14 +27,14 @@ function CustomTable({ isInput, serviceName, data, handleToggleActionClick }) {
headers.forEach((header) => {
column.push({
...header,
sortKey: header.field || null
sortKey: header.field || null,
});
});
}
column.push({ label: 'Actions', field: 'actions', sortKey: '' });
return column;
}
}
};

const [columns, setColumns] = useState(() => generateColumns());

Expand All @@ -49,57 +49,49 @@ function CustomTable({ isInput, serviceName, data, handleToggleActionClick }) {
const getTableHeaders = () => {
return (
<Table.Head>
{columns && columns.length && columns.map((headData) => (
<Table.HeadCell
key={headData.field}
onSort={headData.sortKey ? handleSort : null}
sortKey={headData.sortKey ? headData.sortKey : null}
sortDir={headData.sortKey && headData.sortKey === sortKey ? sortDir : 'none'}
>
{headData.label}
</Table.HeadCell>
))}
{columns &&
columns.length &&
columns.map((headData) => (
<Table.HeadCell
key={headData.field}
onSort={headData.sortKey ? handleSort : null}
sortKey={headData.sortKey ? headData.sortKey : null}
sortDir={
headData.sortKey && headData.sortKey === sortKey ? sortDir : 'none'
}
>
{headData.label}
</Table.HeadCell>
))}
</Table.Head>
)
}

const handleEditActionClick = () => {

}

const handleCloneActionClick = () => {
);
};

}
const handleEditActionClick = () => {};

const handleDeleteActionClick = () => {
const handleCloneActionClick = () => {};

}
const handleDeleteActionClick = () => {};

const rowActionsPrimaryButton = (row) => {
return (
<Table.Cell key={row.id}>
<ButtonGroup>
<Tooltip
content={_('Edit')}
>
<Tooltip content={_('Edit')}>
<ActionButtonComponent
appearance="flat"
icon={<Pencil screenReaderText={null} size={1} />}
onClick={() => handleEditActionClick(row)}
/>
</Tooltip>
<Tooltip
content={_('Clone')}
>
<Tooltip content={_('Clone')}>
<ActionButtonComponent
appearance="flat"
icon={<Clone screenReaderText={null} size={1} />}
onClick={() => handleCloneActionClick(row)}
/>
</Tooltip>
<Tooltip
content={_('Delete')}
>
<Tooltip content={_('Delete')}>
<ActionButtonComponent
appearance="destructive"
icon={<Trash screenReaderText={null} size={1} />}
Expand All @@ -108,76 +100,79 @@ function CustomTable({ isInput, serviceName, data, handleToggleActionClick }) {
</Tooltip>
</ButtonGroup>
</Table.Cell>
)
}
);
};

const getTableRow = (row) => {
return (
<Table.Row
key={row.id}
expansionRow={getExpansionRow(columns.length, row)}
>
{columns && columns.length && columns.map((header) => {
if (header.field === "disabled") {
return (
<Table.Cell key={header.field}>
<Switch
key={row.name}
value={row.disabled}
onClick={() => handleToggleActionClick(row)}
selected={!row.disabled}
appearance="toggle"
>
{row.disabled ? "Disabled" : "Enabled"}
</Switch>
</Table.Cell>
)
}

if (header.field === "actions") {
return rowActionsPrimaryButton(row);
}

return (
<Table.Cell key={header.field}>
{row[header.field]}
</Table.Cell>
)

})}
<Table.Row key={row.id} expansionRow={getExpansionRow(columns.length, row)}>
{columns &&
columns.length &&
columns.map((header) => {
if (header.field === 'disabled') {
return (
<Table.Cell key={header.field}>
<Switch
key={row.name}
value={row.disabled}
onClick={() => handleToggleActionClick(row)}
selected={!row.disabled}
disabled={row.__toggleDisable}
appearance="toggle"
style={{ padding: 0 }}
>
{!row.__toggleDisable ? (
row.disabled ? (
'Disabled'
) : (
'Enabled'
)
) : (
<WaitSpinner />
)}
</Switch>
</Table.Cell>
);
}

if (header.field === 'actions') {
return rowActionsPrimaryButton(row);
}

return <Table.Cell key={header.field}>{row[header.field]}</Table.Cell>;
})}
</Table.Row>
);
}
};

const getTableBody = () => {
return (
<Table.Body>
{data && data.length && data
.sort((rowA, rowB) => {
if (sortDir === 'asc') {
return rowA[sortKey] > rowB[sortKey] ? 1 : -1;
}
if (sortDir === 'desc') {
return rowB[sortKey] > rowA[sortKey] ? 1 : -1;
}
return 0;
})
.map((row) => (
getTableRow(row)
))
}
{data &&
data.length &&
data
.sort((rowA, rowB) => {
if (sortDir === 'asc') {
return rowA[sortKey] > rowB[sortKey] ? 1 : -1;
}
if (sortDir === 'desc') {
return rowB[sortKey] > rowA[sortKey] ? 1 : -1;
}
return 0;
})
.map((row) => getTableRow(row))}
</Table.Body>
);
}
};

return (
<>
{ columns && columns.length &&
{columns && columns.length && (
<Table stripeRows rowExpansion="single">
{getTableHeaders()}
{getTableBody()}
</Table>
}
)}
</>
);
}
Expand All @@ -186,7 +181,7 @@ CustomTable.propTypes = {
isInput: PropTypes.bool,
serviceName: PropTypes.string.isRequired,
data: PropTypes.array.isRequired,
handleToggleActionClick: PropTypes.func
handleToggleActionClick: PropTypes.func,
};

export default CustomTable;

0 comments on commit b30ea13

Please sign in to comment.