@patternfly/react-core#Modal JavaScript Examples
The following examples show how to use
@patternfly/react-core#Modal.
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: delete-modal.js From ibutsu-server with MIT License | 6 votes |
render () {
return (
<Modal
variant={ModalVariant.small}
title={this.props.title}
isOpen={this.props.isOpen}
onClose={this.onClose}
actions={[
<Button key="delete" variant="danger" onClick={this.onDelete}>Delete</Button>,
<Button key="cancel" variant="link" onClick={this.onClose}>Cancel</Button>
]}
>
<Text>{this.props.body}</Text>
</Modal>
);
}
Example #2
Source File: new-dashboard-modal.js From ibutsu-server with MIT License | 6 votes |
render () {
return (
<Modal
variant={ModalVariant.small}
title="New Dashboard"
isOpen={this.props.isOpen}
onClose={this.onClose}
actions={[
<Button key="save" variant="primary" onClick={this.onSave}>Save</Button>,
<Button key="cancel" variant="link" onClick={this.onClose}>Cancel</Button>
]}
>
<Form>
<FormGroup label="Title" fieldId="dashboard-title" helperTextInvalid="A dashboard title is required" helperTextInvalidIcon={<ExclamationCircleIcon />} validated={this.state.isTitleValid} isRequired>
<TextInput type="text" id="dashboard-title" name="dashboard-title" value={this.state.title} onChange={this.onTitleChange} validated={this.state.isTitleValid} isRequired />
</FormGroup>
<FormGroup label="Description" fieldId="dashboard-description">
<TextInput type="text" id="dashboard-description" name="dashboard-description" value={this.state.description} onChange={this.onDescriptionChange} />
</FormGroup>
</Form>
</Modal>
);
}
Example #3
Source File: index.js From sed-frontend with Apache License 2.0 | 5 votes |
ConnectLog = () => {
const [activeTabKey, setActiveTabKey] = useState(0);
const dispatch = useDispatch();
const { push, location } = useHistory();
useEffect(() => {
dispatch(clearNotifications());
const searchParams = new URLSearchParams(location.search);
const activeTab = tabMapper.findIndex(
(item) => item === searchParams.get('active_tab')
);
if (activeTab !== -1) {
setActiveTabKey(activeTab);
} else {
push({
pathname: location.pathname,
search: new URLSearchParams({
active_tab: tabMapper[0],
}).toString(),
});
}
}, []);
return (
<Modal
title="Red Hat connect log"
variant="medium"
isOpen={true}
onClose={() => push(paths.connector)}
>
<Tabs
activeKey={activeTabKey}
onSelect={(_e, tabKey) => {
push({
pathname: location.pathname,
search: new URLSearchParams({
active_tab: tabMapper[tabKey],
}).toString(),
});
setActiveTabKey(tabKey);
}}
>
<Tab eventKey={0} title={<TabTitleText>Runs</TabTitleText>}>
<LogsTable />
</Tab>
<Tab eventKey={1} title={<TabTitleText>Systems</TabTitleText>}>
<SystemsTable />
</Tab>
</Tabs>
</Modal>
);
}
Example #4
Source File: add-token-modal.js From ibutsu-server with MIT License | 5 votes |
render () {
return (
<Modal
variant={ModalVariant.small}
title="Add Token"
isOpen={this.props.isOpen}
onClose={this.onClose}
actions={[
<Button key="save" variant="primary" onClick={this.onSave}>Save</Button>,
<Button key="cancel" variant="link" onClick={this.onClose}>Cancel</Button>
]}
>
<Form>
<FormGroup
label="Name"
fieldId="token-name"
helperTextInvalid="A token name is required"
helperTextInvalidIcon={<ExclamationCircleIcon />}
validated={this.state.isNameValid ? ValidatedOptions.default : ValidatedOptions.error}
isRequired
>
<TextInput
type="text"
id="token-name"
name="token-name"
value={this.state.name}
onChange={this.onNameChange}
validated={this.state.isNameValid ? ValidatedOptions.default : ValidatedOptions.error}
isRequired
/>
</FormGroup>
<FormGroup
label="Expiry"
fieldId="token-expiry-date"
helperTextInvalid="A valid epiry date is required"
helperTextInvalidIcon={<ExclamationCircleIcon />}
validated={this.state.isExpiryValid ? ValidatedOptions.default : ValidatedOptions.error}
isRequired
>
<DatePicker
onChange={this.onExpiryDateChange}
value={this.state.expiryDate}
inputProps={{
id: "token-expiry-date",
validated: this.state.isExpiryValid ? ValidatedOptions.default : ValidatedOptions.error
}}
/>
</FormGroup>
</Form>
</Modal>
);
}
Example #5
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 #6
Source File: EditActivationKeyModal.js From sed-frontend with Apache License 2.0 | 5 votes |
EditActivationKeyModal = (props) => {
const { activationKeyName } = props;
const queryClient = useQueryClient();
const [updated, setUpdated] = React.useState(false);
const [error, setError] = React.useState(false);
const { handleModalToggle, isOpen } = props;
const { mutate, isLoading } = useUpdateActivationKey();
const {
isLoading: isKeyLoading,
error: keyError,
data: activationKey,
} = useActivationKey(activationKeyName);
const submitForm = (name, role, serviceLevel, usage) => {
mutate(
{ activationKeyName, role, serviceLevel, usage },
{
onSuccess: () => {
setError(false);
setUpdated(true);
queryClient.invalidateQueries('activation_keys');
queryClient.resetQueries(`activation_key_${activationKeyName}`);
},
onError: () => {
setError(true);
setUpdated(false);
},
}
);
};
return (
<Modal
variant={ModalVariant.large}
title="Edit activation key"
description=""
isOpen={isOpen}
onClose={handleModalToggle}
>
{(isLoading || isKeyLoading) && !keyError ? (
<Loading />
) : (
<ActivationKeyForm
activationKey={activationKey}
handleModalToggle={handleModalToggle}
submitForm={submitForm}
isSuccess={updated}
isError={error}
/>
)}
</Modal>
);
}
Example #7
Source File: DeleteActivationKeyConfirmationModal.js From sed-frontend with Apache License 2.0 | 5 votes |
DeleteActivationKeyConfirmationModal = (props) => { const { isOpen, handleModalToggle, name } = props; const { addSuccessNotification, addErrorNotification } = useNotifications(); const { mutate, isLoading } = useDeleteActivationKey(); const queryClient = useQueryClient(); const deleteActivationKey = (name) => { mutate(name, { onSuccess: (_data, name) => { queryClient.setQueryData('activation_keys', (oldData) => oldData.filter((entry) => entry.name != name) ); addSuccessNotification(`Activation Key ${name} deleted`); handleModalToggle(); }, onError: () => { addErrorNotification('Something went wrong. Please try again'); handleModalToggle(); }, }); mutate; }; const actions = [ <Button key="confirm" variant="danger" onClick={() => deleteActivationKey(name)} data-testid="delete-activation-key-confirmation-modal-confirm-button" > Delete </Button>, <Button key="cancel" variant="link" onClick={handleModalToggle}> Cancel </Button>, ]; const title = ( <> <TextContent> <Text component={TextVariants.h2}> <ExclamationTriangleIcon size="md" color="#F0AB00" /> Delete Activation Key? </Text> </TextContent> </> ); const content = () => { if (isLoading) { return <Loading />; } else { return ( <TextContent> <Text component={TextVariants.p}> <b>{name}</b> will no longer be available for use. This operation cannot be undone. </Text> </TextContent> ); } }; return ( <Modal title={title} isOpen={isOpen} onClose={handleModalToggle} variant={ModalVariant.small} actions={actions} > {content()} </Modal> ); }
Example #8
Source File: CreateActivationKeyModal.js From sed-frontend with Apache License 2.0 | 5 votes |
CreateActivationKeyModal = (props) => {
const queryClient = useQueryClient();
const [created, setCreated] = React.useState(false);
const [error, setError] = React.useState(false);
const { handleModalToggle, isOpen } = props;
const { mutate, isLoading } = useCreateActivationKey();
const submitForm = (name, role, serviceLevel, usage) => {
mutate(
{ name, role, serviceLevel, usage },
{
onSuccess: () => {
setError(false);
setCreated(true);
queryClient.invalidateQueries('activation_keys');
},
onError: () => {
setError(true);
setCreated(false);
},
}
);
};
return (
<Modal
variant={ModalVariant.large}
title="Create new activation key"
description=""
isOpen={isOpen}
onClose={handleModalToggle}
>
{isLoading ? (
<Loading />
) : (
<ActivationKeyForm
handleModalToggle={handleModalToggle}
submitForm={submitForm}
isSuccess={created}
isError={error}
/>
)}
</Modal>
);
}
Example #9
Source File: index.js From sed-frontend with Apache License 2.0 | 5 votes |
ConfirmChangesModal = ({
isOpen = false,
handleCancel,
handleConfirm,
systemsCount,
data,
}) => {
return (
<Modal
variant="small"
title="Confirm changes"
isOpen={isOpen}
onClose={handleCancel}
actions={[
<Button
key="confirm"
variant="primary"
type="button"
onClick={handleConfirm}
>
Confirm changes
</Button>,
<Button
key="cancel"
variant="link"
type="button"
onClick={handleCancel}
>
Cancel
</Button>,
]}
>
<TextContent>
<Text component="p">
Your changes applies to{' '}
<b>
{systemsCount} connected {pluralize(systemsCount, 'system')}
</b>
. Selected settings will also be applied to <b>all future systems</b>{' '}
that are connected through remote host configuration (rhc).
</Text>
<Text component="p" className="pf-u-mb-sm">
Upon confirmation, an Ansible Playbook will be pushed to{' '}
{systemsCount} {pluralize(systemsCount, 'system')} to apply changes.
</Text>
</TextContent>
<Button
variant="link"
onClick={() => {
(async () => {
const playbook = await configApi.getPlaybookPreview({
compliance_openscap: data.useOpenSCAP ? 'enabled' : 'disabled',
insights: data.hasInsights ? 'enabled' : 'disabled',
remediations: data.enableCloudConnector ? 'enabled' : 'disabled',
});
downloadFile(playbook);
})();
}}
style={{ paddingLeft: 0 }}
>
View playbook
</Button>
</Modal>
);
}
Example #10
Source File: user-list.js From ibutsu-server with MIT License | 5 votes |
render() {
document.title = 'Users - 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 user..." value={textFilter || ''} onChange={this.onTextChanged} style={{height: "inherit"}} key="textFilter"/>
];
return (
<React.Fragment>
<PageSection id="page" variant={PageSectionVariants.light}>
<TextContent>
<Text className="title" component="h1" ouiaId="users">Users</Text>
</TextContent>
</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" isLoading={this.state.isDeleting} isDisabled={this.state.isDeleting} onClick={this.onModalDeleteClick}>
{this.state.isDeleting ? 'Deleting...' : 'Delete'}
</Button>,
<Button key="cancel" variant="secondary" isDisabled={this.state.isDeleting} onClick={this.onDeleteModalClose}>
Cancel
</Button>
]}
>
Are you sure you want to delete “{this.state.selectedUser && this.state.selectedUser.name}”? This cannot be undone!
</Modal>
</React.Fragment>
);
}
Example #11
Source File: ModalConfirm.js From cockpit-wicked with GNU General Public License v2.0 | 5 votes |
ModalConfirm = ({
caption,
title,
isOpen = false,
onConfirm,
onConfirmDisable = false,
onConfirmLabel = _("Confirm"),
onCancel,
onCancelLabel = _("Cancel"),
variant = ModalVariant.small,
children
}) => {
if (!isOpen) return;
return (
<Modal
aria-label={title}
variant={variant}
isOpen={isOpen}
showClose={false}
header={
<>
<Text component={TextVariants.small} className='modal-form-caption'>
{caption}
</Text>
<Title headingLevel="h1">
{title}
</Title>
</>
}
footer={
<ActionGroup>
<Button key="confirm" variant="danger" onClick={onConfirm}>
{onConfirmLabel}
</Button>
<Button key="cancel" variant="link" onClick={onCancel}>
{onCancelLabel}
</Button>
</ActionGroup>
}
>
{children}
</Modal>
);
}
Example #12
Source File: Modal.js From edge-frontend with Apache License 2.0 | 5 votes |
RepoModal = ({
isOpen,
title,
titleIconVariant,
openModal, // should be closeModal, update here and other places that use it
submitLabel,
schema,
initialValues,
variant,
reloadData,
size,
onSubmit,
additionalMappers,
}) => {
return (
<Modal
variant={size ?? 'small'}
title={title}
titleIconVariant={titleIconVariant ?? null}
isOpen={isOpen}
onClose={openModal}
>
<FormRenderer
schema={schema}
FormTemplate={(props) => (
<FormTemplate
{...props}
submitLabel={submitLabel}
disableSubmit={['invalid']}
buttonsProps={{
submit: { variant },
}}
/>
)}
initialValues={initialValues}
componentMapper={
additionalMappers
? { ...additionalMappers, ...componentMapper }
: componentMapper
}
onSubmit={async (values) => {
await onSubmit(values);
setTimeout(async () => await reloadData(), 500);
openModal();
}}
onCancel={() => openModal()}
/>
</Modal>
);
}
Example #13
Source File: AuthModal.js From edge-frontend with Apache License 2.0 | 5 votes |
AuthModal = () => {
return (
<Modal
style={{ padding: '15px' }}
isOpen={true}
variant="small"
onClose={() => (window.location.href = 'https://console.redhat.com/')}
aria-label="auth-modal"
header={
<h2 className="pf-u-pr-xl pf-u-pl-xl pf-u-font-size-2xl pf-u-text-align-center pf-u-font-weight-bold">
Edge management requires a valid Smart Management subscription
</h2>
}
footer={
<ModalBoxFooter
style={{
display: 'flex',
justifyContent: 'center',
width: '100%',
flexDirection: 'column',
paddingTop: 0,
}}
>
<Button
key="get-started"
component="a"
className="pf-u-mb-md"
variant="primary"
target="_blank"
href="https://www.redhat.com/en/technologies/linux-platforms/enterprise-linux/try-it"
>
Get started
</Button>
<Button
component="a"
key="interactive-demo"
className="pf-u-mb-md"
variant="secondary"
target="_blank"
href="https://red.ht/edgemanagementlab"
>
Try the interactive demo
</Button>
<Button
component="a"
key="not-now"
variant="link"
href="https://console.redhat.com/"
>
Not now
</Button>
</ModalBoxFooter>
}
title="Edge management requires a valid subscription"
width="640px"
>
<img
style={{ margin: '0 auto', display: 'block' }}
src={edgeIcon}
width="200px"
alt="edge icon"
/>
<p className="pf-u-pr-xl pf-u-pl-xl pf-u-text-align-center">
Securely manage and scale deployments at the edge with zero-touch
provisioning, system health visibility, and quick security remediations
and more with a Red Hat Smart Management subscription
</p>
</Modal>
);
}
Example #14
Source File: AddSystemsToGroupModal.js From edge-frontend with Apache License 2.0 | 5 votes |
AddSystemsToGroupModal = ({
groupId,
closeModal,
isOpen,
reloadData,
groupName,
}) => {
const [response, fetchDevices] = useApi({
api: getInventory,
tableReload: true,
});
const { data, isLoading, hasError } = response;
const [deviceIds, setDeviceIds] = useState([]);
const dispatch = useDispatch();
const handleAddDevicesToGroup = () => {
const statusMessages = {
onSuccess: {
title: 'Success',
description: `Device(s) have been added to ${groupName} successfully`,
},
onError: {
title: 'Error',
description: `An error occurred making the request`,
},
};
apiWithToast(
dispatch,
() =>
addDevicesToGroup(
parseInt(groupId),
deviceIds.map((device) => ({ ID: device.deviceID }))
),
statusMessages
);
setTimeout(async () => await reloadData(), 500);
closeModal();
};
return (
<Modal
id="add-systems-modal"
title="Add systems"
position="top"
isOpen={isOpen}
onClose={closeModal}
variant="large"
actions={[
<Button
isDisabled={deviceIds.length === 0}
key="confirm"
variant="primary"
onClick={handleAddDevicesToGroup}
>
Add systems
</Button>,
<Button key="cancel" variant="link" onClick={closeModal}>
Cancel
</Button>,
]}
>
<DeviceTable
selectedItems={setDeviceIds}
skeletonRowQuantity={15}
hasCheckbox={true}
isLoading={isLoading}
hasError={hasError}
count={data?.count}
data={data?.data?.devices || []}
fetchDevices={fetchDevices}
/>
</Modal>
);
}
Example #15
Source File: ModalForm.js From cockpit-wicked with GNU General Public License v2.0 | 5 votes |
ModalForm = ({
caption,
title,
isOpen = false,
onSubmit,
onSubmitDisable = false,
onSubmitLabel = _("Apply"),
onCancel,
onCancelLabel = _("Cancel"),
variant = ModalVariant.small,
children
}) => {
if (!isOpen) return;
return (
<Modal
aria-label={title}
variant={variant}
isOpen={isOpen}
showClose={false}
header={
<>
<Text component={TextVariants.small} className='modal-form-caption'>
{caption}
</Text>
<Title headingLevel="h1">
{title}
</Title>
</>
}
footer={
<ActionGroup>
<Button key="submit" onClick={onSubmit} isDisabled={onSubmitDisable}>
{onSubmitLabel}
</Button>
<Button key="cancel" variant="link" onClick={onCancel}>
{onCancelLabel}
</Button>
</ActionGroup>
}
>
<Form>
{children}
</Form>
</Modal>
);
}
Example #16
Source File: CancelRequestModal.js From access-requests-frontend with Apache License 2.0 | 5 votes |
CancelRequestModal = ({ requestId, onClose }) => {
const [isLoading, setIsLoading] = React.useState(false);
const dispatch = useDispatch();
const onCancel = () => {
setIsLoading(true);
// https://ci.cloud.redhat.com/docs/api-docs/rbac#operations-CrossAccountRequest-patchCrossAccountRequest
apiInstance
.patch(
`${API_BASE}/cross-account-requests/${requestId}/`,
{ status: 'cancelled' },
{
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
}
)
.then((res) => {
if (res.errors && res.errors.length > 0) {
throw Error(res.errors.map((e) => e.detail).join('\n'));
}
dispatch(
addNotification({
variant: 'success',
title: 'Request cancelled successfully',
})
);
setIsLoading(false);
onClose(true);
})
.catch((err) => {
dispatch(
addNotification({
variant: 'danger',
title: 'There was an error cancelling your request',
description: err.message,
})
);
setIsLoading(false);
onClose(true);
});
};
return (
<Modal
title="Cancel request?"
isOpen
variant="small"
onClose={() => onClose(false)}
actions={[
<Button key="confirm" variant="danger" onClick={onCancel}>
Yes, cancel
</Button>,
<Button key="cancel" variant="link" onClick={() => onClose(false)}>
No, keep
</Button>,
]}
>
Request <b>{requestId}</b> will be withdrawn.
{isLoading && <Spinner size="lg" />}
</Modal>
);
}
Example #17
Source File: WirelessForm.js From cockpit-wicked with GNU General Public License v2.0 | 4 votes |
WirelessForm = ({ isOpen, onClose, iface, connection }) => {
const { wireless } = connection || {};
const isEditing = !!connection;
const [essid, setEssid] = useState(wireless?.essid);
const [mode, setMode] = useState(wireless?.mode || wirelessModes.MANAGED);
const [authMode, setAuthMode] = useState(wireless?.authMode || wirelessAuthModes.WEP_OPEN);
const [password, setPassword] = useState(wireless?.password || "");
const dispatch = useNetworkDispatch();
const addOrUpdateConnection = () => {
if (isEditing) {
updateConnection(
dispatch, connection,
{ wireless: { essid, mode, authMode, password } }
);
} else {
addConnection(
dispatch, { name: iface.name, type: interfaceType.WIRELESS, wireless: { essid, mode, authMode, password } }
);
}
onClose();
};
return (
<Modal
variant={ModalVariant.small}
title={isEditing ? _("Edit WiFi settings") : _("Add WiFi settings")}
isOpen={isOpen}
onClose={onClose}
actions={[
<Button key="confirm" variant="primary" onClick={addOrUpdateConnection}>
{isEditing ? _("Change") : _("Add")}
</Button>,
<Button key="cancel" variant="link" onClick={onClose}>
{_("Cancel")}
</Button>
]}
>
<Form>
<FormGroup
label={_("Mode")}
isRequired
fieldId="wireless-mode"
>
<FormSelect value={mode} onChange={setMode} id="wireless-mode">
{modeOptions.map((option, index) => (
<FormSelectOption key={index} {...option} />
))}
</FormSelect>
</FormGroup>
<FormGroup
label={_("ESSID")}
isRequired
fieldId="essid"
>
<WirelessEssidSelect essid={essid} setEssid={setEssid} iface={iface} />
</FormGroup>
<FormGroup
label={_("Auth Mode")}
isRequired
fieldId="wireless-auth-mode"
>
<FormSelect value={authMode} onChange={setAuthMode} id="wireless-auth-mode">
{authModeOptions.map((option, index) => (
<FormSelectOption key={index} {...option} />
))}
</FormSelect>
</FormGroup>
{ (authMode === "psk") &&
<FormGroup
label={_("Password")}
isRequired
fieldId="password"
>
<TextInput
isRequired
id="password"
value={password}
onChange={setPassword}
type='password'
/>
</FormGroup>}
</Form>
</Modal>
);
}
Example #18
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 #19
Source File: new-widget-wizard.js From ibutsu-server with MIT License | 4 votes |
render() {
const { widgetTypes, selectedType, selectedTypeId, stepIdReached, isTitleValid, areParamsFilled } = this.state;
const steps = [
{
id: 1,
name: 'Select type',
enableNext: selectedType,
component: (
<Form>
<Title headingLevel="h1" size="xl">Select a widget type</Title>
{widgetTypes.map(widgetType => {
return (
<div key={widgetType.id}>
<Radio id={widgetType.id} value={widgetType.id} label={widgetType.title} description={widgetType.description} isChecked={selectedTypeId === widgetType.id} onChange={this.onSelectType}/>
</div>
);
})}
</Form>
)
},
{
id: 2,
name: 'Set info',
canJumpTo: stepIdReached >= 2,
enableNext: isTitleValid,
component: (
<Form isHorizontal>
<Title headingLevel="h1" size="xl">Set widget information</Title>
<FormGroup label="Title" fieldId="widget-title" helperText="A title for the widget" validated={this.isTitleValid} helperTextInvalid="Please enter a title for this widget" helperTextInvalidIcon={<ExclamationCircleIcon/>} isRequired>
<TextInput type="text" id="widget-title" name="widget-title" value={this.state.title} onChange={this.onTitleChange} validated={this.state.isTitleValid} isRequired />
</FormGroup>
<FormGroup label="Weight" fieldId="widget-weight" helperText="How widgets are ordered on the dashboard">
<TextInput type="number" id="widget-weight" name="widget-weight" value={this.state.weight} onChange={this.onWeightChange} />
</FormGroup>
</Form>
)
},
{
id: 3,
name: 'Set parameters',
canJumpTo: stepIdReached >= 3,
enableNext: areParamsFilled,
component: (
<Form isHorizontal>
<Title headingLevel="h1" size="xl">Set widget parameters</Title>
{!!selectedType && selectedType.params.map(param => {
return (
<React.Fragment key={param.name}>
{(param.type === 'string' || param.type === 'integer' || param.type === 'float') &&
<FormGroup
label={param.name}
fieldId={param.name}
helperText={<Linkify componentDecorator={linkifyDecorator}>{param.description}</Linkify>}
isRequired={param.required}>
<TextInput
value={this.state.params[param.name]}
type={(param.type === 'integer' || param.type === 'float') ? 'number' : 'text'}
id={param.name}
aria-describedby={`${param.name}-helper`}
name={param.name}
onChange={this.onParamChange}
isRequired={param.required}
/>
</FormGroup>
}
{param.type === 'boolean' &&
<FormGroup
label={param.name}
fieldId={param.name}
isRequired={param.required}
hasNoPaddingTop>
<Checkbox
isChecked={this.state.params[param.name]}
onChange={this.onParamChange}
id={param.name}
name={param.name}
label={param.description} />
</FormGroup>
}
{param.type === 'list' &&
<FormGroup
label={param.name}
fieldId={param.name}
helperText={`${param.description}. Place items on separate lines.`}>
isRequired={param.required}
<TextArea
id={param.name}
name={param.name}
isRequired={param.required}
value={this.state.params[param.name]}
onChange={this.onParamChange}
resizeOrientation='vertical' />
</FormGroup>
}
</React.Fragment>
);
})}
</Form>
)
},
{
id: 4,
name: 'Review details',
canJumpTo: stepIdReached >= 4,
nextButtonText: 'Finish',
component: (
<Stack hasGutter>
<StackItem>
<Title headingLevel="h1" size="xl">Review details</Title>
</StackItem>
<StackItem>
<Grid hasGutter>
<GridItem span="2">
<Title headingLevel="h4">Title</Title>
</GridItem>
<GridItem span="10">
<TextContent><Text>{this.state.title}</Text></TextContent>
</GridItem>
<GridItem span="2">
<Title headingLevel="h4">Weight</Title>
</GridItem>
<GridItem span="10">
<TextContent><Text>{this.state.weight}</Text></TextContent>
</GridItem>
<GridItem span="2">
<Title headingLevel="h4">Parameters</Title>
</GridItem>
<GridItem span="10">
<Table
cells={["Name", "Value"]}
variant="compact"
borders="compactBorderless"
rows={Object.entries(this.state.params).map(param => { return [param[0], param[1].toString()]; })}
aria-label="Parameters">
<TableHeader />
<TableBody />
</Table>
</GridItem>
</Grid>
</StackItem>
</Stack>
)
}
];
return (
<Modal
isOpen={this.props.isOpen}
variant={ModalVariant.large}
showClose={false}
onClose={this.onClose}
hasNoBodyWrapper
aria-describedby="add-widget-description"
aria-labelledby="add-widget-title"
>
<Wizard
titleId="add-widget-title"
descriptionId="add-widget-description"
title="Add Widget"
description="Add a widget to the current dashboard"
steps={steps}
onNext={this.onNext}
onSave={this.onSave}
onClose={this.onClose}
height={400}
/>
</Modal>
);
}
Example #20
Source File: requestCertificate.jsx From cockpit-certificates with GNU Lesser General Public License v2.1 | 4 votes |
RequestCertificateModal = ({ onClose, hostname, cas, addAlert, mode }) => {
const [_userChangedNickname, setUserChangedNickname] = useState(false);
const [ca, _setCa] = useState(cas[Object.keys(cas)[0]] ? cas[Object.keys(cas)[0]].nickname.v : undefined);
const [storage, setStorage] = useState(mode === "request" ? "nssdb" : "file");
const [nickname, _setNickname] = useState(makeNickName(hostname, ca));
const [certFile, setCertFile] = useState("");
const [keyFile, setKeyFile] = useState("");
const [subjectName, setSubjectName] = useState("");
const [dnsName, _setDnsName] = useState("");
const [principalName, setPricipalName] = useState("");
const [signingParameters, setSigningParameters] = useState("");
const [errorName, setErrorName] = useState();
const [errorMessage, setErrorMessage] = useState();
const setCa = value => {
if (!_userChangedNickname)
_setNickname(makeNickName(hostname, value));
_setCa(value);
};
const setNickname = value => {
setUserChangedNickname(true);
_setNickname(value);
};
const setDnsName = value => {
value = value.replace(/\s/g, ',');
while (value.includes(",,"))
value = value.replace(",,", ',');
_setDnsName(value);
};
const onRequest = () => {
const casKeys = Object.keys(cas);
let caPath;
casKeys.forEach(key => {
if (cas[key].nickname.v === ca)
caPath = key;
});
const parameter = {
"cert-storage": cockpit.variant("s", storage),
"key-storage": cockpit.variant("s", storage),
ca: cockpit.variant("s", caPath),
};
if (storage === "nssdb") {
parameter["cert-database"] = cockpit.variant("s", NSSDB_PATH);
parameter["cert-nickname"] = cockpit.variant("s", nickname);
parameter["key-database"] = cockpit.variant("s", NSSDB_PATH);
parameter["key-nickname"] = cockpit.variant("s", nickname);
} else { // file
parameter["cert-file"] = cockpit.variant("s", certFile);
parameter["key-file"] = cockpit.variant("s", keyFile);
}
if (signingParameters) {
let subjectNameParam;
if (subjectName && !subjectName.includes("="))
subjectNameParam = "CN=" + subjectName;
let dnsNamesParam = dnsName.split(',');
dnsNamesParam = dnsNamesParam.filter(Boolean); // Removes empty string entries
if (subjectName)
parameter["template-subject"] = cockpit.variant("s", subjectNameParam);
if (principalName)
parameter["template-principal"] = cockpit.variant("as", [principalName]);
if (dnsName)
parameter["template-hostname"] = cockpit.variant("as", dnsNamesParam);
}
addRequest(parameter)
.then(onClose)
.catch(error => {
setErrorName(error.name);
setErrorMessage(error.message);
});
};
const body = (
<Form isHorizontal>
<CAsRow ca={ca} setCa={setCa} cas={Object.values(cas)} />
<StorageRow storage={storage} setStorage={setStorage} />
{storage === "nssdb" &&
<NicknameRow nickname={nickname} setNickname={setNickname} />}
{storage === "file" && <>
<CertFileRow setCertFile={setCertFile} mode={mode} />
<KeyFileRow setKeyFile={setKeyFile} mode={mode} />
</>}
<SetSigningParametersRow signingParameters={signingParameters} setSigningParameters={setSigningParameters} />
{signingParameters && <>
<SubjectNameRow subjectName={subjectName} setSubjectName={setSubjectName} />
<DNSNameRow dnsName={dnsName} setDnsName={setDnsName} />
<PrincipalNameRow principalName={principalName} setPricipalName={setPricipalName} />
</>}
</Form>
);
return (
<Modal id="request-certificate-dialog" onClose={onClose}
position="top" variant="medium"
isOpen
title={mode === "request" ? _("Request certificate") : _("Import certificate")}
footer={<>
{errorName && <ModalError dialogError={errorName} dialogErrorDetail={errorMessage} />}
<Button variant="primary"
onClick={onRequest}>
{mode === "request" ? _("Request") : _("Import")}
</Button>
<Button variant="link" className="btn-cancel" onClick={onClose}>
{_("Cancel")}
</Button>
</>}>
{body}
</Modal>
);
}
Example #21
Source File: requestCertificate.jsx From cockpit-certificates with GNU Lesser General Public License v2.1 | 4 votes |
ResubmitCertificateModal = ({ onClose, cas, addAlert, cert, certPath, mode }) => {
const [ca, setCa] = useState(getCAName(cas, cert));
const [subjectName, setSubjectName] = useState(cert.subject && cert.subject.v);
const [dnsName, _setDnsName] = useState(cert.hostname && cert.hostname.v.join(','));
const [principalName, setPricipalName] = useState(cert.principal && cert.principal.v.join(','));
const [errorName, setErrorName] = useState("");
const [errorMessage, setErrorMessage] = useState("");
const setDnsName = (value) => {
let newValue = value.replace(/\s/g, ',');
while (newValue.includes(",,"))
newValue = value.replace(",,", ',');
_setDnsName(newValue);
};
const onResubmit = () => {
const casKeys = Object.keys(cas);
let caPath;
casKeys.forEach(key => {
if (cas[key].nickname.v === ca)
caPath = key;
});
let subjectNameParam = subjectName;
if (subjectNameParam && !subjectNameParam.includes("="))
subjectNameParam = "CN=" + subjectNameParam;
let dnsNameParam;
if (dnsName) {
dnsNameParam = dnsName.split(',');
dnsNameParam = dnsNameParam.filter(Boolean); // Removes empty string entries
}
const parameter = { ca: cockpit.variant("s", caPath) };
parameter["template-subject"] = cockpit.variant("s", subjectNameParam || "");
parameter["template-principal"] = cockpit.variant("as", [principalName || ""]);
parameter["template-hostname"] = cockpit.variant("as", dnsNameParam || [""]);
modifyRequest(certPath, parameter)
.then(() => resubmitRequest(certPath))
.then(onClose)
.catch(error => {
setErrorName(error.name);
setErrorMessage(error.message);
});
};
const body = (
<Form isHorizontal>
{cert["cert-storage"].v === "NSSDB" && <>
<FormGroup label={_("Database path")} hasNoPaddingTop>
<span id="database-path-row">{ cert["cert-database"].v }</span>
</FormGroup>
<FormGroup label={_("Nickname")} hasNoPaddingTop>
<span id="nickname-row">{ cert["cert-nickname"].v }</span>
</FormGroup>
</>}
{cert["cert-storage"].v === "FILE" && <>
<FormGroup label={_("Certificate file")} hasNoPaddingTop>
<span id="cert-file-row">{ cert["cert-file"].v }</span>
</FormGroup>
<FormGroup label={_("Key file")} hasNoPaddingTop>
<span id="key-file-row">{ cert["key-file"].v }</span>
</FormGroup>
</>}
<CAsRow ca={ca} setCa={setCa} cas={Object.values(cas)} />
<SubjectNameRow subjectName={subjectName} setSubjectName={setSubjectName} />
<DNSNameRow dnsName={dnsName} setDnsName={setDnsName} />
<PrincipalNameRow principalName={principalName} setPricipalName={setPricipalName} />
</Form>
);
return (
<Modal id="resubmit-certificate-dialog"
position="top" variant="medium"
onClose={onClose}
isOpen
title={_("Resubmit Certificate")}
footer={<>
{errorName && <ModalError dialogError={errorName} dialogErrorDetail={errorMessage} />}
<Button variant="primary" onClick={onResubmit}>
{_("Resubmit")}
</Button>
<Button variant="link" className="btn-cancel" onClick={onClose}>
{_("Cancel")}
</Button>
</>}>
{body}
</Modal>
);
}
Example #22
Source File: certificateActions.jsx From cockpit-certificates with GNU Lesser General Public License v2.1 | 4 votes |
RemoveModal = ({ onClose, certs, cert, certPath, addAlert, appOnValueChanged, idPrefix }) => {
const [deleteFiles, setDeleteFiles] = useState(false);
const onRemoveResponse = () => {
delete certs[certPath];
appOnValueChanged("certs, certs");
onClose();
};
const onRemove = () => {
if (deleteFiles) {
cockpit.file(cert["key-file"].v, { superuser: "try" }).replace(null) // delete key file
.then(() => cockpit.file(cert["cert-file"].v, { superuser: "try" }).replace(null)) // delete cert file
.then(() => removeRequest(certPath))
// There is no dbus signal for cert removal, so we have to update UI manually
.then(() => onRemoveResponse())
.catch(error => {
addAlert(_("Error: ") + (error.name || error.problem), error.message);
onClose();
});
} else {
removeRequest(certPath)
// There is no dbus signal for cert removal, so we have to update UI manually
.then(() => onRemoveResponse())
.catch(error => {
addAlert(_("Error: ") + error.name, error.message);
onClose();
});
}
};
const title = _("Remove certificate: ") + (cert["cert-storage"].v === "FILE" ? cert.nickname.v : cert["cert-nickname"].v);
const fileCertBody = (
<Form isHorizontal>
<FormGroup label={_("Certificate file")} hasNoPaddingTop>
<samp id={idPrefix + "cert-file"}>
{cert["cert-file"].v}
</samp>
</FormGroup>
<FormGroup label={_("Key file")}>
<samp id={idPrefix + "key-file"} hasNoPaddingTop>
{cert["key-file"].v}
</samp>
</FormGroup>
</Form>
);
const nssdbCertBody = (
<Form isHorizontal>
<FormGroup label={_("NSSDB path")} hasNoPaddingTop>
<samp id={idPrefix + "cert-database"}>
{cert["cert-database"].v}
</samp>
</FormGroup>
<FormGroup label={_("Nickname")} hasNoPaddingTop>
<samp id={idPrefix + "cert-nickname"}>
{cert["cert-nickname"].v}
</samp>
</FormGroup>
</Form>
);
const body = (<>
{ cert["cert-storage"].v === "FILE" ? fileCertBody : nssdbCertBody }
{ cert["key-file"] && cert["cert-file"] && cert["key-file"].v && cert["cert-file"].v && (
<Checkbox id={idPrefix + "-delete-files"}
className="checkbox-delete-files"
isChecked={deleteFiles}
label={_("Also delete certificate and key files")}
onChange={e => setDeleteFiles(!deleteFiles)} />
)}
</>);
return (
<Modal id={idPrefix + "-remove-dialog"}
position="top" variant="medium"
onClose={onClose}
isOpen
title={title}
footer={<>
<Button variant="danger" onClick={onRemove}>
{ deleteFiles ? _("Remove and delete") : _("Remove") }
</Button>
<Button variant="link" className="btn-cancel" onClick={onClose}>
{_("Cancel")}
</Button>
</>}>
{body}
</Modal>
);
}
Example #23
Source File: ViewHostAcks.js From ocp-advisor-frontend with Apache License 2.0 | 4 votes |
ViewHostAcks = ({
handleModalToggle,
isModalOpen,
clusters,
recId,
afterFn,
}) => {
const intl = useIntl();
const dispatch = useDispatch();
const addNotification = (data) => dispatch(notification(data));
const { data, isFetching, isLoading, refetch } = clusters;
const hostAcks = data?.disabled || [];
const [rows, setRows] = useState([]);
const [unclean, setUnclean] = useState(false);
const columns = [
{
title: intl.formatMessage(messages.clusterName),
transforms: [cellWidth(50)],
},
{
title: intl.formatMessage(messages.justificationNote),
transforms: [cellWidth(25)],
},
{
title: intl.formatMessage(messages.dateDisabled),
transforms: [cellWidth(15)],
},
'',
];
const deleteAck = async (host) => {
try {
await enableRuleForCluster({ uuid: host.cluster_id, recId });
refetch();
setUnclean(true);
} catch (error) {
handleModalToggle(false);
addNotification({
variant: 'danger',
dismissable: true,
title: intl.formatMessage(messages.error),
description: `${error}`,
});
}
};
useEffect(() => {
const rows = hostAcks?.map((item) => ({
cells: [
item.cluster_name || item.cluster_id,
item.justification || intl.formatMessage(messages.none),
{
title: (
<DateFormat date={new Date(item.disabled_at)} type="onlyDate" />
),
},
{
title: (
<Button
key={item.cluster_id}
ouiaId="enable"
isInline
variant="link"
onClick={() => deleteAck(item)}
>
<OutlinedBellIcon size="sm" />
{` ${intl.formatMessage(messages.enable)}`}
</Button>
),
},
],
}));
if (!isLoading && hostAcks.length === 0) {
afterFn();
handleModalToggle(false);
}
setRows(rows);
}, [hostAcks]);
return (
<Modal
width={'75%'}
title={intl.formatMessage(messages.hostAckModalTitle)}
isOpen={isModalOpen}
onClose={() => {
unclean && afterFn();
handleModalToggle(false);
}}
>
{!isFetching ? (
<Table aria-label="host-ack-table" rows={rows} cells={columns}>
<TableHeader />
<TableBody />
</Table>
) : (
<Table
aria-label="host-ack-table"
rows={[
{
cells: [{ props: { colSpan: 3 }, title: <List /> }],
},
]}
cells={columns}
>
<TableHeader />
<TableBody />
</Table>
)}
</Modal>
);
}
Example #24
Source File: DisableRule.js From ocp-advisor-frontend with Apache License 2.0 | 4 votes |
DisableRule = ({
isModalOpen,
handleModalToggle,
rule,
afterFn,
host,
hosts,
}) => {
const intl = useIntl();
const [justification, setJustificaton] = useState('');
const [singleHost, setSingleHost] = useState(!!host);
const [multipleHosts, setMultipleHosts] = useState(hosts.length > 0);
const [setAck] = useSetAckMutation();
const dispatch = useDispatch();
const notify = (data) => dispatch(addNotification(data));
const bulkHostActions = async () => {
// disable for a group of hosts (clusters)
try {
const requests = hosts.map((h) =>
disableRuleForCluster({
uuid: h.id,
recId: rule.rule_id,
justification,
})
);
await Promise.all(requests);
notify({
variant: 'success',
dismissable: true,
timeout: true,
title: intl.formatMessage(messages.recSuccessfullyDisabledForCluster),
});
afterFn && afterFn();
} catch (error) {
notify({
variant: 'danger',
dismissable: true,
title: intl.formatMessage(messages.error),
description: `${error}`,
});
}
};
const disableRule = async () => {
try {
if (singleHost) {
// disable the rec for this single cluster
await disableRuleForCluster({
uuid: host,
recId: rule.rule_id,
justification,
});
notify({
variant: 'success',
timeout: true,
dismissable: true,
title: intl.formatMessage(messages.recSuccessfullyDisabledForCluster),
});
} else if (multipleHosts) {
bulkHostActions();
} else {
// disable the whole rec
await setAck({
rule_id: rule.rule_id,
justification,
}).unwrap();
notify({
variant: 'success',
timeout: true,
dismissable: true,
title: intl.formatMessage(messages.recSuccessfullyDisabled),
});
}
setJustificaton('');
afterFn && afterFn();
} catch (error) {
notify({
variant: 'danger',
dismissable: true,
title: intl.formatMessage(messages.error),
description: `${error}`,
});
}
handleModalToggle(false);
};
return (
<Modal
variant="small"
title={intl.formatMessage(messages.disableRule)}
isOpen={isModalOpen}
onClose={() => {
handleModalToggle();
setJustificaton('');
}}
actions={[
<Button
key="confirm"
variant="primary"
onClick={() => disableRule()}
ouiaId="confirm"
>
{intl.formatMessage(messages.save)}
</Button>,
<Button
key="cancel"
variant="link"
onClick={() => {
handleModalToggle(false);
setJustificaton('');
}}
ouiaId="cancel"
>
{intl.formatMessage(messages.cancel)}
</Button>,
]}
ouiaId="recommendation-disable"
>
{intl.formatMessage(messages.disableRuleBody)}
<Form>
<FormGroup fieldId="blank-form" />
{(host || hosts.length > 0) && (
<FormGroup fieldId="disable-rule-one-system">
<Checkbox
isChecked={singleHost || multipleHosts}
onChange={() => {
host
? setSingleHost(!singleHost)
: setMultipleHosts(!multipleHosts);
}}
label={
host
? intl.formatMessage(messages.disableRuleSingleCluster)
: intl.formatMessage(messages.disableRuleForClusters)
}
id="disable-rule-one-system"
name="disable-rule-one-system"
ouiaId="disable-recommendation-one-cluster"
/>
</FormGroup>
)}
<FormGroup
label={intl.formatMessage(messages.justificationNote)}
fieldId="disable-rule-justification"
>
<TextInput
type="text"
id="disable-rule-justification"
aria-describedby="disable-rule-justification"
value={justification}
onChange={(text) => setJustificaton(text)}
onKeyDown={(e) =>
e.key === 'Enter' && (e.preventDefault(), disableRule())
}
/>
</FormGroup>
</Form>
</Modal>
);
}
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: EditRequestModal.js From access-requests-frontend with Apache License 2.0 | 4 votes |
EditRequestModal = ({ requestId, variant, onClose }) => {
const isEdit = variant === 'edit';
const [isLoading, setIsLoading] = React.useState(true);
const [error, setError] = React.useState();
const [user, setUser] = React.useState();
const [targetAccount, setTargetAccount] = React.useState();
const [targetOrg, setTargetOrg] = React.useState();
const [start, setStart] = React.useState();
const [end, setEnd] = React.useState();
const [roles, setRoles] = React.useState([]);
const [warnClose, setWarnClose] = React.useState(false);
const [step, setStep] = React.useState(1);
const dispatch = useDispatch();
const isDirty = Boolean(targetAccount || start || end || roles.length > 0);
// We need to be logged in (and see the username) which is an async request.
// If we're editing we also need to fetch the roles
React.useEffect(() => {
const userPromise = window.insights.chrome.auth.getUser();
const detailsPromise = isEdit
? apiInstance.get(
`${API_BASE}/cross-account-requests/${requestId}/?query_by=user_id`,
{
headers: { Accept: 'application/json' },
}
)
: new Promise((res) => res(true));
Promise.all([userPromise, detailsPromise])
.then(([user, details]) => {
if (user && user.identity && user.identity.user) {
setUser(user.identity.user);
} else {
throw Error("Couldn't get current user. Make sure you're logged in");
}
if (isEdit) {
if (details.errors) {
throw Error(details.errors.map((e) => e.detail).join('\n'));
}
if (details && details.target_account) {
setTargetAccount(details.target_account);
setStart(details.start_date);
setEnd(details.end_date);
setRoles(details.roles.map((role) => role.display_name));
setTargetOrg(details.target_org);
} else {
throw Error(`Could not fetch details for request ${requestId}`);
}
}
setIsLoading(false);
})
.catch((err) => {
dispatch(
addNotification({
variant: 'danger',
title: 'Could not load access request',
description: err.message,
})
);
});
}, []);
const onSave = () => {
setIsLoading(true);
// https://cloud.redhat.com/docs/api-docs/rbac#operations-CrossAccountRequest-createCrossAccountRequests
const body = {
target_account: targetAccount,
start_date: start,
end_date: end,
target_org: targetOrg,
roles,
};
apiInstance[isEdit ? 'put' : 'post'](
`${API_BASE}/cross-account-requests/${isEdit ? `/${requestId}/` : ''}`,
body,
{
headers: {
'Content-Type': 'application/json',
Accept: 'application/json',
},
}
)
.then((res) => {
if (res.errors && res.errors.length > 0) {
throw Error(res.errors[0].detail);
}
dispatch(
addNotification({
variant: 'success',
title: `${isEdit ? 'Edited' : 'Created'} access request`,
description: res.request_id,
})
);
onClose(true);
})
.catch((err) => {
const isInvalidAccount = /Account .* does not exist/.test(err.message);
setError({
title: isInvalidAccount
? invalidAccountTitle
: `Could not ${variant} access request`,
description: isInvalidAccount
? 'Please return to Step 1: Request details and input a new account number for your request.'
: err.message,
});
setIsLoading(false);
});
};
const step1Complete = [targetAccount, start, end].every(Boolean);
const step2Complete = roles.length > 0;
const steps = [
{
id: 1,
name: 'Request details',
component: (
<RequestDetailsForm
user={user}
targetAccount={targetAccount}
setTargetAccount={setTargetAccount}
targetOrg={targetOrg}
setTargetOrg={setTargetOrg}
start={start}
setStart={setStart}
end={end}
setEnd={setEnd}
disableAccount={isEdit}
disableOrgId={isEdit}
isLoading={isLoading}
error={error}
/>
),
enableNext: step1Complete,
},
{
id: 2,
name: 'Select roles',
component: <MUARolesTable roles={roles} setRoles={setRoles} />,
enableNext: step2Complete,
canJumpTo: step1Complete,
},
{
id: 3,
name: 'Review details',
component: (
<ReviewStep
targetAccount={targetAccount}
start={start}
end={end}
roles={roles}
isLoading={isLoading}
error={error}
setError={setError}
onClose={() => onClose(false)}
/>
),
canJumpTo: step1Complete && step2Complete,
enableNext: !isLoading,
nextButtonText: 'Finish',
},
];
const titleId = `${variant}-request`;
const descriptionId = `${variant} request`;
return (
<React.Fragment>
<Modal
variant="large"
style={{ height: '900px' }}
showClose={false}
hasNoBodyWrapper
isOpen={!warnClose}
aria-describedby={descriptionId}
aria-labelledby={titleId}
>
<Wizard
titleId={titleId}
descriptionId={descriptionId}
title={capitalize(variant) + ' request'}
steps={steps}
onClose={() => (isDirty ? setWarnClose(true) : onClose(false))}
onSave={onSave}
startAtStep={step}
onNext={({ id }) => {
setError();
setStep(id);
}}
onBack={({ id }) => {
setError();
setStep(id);
}}
onGoToStep={({ id }) => {
setError();
setStep(id);
}}
/>
</Modal>
{warnClose && (
<Modal
title="Exit request creation?"
variant="small"
titleIconVariant="warning"
isOpen
onClose={() => setWarnClose(false)}
actions={[
<Button
key="confirm"
variant="primary"
onClick={() => onClose(false)}
>
Exit
</Button>,
<Button
key="cancel"
variant="link"
onClick={() => setWarnClose(false)}
>
Stay
</Button>,
]}
>
All inputs will be discarded.
</Modal>
)}
</React.Fragment>
);
}