@patternfly/react-core#Bullseye JavaScript Examples
The following examples show how to use
@patternfly/react-core#Bullseye.
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: utilities.js From ibutsu-server with MIT License | 7 votes |
export function getSpinnerRow(columnCount) {
return {
heightAuto: true,
cells: [
{
props: {colSpan: columnCount},
title: <Bullseye><center><Spinner size="xl"/></center></Bullseye>
}
]
};
}
Example #2
Source File: Routes.js From dbaas-ui with Apache License 2.0 | 6 votes |
Routes = () => (
<Suspense
fallback={
<Bullseye>
<Spinner />
</Bullseye>
}
>
<Switch>
<Route path="/">
<HomePage />
</Route>
<Route>
<OopsPage />
</Route>
</Switch>
</Suspense>
)
Example #3
Source File: tablestates.js From ibutsu-server with MIT License | 6 votes |
render() {
return (
<Bullseye>
<EmptyState>
<EmptyStateIcon icon={ErrorCircleOIcon} />
<Title headingLevel="h5" size="lg">Error occurred fetching results</Title>
{!!this.props.onClearFilters &&
<React.Fragment>
<EmptyStateBody>
An error occurred while fetching results. Try a different set of filters.
</EmptyStateBody>
<EmptyStateSecondaryActions>
<Button variant="link" onClick={this.props.onClearFilters}>Clear all filters</Button>
</EmptyStateSecondaryActions>
</React.Fragment>
}
</EmptyState>
</Bullseye>
);
}
Example #4
Source File: tablestates.js From ibutsu-server with MIT License | 6 votes |
render() {
return (
<Bullseye>
<EmptyState>
<EmptyStateIcon icon={SearchIcon} />
<Title headingLevel="h5" size="lg">No results found</Title>
{!!this.props.onClearFilters &&
<React.Fragment>
<EmptyStateBody>
No results match this filter criteria. Clear all filters to show results.
</EmptyStateBody>
<EmptyStateSecondaryActions>
<Button variant="link" onClick={this.props.onClearFilters}>Clear all filters</Button>
</EmptyStateSecondaryActions>
</React.Fragment>
}
</EmptyState>
</Bullseye>
);
}
Example #5
Source File: Routes.js From tasks-frontend with Apache License 2.0 | 6 votes |
Routes = () => (
<Suspense
fallback={
<Bullseye>
<Spinner />
</Bullseye>
}
>
<Switch>
<Route exact path="/" render={() => <TasksPage tab={0} />} />
{/*<Redirect exact from="/" to={'/available'} />*/}
<Route exact path="/available" render={() => <TasksPage tab={0} />} />
<Route exact path="/executed" render={() => <TasksPage tab={1} />} />
<Route
exact
path="/executed/:id"
//render={() => <CompletedTaskDetails />}
component={CompletedTaskDetails}
/>
{/* Finally, catch all unmatched routes */}
<Route>
<Redirect to="/" />
</Route>
</Switch>
</Suspense>
)
Example #6
Source File: NoResultsTable.js From tasks-frontend with Apache License 2.0 | 6 votes |
NoResultsTable = ({ type }) => (
<EmptyTable>
<Bullseye>
<EmptyState variant={EmptyStateVariant.full}>
<Title headingLevel="h5" size="lg">
{`No matching ${type} found`}
</Title>
<EmptyStateBody>
To continue, edit your filter settings and search again.
</EmptyStateBody>
</EmptyState>
</Bullseye>
</EmptyTable>
)
Example #7
Source File: Routes.js From sed-frontend with Apache License 2.0 | 6 votes |
Routes = () => (
<Suspense
fallback={
<Bullseye>
<Spinner />
</Bullseye>
}
>
<Authentication>
<Switch>
<Route path={paths.activationKeys} component={ActivationKeys} />
<Route path={paths.connector} component={Dashboard} />
</Switch>
</Authentication>
</Suspense>
)
Example #8
Source File: no-access.js From sed-frontend with Apache License 2.0 | 6 votes |
NoAccessView = () => (
<Bullseye>
<EmptyState>
<EmptyStateIcon icon={LockIcon} />
<Title headingLevel="h4" size="lg">
Activation keys can only be accessed by organization administrators.
</Title>
<EmptyStateBody>
If you already know your organization ID and activation key, you can
register systems with RHC.
</EmptyStateBody>
</EmptyState>
</Bullseye>
)
Example #9
Source File: ErrorBoundary.js From ocp-advisor-frontend with Apache License 2.0 | 6 votes |
render() {
return this.state.hasError ? (
<Bullseye>
<ErrorState />
</Bullseye>
) : (
this.props.children
);
}
Example #10
Source File: Routes.js From ocp-advisor-frontend with Apache License 2.0 | 6 votes |
Routes = () => (
<Suspense
fallback={
<Bullseye>
<Spinner />
</Bullseye>
}
>
<Switch>
{paths.map((path) => (
<Route key={path.title} path={path.path} component={path.component} />
))}
<Redirect exact from="/" to="/recommendations" />
{/* Finally, catch all unmatched routes */}
<Route
path="*"
component={() => (
<EmptyState>
<EmptyStateBody>
<InvalidObject />
</EmptyStateBody>
</EmptyState>
)}
/>
</Switch>
</Suspense>
)
Example #11
Source File: AvailableImagesTile.js From edge-frontend with Apache License 2.0 | 6 votes |
AvailableImageTile = ({ onNewImageClick }) => {
const { isLoading, hasError, data } = useSelector(
({ imagesReducer }) => ({
isLoading:
imagesReducer?.isLoading !== undefined
? imagesReducer?.isLoading
: true,
hasError: imagesReducer?.hasError || false,
data: imagesReducer?.data || null,
}),
shallowEqual
);
return (
<AvailableImageTileBase>
<CardBody>
{isLoading ? (
<Bullseye>
<Spinner />
</Bullseye>
) : hasError ? (
data
) : (
<Button variant="link" style={{ paddingLeft: 0 }}>
{data.meta.count} images
</Button>
)}
</CardBody>
<CardFooter>
<Button variant="primary" onClick={() => onNewImageClick()}>
Create new image
</Button>
</CardFooter>
</AvailableImageTileBase>
);
}
Example #12
Source File: DeviceSummaryTile.js From edge-frontend with Apache License 2.0 | 5 votes |
DeviceSummaryTile = () => {
const { isLoading, hasError, data } = useSelector(
({ deviceSummaryReducer }) => ({
isLoading:
deviceSummaryReducer?.isLoading !== undefined
? deviceSummaryReducer?.isLoading
: true,
hasError: deviceSummaryReducer?.hasError || false,
data: deviceSummaryReducer?.data || null,
}),
shallowEqual
);
if (isLoading) {
return (
<Card className="tiles-card">
<CardTitle>Device summary information</CardTitle>
<CardBody>
<Bullseye>
<Spinner />
</Bullseye>
</CardBody>
</Card>
);
}
if (hasError) {
return (
<Card className="tiles-card">
<CardTitle>Device summary information</CardTitle>
<CardBody>{data}</CardBody>
</Card>
);
}
return (
<DeviceSummaryTileBase
orphaned={data['orphaned']}
active={data['active']}
noReports={data['noReports']}
neverReported={data['neverReported']}
/>
);
}
Example #13
Source File: Loading.js From sed-frontend with Apache License 2.0 | 5 votes |
Loading = () => {
return (
<Bullseye>
<Spinner />
</Bullseye>
);
}
Example #14
Source File: App.js From ocp-advisor-frontend with Apache License 2.0 | 5 votes |
App = ({ useLogger, basename }) => {
const intl = useIntl();
const history = useHistory();
const [isAuthenticated, setIsAuthenticated] = useState(false);
const [isLoading, setIsLoading] = useState(true);
useEffect(() => {
const registry = getRegistry();
registry.register({ notifications: notificationsReducer });
insights.chrome.init();
insights.chrome.auth.getUser().then(() => {
setIsAuthenticated(true);
setIsLoading(false);
});
insights.chrome.identifyApp('ocp-advisor');
const unregister = insights.chrome.on('APP_NAVIGATION', (event) => {
const targetUrl = event.domEvent?.href
?.replace(basename, '/')
.replace(/^\/\//, '/');
if (typeof targetUrl === 'string') {
history.push(targetUrl);
}
});
return () => unregister();
}, []);
return (
<ErrorBoundary>
{isLoading ? (
<Bullseye>
<Spinner />
</Bullseye>
) : isAuthenticated ? (
<Provider store={getStore(useLogger)}>
<NotificationsPortal />
<Routes />
</Provider>
) : (
<Bullseye>
<MessageState
variant="large"
icon={LockIcon}
title={intl.formatMessage(messages.permsTitle)}
text={intl.formatMessage(messages.permsBody)}
/>
</Bullseye>
)}
</ErrorBoundary>
);
}
Example #15
Source File: Routes.js From edge-frontend with Apache License 2.0 | 5 votes |
Routes = () => {
return (
<Suspense
fallback={
<Bullseye>
<Spinner size="xl" />
</Bullseye>
}
>
<Switch>
<Route exact path={paths.groups} component={Groups} />
<Route exact path={paths['groups-detail']} component={GroupsDetail} />
{/* <Route path={paths['device-detail']} component={DeviceDetail} /> */}
{/* <Route path={paths.canaries} component={Canaries} /> */}
<Route exact path={paths['fleet-management']} component={Groups} />
<Route
exact
path={paths['fleet-management-detail']}
component={GroupsDetail}
/>
<Route exact path={paths['inventory']} component={Inventory} />
<Route path={paths['inventory-detail']} component={DeviceDetail} />
<Route
path={paths['manage-images-detail-version']}
component={ImageDetail}
/>
<Route path={paths['manage-images-detail']} component={ImageDetail} />
<Route path={paths['manage-images']} component={Images} />
{useFeatureFlags('fleet-management.custom-repos') && (
<Route exact path={paths['repositories']} component={Repositories} />
)}
<Route
exact
path={paths['learning-resources']}
component={LearningResources}
/>
<Route>
<Redirect to={paths['fleet-management']} />
</Route>
</Switch>
</Suspense>
);
}
Example #16
Source File: Routes.js From access-requests-frontend with Apache License 2.0 | 5 votes |
Routes = () => {
const { getRegistry } = useContext(RegistryContext);
const [isInternal, setIsInternal] = useState(true);
useEffect(() => {
insights.chrome.init();
Promise.resolve(insights.chrome.auth.getUser()).then((user) => {
setIsInternal(user?.identity?.user?.is_internal);
});
});
const AccessRequestDetailsPageWrapper = () => (
<AccessRequestDetailsPage
isInternal={isInternal}
getRegistry={getRegistry}
/>
);
const AccessRequestsPageWrapper = () => (
<AccessRequestsPage isInternal={isInternal} getRegistry={getRegistry} />
);
return (
<Suspense
fallback={
<Bullseye>
<Spinner />
</Bullseye>
}
>
{isDev && (
<ToggleSwitch
id="toggle-view"
label="Internal view"
labelOff="External view"
isChecked={isInternal}
onChange={() => setIsInternal(!isInternal)}
/>
)}
<Switch>
<Route path="/" exact component={AccessRequestsPageWrapper} />
<Route
path="/:requestId"
exact
component={AccessRequestDetailsPageWrapper}
/>
<Route>
<Redirect to="/" />
</Route>
</Switch>
</Suspense>
);
}
Example #17
Source File: App.js From edge-frontend with Apache License 2.0 | 5 votes |
App = (props) => {
const { getRegistry } = useContext(RegistryContext);
const [isLogged, setIsLogged] = useState(false);
const history = useHistory();
const [isAuth, setIsAuth] = useState(null);
useEffect(() => {
insights.chrome.init();
// TODO change this to your appname
insights.chrome.identifyApp('fleet-management');
insights.chrome.on('APP_NAVIGATION', (event) =>
history.push(`/${event.navId}`)
);
const registered = getRegistry().register({
notifications: notificationsReducer,
});
(async () => {
await insights.chrome.auth.getUser();
setIsLogged(true);
})();
(async () => {
const data = await insights.chrome.auth.getUser();
setIsAuth(data.entitlements.smart_management.is_entitled);
})();
return () => {
registered();
};
}, []);
return (
<Fragment>
<NotificationPortal />
{isAuth && isLogged ? (
<Routes childProps={props} />
) : isAuth === null ? (
<Bullseye>
<Spinner size="xl" />
</Bullseye>
) : (
<AuthModal />
)}
</Fragment>
);
}
Example #18
Source File: AddDeviceModal.js From edge-frontend with Apache License 2.0 | 5 votes |
AddDeviceModal = ({
isModalOpen,
setIsModalOpen,
setIsCreateGroupModalOpen,
reloadData,
deviceIds,
}) => {
const dispatch = useDispatch();
const [response] = useApi({ api: getGroups });
const { data, isLoading } = response;
const handleAddDevices = (values) => {
const { group } = values;
const statusMessages = {
onSuccess: {
title: 'Success',
description: `Device(s) have been added to ${group.toString()} successfully`,
},
onError: { title: 'Error', description: 'Failed to add device to group' },
};
apiWithToast(
dispatch,
() => addDevicesToGroup(parseInt(group.groupId), deviceIds),
statusMessages
);
};
return isLoading ? (
<Backdrop>
<Bullseye>
<Spinner isSVG diameter="100px" />
</Bullseye>
</Backdrop>
) : (
<Modal
isOpen={isModalOpen}
openModal={() => setIsModalOpen(false)}
title="Add to group"
submitLabel="Add"
additionalMappers={{
'search-input': {
component: SearchInput,
defaultOptions: data?.data || [],
},
'create-group-btn': {
component: CreateGroupButton,
openModal: () => {
setIsCreateGroupModalOpen(true);
setIsModalOpen(false);
},
},
}}
schema={createSchema(deviceIds)}
onSubmit={handleAddDevices}
reloadData={reloadData}
/>
);
}
Example #19
Source File: ImageVersionDetail.js From edge-frontend with Apache License 2.0 | 5 votes |
ImageVersionDetail = ({ data, imageVersion }) => {
const history = useHistory();
const [isUpdateWizardOpen, setIsUpdateWizardOpen] = useState(false);
const [imageData, setImageData] = useState({});
useEffect(() => {
setImageData(data);
}, [data]);
const openUpdateWizard = () => {
history.push({
pathname: history.location.pathname,
search: new URLSearchParams({
update_image: true,
}).toString(),
});
setIsUpdateWizardOpen(true);
};
return (
<Fragment>
<PageHeader className="pf-m-light">
<Stack hasGutter>
<StackItem>
<DetailsHead
imageData={imageData}
imageVersion={imageVersion}
openUpdateWizard={openUpdateWizard}
/>
</StackItem>
</Stack>
<StackItem>
<Text>{data?.Description}</Text>
</StackItem>
</PageHeader>
<ImageDetailTabs imageData={imageData} imageVersion={imageVersion} />
{isUpdateWizardOpen && (
<Suspense
fallback={
<Bullseye>
<Spinner />
</Bullseye>
}
>
<UpdateImageWizard
navigateBack={() => {
history.push({ pathname: history.location.pathname });
setIsUpdateWizardOpen(false);
}}
updateimageVersionId={data?.ID}
/>
</Suspense>
)}
</Fragment>
);
}
Example #20
Source File: index.js From sed-frontend with Apache License 2.0 | 4 votes |
SamplePage = () => {
const history = useHistory();
const { getRegistry } = useContext(RegistryContext);
const [confirmChangesOpen, setConfirmChangesOpen] = useState(false);
const [madeChanges, setMadeChanges] = useState(false);
const [isEditing, setIsEditing] = useState(false);
const dataRef = useRef();
const dispatch = useDispatch();
const activeStateLoaded = useSelector(
({ activeStateReducer }) => activeStateReducer?.loaded
);
const { useOpenSCAP, enableCloudConnector, hasInsights } = useSelector(
({ activeStateReducer }) => ({
useOpenSCAP: activeStateReducer?.values?.useOpenSCAP,
enableCloudConnector: activeStateReducer?.values?.enableCloudConnector,
hasInsights: activeStateReducer?.values?.hasInsights,
}),
shallowEqual
);
const { systemsCount } = useSelector(
({ connectedSystemsReducer }) => ({
systemsLoaded: connectedSystemsReducer?.loaded,
systemsCount: connectedSystemsReducer?.total,
}),
shallowEqual
);
useEffect(() => {
getRegistry().register({
activeStateReducer,
logReducer,
connectedSystemsReducer,
});
dispatch(fetchCurrState());
dispatch(fetchConnectedHosts());
}, [getRegistry]);
useEffect(() => {
insights?.chrome?.appAction?.('cloud-connector-dashboard');
}, []);
return (
<React.Fragment>
<Route
exact
path={paths.logModal}
render={() => (
<Suspense
fallback={
<Bullseye>
<Spinner />
</Bullseye>
}
>
<ConnectLog />
</Suspense>
)}
/>
<PageHeader className="page-header">
<Split hasGutter className="page-title">
<SplitItem isFilled>
<Flex>
<FlexItem spacer={{ default: 'spacerSm' }}>
<PageHeaderTitle title="Remote Host Configuration Manager" />
</FlexItem>
<FlexItem>
<AboutRemoteHostConfigPopover />
</FlexItem>
</Flex>
</SplitItem>
<SplitItem>
<Button onClick={() => history.push(paths.logModal)} variant="link">
View log
</Button>
</SplitItem>
</Split>
<Stack hasGutter>
<StackItem>
Selections here affect Red Hat Enterprise Linux (RHEL) systems
connected to Red Hat with remote host configuration (rhc). Upon
saving changes, Ansible Playbooks are automatically pushed to
connected systems to update the configuration of the connection to
Red Hat.
</StackItem>
<StackItem>
<a
target="_blank"
rel="noopener noreferrer"
href={
'https://access.redhat.com/documentation/en-us/red_hat_insights/2022/html-single/red_hat_connector_configuration_guide/index'
}
>
Connecting with Red Hat
{<ExternalLinkAltIcon className="pf-u-ml-sm" />}
</a>
</StackItem>
</Stack>
</PageHeader>
<Page>
<div className="dashboard__content">
{activeStateLoaded ||
(useOpenSCAP !== undefined && enableCloudConnector !== undefined) ? (
<Services
madeChanges={madeChanges}
setConfirmChangesOpen={setConfirmChangesOpen}
setMadeChanges={setMadeChanges}
setIsEditing={setIsEditing}
isEditing={isEditing}
defaults={{
useOpenSCAP,
enableCloudConnector,
hasInsights,
}}
onChange={(data) => {
dataRef.current = data;
}}
/>
) : (
<Bullseye>
<Spinner className="pf-u-p-lg" size="xl" />
</Bullseye>
)}
</div>
</Page>
<ConfirmChangesModal
isOpen={confirmChangesOpen}
handleCancel={() => setConfirmChangesOpen(false)}
systemsCount={systemsCount}
data={dataRef.current}
handleConfirm={() => {
setConfirmChangesOpen(false);
(async () => {
const saveAction = saveCurrState(dataRef.current);
dispatch(saveAction);
await saveAction.payload;
dispatch(
addNotification({
variant: 'success',
title: 'Changes saved',
description:
'Your service enablement changes were applied to connected systems',
})
);
setMadeChanges(false);
setIsEditing(false);
})();
}}
/>
</React.Fragment>
);
}
Example #21
Source File: run.js From ibutsu-server with MIT License | 4 votes |
render() {
let passed = 0, failed = 0, errors = 0, xfailed = 0, xpassed = 0, skipped = 0, not_run = 0;
let created = 0;
let calculatePasses = true;
const { run, columns, rows, classificationTable, artifactTabs } = this.state;
const jsonViewTheme = getTheme() === 'dark' ? 'tomorrow' : 'rjv-default';
if (run.start_time) {
created = new Date(run.start_time);
}
else {
created = new Date(run.created);
}
if (run.summary) {
if (run.summary.passes) {
passed = run.summary.passes;
calculatePasses = false;
}
if (run.summary.tests && calculatePasses) {
passed = run.summary.tests;
}
if (run.summary.failures) {
passed -= calculatePasses ? run.summary.failures : 0;
failed = run.summary.failures;
}
if (run.summary.errors) {
passed -= calculatePasses ? run.summary.errors : 0;
errors = run.summary.errors;
}
if (run.summary.xfailures) {
passed -= calculatePasses ? run.summary.xfailures : 0;
xfailed = run.summary.xfailures;
}
if (run.summary.xpasses) {
passed -= calculatePasses ? run.summary.xpasses : 0;
xpassed = run.summary.xpasses;
}
if (run.summary.skips) {
passed -= calculatePasses ? run.summary.skips : 0;
skipped = run.summary.skips;
}
if (run.summary.not_run) {
not_run = run.summary.not_run;
}
else if (run.summary.collected) {
not_run = run.summary.collected - run.summary.tests;
}
}
const pagination = {
pageSize: this.state.pageSize,
page: this.state.page,
totalItems: this.state.totalItems
}
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<TextContent>
<Text component="h1" className="pf-c-title">Run {run.id}</Text>
</TextContent>
</PageSection>
<PageSection>
{!this.state.isRunValid &&
<EmptyObject headingText="Run not found" returnLink="/runs" returnLinkText="Return to runs list" />
}
{this.state.isRunValid &&
<Tabs activeKey={this.state.activeTab} onSelect={this.onTabSelect} isBox>
<Tab eventKey={'summary'} title={<TabTitle icon={InfoCircleIcon} text="Summary" />}>
<Card>
<CardBody style={{padding: 0}} id="run-detail">
<Grid style={{backgroundColor: '#fff'}}>
<GridItem span={6}>
<DataList selectedDataListItemId={null} aria-label="Run properties" style={{borderBottom: 'none', borderTop: 'none'}}>
<DataListItem aria-labelledby="Duration">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1} width={2}><strong>Duration:</strong></DataListCell>,
<DataListCell key={2} width={4}>{round(run.duration)}s</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
<DataListItem aria-labelledby="Started">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1} width={2}><strong>Started:</strong></DataListCell>,
<DataListCell key={2} width={4}>{created.toLocaleString()}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
{run.metadata && run.metadata.component &&
<DataListItem aria-labelledby="Component">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1} width={2}><strong>Component:</strong></DataListCell>,
<DataListCell key={2} width={4}>{run.metadata.component}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
}
{run.metadata && run.metadata.env &&
<DataListItem aria-labelledby="Environment">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1} width={2}><strong>Environment:</strong></DataListCell>,
<DataListCell key={2} width={4}>{run.metadata.env}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
}
{run.metadata && run.metadata.tags &&
<DataListItem aria-labelledby="tags-label">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key="tags-label" width={2}><strong>Tags:</strong></DataListCell>,
<DataListCell key="tags-data" width={4}>
<Flex>
{run.metadata.tags.map((tag) => <FlexItem spacer={{ default: 'spacerXs' }} key={tag}><Label color="blue" variant="filled">{tag}</Label></FlexItem>)}
</Flex>
</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
}
{run.metadata && run.metadata.jenkins && run.metadata.jenkins.job_name &&
<DataListItem aria-labelledby="Jenkins Job Name">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1} width={2}><strong>Jenkins Job Name:</strong></DataListCell>,
<DataListCell key={2} width={4}>{run.metadata.jenkins.job_name}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
}
{run.source &&
<DataListItem aria-labelledby="Source">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1} width={2}><strong>Source:</strong></DataListCell>,
<DataListCell key={2} width={4}>{run.source}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
}
</DataList>
</GridItem>
<GridItem span={6}>
<DataList selectedDataListItemId={null} aria-label="Summary properties" style={{borderBottom: 0, borderTop: 0}}>
<DataListItem aria-labelledby="Summary">
<DataListItemRow>
<DataListItemCells
style={{paddingBottom: 0}}
dataListCells={[
<DataListCell key={1} width={2}><strong>Summary:</strong></DataListCell>,
<DataListCell key={2} width={4} style={{paddingTop: 0}}>
<DataList selectedDataListItemId={null} aria-label="Summary" style={{borderBottom: 0, borderTop: 0}}>
<DataListItem aria-labelledby="Total">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1}>Total:</DataListCell>,
<DataListCell key={2}>{run.summary.collected ? run.summary.collected : run.summary.tests}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
<DataListItem aria-labelledby="Passed">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1}>Passed:</DataListCell>,
<DataListCell key={2}>{passed}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
<DataListItem aria-labelledby="Failed">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1}>Failed:</DataListCell>,
<DataListCell key={2}>{failed}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
<DataListItem aria-labelledby="Error">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1}>Error:</DataListCell>,
<DataListCell key={2}>{errors}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
<DataListItem aria-labelledby="Xfailed">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1}>Xfailed:</DataListCell>,
<DataListCell key={2}>{xfailed}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
<DataListItem aria-labelledby="Xpassed">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1}>Xpassed:</DataListCell>,
<DataListCell key={2}>{xpassed}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
<DataListItem aria-labelledby="Skipped">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1}>Skipped:</DataListCell>,
<DataListCell key={2}>{skipped}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
<DataListItem aria-labelledby="Not Run">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1}>Not Run:</DataListCell>,
<DataListCell key={2}>{not_run}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
</DataList>
</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
</DataList>
</GridItem>
</Grid>
</CardBody>
</Card>
</Tab>
<Tab eventKey={'results-list'} title={<TabTitle icon={CatalogIcon} text="Results List" />}>
<Card className="pf-u-mt-lg">
<CardHeader>
<Flex style={{ width: '100%' }}>
<FlexItem grow={{ default: 'grow' }}>
<TextContent>
<Text component="h2" className="pf-c-title pf-m-xl">Test Results</Text>
</TextContent>
</FlexItem>
<FlexItem>
<Button variant="secondary" onClick={this.refreshResults}>Refresh results</Button>
</FlexItem>
<FlexItem>
<Link to={`/results?run_id[eq]=${run.id}`} className="pf-c-button pf-m-primary" style={{marginLeft: '2px'}}>See all results <ChevronRightIcon /></Link>
</FlexItem>
</Flex>
</CardHeader>
<CardBody>
<FilterTable
columns={columns}
rows={rows}
pagination={pagination}
isEmpty={this.state.isEmpty}
isError={this.state.isError}
onSetPage={this.setPage}
onSetPageSize={this.pageSizeSelect}
/>
</CardBody>
</Card>
</Tab>
<Tab eventKey={'results-tree'} title={<TabTitle icon={RepositoryIcon} text="Results Tree" />}>
<Card className="pf-u-mt-lg">
<CardBody>
<Grid gutter="sm">
{false && <GridItem span={12}>
<div style={{paddingTop: "1em"}}>
<TextInput value={this.state.treeSearch} type="text" onChange={this.onSearch} placeholder="Search tree..." aria-label="Filter tree" />
</div>
</GridItem>
}
{this.state.resultsTree.core.data.length === 0 &&
<GridItem span={12}>
<Bullseye><center><Spinner size="xl"/></center></Bullseye>
</GridItem>
}
{this.state.resultsTree.core.data !== 0 &&
<React.Fragment>
<GridItem span={5}>
<TreeView treeData={this.state.resultsTree} onChange={(e, data) => this.handleJSTreeChange(e, data)}/>
</GridItem>
<GridItem span={7}>
{this.state.testResult &&
<Card className={this.state.testResult.result}>
<CardHeader>
{this.state.testResult.test_id}
{this.state.testResult.metadata.markers &&
<div style={{float: 'right'}}>
{this.state.testResult.metadata.markers.map((marker) => {
return <Badge isRead key={marker.name}>{marker.name}</Badge>;
})}
</div>
}
</CardHeader>
<CardBody style={{backgroundColor: "var(--pf-c-page__main-section--BackgroundColor)", paddingTop: "1.2em"}}>
<ResultView testResult={this.state.testResult}/>
</CardBody>
</Card>
}
</GridItem>
</React.Fragment>
}
</Grid>
</CardBody>
</Card>
</Tab>
<Tab eventKey={'classify-failures'} title={<TabTitle icon={MessagesIcon} text="Classify Failures" />}>
{classificationTable}
</Tab>
{artifactTabs}
<Tab eventKey={'run-object'} title={<TabTitle icon={CodeIcon} text="Run Object" />}>
<Card>
<CardBody>
<ReactJson src={run} name={null} iconStyle={"triangle"} collapseStringsAfterLength={120} enableClipboard={false} displayDataTypes={false} theme={jsonViewTheme} />
</CardBody>
</Card>
</Tab>
</Tabs>
}
</PageSection>
</React.Fragment>
);
}
Example #22
Source File: DeviceDetail.js From edge-frontend with Apache License 2.0 | 4 votes |
DeviceDetail = () => {
const [imageId, setImageId] = useState(null);
const { getRegistry } = useContext(RegistryContext);
const { inventoryId, uuid } = useParams();
const entity = useSelector(({ entityDetails }) => entityDetails?.entity);
const groupName = useSelector(
({ groupsDetailReducer }) => groupsDetailReducer?.name
);
const deviceId = useSelector(
({ entityDetails }) => entityDetails?.entity?.id
);
const [imageData, setImageData] = useState();
const [updateModal, setUpdateModal] = useState({
isOpen: false,
deviceData: null,
});
const [isDeviceStatusLoading, setIsDeviceStatusLoading] = useState(true);
const [reload, setReload] = useState(false);
useEffect(() => {
insights.chrome.registerModule('inventory');
insights.chrome?.hideGlobalFilter?.(true);
insights.chrome.appAction('system-detail');
}, []);
useEffect(() => {
(async () => {
if (!entity?.display_name) {
return;
}
const image_data = await getDeviceHasUpdate(deviceId);
setImageData(image_data);
setIsDeviceStatusLoading(false);
setUpdateModal((prevState) => ({
...prevState,
deviceData: [
{
display_name: entity.display_name,
id: entity.id,
},
],
imageSetId: image_data?.ImageInfo?.Image?.ImageSetID,
}));
setImageId(image_data?.ImageInfo?.Image?.ID);
})();
}, [entity, reload]);
useEffect(() => {
insights?.chrome?.appObjectId?.(inventoryId);
}, [inventoryId]);
return (
<>
<DetailWrapper
hideInvLink
showTags
onLoad={({ mergeWithDetail }) => {
getRegistry().register({
systemProfileStore,
...mergeWithDetail(deviceDetail),
});
}}
>
<PageHeader>
<Breadcrumb ouiaId="systems-list">
<BreadcrumbItem>
<Link to={uuid ? `/groups` : '/inventory'}>
{uuid ? 'Groups' : 'Systems'}
</Link>
</BreadcrumbItem>
{uuid && (
<BreadcrumbItem>
{groupName ? (
<Link to={`/groups/${uuid}`}>{groupName}</Link>
) : (
<Skeleton size={SkeletonSize.xs} />
)}
</BreadcrumbItem>
)}
<BreadcrumbItem isActive>
<div className="ins-c-inventory__detail--breadcrumb-name">
{entity?.display_name || <Skeleton size={SkeletonSize.xs} />}
</div>
</BreadcrumbItem>
</Breadcrumb>
<InventoryDetailHead
fallback=""
actions={[
{
title: 'Update',
isDisabled:
imageData?.UpdateTransactions?.[
imageData?.UpdateTransactions.length - 1
]?.Status === 'BUILDING' ||
imageData?.UpdateTransactions?.[
imageData?.UpdateTransactions.length - 1
]?.Status === 'CREATED' ||
!imageData?.ImageInfo?.UpdatesAvailable?.length > 0 ||
!updateModal.imageSetId,
onClick: () => {
setUpdateModal((prevState) => ({
...prevState,
isOpen: true,
}));
},
},
]}
hideBack
hideInvDrawer
/>
{isDeviceStatusLoading ? (
<Skeleton size={SkeletonSize.xs} />
) : imageData?.UpdateTransactions[
imageData?.UpdateTransactions?.length - 1
]?.Status === 'BUILDING' ||
imageData?.UpdateTransactions[
imageData?.UpdateTransactions?.length - 1
]?.Status === 'CREATED' ? (
<Status type="updating" isLabel={true} className="pf-u-mt-sm" />
) : imageData?.Device?.UpdateAvailable ? (
<Status
type="updateAvailable"
isLabel={true}
className="pf-u-mt-sm"
/>
) : (
<Status type="running" isLabel={true} className="pf-u-mt-sm" />
)}
</PageHeader>
<Grid gutter="md">
<GridItem span={12}>
<DeviceDetailTabs
systemProfile={imageData}
imageId={imageId}
setUpdateModal={setUpdateModal}
setReload={setReload}
/>
</GridItem>
</Grid>
{updateModal.isOpen && (
<Suspense
fallback={
<Bullseye>
<Spinner />
</Bullseye>
}
>
<UpdateDeviceModal
navigateBack={() => {
history.push({ pathname: history.location.pathname });
setUpdateModal((prevState) => {
return {
...prevState,
isOpen: false,
};
});
}}
setUpdateModal={setUpdateModal}
updateModal={updateModal}
refreshTable={() => setReload(true)}
/>
</Suspense>
)}
</DetailWrapper>
</>
);
}
Example #23
Source File: Notification.js From user-preferences-frontend with Apache License 2.0 | 4 votes |
Notification = () => {
const { bundleName } = useParams();
const navigateTo = useChromePush();
const dispatch = useDispatch();
const store = useSelector(
({ notificationPreferences }) => notificationPreferences
);
const bundleDisplayTitle = notificationConfigForBundle(bundleName)?.title;
useEffect(() => {
register(notificationPreferences);
}, []);
useEffect(() => {
(async () => {
await insights.chrome.auth.getUser();
if (bundleName) {
dispatch(getNotificationSchema({ bundleName }));
}
})();
}, [bundleName]);
const { isLoaded, schema } = useMemo(() => {
if (store?.loaded) {
const schema = { ...store.schema };
if (schema.fields) {
schema.fields = [...schema.fields];
schema.fields[0].sections = [...schema.fields[0].sections];
schema.fields[0].sections.push({
fields: unsubscribe,
});
} else {
schema.fields = [];
}
return {
isLoaded: true,
schema: schema,
};
}
return {
isLoaded: false,
schema: [],
};
}, [store]);
const saveValues = useCallback(
async ({ unsubscribe, ...values }) => {
const action = saveNotificationValues({ bundleName, values });
dispatch(action);
try {
await action.payload;
dispatch(
addNotification({
dismissable: false,
variant: 'success',
title: `Notification preferences successfully saved`,
})
);
} catch (e) {
dispatch(
addNotification({
dismissable: false,
variant: 'danger',
title: `Notification preferences unsuccessfully saved`,
})
);
}
},
[bundleName]
);
return (
<React.Fragment>
<PageHeader>
<Split>
<SplitItem isFilled>
<PageHeaderTitle
className="notif-page-header"
title={`My Notifications | ${bundleDisplayTitle}`}
/>
<StackItem>
This service allows you to opt-in and out of receiving
notifications. Your Organization Administrator has configured
which notifications you can or can not receive in their{' '}
<a
onClick={(e) =>
navigateTo(e, `/settings/notifications/${bundleName}`)
}
href={`/settings/notifications/${bundleName}`}
>
Settings
</a>
.
</StackItem>
</SplitItem>
</Split>
</PageHeader>
<Main className="pref-notification">
<Stack hasGutter>
<StackItem>
<Card ouiaId="user-pref-notification-subscriptions-card">
<CardHeader className="pf-u-pb-0"></CardHeader>
<CardBody className="pref-notification_form">
{isLoaded ? (
<FormRender
componentMapper={{
...componentMapper,
[DESCRIPTIVE_CHECKBOX]: DescriptiveCheckbox,
[LOADER]: Loader,
[DATA_LIST]: DataListLayout,
}}
FormTemplate={(props) => (
<FormTemplate {...props} FormButtons={FormButtons} />
)}
schema={schema}
onSubmit={saveValues}
/>
) : (
<Bullseye>
<Spinner />
</Bullseye>
)}
</CardBody>
</Card>
</StackItem>
</Stack>
</Main>
</React.Fragment>
);
}
Example #24
Source File: Email.js From user-preferences-frontend with Apache License 2.0 | 4 votes |
Email = () => {
const dispatch = useDispatch();
const [emailConfig, setEmailConfig] = useState({});
const isLoaded = useLoaded(async () => {
await insights.chrome.auth.getUser();
register(emailPreferences);
setEmailConfig(await calculateEmailConfig(config, dispatch));
});
const store = useSelector(({ emailPreferences }) => emailPreferences);
const saveValues = async ({ unsubscribe, ...values }) => {
const promises = Object.entries(emailConfig)
.filter(([, { isVisible }]) => isVisible === true)
.map(([application, { localFile, schema, url, apiName }]) => {
if (
!localFile &&
!schema &&
store?.[application]?.schema &&
Object.keys(store?.[application]?.schema).length > 0
) {
const action = saveEmailValues({ application, values, url, apiName });
dispatch(action);
return {
promise: action.payload,
meta: action.meta,
};
}
})
.filter(Boolean);
const { success, error } = await distributeSuccessError(promises);
dispatchMessages(dispatch, success, error);
};
const calculateSection = (key, schema) => {
return getSection(key, schema, store?.[key], (isVisible) => {
const { ...config } = emailConfig;
if (isVisible === false) {
delete config[key];
} else {
config[key] = {
...config[key],
isVisible,
};
}
setEmailConfig(config);
});
};
return (
<React.Fragment>
<PageHeader>
<PageHeaderTitle title="Email preferences" />
</PageHeader>
<Main className="pref-email">
<Stack hasGutter>
<StackItem>
<YourInformation />
</StackItem>
<StackItem>
<Card ouiaId="user-pref-email-subscriptions-card">
<CardHeader className="pf-u-pb-0">
<TextContent>
<Text component={TextVariants.h2}>Email subscriptions</Text>
<Text component={TextVariants.p}>
Select the emails you want to receive.
</Text>
</TextContent>
</CardHeader>
<CardBody className="pref-email_form">
{isLoaded ? (
<FormRender
componentMapper={{
...componentMapper,
[DESCRIPTIVE_CHECKBOX]: DescriptiveCheckbox,
[LOADER]: Loader,
[DATA_LIST]: DataListLayout,
}}
FormTemplate={(props) => (
<FormTemplate {...props} FormButtons={FormButtons} />
)}
schema={{
fields: [
{
name: 'email-preferences',
component: DATA_LIST,
sections: Object.entries(emailConfig).map(
([key, schema]) => calculateSection(key, schema)
),
},
],
}}
onSubmit={saveValues}
/>
) : (
<Bullseye>
<Spinner />
</Bullseye>
)}
</CardBody>
</Card>
</StackItem>
</Stack>
</Main>
</React.Fragment>
);
}
Example #25
Source File: UpdateImageModal.js From edge-frontend with Apache License 2.0 | 4 votes |
UpdateImageModal = ({ updateCveModal, setUpdateCveModal, setReload }) => {
const dispatch = useDispatch();
const { getRegistry } = useContext(RegistryContext);
const { data } = useSelector(
({ imageDetailReducer }) => ({
data: imageDetailReducer?.data || null,
}),
shallowEqual
);
useEffect(() => {
const registered = getRegistry().register({
imageDetailReducer,
});
updateCveModal?.imageId &&
loadImageDetail(dispatch, updateCveModal?.imageId);
return () => registered();
}, [dispatch]);
const handleUpdateModal = () => {
const payload = {
Id: data?.image?.ID,
description: data?.image?.Description,
name: data?.image?.Name,
version: data?.image?.Version + 1,
architecture: 'x86_64',
credentials: data?.image?.Installer.SshKey,
username: data?.image?.Installer.Username,
imageType: data?.image?.OutputTypes,
'selected-packages': data?.image?.Packages?.map((pack) => ({
name: pack.Name,
})),
release: data?.image?.Distribution,
};
handleClose();
setReload(true);
createNewImage(dispatch, payload, (resp) => {
dispatch({
...addNotification({
variant: 'info',
title: 'Update image',
description: `${resp.value.Name} image was added to the queue.`,
}),
meta: {
polling: {
id: `FETCH_IMAGE_${resp.value.ID}_BUILD_STATUS`,
fetcher: () => getEdgeImageStatus(resp.value.ID),
condition: (resp) => {
switch (resp.Status) {
case 'BUILDING':
return [true, ''];
case 'ERROR':
return [false, 'failure'];
default:
return [false, 'success'];
}
},
onEvent: {
failure: [
(dispatch) =>
dispatch(
addNotification({
variant: 'danger',
title: 'Image build failed',
description: `${resp.value.Name} image build is completed unsuccessfully`,
})
),
],
success: [
(dispatch) =>
dispatch(
addNotification({
variant: 'success',
title: 'Image is ready',
description: `${resp.value.Name} image build is completed`,
})
),
(dispatch) => loadEdgeImageSets(dispatch),
],
},
},
},
});
loadEdgeImageSets(dispatch);
dispatch(
addImageToPoll({ name: data?.image?.Name, id: data?.image?.ID })
);
});
};
const handleClose = () => {
setUpdateCveModal((prevState) => ({ ...prevState, isOpen: false }));
};
return data ? (
<Modal
variant="medium"
title={`Update image: ${data?.image?.Name}`}
description="Review the information and click Create image to start the build process"
isOpen={updateCveModal.isOpen}
onClose={handleClose}
//onSubmit={handleUpdateModal}
actions={[
<Button key="confirm" variant="primary" onClick={handleUpdateModal}>
Create Image
</Button>,
<Button key="cancel" variant="link" onClick={handleClose}>
Cancel
</Button>,
]}
>
<TextContent>
<TextListItem component={TextVariants.h3}>
<Text component={'b'}>Details</Text>
</TextListItem>
<TextList component={TextListVariants.dl}>
<TextListItem component={TextListItemVariants.dt}>Name</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{data?.image?.Name}
</TextListItem>
<TextListItem component={TextListItemVariants.dt}>
Version
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{data?.image?.Version + 1}
</TextListItem>
<TextListItem component={TextListItemVariants.dt}>
Description
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{data?.image?.Description}
</TextListItem>
</TextList>
<TextListItem component={TextVariants.h3}>
<Text component={'b'}>Output</Text>
</TextListItem>
<TextList component={TextListVariants.dl}>
<TextListItem component={TextListItemVariants.dt}>
Release
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{releaseMapper[data?.image?.Distribution]}
</TextListItem>
<TextListItem component={TextListItemVariants.dt}>
Output type
</TextListItem>
<TextListItem component={TextListItemVariants.dd}>
{imageTypeMapper[data?.image?.ImageType]}
</TextListItem>
</TextList>
<TextListItem component={TextVariants.h3}>
<Text component={'b'}>Packages</Text>
</TextListItem>
<TextList component={TextListVariants.dl}>
<TextListItem component={TextListItemVariants.dt}>
Updated
</TextListItem>
<TextListItem
className="pf-u-pl-lg"
component={TextListItemVariants.dd}
>
{updateCveModal?.cveCount}
</TextListItem>
</TextList>
</TextContent>
</Modal>
) : (
<Backdrop>
<Bullseye>
<Spinner isSVG diameter="100px" />
</Bullseye>
</Backdrop>
);
}
Example #26
Source File: Inventory.js From edge-frontend with Apache License 2.0 | 4 votes |
Inventory = () => {
const [response, fetchDevices] = useApi({
api: getInventory,
tableReload: true,
});
const { data, isLoading, hasError } = response;
const [isAddDeviceModalOpen, setIsAddDeviceModalOpen] = useState(false);
const [isRemoveDeviceModalOpen, setIsRemoveDeviceModalOpen] = useState(false);
const [deviceId, setDeviceId] = useState([]);
const [checkedDeviceIds, setCheckedDeviceIds] = useState([]);
const [isRowSelected, setIsRowSelected] = useState(false);
const [hasModalSubmitted, setHasModalSubmitted] = useState(false);
const [isCreateGroupModalOpen, setIsCreateGroupModalOpen] = useState(false);
const [updateModal, setUpdateModal] = useState({
isOpen: false,
deviceData: null,
imageData: null,
});
const history = useHistory();
const handleAddDevicesToGroup = (ids, isRow) => {
setIsAddDeviceModalOpen(true);
isRow ? setDeviceId(ids) : setCheckedDeviceIds(ids);
setIsRowSelected(isRow);
};
const handleRemoveDevicesFromGroup = (ids, isRow) => {
setIsRemoveDeviceModalOpen(true);
isRow ? setDeviceId(ids) : setCheckedDeviceIds(ids);
setIsRowSelected(isRow);
};
return (
<Fragment>
<PageHeader className="pf-m-light">
<PageHeaderTitle title="Systems" />
</PageHeader>
<Main className="edge-devices">
<DeviceTable
isSystemsView={true}
data={data?.data?.devices}
count={data?.count}
isLoading={isLoading}
hasError={hasError}
setUpdateModal={setUpdateModal}
handleAddDevicesToGroup={handleAddDevicesToGroup}
handleRemoveDevicesFromGroup={handleRemoveDevicesFromGroup}
hasCheckbox={true}
selectedItems={setCheckedDeviceIds}
kebabItems={[
{
isDisabled: !(checkedDeviceIds.length > 0),
title: 'Add to group',
onClick: () =>
handleAddDevicesToGroup(
checkedDeviceIds.map((device) => ({
ID: device.deviceID,
name: device.display_name,
})),
false
),
},
]}
hasModalSubmitted={hasModalSubmitted}
setHasModalSubmitted={setHasModalSubmitted}
fetchDevices={fetchDevices}
/>
</Main>
{updateModal.isOpen && (
<Suspense
fallback={
<Bullseye>
<Spinner />
</Bullseye>
}
>
<UpdateDeviceModal
navigateBack={() => {
history.push({ pathname: history.location.pathname });
setUpdateModal((prevState) => {
return {
...prevState,
isOpen: false,
};
});
}}
setUpdateModal={setUpdateModal}
updateModal={updateModal}
refreshTable={fetchDevices}
/>
</Suspense>
)}
{isAddDeviceModalOpen && (
<AddDeviceModal
isModalOpen={isAddDeviceModalOpen}
setIsModalOpen={setIsAddDeviceModalOpen}
setIsCreateGroupModalOpen={setIsCreateGroupModalOpen}
reloadData={() => {
fetchDevices();
setTimeout(() => setHasModalSubmitted(true), 800);
}}
deviceIds={isRowSelected ? deviceId : checkedDeviceIds}
/>
)}
{isCreateGroupModalOpen && (
<CreateGroupModal
isModalOpen={isCreateGroupModalOpen}
setIsModalOpen={setIsCreateGroupModalOpen}
reloadData={() => {
fetchDevices();
setTimeout(() => setHasModalSubmitted(true), 800);
}}
deviceIds={isRowSelected ? deviceId : checkedDeviceIds}
/>
)}
{isRemoveDeviceModalOpen && (
<RemoveDeviceModal
isModalOpen={isRemoveDeviceModalOpen}
setIsModalOpen={setIsRemoveDeviceModalOpen}
reloadData={() => {
fetchDevices();
setTimeout(() => setHasModalSubmitted(true), 800);
}}
deviceInfo={isRowSelected ? deviceId : checkedDeviceIds}
/>
)}
</Fragment>
);
}
Example #27
Source File: UpdateDeviceModal.js From edge-frontend with Apache License 2.0 | 4 votes |
UpdateDeviceModal = ({ updateModal, setUpdateModal, refreshTable }) => {
const [imageData, setImageData] = useState(null);
const dispatch = useDispatch();
const isMultiple = updateModal.deviceData.length > 1;
const deviceId = updateModal.deviceData.map((device) => device.id);
const deviceName = isMultiple
? updateModal.deviceData.map((device) => device.display_name)
: updateModal?.deviceData[0]?.display_name;
useEffect(() => {
updateModal?.imageSetId
? getImageSet({
id: updateModal.imageSetId,
q: {
limit: 1,
sort_by: '-created_at',
status: 'SUCCESS',
},
}).then((data) => setImageData(data.Data.images[0]))
: getImageData(updateModal.imageId).then((data) =>
setImageData(data.Data.images[0])
);
}, []);
const handleUpdateModal = async () => {
try {
await updateDeviceLatestImage({
DevicesUUID: deviceId,
});
dispatch({
...addNotification({
variant: 'info',
title: 'Updating device',
description: isMultiple
? ` ${deviceName.length} systems were added to the queue.`
: ` ${deviceName} was added to the queue.`,
}),
});
} catch (err) {
dispatch({
...addNotification({
variant: 'danger',
title: 'Updating a device was unsuccessful',
description: `Response: ${err.statusText}`,
}),
});
}
handleClose();
refreshTable ? refreshTable() : null;
};
const handleClose = () => {
setUpdateModal((prevState) => {
return {
...prevState,
isOpen: false,
};
});
};
const WarningText = () => (
<TextContent className="pf-u-pt-md">
<Text
style={{ color: 'var(--pf-global--palette--gold-500)' }}
component="small"
>
<ExclamationTriangleIcon /> After the update is installed, the device
will apply the changes.
</Text>
</TextContent>
);
const Description = () => (
<TextContent>
<Text>
Update{' '}
<span className="pf-u-font-weight-bold pf-u-font-size-md">
{isMultiple ? `${deviceName.length} systems` : deviceName}
</span>{' '}
to latest version of the image linked to it.
</Text>
</TextContent>
);
const updateToDetails = {
title: `Update to version ${imageData?.image.Version}`,
rows: [
{ title: 'Image Name', value: imageData?.image.Name },
{ title: 'Version', value: imageData?.image.Version },
{
title: 'Created',
value: <DateFormat date={imageData?.image.CreatedAt} />,
},
{
title: 'Release',
value: distributionMapper[imageData?.image.Distribution],
},
],
};
const packageDetails = {
title: `Changes from version ${imageData?.image.Version - 1}`,
rows: [
{ title: 'Added', value: imageData?.update_added || 0 },
{ title: 'Removed', value: imageData?.update_removed || 0 },
{ title: 'Updated', value: imageData?.update_updated || 0 },
],
};
const updateSchema = {
fields: [
{
component: componentTypes.PLAIN_TEXT,
name: 'description',
label: Description(),
},
{
component: componentTypes.PLAIN_TEXT,
name: 'update-details',
label: BuildModalReview({
reviewObject: updateToDetails,
key: 'update-details',
}),
},
{
component: componentTypes.PLAIN_TEXT,
name: 'package-details',
label: BuildModalReview({
reviewObject: packageDetails,
key: 'package-details',
}),
},
{
component: componentTypes.PLAIN_TEXT,
name: 'warning-text',
label: WarningText(),
},
],
};
return (
<>
{imageData ? (
<Modal
size="medium"
title={`Update system${
isMultiple ? 's' : ''
} to latest image version`}
isOpen={updateModal.isOpen}
openModal={() =>
setUpdateModal((prevState) => ({ ...prevState, isOpen: false }))
}
submitLabel="Update Device"
schema={updateSchema}
onSubmit={handleUpdateModal}
reloadData={refreshTable}
/>
) : (
<Backdrop>
<Bullseye>
<Spinner isSVG diameter="100px" />
</Bullseye>
</Backdrop>
)}
</>
);
}
Example #28
Source File: GroupTable.js From edge-frontend with Apache License 2.0 | 4 votes |
GroupTable = ({
data,
count,
isLoading,
hasError,
handleCreateModal,
handleRenameModal,
handleDeleteModal,
fetchGroups,
}) => {
const [updateModal, setUpdateModal] = useState({
isOpen: false,
deviceData: null,
imageData: null,
});
const actionResolver = (rowData) => {
if (!rowData?.rowInfo) return [];
const { id, title, devices, devicesImageInfo } = rowData?.rowInfo;
const hasUpdate = devicesImageInfo?.some((image) => image.UpdateAvailable);
return (
id && [
{
title: 'Rename',
onClick: () => handleRenameModal(id, title),
},
{
title: 'Delete',
onClick: () => handleDeleteModal(id, title),
},
{
title: 'Update',
onClick: () =>
setUpdateModal((prevState) => ({
...prevState,
deviceData: devices.map((device) => ({
id: device.UUID,
display_name: device.Name,
})),
imageId: devices.find((device) => device?.ImageID).ImageID,
isOpen: true,
})),
isDisabled:
devices.length > 0
? !(rowData?.rowInfo?.hasValidUpdate && hasUpdate)
: true,
},
]
);
};
const buildRows = data?.map((rowData) => {
const { ID, Name, Devices } = rowData?.DeviceGroup;
let { DevicesImageInfo } = rowData;
if (!DevicesImageInfo) {
DevicesImageInfo = [];
}
const systems = Devices ?? [];
const image = (
<div>
<Tooltip
content={
<div>
{DevicesImageInfo.map((device, index) => (
<p key={index}>{device.Name}</p>
))}
</div>
}
>
<span>Multiple images</span>
</Tooltip>
</div>
);
return {
rowInfo: {
id: ID,
title: Name,
image:
DevicesImageInfo.length === 0
? '-'
: DevicesImageInfo.length > 1
? 'Multiple images'
: DevicesImageInfo[0]?.Name,
devicesImageInfo: rowData.DevicesImageInfo,
devices: Devices,
hasValidUpdate: rowData?.DeviceGroup?.ValidUpdate,
},
cells: [
{
title: <Link to={`${paths['fleet-management']}/${ID}`}>{Name}</Link>,
},
{
title: systems.length,
},
{
title:
DevicesImageInfo.length === 0
? '-'
: DevicesImageInfo.length > 1
? image
: DevicesImageInfo[0]?.Name,
},
],
};
});
return (
<>
<GeneralTable
apiFilterSort={true}
isUseApi={true}
loadTableData={fetchGroups}
filters={filters}
tableData={{
count,
data,
isLoading,
hasError,
}}
columnNames={columns}
rows={buildRows}
actionResolver={actionResolver}
areActionsDisabled={() => false}
defaultSort={{ index: 0, direction: 'asc' }}
emptyFilterState={{
title: 'No matching groups found',
body: 'To continue, edit your filter settings and try again',
}}
toolbarButtons={[
{
title: 'Create group',
click: handleCreateModal,
},
]}
/>
{updateModal.isOpen && (
<Suspense
fallback={
<Bullseye>
<Spinner />
</Bullseye>
}
>
<UpdateDeviceModal
navigateBack={() => {
history.push({ pathname: history.location.pathname });
setUpdateModal((prevState) => {
return {
...prevState,
isOpen: false,
};
});
}}
setUpdateModal={setUpdateModal}
updateModal={updateModal}
refreshTable={fetchGroups}
/>
</Suspense>
)}
</>
);
}
Example #29
Source File: GroupsDetail.js From edge-frontend with Apache License 2.0 | 4 votes |
GroupsDetail = () => {
const dispatch = useDispatch();
const params = useParams();
const history = useHistory();
const { groupId } = params;
const [isDropdownOpen, setIsDropdownOpen] = useState(false);
const [isAddModalOpen, setIsAddModalOpen] = useState(false);
const [removeModal, setRemoveModal] = useState({
isOpen: false,
name: '',
deviceId: null,
});
const [updateModal, setUpdateModal] = useState({
isOpen: false,
deviceData: null,
imageData: null,
});
const [response, fetchDevices] = useApi({
api: getGroupById,
id: groupId,
tableReload: true,
});
const { data, isLoading, hasError } = response;
const groupName = data?.DeviceGroup?.Name;
const [deviceIds, getDeviceIds] = useState([]);
const [hasModalSubmitted, setHasModalSubmitted] = useState(false);
const [modalState, setModalState] = useState({ id: null, name: '' });
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [isRenameModalOpen, setIsRenameModalOpen] = useState(false);
const handleDeleteModal = (id, name) => {
setModalState({ id, name });
setIsDeleteModalOpen(true);
};
const handleRenameModal = (id, name) => {
setModalState({ id, name });
setIsRenameModalOpen(true);
};
const removeDeviceLabel = () =>
`Do you want to remove ${
deviceIds.length > 0
? `${deviceIds.length} system${deviceIds.length === 1 ? '' : 's'}`
: `${removeModal.name}`
} from ${groupName}?`;
useEffect(() => {
history.push({
pathname: history.location.pathname,
search: stateToUrlSearch('add_system_modal=true', isAddModalOpen),
});
}, [isAddModalOpen]);
const handleSingleDeviceRemoval = () => {
const statusMessages = {
onSuccess: {
title: 'Success',
description: `${removeModal.name} has been removed successfully`,
},
onError: { title: 'Error', description: 'Failed to remove device' },
};
apiWithToast(
dispatch,
() => removeDeviceFromGroupById(groupId, removeModal.deviceId),
statusMessages
);
setTimeout(() => setHasModalSubmitted(true), 800);
};
const handleBulkDeviceRemoval = () => {
const statusMessages = {
onSuccess: {
title: 'Success',
description: `${deviceIds.length} systems have been removed successfully`,
},
onError: { title: 'Error', description: 'failed to remove systems' },
};
apiWithToast(
dispatch,
() =>
removeDevicesFromGroup(
parseInt(groupId),
deviceIds.map((device) => ({ ID: device.deviceID }))
),
statusMessages
);
setTimeout(() => setHasModalSubmitted(true), 800);
};
return (
<>
<PageHeader className="pf-m-light">
{groupName ? (
<Breadcrumb>
<BreadcrumbItem>
<Link to={`${paths['fleet-management']}`}>Groups</Link>
</BreadcrumbItem>
<BreadcrumbItem>{groupName}</BreadcrumbItem>
</Breadcrumb>
) : (
<Breadcrumb isActive>
<Skeleton width="100px" />
</Breadcrumb>
)}
<Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
<FlexItem>
{groupName ? (
<PageHeaderTitle title={groupName} />
) : (
<Skeleton width="150px" />
)}
</FlexItem>
<FlexItem>
<Dropdown
position={DropdownPosition.right}
toggle={
<DropdownToggle
id="image-set-details-dropdown"
toggleIndicator={CaretDownIcon}
onToggle={(newState) => setIsDropdownOpen(newState)}
isDisabled={false}
>
Actions
</DropdownToggle>
}
isOpen={isDropdownOpen}
dropdownItems={[
<DropdownItem
key="delete-device-group"
onClick={() => handleDeleteModal(groupId, groupName)}
>
Delete group
</DropdownItem>,
<DropdownItem
key="rename-device-group"
onClick={() => handleRenameModal(groupId, groupName)}
>
Rename group
</DropdownItem>,
<DropdownItem
key="update-all-devices"
isDisabled={canUpdateSelectedDevices({
deviceData: data?.DevicesView?.devices?.map((device) => ({
imageSetId: device?.ImageSetID,
})),
imageData: data?.DevicesView?.devices?.some(
(device) => device.ImageID
),
})}
onClick={() => {
setIsDropdownOpen(false);
setUpdateModal((prevState) => ({
...prevState,
isOpen: true,
deviceData: data?.DevicesView?.devices?.map((device) => ({
id: device?.DeviceUUID,
display_name:
device?.DeviceName === ''
? 'localhost'
: device?.DeviceName,
})),
imageSetId: data?.DevicesView?.devices.find(
(device) => device.ImageSetID
)?.ImageSetID,
}));
}}
>
Update
</DropdownItem>,
]}
/>
</FlexItem>
</Flex>
</PageHeader>
<Main className="edge-devices">
{!emptyStateNoFliters(
isLoading,
data?.DeviceGroup?.Devices.length,
history
) ? (
<DeviceTable
data={data?.DevicesView?.devices || []}
count={data?.DevicesView?.total}
isLoading={isLoading}
hasError={hasError}
hasCheckbox={true}
handleSingleDeviceRemoval={handleSingleDeviceRemoval}
kebabItems={[
{
isDisabled: !(deviceIds.length > 0),
title: 'Remove from group',
onClick: () =>
setRemoveModal({
name: '',
deviceId: null,
isOpen: true,
}),
},
{
isDisabled: canUpdateSelectedDevices({
deviceData: deviceIds,
imageData: deviceIds[0]?.updateImageData,
}),
title: 'Update selected',
onClick: () =>
setUpdateModal((prevState) => ({
...prevState,
isOpen: true,
deviceData: [...deviceIds],
imageSetId: deviceIds.find((device) => device?.imageSetId)
.imageSetId,
})),
},
]}
selectedItems={getDeviceIds}
setRemoveModal={setRemoveModal}
setIsAddModalOpen={setIsAddModalOpen}
setUpdateModal={setUpdateModal}
hasModalSubmitted={hasModalSubmitted}
setHasModalSubmitted={setHasModalSubmitted}
fetchDevices={fetchDevices}
isAddSystemsView={true}
/>
) : (
<Flex justifyContent={{ default: 'justifyContentCenter' }}>
<Empty
icon="plus"
title="Add systems to the group"
body="Create groups to help manage your systems more effectively."
primaryAction={{
text: 'Add systems',
click: () => setIsAddModalOpen(true),
}}
secondaryActions={[
{
type: 'link',
title: 'Learn more about system groups',
link: 'https://access.redhat.com/documentation/en-us/edge_management/2022/html-single/working_with_systems_in_the_edge_management_application/index',
},
]}
/>
</Flex>
)}
</Main>
{isAddModalOpen && (
<AddSystemsToGroupModal
groupId={groupId}
closeModal={() => setIsAddModalOpen(false)}
isOpen={isAddModalOpen}
reloadData={fetchDevices}
groupName={data?.DeviceGroup?.Name}
/>
)}
{removeModal.isOpen && (
<Modal
isOpen={removeModal.isOpen}
openModal={() => setRemoveModal(false)}
title={'Remove from group'}
submitLabel={'Remove'}
variant="danger"
schema={{
fields: [
{
component: componentTypes.PLAIN_TEXT,
name: 'warning-text',
label: removeDeviceLabel(),
},
],
}}
onSubmit={
removeModal.deviceId
? handleSingleDeviceRemoval
: handleBulkDeviceRemoval
}
reloadData={fetchDevices}
/>
)}
{updateModal.isOpen && (
<Suspense
fallback={
<Bullseye>
<Spinner />
</Bullseye>
}
>
<UpdateDeviceModal
navigateBack={() => {
history.push({ pathname: history.location.pathname });
setUpdateModal((prevState) => {
return {
...prevState,
isOpen: false,
};
});
}}
setUpdateModal={setUpdateModal}
updateModal={updateModal}
refreshTable={fetchDevices}
/>
</Suspense>
)}
{isDeleteModalOpen && (
<DeleteGroupModal
isModalOpen={isDeleteModalOpen}
setIsModalOpen={setIsDeleteModalOpen}
reloadData={() => history.push(paths['fleet-management'])}
modalState={modalState}
/>
)}
{isRenameModalOpen && (
<RenameGroupModal
isModalOpen={isRenameModalOpen}
setIsModalOpen={setIsRenameModalOpen}
reloadData={() => fetchDevices()}
modalState={modalState}
/>
)}
</>
);
}