@patternfly/react-core#Flex JavaScript Examples
The following examples show how to use
@patternfly/react-core#Flex.
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: Tiles.js From edge-frontend with Apache License 2.0 | 6 votes |
Tiles = () => {
const { getRegistry } = useContext(RegistryContext);
const dispatch = useDispatch();
useEffect(() => {
const registered = getRegistry().register({
imagesReducer,
deviceSummaryReducer,
});
loadImages(dispatch);
loadDeviceSummary(dispatch);
return () => registered();
}, [dispatch]);
return (
<Flex className="tiles">
<FlexItem>
<DeviceSummaryTile />
</FlexItem>
</Flex>
);
}
Example #2
Source File: FlexibleFlex.js From tasks-frontend with Apache License 2.0 | 6 votes |
FlexibleFlex = ({ data, flexContents, flexProps }) => {
return flexContents.map((item) => {
return (
<Flex key={item.match} {...flexProps}>
{Array.isArray(item.children)
? item.children.map((content) => renderFlexItem(content))
: renderFlexItem(item.children)}
{item.match
? item.renderFunc
? renderFlexItem(
item.renderFunc(item.match.map((prop) => data[prop]))
)
: renderFlexItem(data[item.match])
: null}
</Flex>
);
});
}
Example #3
Source File: certificateList.jsx From cockpit-certificates with GNU Lesser General Public License v2.1 | 6 votes |
function getExpirationTime(cert) {
if (cert.autorenew && cert.autorenew.v) {
return _("Auto-renews before ") + prettyTime(cert["not-valid-after"].v).toLowerCase();
} else {
const expiry = new Date(Number(cert["not-valid-after"].v) * 1000);
const now = new Date();
const diffSeconds = (expiry - now) / 1000;
const diffDays = diffSeconds / 86400;
if (diffSeconds < 0) { // Expired
if (diffDays > -28) { // Expired X days ago
return (
<Flex alignItems={{ default: 'alignItemsCenter' }} spaceItems={{ default: 'spaceItemsSm' }}>
<TimesCircleIcon className="ct-icon-times-circle" />
<FlexItem>{_("Expired ") + expiry.toLocaleDateString(dateLocale())}</FlexItem>
</Flex>
);
}
return (
<Flex alignItems={{ default: 'alignItemsCenter' }} spaceItems={{ default: 'spaceItemsSm' }}>
<TimesCircleIcon className="ct-icon-times-circle" />
<FlexItem>{_("Expired on ") + prettyTime(cert["not-valid-after"].v)}</FlexItem>
</Flex>
);
}
// Expires
if (diffDays < 28) { // Expires in X days
return (
<Flex alignItems={{ default: 'alignItemsCenter' }} spaceItems={{ default: 'spaceItemsSm' }}>
<ExclamationTriangleIcon className="ct-icon-exclamation-triangle" />
<FlexItem>{_("Expires ") + expiry.toLocaleDateString(dateLocale())}</FlexItem>
</Flex>
);
}
return _("Expires on ") + prettyTime(cert["not-valid-after"].v);
}
}
Example #4
Source File: tokens.js From ibutsu-server with MIT License | 5 votes |
render() {
document.title = 'User Tokens | Ibutsu';
const { columns, rows } = this.state;
const pagination = {
pageSize: this.state.pageSize,
page: this.state.page,
totalItems: this.state.totalItems
};
return (
<React.Fragment>
<PageSection id="page" variant={PageSectionVariants.light}>
<Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
<FlexItem spacer={{ default: 'spacerLg' }}>
<TextContent>
<Text className="title" component="h1">Tokens</Text>
</TextContent>
</FlexItem>
<FlexItem>
<Button
aria-label="Add token"
variant="secondary"
title="Add token"
onClick={this.onAddTokenClick}
>
<PlusCircleIcon /> Add Token
</Button>
</FlexItem>
</Flex>
</PageSection>
<PageSection>
<Card>
<CardBody className="pf-u-p-0">
<FilterTable
columns={columns}
rows={rows}
pagination={pagination}
isEmpty={this.state.isEmpty}
isError={this.state.isError}
onSetPage={this.setPage}
onSetPageSize={this.setPageSize}
/>
</CardBody>
</Card>
</PageSection>
<AddTokenModal
isOpen={this.state.isAddTokenOpen}
onSave={this.onAddTokenSave}
onClose={this.onAddTokenClose}
/>
<DeleteModal
title="Delete token"
body="Would you like to delete the selected token?"
isOpen={this.state.isDeleteTokenOpen}
onDelete={this.onDeleteToken}
onClose={this.onDeleteTokenClose}
/>
</React.Fragment>
);
}
Example #5
Source File: CardBuilder.tests.js From tasks-frontend with Apache License 2.0 | 5 votes |
describe('TasksTables', () => {
let props;
beforeEach(() => {
props = {
cardClass: '',
};
});
afterEach(() => {
jest.clearAllMocks();
});
it('should render correctly', () => {
const { asFragment } = render(
<CardBuilder {...props}>
<CardBuilderContent content="Task title" type="title" />
<CardBuilderContent content="Task description" type="body" />
<CardBuilderContent
content={
<Flex direction={{ default: 'column' }}>
<FlexItem>
<a href="#">Download preview of playbook</a>
</FlexItem>
<FlexItem>
<RunTaskButton
isFirst
openTaskModal={jest.fn()}
task={availableTasksTableItems[0]}
variant="primary"
/>
</FlexItem>
</Flex>
}
type="footer"
/>
</CardBuilder>
);
expect(asFragment()).toMatchSnapshot();
});
});
Example #6
Source File: AvailableTasksTable.js From tasks-frontend with Apache License 2.0 | 5 votes |
AvailableTasksTable = ({ availableTasks, error, openTaskModal }) => {
return (
<div aria-label="available-tasks-table">
{error ? (
<EmptyStateDisplay
icon={ExclamationCircleIcon}
color="#c9190b"
title={'Available tasks cannot be displayed'}
text={TASKS_ERROR}
error={`Error ${error?.response?.status}: ${error?.message}`}
/>
) : !availableTasks?.length ? (
<EmptyStateDisplay
title={EMPTY_TASKS_TITLE}
text={EMPTY_TASKS_MESSAGE}
/>
) : (
availableTasks?.map((task) => {
return (
<React.Fragment aria-label={task.title} key={task.title}>
<CardBuilder>
<CardBuilderContent content={task.title} type="title" />
<CardBuilderContent
className="card-task-description"
content={task.description}
type="body"
/>
<CardBuilderContent
content={
<Flex direction={{ default: 'column' }}>
<FlexItem>
<a
href={`${TASKS_API_ROOT}${AVAILABLE_TASKS_ROOT}/${task.slug}/playbook`}
>
Download preview of playbook
</a>
</FlexItem>
<FlexItem>
<RunTaskButton
slug={task.slug}
isFirst
variant="primary"
openTaskModal={openTaskModal}
/>
</FlexItem>
</Flex>
}
type="footer"
/>
</CardBuilder>
<br />
</React.Fragment>
);
})
)}
</div>
);
}
Example #7
Source File: RunTaskModal.js From tasks-frontend with Apache License 2.0 | 5 votes |
RunTaskModal = ({ error, task, isOpen, setModalOpened }) => {
const [selectedIds, setSelectedIds] = useState([]);
const dispatch = useDispatch();
useEffect(() => {
setSelectedIds([]);
}, [task]);
useEffect(() => {
dispatch({
type: 'SELECT_ENTITY',
payload: {
selected: selectedIds,
},
});
}, [selectedIds]);
const selectIds = (_event, _isSelected, _index, entity) => {
let newSelectedIds = [...selectedIds];
!newSelectedIds.includes(entity.id)
? newSelectedIds.push(entity.id)
: newSelectedIds.splice(newSelectedIds.indexOf(entity.id), 1);
setSelectedIds(newSelectedIds);
};
return (
<Modal
aria-label="run-task-modal"
title={task.title || 'Error'}
isOpen={isOpen}
onClose={() => setModalOpened(false)}
width={'70%'}
>
{error ? (
<EmptyStateDisplay
icon={ExclamationCircleIcon}
color="#c9190b"
title={'This task cannot be displayed'}
text={TASK_ERROR}
error={`Error ${error?.response?.status}: ${error?.message}`}
/>
) : (
<React.Fragment>
<Flex>
<FlexItem>
<b>Task description</b>
</FlexItem>
</Flex>
<Flex style={{ paddingBottom: '8px' }}>
<FlexItem>{task.description}</FlexItem>
</Flex>
<Flex>
<FlexItem>
<a
href={`${TASKS_API_ROOT}${AVAILABLE_TASKS_ROOT}/${task.slug}/playbook`}
>
Download preview of playbook
</a>
</FlexItem>
</Flex>
<br />
<b>Systems to run tasks on</b>
<SystemTable selectedIds={selectedIds} selectIds={selectIds} />
</React.Fragment>
)}
</Modal>
);
}
Example #8
Source File: classify-failures.js From ibutsu-server with MIT License | 5 votes |
render() {
const {
columns,
rows,
selectedResults,
includeSkipped,
filters
} = this.state;
const { run_id } = this.props
const pagination = {
pageSize: this.state.pageSize,
page: this.state.page,
totalItems: this.state.totalItems
}
// filters for the metadata
const resultFilters = [
<MetaFilter
key="metafilter"
// user_properties fields shouldn't be injected here
fieldOptions={FILTERABLE_RESULT_FIELDS}
runId={run_id}
setFilter={this.setFilter}
customFilters={{'result': filters['result']}}
/>,
]
return (
<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 Failures</Text>
</TextContent>
</FlexItem>
<FlexItem>
<TextContent>
<Checkbox id="include-skips" label="Include skips, xfails" isChecked={includeSkipped} aria-label="include-skips-checkbox" onChange={this.onSkipCheck}/>
</TextContent>
</FlexItem>
<FlexItem>
<MultiClassificationDropdown selectedResults={selectedResults} refreshFunc={this.refreshResults}/>
</FlexItem>
<FlexItem>
<Button variant="secondary" onClick={this.refreshResults}>Refresh results</Button>
</FlexItem>
</Flex>
</CardHeader>
<CardBody>
<FilterTable
columns={columns}
rows={rows}
pagination={pagination}
isEmpty={this.state.isEmpty}
isError={this.state.isError}
onCollapse={this.onCollapse}
onSetPage={this.setPage}
onSetPageSize={this.pageSizeSelect}
canSelectAll={true}
onRowSelect={this.onTableRowSelect}
variant={TableVariant.compact}
activeFilters={this.state.filters}
filters={resultFilters}
onRemoveFilter={this.removeFilter}
hideFilters={["run_id", "project_id"]}
/>
</CardBody>
</Card>
);
}
Example #9
Source File: CompletedTaskDetails.js From tasks-frontend with Apache License 2.0 | 4 votes |
CompletedTaskDetails = () => {
const { id } = useParams();
const filters = Object.values(Filters);
const [completedTaskDetails, setCompletedTaskDetails] =
useState(LOADING_INFO_PANEL);
const [completedTaskJobs, setCompletedTaskJobs] =
useState(LOADING_JOBS_TABLE);
const [error, setError] = useState();
const isError = (result) => {
return result?.response?.status && result?.response?.status !== 200;
};
const setErrors = (result) => {
setError(result);
dispatchNotification({
variant: 'danger',
title: 'Error',
description: result.message,
dismissable: true,
});
};
useEffect(() => {
const fetchData = async () => {
let taskDetails = await fetchExecutedTask(id);
if (isError(taskDetails)) {
setErrors(taskDetails);
} else {
const taskJobs = await fetchExecutedTaskJobs(id);
if (isError(taskJobs)) {
setErrors(taskJobs);
} else {
taskDetails.messages_count = taskJobs.filter((item) => {
return item.message !== 'No vulnerability found.';
}).length;
taskDetails.system_count = taskJobs.length;
await setCompletedTaskDetails(taskDetails);
await setCompletedTaskJobs(taskJobs);
}
}
};
fetchData();
}, []);
return (
<div>
{error ? (
<EmptyStateDisplay
icon={ExclamationCircleIcon}
color="#c9190b"
title={'Task cannot be displayed'}
text={TASK_ERROR}
error={`Error ${error?.response?.status}: ${error?.message}`}
/>
) : (
<React.Fragment>
<PageHeader>
<Breadcrumb ouiaId="completed-tasks-details-breadcrumb">
<BreadcrumbItem to="/beta/insights/tasks/executed">
Tasks
</BreadcrumbItem>
<BreadcrumbItem isActive>
{completedTaskDetails.task_title}
</BreadcrumbItem>
</Breadcrumb>
<Flex direction={{ default: 'column', md: 'row' }}>
<Flex
direction={{ default: 'column' }}
flex={{ default: 'flex_1' }}
>
<FlexItem>
<PageHeaderTitle title={completedTaskDetails.task_title} />
</FlexItem>
<FlexItem>{completedTaskDetails.description}</FlexItem>
</Flex>
<FlexibleFlex
data={completedTaskDetails}
flexContents={COMPLETED_INFO_BUTTONS}
flexProps={COMPLETED_INFO_BUTTONS_FLEX_PROPS}
/>
</Flex>
</PageHeader>
<Main>
<Card>
<Flex
className="completed-task-details-info-border"
justifyContent={{ default: 'justifyContentSpaceBetween' }}
direction={{ default: 'column', md: 'row' }}
>
<FlexibleFlex
data={completedTaskDetails}
flexContents={COMPLETED_INFO_PANEL}
flexProps={COMPLETED_INFO_PANEL_FLEX_PROPS}
/>
</Flex>
</Card>
<br />
<Card>
<TasksTables
label={`${completedTaskDetails.id}-completed-jobs`}
ouiaId={`${completedTaskDetails.id}-completed-jobs-table`}
columns={columns}
items={completedTaskJobs}
filters={{
filterConfig: filters,
}}
options={{
...TASKS_TABLE_DEFAULTS,
exportable: {
...TASKS_TABLE_DEFAULTS.exportable,
columns: exportableColumns,
},
}}
emptyRows={emptyRows('jobs')}
isStickyHeader
/>
</Card>
</Main>
</React.Fragment>
)}
</div>
);
}
Example #10
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 #11
Source File: project-list.js From ibutsu-server with MIT License | 4 votes |
render() {
document.title = 'Projects - Administration | Ibutsu';
const { columns, rows, textFilter } = this.state;
const pagination = {
pageSize: this.state.pageSize,
page: this.state.page,
totalItems: this.state.totalItems
};
const filters = [
<TextInput type="text" id="filter" placeholder="Search for project..." value={textFilter || ''} onChange={this.onTextChanged} style={{height: "inherit"}} key="textFilter"/>
];
return (
<React.Fragment>
<PageSection id="page" variant={PageSectionVariants.light}>
<Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
<Flex>
<FlexItem spacer={{ default: 'spacerLg' }}>
<TextContent>
<Text className="title" component="h1" ouiaId="admin-projects">Projects</Text>
</TextContent>
</FlexItem>
</Flex>
<Flex>
<FlexItem>
<Button
aria-label="Add project"
variant="secondary"
title="Add project"
ouiaId="admin-projects-add"
component={(props: any) => <Link {...props} to="/admin/projects/new" />}
>
<PlusCircleIcon /> Add Project
</Button>
</FlexItem>
</Flex>
</Flex>
</PageSection>
<PageSection className="pf-u-pb-0">
<Card>
<CardBody className="pf-u-p-0">
<FilterTable
columns={columns}
rows={rows}
filters={filters}
pagination={pagination}
isEmpty={this.state.isEmpty}
isError={this.state.isError}
onSetPage={this.setPage}
onSetPageSize={this.setPageSize}
/>
</CardBody>
</Card>
</PageSection>
<Modal
title="Confirm Delete"
variant="small"
isOpen={this.state.isDeleteModalOpen}
onClose={this.onDeleteModalClose}
actions={[
<Button
key="delete"
variant="danger"
ouiaId="admin-projects-modal-delete"
isLoading={this.state.isDeleting}
isDisabled={this.state.isDeleting}
onClick={this.onModalDeleteClick}
>
{this.state.isDeleting ? 'Deleting...' : 'Delete'}
</Button>,
<Button
key="cancel"
variant="secondary"
ouiaId="admin-projects-modal-cancel"
isDisabled={this.state.isDeleting}
onClick={this.onDeleteModalClose}
>
Cancel
</Button>
]}
>
Are you sure you want to delete “{this.state.selectedProject && this.state.selectedProject.title}”? This cannot be undone!
</Modal>
</React.Fragment>
);
}
Example #12
Source File: dashboard.js From ibutsu-server with MIT License | 4 votes |
render() {
document.title = 'Dashboard | Ibutsu';
const { widgets } = this.state;
const project = getActiveProject();
const dashboard = getActiveDashboard();
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
<Flex>
<FlexItem spacer={{ default: 'spacerLg' }}>
<TextContent>
<Text component="h1">Dashboard</Text>
</TextContent>
</FlexItem>
<FlexItem id="dashboard-selector" spacer={{ default: 'spacerNone' }}>
<Select
ariaLabelTypeAhead="Select a dashboard"
placeholderText="No active dashboard"
variant={SelectVariant.typeahead}
isOpen={this.state.isDashboardSelectorOpen}
isDisabled={!project}
selections={this.state.selectedDashboard}
onToggle={this.onDashboardToggle}
onSelect={this.onDashboardSelect}
onClear={this.onDashboardClear}
onTypeaheadInputChanged={this.onDashboardChanged}
footer={this.state.dashboards.length == 10 && "Search for more..."}
isPlain
>
{this.state.dashboards.map(dash => (
<SelectOption key={dash.id} value={dashboardToSelect(dash)} />
))}
</Select>
</FlexItem>
<FlexItem spacer={{ default: 'spacerNone' }}>
<Button
aria-label="New dashboard"
variant="plain"
title="New dashboard"
isDisabled={!project}
onClick={this.onNewDashboardClick}
>
<PlusCircleIcon />
</Button>
</FlexItem>
<FlexItem>
<Button
aria-label="Delete dashboard"
variant="plain"
title="Delete dashboard"
isDisabled={!dashboard}
onClick={this.onDeleteDashboardClick}
>
<TimesCircleIcon />
</Button>
</FlexItem>
</Flex>
<Flex>
<FlexItem>
<Button
aria-label="Add widget"
variant="secondary"
title="Add widget"
isDisabled={!this.state.selectedDashboard}
onClick={this.onAddWidgetClick}
>
<PlusCircleIcon /> Add Widget
</Button>
</FlexItem>
</Flex>
</Flex>
</PageSection>
<PageSection>
{!!project && !!dashboard && !!widgets &&
<Grid hasGutter>
{widgets.map(widget => {
if (KNOWN_WIDGETS.includes(widget.widget)) {
return (
<GridItem xl={4} lg={6} md={12} key={widget.id}>
{(widget.type === "widget" && widget.widget === "jenkins-heatmap") &&
<JenkinsHeatmapWidget
title={widget.title}
params={widget.params}
includeAnalysisLink={true}
onDeleteClick={() => this.onDeleteWidgetClick(widget.id)}
/>
}
{(widget.type === "widget" && widget.widget === "run-aggregator") &&
<GenericBarWidget
title={widget.title}
params={widget.params}
horizontal={true}
percentData={true}
barWidth={20}
onDeleteClick={() => this.onDeleteWidgetClick(widget.id)}
/>
}
{(widget.type === "widget" && widget.widget === "result-summary") &&
<ResultSummaryWidget
title={widget.title}
params={widget.params}
onDeleteClick={() => this.onDeleteWidgetClick(widget.id)}
/>
}
{(widget.type === "widget" && widget.widget === "result-aggregator") &&
<ResultAggregatorWidget
title={widget.title}
params={widget.params}
onDeleteClick={() => this.onDeleteWidgetClick(widget.id)}
/>
}
</GridItem>
);
}
else {
return '';
}
})}
</Grid>
}
{!project &&
<EmptyState>
<EmptyStateIcon icon={ArchiveIcon} />
<Title headingLevel="h4" size="lg">
No Project Selected
</Title>
<EmptyStateBody>
There is currently no project selected. Please select a project from the dropdown in
order to view the dashboard.
</EmptyStateBody>
</EmptyState>
}
{!!project && !dashboard &&
<EmptyState>
<EmptyStateIcon icon={TachometerAltIcon} />
<Title headingLevel="h4" size="lg">
No Dashboard Selected
</Title>
<EmptyStateBody>
There is currently no dashboard selected. Please select a dashboard from the dropdown
in order to view widgets, or create a new dashboard.
</EmptyStateBody>
<Button variant="primary" onClick={this.onNewDashboardClick}>New Dashboard</Button>
</EmptyState>
}
{(!!project && !!dashboard && widgets.length === 0) &&
<EmptyState>
<EmptyStateIcon icon={CubesIcon} />
<Title headingLevel="h4" size="lg">
No Widgets
</Title>
<EmptyStateBody>
This dashboard currently has no widgets defined.<br />Click on the "Add Widget" button
below to add a widget to this dashboard.
</EmptyStateBody>
<Button variant="primary" onClick={this.onAddWidgetClick}>Add Widget</Button>
</EmptyState>
}
</PageSection>
<NewDashboardModal
project={project}
isOpen={this.state.isNewDashboardOpen}
onSave={this.onNewDashboardSave}
onClose={this.onNewDashboardClose}
/>
<NewWidgetWizard
dashboard={dashboard}
isOpen={this.state.isWidgetWizardOpen}
onSave={this.onNewWidgetSave}
onClose={this.onNewWidgetClose}
/>
<DeleteModal
title="Delete dashboard"
body={<>Would you like to delete the current dashboard? <strong>ALL WIDGETS</strong> on the dashboard will also be deleted.</>}
isOpen={this.state.isDeleteDashboardOpen}
onDelete={this.onDeleteDashboard}
onClose={this.onDeleteDashboardClose}
/>
<DeleteModal
title="Delete widget"
body="Would you like to delete the selected widget?"
isOpen={this.state.isDeleteWidgetOpen}
onDelete={this.onDeleteWidget}
onClose={this.onDeleteWidgetClose}
/>
</React.Fragment>
);
}
Example #13
Source File: test-history.js From ibutsu-server with MIT License | 4 votes |
render() {
const {
columns,
rows,
onlyFailures,
historySummary,
dropdownSelection
} = this.state;
const pagination = {
pageSize: this.state.pageSize,
page: this.state.page,
totalItems: this.state.totalItems
}
const dropdownValues = Object.assign({
"1 Week": 0.25,
"2 Weeks": 0.5,
"1 Month": 1.0,
"2 Months": 2.0,
"3 Months": 3.0,
"5 Months": 5.0
})
let dropdownItems = [];
Object.keys(dropdownValues).forEach(key => {
dropdownItems.push(
<DropdownItem key={key} value={dropdownValues[key]} autoFocus={key === dropdownSelection}>
{key}
</DropdownItem>
)
});
return (
<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 History
</Text>
</TextContent>
</FlexItem>
<FlexItem>
<TextContent>
<Checkbox id="only-failures" label="Only show failures/errors" isChecked={onlyFailures} aria-label="only-failures-checkbox" onChange={this.onFailuresCheck}/>
</TextContent>
</FlexItem>
<FlexItem>
<Dropdown
toggle={<DropdownToggle isDisabled={false} onToggle={this.onDropdownToggle}>Time range</DropdownToggle>}
onSelect={this.onDropdownSelect}
isOpen={this.state.isDropdownOpen}
dropdownItems={dropdownItems}
/>
</FlexItem>
<FlexItem>
<Button variant="secondary" onClick={this.refreshResults}>Refresh results</Button>
</FlexItem>
</Flex>
</CardHeader>
<CardBody>
<FilterTable
columns={columns}
rows={rows}
pagination={pagination}
isEmpty={this.state.isEmpty}
isError={this.state.isError}
onCollapse={this.onCollapse}
onSetPage={this.setPage}
onSetPageSize={this.pageSizeSelect}
canSelectAll={false}
variant={TableVariant.compact}
activeFilters={this.state.filters}
filters={[
<Text key="summary" component="h4">
Summary:
{historySummary &&
<RunSummary summary={historySummary}/>
}
</Text>,
<Text key="last-passed" component="h4">Last passed: {this.state.lastPassedDate}</Text>,
]}
onRemoveFilter={this.removeFilter}
hideFilters={["project_id", "result", "test_id"]}
/>
</CardBody>
</Card>
);
}
Example #14
Source File: result.js From ibutsu-server with MIT License | 4 votes |
render() { let { testResult, artifactTabs, activeTab, testHistoryTable } = this.state; const jsonViewTheme = getTheme() === 'dark' ? 'tomorrow' : 'rjv-default'; if (activeTab === null) { activeTab = this.getDefaultTab(); } let resultIcon = getIconForResult('pending'); let startTime = new Date(); let parameters = <div/>; let runLink = ''; if (testResult) { resultIcon = getIconForResult(testResult.result); startTime = new Date(testResult.start_time); parameters = Object.keys(testResult.params).map((key) => <div key={key}>{key} = {testResult.params[key]}</div>); runLink = <Link to={`/runs/${testResult.run_id}`}>{testResult.run_id}</Link>; } return ( <React.Fragment> {this.state.testResult && <Tabs activeKey={activeTab} onSelect={this.onTabSelect} isBox> {!this.props.hideSummary && <Tab eventKey="summary" title={<TabTitle icon={InfoCircleIcon} text="Summary" />}> <Card> <CardBody style={{padding: 0}}> <DataList selectedDataListItemId={null} aria-label="Test Result" style={{borderBottom: "none", borderTop: "none"}}> <DataListItem isExpanded={false} aria-labelledby="result-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="result-label" width={2}><strong>Result:</strong></DataListCell>, <DataListCell key="result-data" width={4}><span className={testResult.result}>{resultIcon} {testResult.result}</span></DataListCell> ]} /> </DataListItemRow> </DataListItem> <DataListItem aria-labelledby="run-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="run-label" width={2}><strong>Run:</strong></DataListCell>, <DataListCell key="run-data" width={4}>{runLink}</DataListCell> ]} /> </DataListItemRow> </DataListItem> {testResult.component && <DataListItem aria-labelledby="component-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="component-label" width={2}><strong>Component:</strong></DataListCell>, <DataListCell key="component-data" width={4}><Link to={`/results?component[eq]=${testResult.component}`}>{testResult.component}</Link></DataListCell> ]} /> </DataListItemRow> </DataListItem> } {testResult.metadata && testResult.metadata.code_link && <DataListItem aria-labelledby="code-link-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="code-link-label" width={2}><strong>Code Link:</strong></DataListCell>, <DataListCell key="code-link-data" width={4}><Linkify componentDecorator={linkifyDecorator}>{testResult.metadata.code_link}</Linkify></DataListCell> ]} /> </DataListItemRow> </DataListItem> } {testResult.metadata && testResult.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> {testResult.metadata.tags.map((tag) => <FlexItem spacer={{ default: 'spacerXs' }} key={tag}><Label color="blue" variant="filled">{tag}</Label></FlexItem>)} </Flex> </DataListCell> ]} /> </DataListItemRow> </DataListItem> } {testResult.result === 'skipped' && testResult.metadata && testResult.metadata.skip_reason && <DataListItem aria-labelledby="skip-reason-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="skip-reason-label" width={2}><strong>Reason skipped:</strong></DataListCell>, <DataListCell key="skip-reason-data" width={4}><Linkify componentDecorator={linkifyDecorator}>{testResult.metadata.skip_reason}</Linkify></DataListCell> ]} /> </DataListItemRow> </DataListItem> } {testResult.result === 'xfailed' && testResult.metadata && testResult.metadata.xfail_reason && <DataListItem aria-labelledby="xfail-reason-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="xfail-reason-label" width={2}><strong>Reason xfailed:</strong></DataListCell>, <DataListCell key="xfail-reason-data" width={4}><Linkify componentDecorator={linkifyDecorator}>{testResult.metadata.xfail_reason}</Linkify></DataListCell> ]} /> </DataListItemRow> </DataListItem> } {(testResult.result === 'failed' || testResult.result === 'error' || testResult.result === 'skipped') && <DataListItem aria-labelledby="classification-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="classification-label" width={2}><strong>Classification:</strong></DataListCell>, <DataListCell key="classification-data" width={4}> <ClassificationDropdown testResult={testResult} /> </DataListCell> ]} /> </DataListItemRow> </DataListItem> } <DataListItem aria-labelledby="duration"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="duration-label" width={2}><strong>Duration:</strong></DataListCell>, <DataListCell key="duration-data" width={4} style={{paddingTop: 0, paddingBottom: 0, marginBottom: "-25px"}}> <DataList selectedDataListItemId={null} aria-label="Durations" style={{borderTop: "none"}}> {(testResult.start_time ? testResult.start_time : testResult.starttime) > 0 && <DataListItem className="pf-u-p-0" aria-labelledby="started-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="started-label" className="pf-u-p-sm">Started at:</DataListCell>, <DataListCell key="started-data" className="pf-u-p-sm">{startTime.toLocaleString()}</DataListCell> ]} /> </DataListItemRow> </DataListItem> } <DataListItem className="pf-u-p-0" aria-labelledby="total-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="total-label" className="pf-u-p-sm">Total:</DataListCell>, <DataListCell key="total-data" className="pf-u-p-sm">{round(testResult.duration)}s</DataListCell> ]} /> </DataListItemRow> </DataListItem> {testResult.metadata && testResult.metadata.durations && <React.Fragment> {testResult.metadata.durations.setup && <DataListItem className="pf-u-p-0" aria-labelledby="setup-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="setup-label" className="pf-u-p-sm">Set up:</DataListCell>, <DataListCell key="setup-data" className="pf-u-p-sm">{round(testResult.metadata.durations.setup)}s</DataListCell> ]} /> </DataListItemRow> </DataListItem> } {testResult.metadata.durations.call && <DataListItem className="pf-u-p-0" aria-labelledby="call-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="call-label" className="pf-u-p-sm">Call:</DataListCell>, <DataListCell key="call-data" className="pf-u-p-sm">{round(testResult.metadata.durations.call)}s</DataListCell> ]} /> </DataListItemRow> </DataListItem> } {testResult.metadata.durations.teardown && <DataListItem className="pf-u-p-0" aria-labelledby="teardown-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="teardown-label" className="pf-u-p-sm">Tear down:</DataListCell>, <DataListCell key="teardown-data" className="pf-u-p-sm">{round(testResult.metadata.durations.teardown)}s</DataListCell> ]} /> </DataListItemRow> </DataListItem> } </React.Fragment> } </DataList> </DataListCell> ]} /> </DataListItemRow> </DataListItem> {testResult.metadata && testResult.metadata.statuses && <DataListItem aria-labelledby="stages-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="stages-label" width={2}><strong>Stages:</strong></DataListCell>, <DataListCell key="stages-data" width={4} style={{paddingBottom: 0, paddingTop: 0, marginBottom: "-25px"}}> <DataList selectedDataListItemId={null} aria-label="Stages" style={{borderTop: "none"}}> {testResult.metadata.statuses.setup && <DataListItem className="pf-u-p-0" aria-labelledby="setup-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="setup-label" className="pf-u-p-sm">Set up:</DataListCell>, <DataListCell key="setup-data" className="pf-u-p-sm">{testResult.metadata.statuses.setup[0]} {testResult.metadata.statuses.setup[1] && "(xfail)"}</DataListCell> ]} /> </DataListItemRow> </DataListItem> } {testResult.metadata.statuses.call && <DataListItem className="pf-u-p-0" aria-labelledby="call-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="call-label" className="pf-u-p-sm">Call:</DataListCell>, <DataListCell key="call-data" className="pf-u-p-sm">{testResult.metadata.statuses.call[0]} {testResult.metadata.statuses.call[1] && "(xfail)"}</DataListCell> ]} /> </DataListItemRow> </DataListItem> } {testResult.metadata.statuses.teardown && <DataListItem className="pf-u-p-0" aria-labelledby="teardown-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="teardown-label" className="pf-u-p-sm">Tear down:</DataListCell>, <DataListCell key="teardown-data" className="pf-u-p-sm">{testResult.metadata.statuses.teardown[0]} {testResult.metadata.statuses.teardown[1] && "(xfail)"}</DataListCell> ]} /> </DataListItemRow> </DataListItem> } </DataList> </DataListCell> ]} /> </DataListItemRow> </DataListItem> } <DataListItem aria-labelledby="source-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="source-label" width={2}><strong>Source:</strong></DataListCell>, <DataListCell key="source-data" width={4}><Link to={`/results?source[eq]=${testResult.source}`}>{testResult.source}</Link></DataListCell> ]} /> </DataListItemRow> </DataListItem> {parameters.length > 0 && <DataListItem aria-labelledby="params-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="params-label" width={2}><strong>Parameters:</strong></DataListCell>, <DataListCell key="params-data" width={4}>{parameters}</DataListCell> ]} /> </DataListItemRow> </DataListItem> } {testResult.metadata && Object.prototype.hasOwnProperty.call(testResult, 'short_tb') && <DataListItem aria-labelledby="traceback-label"> <DataListItemRow> <DataListItemCells dataListCells={[ <DataListCell key="traceback-label" width={2}><strong>Traceback:</strong></DataListCell>, <DataListCell key="traceback-data" width={4}><div style={{overflow: "scroll", width: "100%"}}><pre><code>{testResult.metadata.short_tb}</code></pre></div></DataListCell> ]} /> </DataListItemRow> </DataListItem> } </DataList> </CardBody> </Card> </Tab> } {artifactTabs} {!this.props.hideTestHistory && <Tab eventKey="test-history" title={<TabTitle icon={SearchIcon} text="Test History"/>}> {testHistoryTable} </Tab> } {!this.props.hideTestObject && <Tab eventKey="test-object" title={<TabTitle icon={CodeIcon} text="Test Object" />}> <Card> <CardBody> <ReactJson src={testResult} name={null} iconStyle={"triangle"} collapseStringsAfterLength={120} enableClipboard={false} displayDataTypes={false} theme={jsonViewTheme} /> </CardBody> </Card> </Tab> } </Tabs> } </React.Fragment> ); }
Example #15
Source File: ibutsu-header.js From ibutsu-server with MIT License | 4 votes |
render() {
document.title = 'Ibutsu';
const apiUiUrl = Settings.serverUrl + '/ui/';
const uploadParams = {};
if (this.state.selectedProject && this.state.selectedProject.project) {
uploadParams['project'] = this.state.selectedProject.project.id;
}
const topNav = (
<Flex>
<FlexItem id="project-selector">
<Select
ariaLabelTypeAhead="Select a project"
placeholderText="No active project"
variant={SelectVariant.typeahead}
isOpen={this.state.isProjectSelectorOpen}
selections={this.state.selectedProject}
onToggle={this.onProjectToggle}
onSelect={this.onProjectSelect}
onClear={this.onProjectClear}
onTypeaheadInputChanged={this.onProjectsChanged}
footer={this.state.projects.length == 10 && "Search for more..."}
>
{this.state.projects.map(project => (
<SelectOption key={project.id} value={projectToOption(project)} description={project.name} />
))}
</Select>
</FlexItem>
</Flex>
);
const headerTools = (
<PageHeaderTools>
<PageHeaderToolsGroup className={css(accessibleStyles.srOnly, accessibleStyles.visibleOnLg)}>
<PageHeaderToolsItem>
<Button variant="plain" onClick={this.toggleAbout}><QuestionCircleIcon /></Button>
</PageHeaderToolsItem>
<PageHeaderToolsItem>
<FileUpload component="button" className="pf-c-button pf-m-plain" isUnstyled name="importFile" url={`${Settings.serverUrl}/import`} params={uploadParams} multiple={false} beforeUpload={this.onBeforeUpload} afterUpload={this.onAfterUpload} title="Import xUnit XML or Ibutsu Archive"><UploadIcon /> Import</FileUpload>
</PageHeaderToolsItem>
<PageHeaderToolsItem>
<a href={apiUiUrl} className="pf-c-button pf-m-plain" target="_blank" rel="noopener noreferrer"><ServerIcon/> API</a>
</PageHeaderToolsItem>
<PageHeaderToolsItem>
<Switch id="dark-theme" label={<MoonIcon />} isChecked={this.state.isDarkTheme} onChange={this.onThemeChanged} />
</PageHeaderToolsItem>
<PageHeaderToolsItem id="user-dropdown">
<UserDropdown eventEmitter={this.eventEmitter}/>
</PageHeaderToolsItem>
</PageHeaderToolsGroup>
</PageHeaderTools>
);
return (
<React.Fragment>
<AboutModal
isOpen={this.state.isAboutOpen}
onClose={this.toggleAbout}
brandImageSrc="/images/ibutsu.svg"
brandImageAlt="Ibutsu"
productName="Ibutsu"
backgroundImageSrc="/images/about-bg.jpg"
trademark="Copyright (c) 2021 Red Hat, Inc."
>
<TextContent>
<TextList component="dl">
<TextListItem component="dt">Version</TextListItem>
<TextListItem component="dd">{this.state.version}</TextListItem>
<TextListItem component="dt">Source code</TextListItem>
<TextListItem component="dd"><a href="https://github.com/ibutsu/ibutsu-server" target="_blank" rel="noopener noreferrer">github.com/ibutsu/ibutsu-server</a></TextListItem>
<TextListItem component="dt">Documentation</TextListItem>
<TextListItem component="dd"><a href="https://docs.ibutsu-project.org/" target="_blank" rel="noopener noreferrer">docs.ibutsu-project.org</a></TextListItem>
<TextListItem component="dt">Report bugs</TextListItem>
<TextListItem component="dd"><a href="https://github.com/ibutsu/ibutsu-server/issues/new" target="_blank" rel="noopener noreferrer">Submit an issue</a></TextListItem>
</TextList>
</TextContent>
<p style={{marginTop: "2rem"}}>* Note: artifact files (screenshots, logs) are retained for 3 months</p>
</AboutModal>
<PageHeader
logo={<Brand src="/images/ibutsu-wordart-164.png" alt="Ibutsu"/>}
logoComponent={Link}
logoProps={{to: '/'}}
headerTools={headerTools}
showNavToggle={true}
topNav={topNav}
/>
</React.Fragment>
);
}
Example #16
Source File: filtertable.js From ibutsu-server with MIT License | 4 votes |
render() {
const {
isEmpty,
isError,
onCollapse,
onRowSelect,
onApplyFilter,
onRemoveFilter,
onClearFilters,
onApplyReport,
onSetPage,
onSetPageSize,
variant
} = this.props;
let columns = this.props.columns || [];
let rows = this.props.rows || [];
let actions = this.props.actions || [];
let filters = this.props.filters || [];
let hideFilters = this.props.hideFilters || [];
let activeFilters = this.props.activeFilters || {};
let pagination = this.props.pagination || {page: 0, pageSize: 0, totalItems: 0};
let canSelectAll = this.props.canSelectAll || false;
return (
<React.Fragment>
<Flex>
{(filters || onApplyFilter) &&
<Flex spaceItems={{default: 'spaceItemsXs'}} grow={{default: 'grow'}}>
{filters && filters.map((filter, index) => {
return (
<FlexItem key={index}>{filter}</FlexItem>
);
})}
{onApplyFilter &&
<FlexItem>
<Button onClick={onApplyFilter}>Apply Filter</Button>
</FlexItem>
}
</Flex>
}
<Flex align={{default: 'alignRight'}}>
<FlexItem>
<Pagination
perPage={pagination.pageSize}
page={pagination.page}
variant={PaginationVariant.top}
itemCount={pagination.totalItems}
onSetPage={onSetPage}
onPerPageSelect={onSetPageSize}
isCompact
/>
</FlexItem>
</Flex>
</Flex>
{Object.keys(activeFilters).length > 0 &&
<Flex style={{marginTop: "1rem"}}>
<Flex>
<FlexItem>
Active filters
</FlexItem>
</Flex>
<Flex grow={{default: 'grow'}}>
{Object.keys(activeFilters).map(key => (
<FlexItem spacer={{ default: 'spacerXs'}} key={key}>
{!hideFilters.includes(key) &&
<ChipGroup categoryName={key}>
<Chip onClick={() => onRemoveFilter(key)}>
{(typeof activeFilters[key] === 'object') &&
<React.Fragment>
<Badge isRead={true}>{activeFilters[key]['op']}</Badge>
{activeFilters[key]['val']}
</React.Fragment>
}
{(typeof activeFilters[key] !== 'object') && activeFilters[key]}
</Chip>
</ChipGroup>
}
</FlexItem>
))}
</Flex>
{onApplyReport &&
<Flex>
<FlexItem style={{marginLeft: "0.75em"}}>
<Button onClick={onApplyReport} variant="secondary">Use Active Filters in Report</Button>
</FlexItem>
</Flex>
}
</Flex>
}
<Table
cells={columns}
rows={rows}
actions={actions}
aria-label="List"
canSelectAll={canSelectAll}
onCollapse={onCollapse}
onSelect={onRowSelect}
variant={variant}
>
<TableHeader />
<TableBody />
</Table>
{isEmpty && <TableEmptyState onClearFilters={onClearFilters} />}
{isError && <TableErrorState onClearFilters={onClearFilters} />}
<Pagination
widgetId="pagination-options-menu-bottom"
perPage={pagination.pageSize}
page={pagination.page}
variant={PaginationVariant.bottom}
itemCount={pagination.totalItems}
dropDirection="up"
onSetPage={onSetPage}
onPerPageSelect={onSetPageSize}
style={{marginTop: "1rem"}}
/>
</React.Fragment>
);
}
Example #17
Source File: certificateList.jsx From cockpit-certificates with GNU Lesser General Public License v2.1 | 4 votes |
generalDetails = ({ idPrefix, cas, cert, certPath, onAutorenewChanged }) => {
const caName = getCAName(cas, cert);
return (<Flex justifyContent={{ default: "justifyContentCenter" }}>
<Flex direction={{ default:"column" }} flex={{ default: 'flex_1' }}>
<DescriptionList isHorizontal>
{cert.status && cert.status.v && <DescriptionListGroup>
<DescriptionListTerm>{_("Status")}</DescriptionListTerm>
<DescriptionListDescription id={`${idPrefix}-general-status`}>
{cert.stuck.v && (
<Flex alignItems={{ default: 'alignItemsCenter' }} spaceItems={{ default: 'spaceItemsSm' }}>
<ExclamationTriangleIcon className="ct-icon-exclamation-triangle" />
<span id={`${idPrefix}-general-stuck`}>{_("Stuck: ")}</span>
</Flex>
)}
<Flex alignItems={{ default: 'alignItemsCenter' }} spaceItems={{ default: 'spaceItemsSm' }}>
<FlexItem>
{cert.status.v.includes('_')
? cert.status.v
: cert.status.v.charAt(0) + cert.status.v.slice(1).toLowerCase()}
</FlexItem>
<Tooltip position={TooltipPosition.top}
entryDelay={0}
content={certificateStates[cert.status.v]}>
<span className="info-circle">
<InfoAltIcon />
</span>
</Tooltip>
</Flex>
</DescriptionListDescription>
</DescriptionListGroup>}
{cert.ca && cert.ca.v && <DescriptionListGroup>
<DescriptionListTerm>{_("Certificate authority")}</DescriptionListTerm>
<DescriptionListDescription id={`${idPrefix}-general-ca`}>{caName == "SelfSign" ? _("Self-signed") : caName}</DescriptionListDescription>
</DescriptionListGroup>}
{cert["not-valid-after"] && cert["not-valid-after"].v !== 0 && <DescriptionListGroup>
<DescriptionListTerm>
{_("Valid")}
</DescriptionListTerm>
<DescriptionListDescription id={`${idPrefix}-general-validity`}>
{prettyTime(cert["not-valid-before"].v) +
_(" to ") + prettyTime(cert["not-valid-after"].v)}
</DescriptionListDescription>
</DescriptionListGroup>}
{cert.autorenew && <DescriptionListGroup>
<DescriptionListTerm>
{_("Auto-renewal")}
</DescriptionListTerm>
<DescriptionListDescription>
<Checkbox id={`${idPrefix}-general-autorenewal`}
isChecked={cert.autorenew.v}
label={_("Renew before expiration")}
onChange={() => onAutorenewChanged(cert, certPath)} />
</DescriptionListDescription>
</DescriptionListGroup>}
</DescriptionList>
</Flex>
<Flex direction={{ default:"column" }} flex={{ default: 'flex_1' }}>
<DescriptionList isHorizontal>
{cert.subject && cert.subject.v && <DescriptionListGroup>
<DescriptionListTerm>
{_("Subject name")}
</DescriptionListTerm>
<DescriptionListDescription>
<span id={`${idPrefix}-general-subject`}>{cert.subject.v}</span>
</DescriptionListDescription>
</DescriptionListGroup>}
{cert.principal && cert.principal.v.length > 0 && <DescriptionListGroup>
<DescriptionListTerm>
{_("Principal name")}
</DescriptionListTerm>
<DescriptionListDescription>
<span id={`${idPrefix}-general-principal`}>{cert.principal.v.join(", ")}</span>
</DescriptionListDescription>
</DescriptionListGroup>}
{cert.hostname && cert.hostname.v.length > 0 && <DescriptionListGroup>
<DescriptionListTerm>
{_("DNS name")}
</DescriptionListTerm>
<DescriptionListDescription>
<span id={`${idPrefix}-general-dns`}>{cert.hostname.v.join(", ")}</span>
</DescriptionListDescription>
</DescriptionListGroup>}
</DescriptionList>
</Flex>
</Flex>);
}
Example #18
Source File: AccessRequestDetailsPage.js From access-requests-frontend with Apache License 2.0 | 4 votes |
BaseAccessRequestDetailsPage = ({ isInternal }) => {
const [request, setRequest] = React.useState();
const { requestId } = useParams();
const dispatch = useDispatch();
React.useEffect(() => {
apiInstance
.get(
`${API_BASE}/cross-account-requests/${requestId}/${
isInternal ? '?query_by=user_id' : '?query_by=target_account'
}`,
{ headers: { Accept: 'application/json' } }
)
.then((res) => {
if (res.errors) {
throw Error(res.errors.map((e) => e.detail).join('\n'));
}
setRequest(res);
})
.catch((err) => {
dispatch(
addNotification({
variant: 'danger',
title: 'Could not load access request',
description: err.message,
})
);
});
}, []);
// Modal actions
const [openModal, setOpenModal] = React.useState({ type: null });
const onModalClose = () => setOpenModal({ type: null });
const actions = getInternalActions(
request && request.status,
requestId,
setOpenModal
);
const [isDropdownOpen, setIsDropdownOpen] = React.useState(false);
const requestDisplayProps = [
...(isInternal
? ['request_id', 'target_account']
: ['first_name', 'last_name']),
'start_date',
'end_date',
'created',
];
return (
<React.Fragment>
<PageSection variant="light">
<Breadcrumb>
<BreadcrumbItem
render={() => (
<Link to={isInternal ? '/' : '/access-requests'}>
{!isInternal && 'Red Hat '}Access Requests
</Link>
)}
/>
<BreadcrumbItem>{requestId}</BreadcrumbItem>
</Breadcrumb>
<Flex direction={{ default: 'column', md: 'row' }}>
<FlexItem grow={{ default: 'grow' }}>
<Title headingLevel="h1" size="2xl" className="pf-u-pt-md">
{requestId}
</Title>
</FlexItem>
{isInternal && actions.items.length > 0 && (
<FlexItem alignSelf={{ default: 'alignRight' }}>
<Dropdown
position="right"
toggle={
<KebabToggle
onToggle={() => setIsDropdownOpen(!isDropdownOpen)}
id="actions-toggle"
/>
}
isOpen={isDropdownOpen}
isPlain
dropdownItems={actions.items.map(({ title, onClick }) => (
<DropdownItem
key={title}
component="button"
onClick={onClick}
>
{title}
</DropdownItem>
))}
isDisabled={actions.disable}
/>
</FlexItem>
)}
</Flex>
</PageSection>
<PageSection>
<Flex
spaceItems={{ xl: 'spaceItemsLg' }}
direction={{ default: 'column', lg: 'row' }}
>
<FlexItem
flex={{ default: 'flex_1' }}
alignSelf={{ default: 'alignSelfStretch' }}
>
<Card ouiaId="request-details" style={{ height: '100%' }}>
<CardTitle>
<Title headingLevel="h2" size="xl">
Request details
</Title>
</CardTitle>
<CardBody>
{!request ? (
<Spinner size="xl" />
) : (
<React.Fragment>
<div className="pf-u-pb-md">
{isInternal ? (
<div>
<label>
<b>Request status</b>
</label>
<br />
<Label
className="pf-u-mt-sm"
{...getLabelProps(request.status)}
>
{capitalize(request.status)}
</Label>
</div>
) : (
<React.Fragment>
<label>
<b>Request decision</b>
</label>
<br />
<StatusLabel
requestId={requestId}
status={request.status}
/>
</React.Fragment>
)}
</div>
{requestDisplayProps.map((prop, key) => (
<div className="pf-u-pb-md" key={key}>
<label>
<b>
{capitalize(
prop.replace(/_/g, ' ').replace('id', 'ID')
)}
</b>
</label>
<br />
<div>{request[prop]}</div>
</div>
))}
</React.Fragment>
)}
</CardBody>
</Card>
</FlexItem>
<FlexItem
flex={{ default: 'flex_3' }}
grow={{ default: 'grow' }}
alignSelf={{ default: 'alignSelfStretch' }}
>
<Card ouiaId="request-roles" style={{ height: '100%' }}>
<CardTitle>
<Title headingLevel="h2" size="xl">
Roles requested
</Title>
</CardTitle>
<CardBody>
{!request ? (
<Spinner size="xl" />
) : (
<MUARolesTable roles={request.roles} />
)}
</CardBody>
</Card>
</FlexItem>
</Flex>
</PageSection>
{openModal.type === 'cancel' && (
<CancelRequestModal requestId={requestId} onClose={onModalClose} />
)}
{openModal.type === 'edit' && (
<EditRequestModal
variant="edit"
requestId={requestId}
onClose={onModalClose}
/>
)}
</React.Fragment>
);
}
Example #19
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 #20
Source File: Services.js From sed-frontend with Apache License 2.0 | 4 votes |
Services = ({
defaults,
setConfirmChangesOpen,
onChange,
isEditing,
setIsEditing,
}) => {
const initState = {
enableCloudConnector: {
value: defaults.enableCloudConnector,
isDisabled: false,
},
useOpenSCAP: { value: defaults.useOpenSCAP, isDisabled: false },
};
const [formState, setFormState] = useState(initState);
const [madeChanges, setMadeChanges] = useState(false);
const { hasAccess, isLoading } = usePermissions(
'',
[
'config-manager:activation_keys:*',
'config-manager:state:read',
'config-manager:state:write',
'config-manager:state-changes:read',
'inventory:*:read',
'playbook-dispatcher:run:read',
],
false,
true
);
const cancelEditing = () => {
setFormState(initState);
setIsEditing(false);
};
useEffect(() => {
setMadeChanges(
formState.useOpenSCAP.value !== defaults.useOpenSCAP ||
formState.enableCloudConnector.value != defaults.enableCloudConnector
);
onChange({
useOpenSCAP: formState.useOpenSCAP.value,
enableCloudConnector: formState.enableCloudConnector.value,
});
}, [formState]);
const getStatusIcon = (row) => {
if (formState[row.id].value) {
return (
<Flex style={{ color: 'var(--pf-global--success-color--200)' }}>
<FlexItem spacer={{ default: 'spacerXs' }}>
<CheckCircleIcon />
</FlexItem>
<FlexItem className="status">
<b>Enabled</b>
</FlexItem>
</Flex>
);
}
return (
<Flex style={{ color: 'var(--pf-global--default-color--300)' }}>
<FlexItem spacer={{ default: 'spacerXs' }}>
<BanIcon />
</FlexItem>
<FlexItem className="status">
<b>Disabled</b>
</FlexItem>
</Flex>
);
};
return (
<Stack hasGutter className="pf-u-p-md">
<StackItem>
<Toolbar id="toolbar-items">
<ToolbarContent>
{!isEditing && (
<ToolbarItem>
{!hasAccess ? (
<Tooltip
content={
<div>
To perform this action, you must be granted the
"System Administrator" role by your
Organization Administrator in your Setting's User
Access area.
</div>
}
>
{changeSettingsButton(isLoading, hasAccess, setIsEditing)}
</Tooltip>
) : (
changeSettingsButton(isLoading, hasAccess, setIsEditing)
)}
</ToolbarItem>
)}
{isEditing && (
<>
<ToolbarItem>
<Button
ouiaId="primary-save-button"
onClick={() => setConfirmChangesOpen(true)}
isDisabled={!madeChanges}
>
Save changes
</Button>
</ToolbarItem>
<ToolbarItem>
<Button
ouiaId="secondary-cancel-button"
onClick={() => cancelEditing()}
variant="secondary"
>
Cancel
</Button>
</ToolbarItem>
<ToolbarItem>
<Alert
variant="info"
isInline
isPlain
title="Changes will affect all systems connected with Red Hat connector"
/>
</ToolbarItem>
</>
)}
</ToolbarContent>
</Toolbar>
</StackItem>
<StackItem>
<TableComposable aria-label="Settings table">
<Thead>
<Tr>
<Th>Permission</Th>
<Th>Status</Th>
</Tr>
</Thead>
<Tbody>
{permissions.map((row) => (
<Tr key={row.name}>
<Td
dataLabel="Permission"
width={80}
style={row.secondary && { paddingLeft: 70, fontSize: 14 }}
>
<Stack>
<StackItem>
<Flex>
<FlexItem>
<b>{row.name}</b>
</FlexItem>
{row.additionalInfo && (
<FlexItem
style={{ color: 'var(--pf-global--Color--100)' }}
>
<i>{row.additionalInfo}</i>
</FlexItem>
)}
</Flex>
</StackItem>
<StackItem style={{ fontSize: 14 }}>
{row.description}
</StackItem>
{row.links && (
<StackItem className="stack-item">
<Flex>
{row.links.map((link) => (
<FlexItem key={link.name}>
<a
href={link.link}
target="_blank"
rel="noopener noreferrer"
>
{link.name}
<ExternalLinkAltIcon className="pf-u-ml-sm" />
</a>
</FlexItem>
))}
</Flex>
</StackItem>
)}
</Stack>
</Td>
{!isEditing && <Td dataLabel="Status">{getStatusIcon(row)}</Td>}
{isEditing && (
<Td dataLabel="Status">
<ToggleGroup aria-label="Default with single selectable">
<ToggleGroupItem
text="Enabled"
isSelected={formState[row.id].value}
onChange={() =>
setFormState({
...formState,
[row.id]: { ...formState[row.id], value: true },
})
}
isDisabled={formState[row.id].isDisabled}
/>
<ToggleGroupItem
text="Disabled"
isSelected={!formState[row.id].value}
onChange={() =>
setFormState({
...formState,
[row.id]: { ...formState[row.id], value: false },
})
}
isDisabled={formState[row.id].isDisabled}
/>
</ToggleGroup>
</Td>
)}
</Tr>
))}
</Tbody>
</TableComposable>
</StackItem>
</Stack>
);
}
Example #21
Source File: ActivationKeys.js From sed-frontend with Apache License 2.0 | 4 votes |
ActivationKeys = () => {
const queryClient = useQueryClient();
const user = queryClient.getQueryData('user');
const { isLoading, error, data } = useActivationKeys();
const [isOpen, setisOpen] = useState(false);
const [currentKeyName, setCurrentKeyName] = useState('');
const [isDeleteActivationKeyModalOpen, setIsDeleteActivationKeyModalOpen] =
useState(false);
const [isEditActivationKeyModalOpen, setIsEditActivationKeyModalOpen] =
useState(false);
const handleModalToggle = () => {
setisOpen(!isOpen);
};
const actions = (activationKeyName) => {
return [
{
title: 'Edit',
onClick: () => handleEditActivationKeyModalToggle(activationKeyName),
},
{
title: 'Delete',
onClick: () => handleDeleteActivationKeyModalToggle(activationKeyName),
},
];
};
let pageContent;
if (isLoading) {
pageContent = <Loading />;
} else if (!isLoading && !error && !data.length) {
pageContent = (
<NoActivationKeysFound handleModalToggle={handleModalToggle} />
);
} else if (!isLoading && !error && data.length) {
pageContent = (
<>
<ActionGroup>
<CreateActivationKeyButton onClick={handleModalToggle} />
</ActionGroup>
<ActivationKeysTable actions={actions} />
</>
);
}
const setKeyName = (modalOpen, name) => {
let currentName = modalOpen ? '' : name;
setCurrentKeyName(currentName);
};
const handleDeleteActivationKeyModalToggle = (name) => {
setKeyName(isDeleteActivationKeyModalOpen, name);
setIsDeleteActivationKeyModalOpen(!isDeleteActivationKeyModalOpen);
};
const handleEditActivationKeyModalToggle = (name) => {
setKeyName(isEditActivationKeyModalOpen, name);
setIsEditActivationKeyModalOpen(!isEditActivationKeyModalOpen);
};
const Page = () => {
return (
<React.Fragment>
<PageHeader>
<Split hasGutter className="page-title">
<SplitItem isFilled>
<Flex>
<FlexItem spacer={{ default: 'spacerSm' }}>
<PageHeaderTitle title="Activation Keys" />
</FlexItem>
<FlexItem>
<ActivationKeysDocsPopover orgId={user.orgId} />
</FlexItem>
</Flex>
</SplitItem>
</Split>
<TextContent>
<Text component={TextVariants.p}>
Organization ID: {user.orgId}
</Text>
</TextContent>
</PageHeader>
<Main>
<PageSection variant={PageSectionVariants.light}>
{pageContent}
</PageSection>
</Main>
<CreateActivationKeyModal
isOpen={isOpen}
handleModalToggle={handleModalToggle}
/>
<EditActivationKeyModal
isOpen={isEditActivationKeyModalOpen}
handleModalToggle={handleEditActivationKeyModalToggle}
activationKeyName={currentKeyName}
/>
<DeleteActivationKeyConfirmationModal
handleModalToggle={handleDeleteActivationKeyModalToggle}
isOpen={isDeleteActivationKeyModalOpen}
name={currentKeyName}
/>
</React.Fragment>
);
};
if (user.rbacPermissions.canReadActivationKeys) {
return <Page />;
} else {
return <NoAccessView />;
}
}
Example #22
Source File: Recommendation.js From ocp-advisor-frontend with Apache License 2.0 | 4 votes |
Recommendation = ({ rule, ack, clusters, match }) => {
const intl = useIntl();
const dispatch = useDispatch();
const notify = (data) => dispatch(addNotification(data));
const recId = match.params.recommendationId;
const [disableRuleModalOpen, setDisableRuleModalOpen] = useState(false);
const [actionsDropdownOpen, setActionsDropdownOpen] = useState(false);
const [viewSystemsModalOpen, setViewSystemsModalOpen] = useState(false);
// rule's info
const {
isError,
isUninitialized,
isLoading,
isFetching,
isSuccess,
data,
refetch,
} = rule;
// justification note, last time acknowledged, etc.
const { data: ackData, isFetching: ackIsFetching, refetch: refetchAck } = ack;
const ruleDate = new Date(ackData?.updated_at || ackData?.created_at);
// affected and acked clusters lists
const {
data: clustersData,
isFetching: clustersIsFetching,
refetch: refetchClusters,
} = clusters;
const content =
isSuccess && data ? adjustOCPRule(data.content, recId) : undefined;
const ackedClusters =
!clustersIsFetching && clustersData ? clustersData.disabled : undefined;
const afterDisableFn = async () => {
refetch();
refetchAck();
refetchClusters();
};
const handleModalToggle = (disableRuleModalOpen) => {
setDisableRuleModalOpen(disableRuleModalOpen);
};
const enableRecForHosts = async ({ uuids }) => {
try {
const requests = uuids.map((uuid) =>
enableRuleForCluster({ uuid, recId })
);
await Promise.all(requests);
refetch();
refetchAck();
refetchClusters();
notify({
variant: 'success',
timeout: true,
dismissable: true,
title: intl.formatMessage(messages.recSuccessfullyEnabledForCluster),
});
} catch (error) {
notify({
variant: 'danger',
dismissable: true,
title: intl.formatMessage(messages.error),
description: `${error}`,
});
}
};
const enableRule = async (rule) => {
try {
await Delete(`${BASE_URL}/v2/ack/${rule.data.content.rule_id}/`);
notify({
variant: 'success',
timeout: true,
dismissable: true,
title: intl.formatMessage(messages.recSuccessfullyEnabled),
});
refetch();
} catch (error) {
handleModalToggle(false);
notify({
variant: 'danger',
dismissable: true,
title: intl.formatMessage(messages.error),
description: `${error}`,
});
}
};
const messagesValues = useMemo(
() => (content ? mapContentToValues(intl, content) : {}),
[intl, content]
);
return (
<React.Fragment>
{viewSystemsModalOpen && (
<ViewHostAcks
handleModalToggle={(toggleModal) =>
setViewSystemsModalOpen(toggleModal)
}
isModalOpen={viewSystemsModalOpen}
clusters={clusters}
afterFn={() => refetchClusters()}
recId={recId}
/>
)}
{disableRuleModalOpen && (
<DisableRule
handleModalToggle={handleModalToggle}
isModalOpen={disableRuleModalOpen}
rule={content}
afterFn={afterDisableFn}
/>
)}
<PageHeader className="pageHeaderOverride">
<Breadcrumbs current={content?.description || recId} />
</PageHeader>
{(isUninitialized || isLoading || isFetching) && (
<Main>
<Loading />
</Main>
)}
{isError && (
<Main>
<ErrorState />
</Main>
)}
{!(isUninitialized || isLoading || isFetching) && isSuccess && (
<React.Fragment>
<Main className="pf-m-light pf-u-pt-sm">
<RuleDetails
messages={formatMessages(
intl,
RuleDetailsMessagesKeys,
messagesValues
)}
product={AdvisorProduct.ocp}
rule={content}
isDetailsPage
header={
<React.Fragment>
<PageHeaderTitle
title={
<React.Fragment>
{content.description} <RuleLabels rule={content} />
</React.Fragment>
}
/>
<p>
{intl.formatMessage(messages.rulesDetailsPubishdate, {
date: (
<DateFormat
date={new Date(content.publish_date)}
type="onlyDate"
/>
),
})}
{content.tags &&
(Array.isArray(content.tags) ? (
<LabelGroup
className="categoryLabels"
numLabels={1}
isCompact
>
{content.tags.reduce((labels, tag) => {
if (RULE_CATEGORIES[tag]) {
labels.push(
<Label
key={`label-${tag}`}
color="blue"
isCompact
>
{
FILTER_CATEGORIES.category.values[
RULE_CATEGORIES[tag] - 1
].label
}
</Label>
);
}
return labels;
}, [])}
</LabelGroup>
) : (
<Label isCompact>{content.tags}</Label>
))}
</p>
</React.Fragment>
}
onVoteClick={async (rule, rating) =>
await Post(`${BASE_URL}/v2/rating`, {}, { rule, rating })
}
>
<Flex>
<FlexItem align={{ default: 'alignRight' }}>
<Dropdown
className="ins-c-rec-details__actions_dropdown"
onSelect={() =>
setActionsDropdownOpen(!actionsDropdownOpen)
}
position="right"
ouiaId="actions"
toggle={
<DropdownToggle
onToggle={(actionsDropdownOpen) =>
setActionsDropdownOpen(actionsDropdownOpen)
}
toggleIndicator={CaretDownIcon}
>
{intl.formatMessage(messages.actions)}
</DropdownToggle>
}
isOpen={actionsDropdownOpen}
dropdownItems={
content?.disabled
? [
<DropdownItem
key="link"
ouiaId="enable"
onClick={() => {
enableRule(rule);
}}
>
{intl.formatMessage(messages.enableRule)}
</DropdownItem>,
]
: [
<DropdownItem
key="link"
ouiaId="disable"
onClick={() => {
handleModalToggle(true);
}}
>
{intl.formatMessage(messages.disableRule)}
</DropdownItem>,
]
}
/>
</FlexItem>
</Flex>
</RuleDetails>
</Main>
<Main>
<React.Fragment>
{(content?.hosts_acked_count ||
ackedClusters?.length > 0 ||
content?.disabled) && (
<Card className="cardOverride" ouiaId="hosts-acked">
<CardHeader>
<Title headingLevel="h4" size="xl">
<BellSlashIcon size="sm" />
{intl.formatMessage(
(content?.hosts_acked_count ||
ackedClusters?.length > 0) &&
!content?.disabled
? messages.ruleIsDisabledForClusters
: messages.ruleIsDisabled
)}
</Title>
</CardHeader>
<CardBody>
{(content?.hosts_acked_count ||
ackedClusters?.length > 0) &&
!content?.disabled ? (
<React.Fragment>
{intl.formatMessage(
messages.ruleIsDisabledForClustersBody,
{
clusters: ackedClusters?.length,
}
)}
{!clustersIsFetching && ackedClusters?.length > 0 ? (
<React.Fragment>
<Button
isInline
variant="link"
onClick={() => setViewSystemsModalOpen(true)}
ouiaId="view-clusters"
>
{intl.formatMessage(messages.viewClusters)}
</Button>
</React.Fragment>
) : (
<OneLineLoader />
)}
</React.Fragment>
) : (
!ackIsFetching &&
ackData && (
<React.Fragment>
{ackData?.justification
? intl.formatMessage(
messages.ruleIsDisabledWithJustificaiton,
{
date: (
<span>
<DateFormat
date={ruleDate}
type="onlyDate"
/>
</span>
),
reason: ackData.justification,
}
)
: intl.formatMessage(
messages.ruleIsDisabledWithoutJustificaiton,
{
date: (
<span>
<DateFormat
date={ruleDate}
type="onlyDate"
/>
</span>
),
}
)}
</React.Fragment>
)
)}
</CardBody>
<CardFooter>
{(content?.hosts_acked_count ||
ackedClusters?.length > 0) &&
!content?.disabled ? (
!clustersIsFetching && ackedClusters ? (
<Button
isInline
variant="link"
onClick={() =>
enableRecForHosts({
uuids: ackedClusters.map((c) => c.cluster_id),
})
}
ouiaId="enable"
>
{intl.formatMessage(messages.enableRuleForClusters)}
</Button>
) : (
<OneLineLoader />
)
) : (
<Button
isInline
variant="link"
onClick={() => enableRule(rule)}
ouiaId="enable"
>
{intl.formatMessage(messages.enableRule)}
</Button>
)}
</CardFooter>
</Card>
)}
{!content?.disabled && (
<React.Fragment>
<Title className="titleOverride" headingLevel="h3" size="2xl">
{intl.formatMessage(messages.affectedClusters)}
</Title>
<AffectedClustersTable
query={clusters}
rule={content}
afterDisableFn={afterDisableFn}
/>
</React.Fragment>
)}
{content?.disabled && (
<MessageState
icon={BellSlashIcon}
title={intl.formatMessage(messages.ruleIsDisabled)}
text={intl.formatMessage(messages.ruleIsDisabledBody)}
/>
)}
</React.Fragment>
</Main>
</React.Fragment>
)}
</React.Fragment>
);
}
Example #23
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}
/>
)}
</>
);
}
Example #24
Source File: Groups.js From edge-frontend with Apache License 2.0 | 4 votes |
Groups = () => {
const history = useHistory();
const [response, fetchGroups] = useApi({
api: getGroups,
tableReload: true,
});
const { data, isLoading, hasError } = response;
const [modalState, setModalState] = useState({ id: null, name: '' });
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false);
const [isRenameModalOpen, setIsRenameModalOpen] = useState(false);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const handleRenameModal = (id, name) => {
setModalState({ id, name });
setIsRenameModalOpen(true);
};
const handleDeleteModal = (id, name) => {
setModalState({ id, name });
setIsDeleteModalOpen(true);
};
return (
<>
<PageHeader className="pf-m-light">
<PageHeaderTitle title="Groups" />
</PageHeader>
<Main className="edge-devices">
{!emptyStateNoFliters(isLoading, data?.count, history) ? (
<GroupTable
data={data?.data || []}
count={data?.count}
isLoading={isLoading}
hasError={hasError}
handleRenameModal={handleRenameModal}
handleDeleteModal={handleDeleteModal}
handleCreateModal={() => setIsCreateModalOpen(true)}
fetchGroups={fetchGroups}
/>
) : (
<Flex justifyContent={{ default: 'justifyContentCenter' }}>
<Empty
icon="plus"
title="Create a system group"
body="Create system groups to help manage your devices more effectively."
primaryAction={{
text: 'Create group',
click: () => setIsCreateModalOpen(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>
{isCreateModalOpen && (
<CreateGroupModal
isModalOpen={isCreateModalOpen}
setIsModalOpen={setIsCreateModalOpen}
reloadData={fetchGroups}
/>
)}
{isRenameModalOpen && (
<RenameGroupModal
isModalOpen={isRenameModalOpen}
setIsModalOpen={setIsRenameModalOpen}
reloadData={fetchGroups}
modalState={modalState}
/>
)}
{isDeleteModalOpen && (
<DeleteGroupModal
isModalOpen={isDeleteModalOpen}
setIsModalOpen={setIsDeleteModalOpen}
reloadData={fetchGroups}
modalState={modalState}
/>
)}
</>
);
}
Example #25
Source File: Details.js From content-preview with Apache License 2.0 | 4 votes |
Details = ({
match,
fetchContentDetails,
details,
fetchContentDetailsHits,
contentDetailsHits
}) => {
const [selectedListItem, setSelectedListItem] = useState(0);
const capitalize = (string) => string[0].toUpperCase() + string.substring(1);
const [expanded, setExpanded] = useState(true);
const pyFilter = (data) => {
const keysToInclude = Object.keys(data).filter(
(key) => !key.includes('__')
);
const arrayObj = keysToInclude.map((key) => ({ [key]: data[key] }));
return Object.assign({}, ...arrayObj);
};
const selectedPyData =
selectedListItem >= 1 && pyFilter(contentDetailsHits[selectedListItem - 1]);
const detailHref = `https://access.redhat.com/node/${details.node_id}`;
const [freeStyle, setFreeStyle] = useState('');
const [freeStyleValidated, setFreeStyleValidated] = useState('default');
const [validFreeStyle, setValidFreeStyle] = useState('');
const [helperText, setHelperText] = useState('Please enter valid JSON');
const [kbaDetailsData, setLbaDetailsData] = useState({});
const [kbaLoading, setKbaLoading] = useState(true);
const freeStyleChange = (input) => {
let isValid;
const parser = (input) => {
try {
return JSON.parse(input);
} catch (error) {
return false;
}
};
if (input.length > 0) {
const validInput = parser(input);
if (validInput) {
isValid = 'success';
setValidFreeStyle(validInput);
setHelperText('Valid JSON! ?');
} else {
isValid = 'error';
setValidFreeStyle('');
}
} else {
isValid = 'default';
setValidFreeStyle('');
setHelperText('Please enter valid JSON');
}
setFreeStyleValidated(isValid);
setFreeStyle(input);
};
const severityLabelColor = (severity) =>
severity === 'ERROR'
? 'red'
: severity === 'WARN'
? 'orange'
: severity === 'INFO'
? 'purple'
: 'blue';
const fetchKbaDetails = async (kbaId) => {
try {
const kbaDetailsFetch = (
await API.get(
`https://access.redhat.com/hydra/rest/search/kcs?q=id:(${kbaId})&fl=view_uri,id,publishedTitle&rows=1&redhat_client=$ADVISOR`,
{},
{ credentials: 'include' }
)
).data.response.docs;
setLbaDetailsData(kbaDetailsFetch[0]);
setKbaLoading(false);
} catch (error) {
console.error(error, 'KBA fetch failed.');
}
};
const ruleDescription = (data, isGeneric) =>
typeof data === 'string' &&
Boolean(data) && (
<span className={isGeneric && 'genericOverride'}>
<Markdown rehypePlugins={[rehypeRaw, rehypeSanitize]}>{data}</Markdown>
</span>
);
useEffect(() => {
const detailName = { name: match.params.recDetail };
fetchContentDetails(detailName);
fetchContentDetailsHits(detailName);
fetchKbaDetails(details.node_id);
}, [
fetchContentDetails,
match.params.recDetail,
fetchContentDetailsHits,
details.node_id
]);
return (
<Page
breadcrumb={
<Breadcrumb>
<BreadcrumbItem>
<Link to="/preview">Content Preview</Link>
</BreadcrumbItem>
<BreadcrumbHeading to="#">{`${match.params.recDetail}`}</BreadcrumbHeading>
</Breadcrumb>
}
>
<PageHeader>
<Flex justifyContent={{ default: 'justifyContentSpaceBetween' }}>
<PageHeaderTitle
title={
<>
{details.rule_id || 'loading...'}{' '}
{details.status !== undefined && (
<Label color={details.status === 'active' ? 'green' : 'red'}>
{capitalize(details.status)}
</Label>
)}{' '}
</>
}
/>
<Toolbar>
<HostSelector />
</Toolbar>
</Flex>
</PageHeader>
<PageSection>
<Grid hasGutter>
<GridItem span={6}>
<Stack hasGutter>
<Card>
<CardBody>
<ExpandableSection
toggleText={details.description}
onToggle={() => setExpanded(!expanded)}
isExpanded={expanded}
>
<Stack hasGutter>
<StackItem>
<p>
{`Publish Date: ${details.publish_date} | `}
{details.node_id ? (
<a href={detailHref}>{detailHref}</a>
) : (
<Label variant="outline" color="gray">
No node_id present
</Label>
)}
</p>
{(details.reboot_required ||
details.category ||
details.severity) && (
<LabelGroup>
{details.reboot_required && (
<Label variant="outline" color="gray">
Reboot required
</Label>
)}
{details.category && (
<Label variant="outline" color="gray">
{details.category}
</Label>
)}
{details.severity && (
<Label
variant="outline"
color={severityLabelColor(details.severity)}
>
{details.severity}
</Label>
)}
</LabelGroup>
)}
</StackItem>
<StackItem>
<Stack hasGutter>
<StackItem>
<strong>Name:</strong>
{ruleDescription(details.name)}
</StackItem>
<StackItem>
<strong>Summary:</strong>
{ruleDescription(details.summary)}
</StackItem>
<StackItem>
<strong>Generic:</strong>
{ruleDescription(details.generic, true)}
</StackItem>
</Stack>
</StackItem>
<StackItem>
<Form>
<FormGroup
label="Free Style JSON input:"
type="string"
helperText={helperText}
helperTextInvalid="Not valid JSON"
fieldId="selection"
validated={freeStyleValidated}
>
<TextArea
value={freeStyle}
onChange={freeStyleChange}
isRequired
validated={freeStyleValidated}
aria-label="free style JSON input"
/>
</FormGroup>
</Form>
</StackItem>
</Stack>
</ExpandableSection>
</CardBody>
</Card>
<DataList
className="pyDataList"
aria-label="selectable data list example"
selectedDataListItemId={selectedListItem}
onSelectDataListItem={(id) =>
id !== selectedListItem
? setSelectedListItem(id)
: setSelectedListItem(0)
}
>
{contentDetailsHits.map((item, key) => (
<DataListItem
aria-labelledby="selectable-action-item1"
key={key + 1}
id={key + 1}
>
<DataListItemRow className="overFlow">
<DataListItemCells
dataListCells={[
<DataListCell key="primary content">
<Split hasGutter>
<SplitItem>
<b>{item.__name}</b>
</SplitItem>
<SplitItem>
<Label color="blue">{item.__source}</Label>
</SplitItem>
</Split>
<h5>{item.__date}</h5>
<pre>{JSON.stringify(pyFilter(item), null, 2)}</pre>
</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
))}
</DataList>
</Stack>
</GridItem>
<GridItem span={6}>
<ReportDetails
report={{
...details,
rule: details,
...(selectedPyData && { details: selectedPyData }),
...(validFreeStyle && { details: validFreeStyle }),
resolution: details.resolution
}}
kbaDetail={kbaDetailsData}
kbaLoading={kbaLoading}
/>
</GridItem>
</Grid>
</PageSection>
</Page>
);
}