@patternfly/react-core#InputGroup JavaScript Examples
The following examples show how to use
@patternfly/react-core#InputGroup.
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: HostSelector.js From content-preview with Apache License 2.0 | 6 votes |
HostSelector = ({ baseUrl, setBaseUrl }) => {
const [input, setInput] = useState(baseUrl);
const history = useHistory();
const setUrl = (url) => {
setInput(url);
setBaseUrl(url);
setBaseUrlConstant(url);
history.push(history.location.pathname);
};
return <InputGroup>
<Button id="select-production" variant="control" onClick={() => setUrl(PRODUCTION_URL)}>Production</Button>
<Button id="select-localhost" variant="control" onClick={() => setUrl(LOCALHOST)}>Localhost</Button>
<TextInput id="custom-input" type='url' aria-label="custom input field" value={input} onChange={(input) => setInput(input)} />
<Button variant="primary" onClick={() => setUrl(input)}>Submit</Button>
</InputGroup>;
}
Example #2
Source File: tokens.js From ibutsu-server with MIT License | 6 votes |
tokenToRow(token) {
return {
"cells": [
{title: token.name},
{title: (
<InputGroup>
<TextInput value={token.token} aria-label={`token-input-${token.id}`} ouiaId={`token-input-${token.id}`} />
<Button variant="control" onClick={() => this.copyToClipboard(token.token)} ouiaId={`copy-button-${token.id}`}><CopyIcon /></Button>
</InputGroup>
)},
{title: token.expires},
{title: <Button variant="danger" onClick={() => this.onDeleteTokenClick(token)}>Delete</Button>}
]
};
}
Example #3
Source File: WirelessEssidSelect.js From cockpit-wicked with GNU General Public License v2.0 | 5 votes |
WirelessEssidSelect = ({ essid, setEssid, iface }) => {
const [isOpen, setIsOpen] = useState(false);
const [essidList, setEssidList] = useState(undefined);
const refreshList = (name) => {
fetchEssidList(name)
.then(result => {
const list = [...new Set([...result])];
setEssidList(list.sort());
})
.catch(console.error);
};
const onToggle = isOpen => {
if (isOpen) {
setEssidList(undefined);
refreshList(iface.name);
}
setIsOpen(isOpen);
};
const onSelect = (selection) => {
setEssid(selection);
setIsOpen(false);
};
const renderOptions = () => {
if (!essidList) {
return [
<DropdownItem isDisabled key="scanning" icon={<Spinner size="md" />}>
{_("Scanning...")}
</DropdownItem>
];
}
if (essidList.length === 0) {
return [
<DropdownItem isDisabled key="no-networks-found" icon={<ExclamationIcon />}>
{_("No networks found")}
</DropdownItem>
];
}
return essidList.map(value => <DropdownItem key={value} onClick={() => onSelect(value)}>{value}</DropdownItem>);
};
return (
<InputGroup>
<TextInput id="essid" value={essid} onChange={setEssid} type="text" aria-label="Essid" />
<Dropdown
position={DropdownPosition.right}
isOpen={isOpen}
dropdownItems={renderOptions()}
toggle={
<DropdownToggle id="essid-scanned-list" toggleIndicator={null} onToggle={onToggle} aria-label="Essid scanned list">
<SearchIcon />
</DropdownToggle>
}
/>
</InputGroup>
);
}
Example #4
Source File: AccessRequestsTable.js From access-requests-frontend with Apache License 2.0 | 4 votes |
AccessRequestsTable = ({ isInternal }) => {
const columns = isInternal
? [
'Request ID',
'Account number',
'Start date',
'End date',
'Created',
'Status',
]
: [
'Request ID',
'First name',
'Last name',
'Start date',
'End date',
'Created',
'Decision',
];
// Sorting
const [activeSortIndex, setActiveSortIndex] = React.useState(
isInternal ? 4 : 5
);
const [activeSortDirection, setActiveSortDirection] = React.useState('desc');
const onSort = (_ev, index, direction) => {
setActiveSortIndex(index);
setActiveSortDirection(direction);
};
// Pagination
const [page, setPage] = React.useState(1);
const [perPage, setPerPage] = React.useState(20);
const AccessRequestsPagination = ({ id }) => (
<Pagination
itemCount={numRows}
perPage={perPage}
page={page}
onSetPage={(_ev, pageNumber) => setPage(pageNumber)}
id={'access-requests-table-pagination-' + id}
variant={id}
perPageOptions={[5, 10, 20, 50].map((n) => ({ title: n, value: n }))}
onPerPageSelect={(_ev, perPage) => {
setPage(1);
setPerPage(perPage);
}}
isCompact={id === 'top'}
/>
);
AccessRequestsPagination.propTypes = {
id: PropTypes.string,
};
// Filtering
const [isDropdownOpen, setIsDropdownOpen] = React.useState(false);
const [filterColumn, setFilterColumn] = React.useState(
columns[isInternal ? 1 : 6]
);
const [isSelectOpen, setIsSelectOpen] = React.useState(false);
const [statusSelections, setStatusSelections] = React.useState([]);
// Harder than it needs to be to match rest of RBAC which doesn't wait
// for user to click a button or press enter.
const [accountFilter, setAccountFilter] = React.useState('');
const [filtersDirty, setFiltersDirty] = React.useState(false);
const hasFilters = statusSelections.length > 0 || accountFilter;
// Row loading
const [isLoading, setIsLoading] = React.useState(true);
const [numRows, setNumRows] = React.useState(0);
const [rows, setRows] = React.useState([]);
const dispatch = useDispatch();
const fetchAccessRequests = () => {
setIsLoading(true);
const listUrl = new URL(
`${window.location.origin}${API_BASE}/cross-account-requests/`
);
isInternal
? listUrl.searchParams.append('query_by', 'user_id')
: listUrl.searchParams.append('query_by', 'target_account');
listUrl.searchParams.append('offset', (page - 1) * perPage);
listUrl.searchParams.append('limit', perPage);
// https://github.com/RedHatInsights/insights-rbac/blob/master/rbac/api/cross_access/view.py
if (accountFilter) {
listUrl.searchParams.append('account', accountFilter);
}
if (statusSelections.length > 0) {
listUrl.searchParams.append('status', statusSelections.join(','));
}
const orderBy = `${activeSortDirection === 'desc' ? '-' : ''}${columns[
activeSortIndex
]
.toLowerCase()
.replace(' ', '_')}`;
listUrl.searchParams.append('order_by', orderBy);
apiInstance
.get(listUrl.href, { headers: { Accept: 'application/json' } })
.then((res) => {
setNumRows(res.meta.count);
setRows(
res.data.map((d) =>
isInternal
? [
d.request_id,
d.target_account,
d.start_date,
d.end_date,
d.created,
d.status,
]
: [
d.request_id,
d.first_name,
d.last_name,
d.start_date,
d.end_date,
d.created,
d.status,
]
)
);
setIsLoading(false);
})
.catch((err) => {
setIsLoading(false);
dispatch(
addNotification({
variant: 'danger',
title: 'Could not list access requests',
description: err.message,
})
);
});
};
const debouncedAccountFilter = useDebounce(accountFilter, 400);
React.useEffect(() => {
fetchAccessRequests();
}, [
debouncedAccountFilter,
statusSelections,
activeSortIndex,
activeSortDirection,
perPage,
page,
]);
// Modal actions
const [openModal, setOpenModal] = React.useState({ type: null });
const onModalClose = (isChanged) => {
setOpenModal({ type: null });
if (isChanged) {
fetchAccessRequests();
}
};
const modals = (
<React.Fragment>
{openModal.type === 'cancel' && (
<CancelRequestModal
requestId={openModal.requestId}
onClose={onModalClose}
/>
)}
{['edit', 'create'].includes(openModal.type) && (
<EditRequestModal
variant={openModal.type}
requestId={openModal.requestId}
onClose={onModalClose}
/>
)}
</React.Fragment>
);
// Rendering
const createButton = isInternal && (
<Button variant="primary" onClick={() => setOpenModal({ type: 'create' })}>
Create request
</Button>
);
if (rows.length === 0 && !isLoading && !filtersDirty) {
return (
<Bullseye style={{ height: 'auto' }} className="pf-u-mt-lg">
<EmptyState variant="large">
<EmptyStateIcon icon={PlusCircleIcon} />
<Title headingLevel="h3" size="lg">
{isInternal ? 'No access requests' : 'You have no access requests'}
</Title>
<EmptyStateBody>
{isInternal
? 'Click the button below to create an access request.'
: 'You have no pending Red Hat access requests.'}
</EmptyStateBody>
{createButton}
</EmptyState>
{modals}
</Bullseye>
);
}
const selectLabelId = 'filter-status';
const selectPlaceholder = `Filter by ${uncapitalize(
columns[columns.length - 1]
)}`;
const clearFiltersButton = (
<Button
variant="link"
onClick={() => {
setStatusSelections([]);
setAccountFilter('');
setPage(1);
}}
>
Clear filters
</Button>
);
const toolbar = (
<Toolbar id="access-requests-table-toolbar">
<ToolbarContent>
<ToolbarItem>
<InputGroup>
<Dropdown
isOpen={isDropdownOpen}
onSelect={(ev) => {
setIsDropdownOpen(false);
setFilterColumn(ev.target.value);
setIsSelectOpen(false);
setFiltersDirty(true);
}}
toggle={
<DropdownToggle
onToggle={(isOpen) => setIsDropdownOpen(isOpen)}
>
<FilterIcon /> {filterColumn}
</DropdownToggle>
}
// https://marvelapp.com/prototype/257je526/screen/74764732
dropdownItems={(isInternal ? [1, 5] : [6])
.map((i) => columns[i])
.map((colName) => (
// Filterable columns are RequestID, AccountID, and Status
<DropdownItem
key={colName}
value={colName}
component="button"
>
{capitalize(colName)}
</DropdownItem>
))}
/>
{['Status', 'Decision'].includes(filterColumn) && (
<React.Fragment>
<span id={selectLabelId} hidden>
{selectPlaceholder}
</span>
<Select
aria-labelledby={selectLabelId}
variant="checkbox"
aria-label="Select statuses"
onToggle={(isOpen) => setIsSelectOpen(isOpen)}
onSelect={(_ev, selection) => {
setFiltersDirty(true);
if (statusSelections.includes(selection)) {
setStatusSelections(
statusSelections.filter((s) => s !== selection)
);
} else {
setStatusSelections([...statusSelections, selection]);
}
setPage(1);
}}
isOpen={isSelectOpen}
selections={Array.from(statusSelections)}
isCheckboxSelectionBadgeHidden
placeholderText={selectPlaceholder}
>
{statuses.map((status) => (
<SelectOption key={status} value={status}>
{capitalize(status)}
</SelectOption>
))}
</Select>
</React.Fragment>
)}
{filterColumn === 'Account number' && (
<form
style={{ display: 'flex' }}
onSubmit={(ev) => ev.preventDefault()}
>
<TextInput
name={`${filterColumn}-filter`}
id={`${filterColumn}-filter`}
type="search"
iconVariant="search"
placeholder={`Filter by ${uncapitalize(filterColumn)}`}
aria-label={`${filterColumn} search input`}
value={accountFilter}
onChange={(val) => {
setAccountFilter(val), setFiltersDirty(true), setPage(1);
}}
/>
</form>
)}
</InputGroup>
</ToolbarItem>
<ToolbarItem>{createButton}</ToolbarItem>
<ToolbarItem variant="pagination" align={{ default: 'alignRight' }}>
<AccessRequestsPagination id="top" />
</ToolbarItem>
</ToolbarContent>
<ToolbarContent>
<ChipGroup categoryName="Status">
{statusSelections.map((status) => (
<Chip
key={status}
onClick={() => {
setStatusSelections(
statusSelections.filter((s) => s !== status)
);
setPage(1);
}}
>
{status}
</Chip>
))}
</ChipGroup>
{accountFilter && (
<ChipGroup categoryName="Account number">
<Chip
onClick={() => {
setAccountFilter(''), setPage(1);
}}
>
{accountFilter}
</Chip>
</ChipGroup>
)}
{hasFilters && clearFiltersButton}
</ToolbarContent>
</Toolbar>
);
function getColumnWidth(columnIndex) {
if (isInternal) {
return columnIndex === 0 ? 30 : 15;
}
return [0, 6].includes(columnIndex) ? 20 : 10;
}
const { url } = useRouteMatch();
const table = (
<TableComposable aria-label="Access requests table" variant="compact">
<Thead>
<Tr>
{columns.map((column, columnIndex) => (
<Th
key={columnIndex}
{...(!column.includes('name') &&
column !== 'Decision' && {
sort: {
sortBy: {
index: activeSortIndex,
direction: activeSortDirection,
},
onSort,
columnIndex,
},
})}
width={getColumnWidth(columnIndex)}
>
{column}
</Th>
))}
{isInternal && <Th />}
</Tr>
</Thead>
<Tbody>
{isLoading
? [...Array(rows.length || perPage).keys()].map((i) => (
<Tr key={i}>
{columns.map((name, j) => (
<Td key={j} dataLabel={name}>
<div
style={{ height: '30px' }}
className="ins-c-skeleton ins-c-skeleton__md"
>
{' '}
</div>
</Td>
))}
</Tr>
))
: rows.map((row, rowIndex) => (
<Tr key={rowIndex}>
<Td dataLabel={columns[0]}>
<Link to={`${url}${url.endsWith('/') ? '' : '/'}${row[0]}`}>
{row[0]}
</Link>
</Td>
<Td dataLabel={columns[1]}>{row[1]}</Td>
<Td dataLabel={columns[2]}>{row[2]}</Td>
<Td dataLabel={columns[3]}>{row[3]}</Td>
<Td dataLabel={columns[4]}>{row[4]}</Td>
{isInternal ? (
<Td dataLabel={columns[5]}>
<StatusLabel
requestId={row[0]}
status={row[5]}
onLabelClick={() => {
setStatusSelections([
...statusSelections.filter((s) => s !== status),
status,
]);
setPage(1);
}}
hideActions
/>
</Td>
) : (
<Td dataLabel={columns[5]}>{row[5]}</Td>
)}
{isInternal ? (
// Different actions based on status
<Td
actions={getInternalActions(row[5], row[0], setOpenModal)}
/>
) : (
<Td dataLabel={columns[6]}>
<StatusLabel requestId={row[0]} status={row[6]} />
</Td>
)}
</Tr>
))}
{rows.length === 0 && hasFilters && (
<Tr>
<Td colSpan={columns.length}>
<EmptyState variant="small">
<EmptyStateIcon icon={SearchIcon} />
<Title headingLevel="h2" size="lg">
No matching requests found
</Title>
<EmptyStateBody>
No results match the filter criteria. Remove all filters or
clear all filters to show results.
</EmptyStateBody>
{clearFiltersButton}
</EmptyState>
</Td>
</Tr>
)}
</Tbody>
</TableComposable>
);
return (
<React.Fragment>
{toolbar}
{table}
<AccessRequestsPagination id="bottom" />
{modals}
</React.Fragment>
);
}
Example #5
Source File: MUARolesTable.js From access-requests-frontend with Apache License 2.0 | 4 votes |
MUARolesTable = ({
roles: selectedRoles,
setRoles: setSelectedRoles,
}) => {
const isReadOnly = setSelectedRoles === undefined;
const columns = ['Role name', 'Role description', 'Permissions'];
const [rows, setRows] = React.useState(Array.from(rolesCache));
const [applications, setApplications] = React.useState(applicationsCache);
React.useEffect(() => {
if (rolesCache.length === 0 || applicationsCache.length === 0) {
apiInstance
.get(
`${API_BASE}/roles/?limit=9999&order_by=display_name&add_fields=groups_in_count`,
{ headers: { Accept: 'application/json' } }
)
.then(({ data }) => {
data.forEach((role) => {
role.isExpanded = false;
role.permissions = role.accessCount;
});
rolesCache = data.map((role) => Object.assign({}, role));
setRows(data);
// Build application filter from data
const apps = Array.from(
data
.map((role) => role.applications)
.flat()
.reduce((acc, cur) => {
acc.add(cur);
return acc;
}, new Set())
).sort();
applicationsCache = apps;
setApplications(apps);
})
.catch((err) =>
dispatch(
addNotification({
variant: 'danger',
title: 'Could not fetch roles list',
description: err.message,
})
)
);
}
}, []);
// Sorting
const [activeSortIndex, setActiveSortIndex] = React.useState('name');
const [activeSortDirection, setActiveSortDirection] = React.useState('asc');
const onSort = (_ev, index, direction) => {
setActiveSortIndex(index);
setActiveSortDirection(direction);
};
// Filtering
const [isDropdownOpen, setIsDropdownOpen] = React.useState(false);
const [filterColumn, setFilterColumn] = React.useState(columns[0]);
const [isSelectOpen, setIsSelectOpen] = React.useState(false);
const [appSelections, setAppSelections] = React.useState([]);
const [nameFilter, setNameFilter] = React.useState('');
const hasFilters = appSelections.length > 0 || nameFilter;
const selectLabelId = 'filter-application';
const selectPlaceholder = 'Filter by application';
const selectedNames = selectedRoles.map((role) => role.display_name);
const filteredRows = rows
.filter((row) =>
appSelections.length > 0
? row.applications.find((app) => appSelections.includes(app))
: true
)
.filter((row) => row.name.toLowerCase().includes(nameFilter))
.filter((row) =>
isReadOnly ? selectedNames.includes(row.display_name) : true
);
// Pagination
const [page, setPage] = React.useState(1);
const [perPage, setPerPage] = React.useState(10);
const AccessRequestsPagination = ({ id }) => (
<Pagination
itemCount={filteredRows.length}
perPage={perPage}
page={page}
onSetPage={(_ev, pageNumber) => setPage(pageNumber)}
id={'access-requests-roles-table-pagination-' + id}
variant={id}
onPerPageSelect={(_ev, perPage) => {
setPage(1);
setPerPage(perPage);
}}
isCompact={id === 'top'}
/>
);
AccessRequestsPagination.propTypes = {
id: PropTypes.string,
};
const pagedRows = filteredRows
.sort((a, b) => {
if (typeof a[activeSortIndex] === 'number') {
// numeric sort
if (activeSortDirection === 'asc') {
return a[activeSortIndex] - b[activeSortIndex];
}
return b[activeSortIndex] - a[activeSortIndex];
} else {
// string sort
if (activeSortDirection === 'asc') {
return (a[activeSortIndex] + '').localeCompare(b[activeSortIndex]);
}
return (b[activeSortIndex] + '').localeCompare(a[activeSortIndex]);
}
})
.slice((page - 1) * perPage, page * perPage);
// Selecting
const [isBulkSelectOpen, setIsBulkSelectOpen] = React.useState(false);
const anySelected = selectedRoles.length > 0;
const someChecked = anySelected ? null : false;
const isChecked =
selectedRoles.length === filteredRows.length && selectedRoles.length > 0
? true
: someChecked;
const onSelect = (_ev, isSelected, rowId) => {
const changed = pagedRows[rowId].display_name;
if (isSelected) {
setSelectedRoles(selectedRoles.concat(changed));
} else {
setSelectedRoles(selectedRoles.filter((role) => role !== changed));
}
};
const onSelectAll = (_ev, isSelected) => {
if (isSelected) {
setSelectedRoles(filteredRows.map((row) => row.display_name));
} else {
setSelectedRoles([]);
}
};
const clearFiltersButton = (
<Button
variant="link"
onClick={() => {
setAppSelections([]);
setNameFilter('');
}}
>
Clear filters
</Button>
);
const roleToolbar = isReadOnly ? null : (
<Toolbar id="access-requests-roles-table-toolbar">
<ToolbarContent>
<ToolbarItem>
<Dropdown
onSelect={() => setIsBulkSelectOpen(!isBulkSelectOpen)}
position="left"
toggle={
<DropdownToggle
splitButtonItems={[
<DropdownToggleCheckbox
key="a"
id="example-checkbox-2"
aria-label={anySelected ? 'Deselect all' : 'Select all'}
isChecked={isChecked}
onClick={() => onSelectAll(null, !anySelected)}
/>,
]}
onToggle={(isOpen) => setIsBulkSelectOpen(isOpen)}
isDisabled={rows.length === 0}
>
{selectedRoles.length !== 0 && (
<React.Fragment>
{selectedRoles.length} selected
</React.Fragment>
)}
</DropdownToggle>
}
isOpen={isBulkSelectOpen}
dropdownItems={[
<DropdownItem key="0" onClick={() => onSelectAll(null, false)}>
Select none (0 items)
</DropdownItem>,
<DropdownItem
key="1"
onClick={() =>
setSelectedRoles(
selectedRoles.concat(pagedRows.map((r) => r.display_name))
)
}
>
Select page ({Math.min(pagedRows.length, perPage)} items)
</DropdownItem>,
<DropdownItem key="2" onClick={() => onSelectAll(null, true)}>
Select all ({filteredRows.length} items)
</DropdownItem>,
]}
/>
</ToolbarItem>
<ToolbarItem>
<InputGroup>
<Dropdown
isOpen={isDropdownOpen}
onSelect={(ev) => {
setIsDropdownOpen(false);
setFilterColumn(ev.target.value);
setIsSelectOpen(false);
}}
toggle={
<DropdownToggle
onToggle={(isOpen) => setIsDropdownOpen(isOpen)}
>
<FilterIcon /> {filterColumn}
</DropdownToggle>
}
dropdownItems={['Role name', 'Application'].map((colName) => (
// Filterable columns are RequestID, AccountID, and Status
<DropdownItem key={colName} value={colName} component="button">
{capitalize(colName)}
</DropdownItem>
))}
/>
{filterColumn === 'Application' ? (
<React.Fragment>
<span id={selectLabelId} hidden>
{selectPlaceholder}
</span>
<Select
aria-labelledby={selectLabelId}
variant="checkbox"
aria-label="Select applications"
onToggle={(isOpen) => setIsSelectOpen(isOpen)}
onSelect={(_ev, selection) => {
if (appSelections.includes(selection)) {
setAppSelections(
appSelections.filter((s) => s !== selection)
);
} else {
setAppSelections([...appSelections, selection]);
}
}}
isOpen={isSelectOpen}
selections={appSelections}
isCheckboxSelectionBadgeHidden
placeholderText={selectPlaceholder}
style={{ maxHeight: '400px', overflowY: 'auto' }}
>
{applications.map((app) => (
<SelectOption key={app} value={app}>
{capitalize(app.replace(/-/g, ' '))}
</SelectOption>
))}
</Select>
</React.Fragment>
) : (
<TextInput
name="rolesSearch"
id="rolesSearch"
type="search"
iconVariant="search"
aria-label="Search input"
placeholder="Filter by role name"
value={nameFilter}
onChange={(val) => setNameFilter(val)}
/>
)}
</InputGroup>
</ToolbarItem>
<ToolbarItem variant="pagination" align={{ default: 'alignRight' }}>
<AccessRequestsPagination id="top" />
</ToolbarItem>
</ToolbarContent>
{hasFilters && (
<ToolbarContent>
{nameFilter && (
<ChipGroup categoryName="Role name">
<Chip onClick={() => setNameFilter('')}>{nameFilter}</Chip>
</ChipGroup>
)}
{appSelections.length > 0 && (
<ChipGroup categoryName="Status">
{appSelections.map((status) => (
<Chip
key={status}
onClick={() =>
setAppSelections(appSelections.filter((s) => s !== status))
}
>
{status}
</Chip>
))}
</ChipGroup>
)}
{clearFiltersButton}
</ToolbarContent>
)}
</Toolbar>
);
const expandedColumns = ['Application', 'Resource type', 'Operation'];
const dispatch = useDispatch();
const onExpand = (row) => {
row.isExpanded = !row.isExpanded;
setRows([...rows]);
if (!row.access) {
apiInstance
.get(`${API_BASE}/roles/${row.uuid}/`, {
headers: { Accept: 'application/json' },
})
.then((res) => {
row.access = res.access.map((a) => a.permission.split(':'));
setRows([...rows]);
})
.catch((err) =>
dispatch(
addNotification({
variant: 'danger',
title: `Could not fetch permission list for ${row.name}.`,
description: err.message,
})
)
);
}
};
const roleTable = (
<TableComposable aria-label="My user access roles" variant="compact">
<Thead>
<Tr>
{!isReadOnly && <Th />}
<Th
width={30}
sort={{
sortBy: {
index: activeSortIndex,
direction: activeSortDirection,
},
onSort,
columnIndex: 'name',
}}
>
{columns[0]}
</Th>
<Th
width={50}
sort={{
sortBy: {
index: activeSortIndex,
direction: activeSortDirection,
},
onSort,
columnIndex: 'description',
}}
>
{columns[1]}
</Th>
<Th
width={10}
sort={{
sortBy: {
index: activeSortIndex,
direction: activeSortDirection,
},
onSort,
columnIndex: 'permissions',
}}
modifier="nowrap"
>
{columns[2]}
</Th>
</Tr>
</Thead>
{rows.length === 0 &&
[...Array(perPage).keys()].map((i) => (
<Tbody key={i}>
<Tr>
{!isReadOnly && <Td />}
{columns.map((col, key) => (
<Td dataLabel={col} key={key}>
<div
style={{ height: '22px' }}
className="ins-c-skeleton ins-c-skeleton__md"
>
{' '}
</div>
</Td>
))}
</Tr>
</Tbody>
))}
{pagedRows.map((row, rowIndex) => (
<Tbody key={rowIndex}>
<Tr>
{!isReadOnly && (
<Td
select={{
rowIndex,
onSelect,
isSelected: selectedRoles.find((r) => r === row.display_name),
}}
/>
)}
<Td dataLabel={columns[0]}>{row.display_name}</Td>
<Td dataLabel={columns[1]} className="pf-m-truncate">
<Tooltip entryDelay={1000} content={row.description}>
<span className="pf-m-truncate pf-c-table__text">
{row.description}
</span>
</Tooltip>
</Td>
<Td
dataLabel={columns[2]}
className={css(
'pf-c-table__compound-expansion-toggle',
row.isExpanded && 'pf-m-expanded'
)}
>
<button
type="button"
className="pf-c-table__button"
onClick={() => onExpand(row)}
>
{row.permissions}
</button>
</Td>
</Tr>
<Tr isExpanded={row.isExpanded} borders={false}>
{!isReadOnly && <Td />}
<Td className="pf-u-p-0" colSpan={3}>
<TableComposable isCompact className="pf-m-no-border-rows">
<Thead>
<Tr>
{expandedColumns.map((col) => (
<Th key={col}>{col}</Th>
))}
</Tr>
</Thead>
<Tbody>
{Array.isArray(row.access)
? row.access.map((permissions) => (
<Tr key={permissions.join(':')}>
<Td dataLabel={expandedColumns[0]}>
{permissions[0]}
</Td>
<Td dataLabel={expandedColumns[1]}>
{permissions[1]}
</Td>
<Td dataLabel={expandedColumns[2]}>
{permissions[2]}
</Td>
</Tr>
))
: [...Array(row.permissions).keys()].map((i) => (
<Tr key={i}>
{expandedColumns.map((val) => (
<Td key={val} dataLabel={val}>
<div
style={{ height: '22px' }}
className="ins-c-skeleton ins-c-skeleton__sm"
>
{' '}
</div>
</Td>
))}
</Tr>
))}
</Tbody>
</TableComposable>
</Td>
</Tr>
</Tbody>
))}
{pagedRows.length === 0 && hasFilters && (
<Tr>
<Td colSpan={columns.length}>
<EmptyState variant="small">
<EmptyStateIcon icon={SearchIcon} />
<Title headingLevel="h2" size="lg">
No matching requests found
</Title>
<EmptyStateBody>
No results match the filter criteria. Remove all filters or
clear all filters to show results.
</EmptyStateBody>
{clearFiltersButton}
</EmptyState>
</Td>
</Tr>
)}
</TableComposable>
);
return (
<React.Fragment>
{!isReadOnly && (
<React.Fragment>
<Title headingLevel="h2">Select roles</Title>
<p>Select the roles you would like access to.</p>
</React.Fragment>
)}
{roleToolbar}
{roleTable}
{isReadOnly && <AccessRequestsPagination id="bottom" />}
</React.Fragment>
);
}
Example #6
Source File: Packages.js From edge-frontend with Apache License 2.0 | 4 votes |
Packages = ({ defaultArch, ...props }) => {
const { change, getState } = useFormApi();
const { input } = useFieldApi(props);
const [availableOptions, setAvailableOptions] = React.useState([]);
const [chosenOptions, setChosenOptions] = React.useState([]);
const [availableInputValue, setAvailableInputValue] = React.useState('');
const [enterPressed, setEnterPressed] = useState(false);
const [hasMoreResults, setHasMoreResults] = useState(false);
const [scrollTo, setScrollTo] = useState(null);
const [hasNoSearchResults, setHasNoSearchResults] = useState(false);
const [searchFocused, setSearchFocused] = useState(false);
const [exactMatch, setExactMatch] = useState(false);
useEffect(() => {
const loadedPackages = getState()?.values?.[input.name] || [];
setChosenOptions(sortedOptions(mapPackagesToOptions(loadedPackages)));
const availableSearchInput = document.querySelector(
'[aria-label="available search input"]'
);
availableSearchInput?.addEventListener('keydown', handleSearchOnEnter);
return () =>
availableSearchInput.removeEventListener('keydown', handleSearchOnEnter);
}, []);
useEffect(() => {
if (enterPressed) {
handlePackageSearch();
setEnterPressed(false);
}
}, [enterPressed]);
useEffect(() => {
scrollToAddedPackages();
}, [scrollTo]);
const handlePackageSearch = async () => {
if (availableInputValue === '') {
return;
}
const { data, meta } = await getPackages(
getState()?.values?.release || 'rhel-85',
getState()?.values?.architecture || defaultArch,
availableInputValue
);
if (!data) {
setHasNoSearchResults(true);
setHasMoreResults(false);
setAvailableOptions([]);
return;
}
if (meta.count > 100) {
setHasNoSearchResults(false);
setHasMoreResults(true);
let exactMatchIndex = null;
data.forEach(({ name }, index) => {
if (name === availableInputValue) {
exactMatchIndex = index;
return;
}
});
const isNotChosen = !chosenOptions.find(
(option) => option.name === data[exactMatchIndex].name
);
if (exactMatchIndex !== null && isNotChosen) {
setExactMatch(true);
setAvailableOptions(mapPackagesToOptions([data[exactMatchIndex]]));
return;
}
setExactMatch(false);
setAvailableOptions([]);
return;
} else {
setHasMoreResults(false);
setExactMatch(false);
}
const removeChosenPackages = data.filter(
(newPkg) =>
!chosenOptions.find((chosenPkg) => chosenPkg.name === newPkg.name)
);
setAvailableOptions(
sortedOptions(mapPackagesToOptions(removeChosenPackages))
);
setHasNoSearchResults(false);
};
const handleSearchOnEnter = (e) => {
if (e.key === 'Enter') {
e.stopPropagation();
setEnterPressed(true);
}
};
const scrollToAddedPackages = () => {
if (!scrollTo) {
return;
}
const destination = document.querySelector(
`.pf-m-${scrollTo.pane} .pf-c-dual-list-selector__menu`
);
scrollTo.pkgs.forEach((pkg) =>
document
.getElementById(`package-${pkg.name}`)
.closest('.pf-c-dual-list-selector__list-item-row')
.classList.add('pf-u-background-color-disabled-color-300')
);
setTimeout(() => {
scrollTo.pkgs.forEach((pkg) =>
document
.getElementById(`package-${pkg.name}`)
.closest('.pf-c-dual-list-selector__list-item-row')
.classList.remove('pf-u-background-color-disabled-color-300')
);
}, 400);
destination.scrollTop = scrollTo.scrollHeight;
setScrollTo(null);
};
const moveSelected = (fromAvailable) => {
const sourceOptions = fromAvailable ? availableOptions : chosenOptions;
let destinationOptions = fromAvailable ? chosenOptions : availableOptions;
const selectedOptions = [];
for (let i = 0; i < sourceOptions.length; i++) {
const option = sourceOptions[i];
if (option.selected && option.isVisible) {
selectedOptions.push(option);
sourceOptions.splice(i, 1);
option.selected = false;
i--;
}
}
destinationOptions = sortedOptions([
...destinationOptions,
...selectedOptions,
]);
const packageHeight = 61;
const scrollHeight =
destinationOptions.findIndex(
(pkg) => pkg.name === selectedOptions[0].name
) * packageHeight;
if (fromAvailable) {
setAvailableOptions(sortedOptions([...sourceOptions]));
setChosenOptions(destinationOptions);
change(input.name, destinationOptions);
} else {
setChosenOptions(sortedOptions([...sourceOptions]));
setAvailableOptions(destinationOptions);
change(input.name, [...sourceOptions]);
}
setScrollTo({
pkgs: selectedOptions,
pane: fromAvailable ? 'chosen' : 'available',
scrollHeight,
});
setExactMatch(false);
};
const moveAll = (fromAvailable) => {
if (fromAvailable) {
setChosenOptions(
sortedOptions([
...availableOptions.filter((x) => x.isVisible),
...chosenOptions,
])
);
setAvailableOptions(
sortedOptions([...availableOptions.filter((x) => !x.isVisible)])
);
change(input.name, [...availableOptions, ...chosenOptions]);
} else {
setAvailableOptions(
sortedOptions([
...chosenOptions.filter((x) => x.isVisible),
...availableOptions,
])
);
setChosenOptions(
sortedOptions([...chosenOptions.filter((x) => !x.isVisible)])
);
change(input.name, []);
}
setExactMatch(false);
};
const onOptionSelect = (_event, index, isChosen) => {
if (isChosen) {
const newChosen = [...chosenOptions];
newChosen[index].selected = !chosenOptions[index].selected;
setChosenOptions(sortedOptions(newChosen));
} else {
const newAvailable = [...availableOptions];
newAvailable[index].selected = !availableOptions[index].selected;
setAvailableOptions(sortedOptions(newAvailable));
}
};
const buildSearchInput = (isAvailable) => {
const onChange = (value) => {
setAvailableInputValue(value);
if (!isAvailable) {
const toFilter = [...chosenOptions];
toFilter.forEach((option) => {
option.isVisible =
value === '' ||
option.name.toLowerCase().includes(value.toLowerCase());
});
}
};
return (
<>
<InputGroup>
<TextInput
id={`${isAvailable ? 'available' : 'chosen'}-textinput`}
type="search"
onChange={onChange}
placeholder="Search for packages"
onFocus={() => setSearchFocused(true)}
onBlur={() => setSearchFocused(false)}
validated={
hasMoreResults && isAvailable && !searchFocused ? 'warning' : ''
}
aria-label={
isAvailable ? 'available search input' : 'chosen search input'
}
data-testid={
isAvailable ? 'available-search-input' : 'chosen-search-input'
}
/>
{isAvailable ? (
<Button
onClick={handlePackageSearch}
isDisabled={!isAvailable}
variant="control"
aria-label="search button for search input"
data-testid="package-search"
>
<SearchIcon />
</Button>
) : (
<InputGroupText>
<SearchIcon className="pf-u-ml-xs pf-u-mr-xs" />
</InputGroupText>
)}
</InputGroup>
{hasMoreResults && isAvailable && (
<HelperText>
<HelperTextItem variant="warning">
Over 100 results found. Refine your search.
</HelperTextItem>
</HelperText>
)}
</>
);
};
const displayPackagesFrom = (options, isChosen) => {
return options.map((option, index) => {
return option.isVisible ? (
<DualListSelectorListItem
key={index}
isSelected={option.selected}
id={`composable-option-${index}`}
onOptionSelect={(e) => onOptionSelect(e, index, isChosen)}
>
<TextContent>
<span
id={`package-${option.name}`}
className="pf-c-dual-list-selector__item-text"
>
{option.name}
</span>
<small>{option.summary}</small>
</TextContent>
</DualListSelectorListItem>
) : null;
});
};
const selectedStatus = (options) => {
const totalItemNum = options.filter((x) => x.isVisible).length;
const selectedItemNum = options.filter(
(x) => x.selected && x.isVisible
).length;
return selectedItemNum > 0
? `${selectedItemNum} of ${totalItemNum} items selected`
: `${totalItemNum} ${totalItemNum > 1 ? 'items' : 'item'}`;
};
return (
<DualListSelector>
<DualListSelectorPane
title="Available packages"
status={selectedStatus(availableOptions)}
searchInput={buildSearchInput(true)}
>
<DualListSelectorList
style={{ height: '290px' }}
data-testid="available-packages-list"
>
{availableOptions.length > 0 && !exactMatch ? (
displayPackagesFrom(availableOptions, false)
) : hasNoSearchResults ? (
<NoResultsText
heading="No Results Found"
body="Adjust your search and try again"
/>
) : hasMoreResults ? (
<>
{exactMatch && (
<HelperText>
<HelperTextItem
className="pf-u-ml-md pf-u-mt-md"
variant="indeterminate"
>
Exact match
</HelperTextItem>
</HelperText>
)}
{exactMatch && displayPackagesFrom(availableOptions, false)}
{exactMatch && (
<Divider
className="pf-u-mt-md"
inset={{ default: 'insetMd' }}
/>
)}
<NoResultsText
heading="Too many results to display"
body="Please make the search more specific and try again"
/>
</>
) : (
<EmptyText text="Search above to add additional packages to your image." />
)}
</DualListSelectorList>
</DualListSelectorPane>
<DualListSelectorControlsWrapper aria-label="Selector controls">
<DualListSelectorControl
isDisabled={!availableOptions.some((option) => option.selected)}
onClick={() => moveSelected(true)}
aria-label="Add selected"
tooltipContent="Add selected"
>
<AngleRightIcon />
</DualListSelectorControl>
<DualListSelectorControl
isDisabled={availableOptions.length === 0}
onClick={() => moveAll(true)}
aria-label="Add all"
tooltipContent="Add all"
>
<AngleDoubleRightIcon />
</DualListSelectorControl>
<DualListSelectorControl
isDisabled={chosenOptions.length === 0}
onClick={() => moveAll(false)}
aria-label="Remove all"
tooltipContent="Remove all"
>
<AngleDoubleLeftIcon />
</DualListSelectorControl>
<DualListSelectorControl
onClick={() => moveSelected(false)}
isDisabled={!chosenOptions.some((option) => option.selected)}
aria-label="Remove selected"
tooltipContent="Remove selected"
>
<AngleLeftIcon />
</DualListSelectorControl>
</DualListSelectorControlsWrapper>
<DualListSelectorPane
title="Chosen packages"
status={selectedStatus(chosenOptions)}
searchInput={buildSearchInput(false)}
isChosen
>
<DualListSelectorList
style={{ height: '290px' }}
data-testid="chosen-packages-list"
>
{chosenOptions.length === 0 ? (
<EmptyText text="No packages added." />
) : chosenOptions.filter((option) => option.isVisible).length > 0 ? (
displayPackagesFrom(chosenOptions, true)
) : (
<NoResultsText
heading="No Results Found"
body="Adjust your search and try again"
/>
)}
</DualListSelectorList>
</DualListSelectorPane>
</DualListSelector>
);
}
Example #7
Source File: FilterInput.js From edge-frontend with Apache License 2.0 | 4 votes |
FilterInput = ({ filterValues, setFilterValues, input }) => {
const selectedFilter = filterValues.find((filter) => filter.label === input);
const [isOpen, setIsOpen] = useState(false);
const handleFilterChange = () => (value, checkboxValue) => {
setFilterValues((prevState) => {
const selectedIndex = prevState.findIndex(
(filter) => filter.label === selectedFilter.label
);
const checkedType = prevState.find(
(filter) => filter.label === selectedFilter.label
);
const checkboxIndex =
selectedFilter.type === 'checkbox'
? checkedType.value.findIndex((i) => i.option === checkboxValue)
: 0;
const newValueArray = Object.values({
...checkedType.value,
[checkboxIndex]: {
...checkedType.value[checkboxIndex],
isChecked: !checkedType?.value[checkboxIndex]?.isChecked,
},
});
const newTextValue = value;
return Object.values({
...prevState,
[selectedIndex]: {
...prevState[selectedIndex],
value:
selectedFilter.type === 'checkbox' ? newValueArray : newTextValue,
},
});
});
};
const handleDeleteTextInput = () => {
const filterLabelIndex = filterValues.findIndex(
(value) => value.type === 'text'
);
setFilterValues((prevState) => {
const changedValue = prevState[filterLabelIndex];
if (changedValue.type === 'text') {
return [
...prevState.slice(0, filterLabelIndex),
{ ...prevState[filterLabelIndex], value: '' },
...prevState.slice(filterLabelIndex + 1, prevState.length),
];
}
return prevState;
});
};
if (selectedFilter.type === 'text') {
return (
<ToolbarItem data-testid="filter-input-testid">
<InputGroup>
<SearchInput
name="textInput1"
id="textInput1"
type="search"
aria-label={`Select input for ${selectedFilter.label.toLowerCase()}`}
placeholder={`Filter by ${selectedFilter.label.toLowerCase()}`}
onChange={debounce(handleFilterChange(), 500)}
onClear={handleDeleteTextInput}
value={filterValues.find((filter) => filter.type === 'text').value}
/>
</InputGroup>
</ToolbarItem>
);
}
if (selectedFilter.type === 'checkbox') {
return (
<ToolbarItem data-testid="filter-input-testid">
<InputGroup>
<Select
variant="checkbox"
aria-label={`Select input for ${selectedFilter.label.toLowerCase()}`}
width="11rem"
placeholderText={`Filter by ${selectedFilter.label.toLowerCase()}`}
isCheckboxSelectionBadgeHidden
onToggle={() => setIsOpen((prevState) => !prevState)}
onSelect={handleFilterChange()}
selections={selectedFilter.value
.filter((value) => value.isChecked == true)
.map((arr) => arr.option)}
isOpen={isOpen}
>
{selectedFilter.value.map((filter, index) => (
<SelectOption
key={index}
value={filter.option}
isChecked={filter.isChecked}
/>
))}
</Select>
</InputGroup>
</ToolbarItem>
);
}
}
Example #8
Source File: login.js From ibutsu-server with MIT License | 4 votes |
render() {
const socialMediaLoginContent = (
<React.Fragment>
{this.state.externalLogins.keycloak &&
<LoginMainFooterLinksItem onClick={this.onKeycloakLogin} href="#" linkComponentProps={{ 'aria-label': `Login with ${this.getKeycloakName()}`, 'title': `Login with ${this.getKeycloakName()}` }}>
{this.getKeycloakIcon()}
</LoginMainFooterLinksItem>
}
{this.state.externalLogins.google &&
<GoogleLogin
clientId={this.state.externalLogins.google.client_id}
scope={this.state.externalLogins.google.scope}
redirectUri={this.state.externalLogins.google.redirect_uri}
onSuccess={this.onGoogleLogin}
onFailure={(response) => console.error(response)}
render={renderProps => (
<LoginMainFooterLinksItem onClick={renderProps.onClick} href="#" linkComponentProps={{ 'aria-label': 'Login with Google', 'title': 'Login with Google' }}>
<GoogleIcon size="lg" />
</LoginMainFooterLinksItem>
)}
/>
}
{this.state.externalLogins.github &&
<OAuth2Login
isCrossOrigin={true}
authorizationUrl={this.state.externalLogins.github.authorization_url}
responseType="code"
clientId={this.state.externalLogins.github.client_id}
redirectUri={this.state.externalLogins.github.redirect_uri}
scope={this.state.externalLogins.github.scope}
onSuccess={this.onOAuth2Success}
onFailure={(response) => console.error(response)}
render={renderProps => (
<LoginMainFooterLinksItem onClick={renderProps.onClick} href="#" linkComponentProps={{ 'aria-label': 'Login with GitHub', 'title': 'Login with GitHub' }}>
<GithubIcon size="lg" />
</LoginMainFooterLinksItem>
)}
/>
}
{this.state.externalLogins.facebook &&
<FacebookLogin
appId={this.state.externalLogins.facebook.app_id}
onSuccess={this.onFacebookLogin}
onFail={(response) => console.error(response)}
// useRedirect={true}
dialogParams={{redirect_uri: this.state.externalLogins.facebook.redirect_uri, response_type: 'code'}}
render={(renderProps) => (
<LoginMainFooterLinksItem onClick={renderProps.onClick} href="#" linkComponentProps={{ 'aria-label': 'Login with Facebook' }}>
<FacebookIcon size="lg" />
</LoginMainFooterLinksItem>
)}
/>
}
{this.state.externalLogins.gitlab &&
<OAuth2Login
isCrossOrigin={true}
authorizationUrl={this.state.externalLogins.gitlab.authorization_url}
responseType="code"
clientId={this.state.externalLogins.gitlab.client_id}
redirectUri={this.state.externalLogins.gitlab.redirect_uri}
scope={this.state.externalLogins.gitlab.scope}
onSuccess={this.onOAuth2Success}
onFailure={(response) => console.error(response)}
render={renderProps => (
<LoginMainFooterLinksItem onClick={renderProps.onClick} href="#" linkComponentProps={{ 'aria-label': 'Login with GitLab', 'title': 'Login with GitLab' }}>
<GitlabIcon size="lg" />
</LoginMainFooterLinksItem>
)}
/>
}
</React.Fragment>
);
const signUpForAccountMessage = (
<LoginMainFooterBandItem>
Need an account? <NavLink to="/sign-up">Sign up.</NavLink>
</LoginMainFooterBandItem>
);
const forgotCredentials = (
<LoginMainFooterBandItem>
<NavLink to="/forgot-password">Forgot username or password?</NavLink>
</LoginMainFooterBandItem>
);
const loginWithUserDescription = 'Please use your e-mail address and password, or login via one of the icons below the Log In button.';
const loginWithoutUserDescription = 'Log in via one of the icons below.';
const backgroundImages = {
lg: '/images/pfbg_1200.jpg',
sm: '/images/pfbg_768.jpg',
sm2x: '/images/[email protected]',
xs: '/images/pfbg_576.jpg',
xs2x: '/images/[email protected]'
};
return (
<LoginPage
footerListVariants="inline"
brandImgSrc="/images/ibutsu-wordart-164.png"
brandImgAlt="Ibutsu"
backgroundImgSrc={backgroundImages}
backgroundImgAlt="Background image"
textContent="Ibutsu is an open source test result aggregation tool. Collect and display your test results, view artifacts, and monitor tests."
loginTitle="Log in to your account"
loginSubtitle={this.state.loginSupport.user ? loginWithUserDescription : loginWithoutUserDescription}
socialMediaLoginContent={socialMediaLoginContent}
signUpForAccountMessage={this.state.loginSupport.user ? signUpForAccountMessage : ''}
forgotCredentials={this.state.loginSupport.user ? forgotCredentials : ''}
>
{this.state.loginSupport.user &&
<Form>
<FormAlert>
{this.state.alert && this.state.alert.message &&
<Alert
variant={this.state.alert.status || 'info'}
title={this.state.alert.message}
aria-live="polite"
isInline
/>
}
</FormAlert>
<FormGroup
label="Email address"
isRequired
fieldId="email"
validated={this.state.isValidEmail ? 'default' : 'error'}
>
<TextInput
isRequired
type="email"
id="email"
name="email"
validated={this.state.isValidEmail ? 'default' : 'error'}
aria-describedby="email-helper"
value={this.state.emailValue}
onChange={this.onEmailChange}
onKeyPress={this.onEnterKeyPress}
/>
</FormGroup>
<FormGroup
label="Password"
isRequired
fieldId="password"
validated={this.state.isValidPassword ? 'default' : 'error'}
>
<InputGroup>
{!this.state.isPasswordVisible &&
<TextInput
isRequired
type="password"
id="password"
name="password"
validated={this.state.isValidPassword ? 'default' : 'error'}
aria-describedby="password-helper"
value={this.state.passwordValue}
onChange={this.onPasswordChange}
onKeyPress={this.onEnterKeyPress} />
}
{this.state.isPasswordVisible &&
<TextInput
isRequired
type="text"
id="password"
name="password"
validated={this.state.isValidPassword ? 'default' : 'error'}
aria-describedby="password-helper"
value={this.state.passwordValue}
onChange={this.onPasswordChange}
onKeyPress={this.onEnterKeyPress} />
}
<Button variant="control" aria-label="Show password" onClick={this.onPasswordVisibleClick}>
{!this.state.isPasswordVisible && <EyeIcon/>}
{this.state.isPasswordVisible && <EyeSlashIcon/>}
</Button>
</InputGroup>
</FormGroup>
<ActionGroup>
<Button
variant="primary"
isBlock
isLoading={this.state.isLoggingIn}
isDisabled={this.state.isLoggingIn}
onClick={this.onLoginButtonClick}
>
{this.state.isLoggingIn ? 'Logging in...' : 'Log In'}
</Button>
</ActionGroup>
</Form>
}
</LoginPage>
);
}
Example #9
Source File: user.js From ibutsu-server with MIT License | 4 votes |
render() {
const { user, projects } = this.state;
let projectInfo = [];
// create the project rows
if (projects && user) {
projectInfo.push(projects.map((project) => (
<DataListCell key={project.name} className="pf-u-p-sm">
<span> {project.title} </span>
{project.owner_id === user.id &&
<Label className="project-owner-label" variant="filled" color="green" isCompact>Owner</Label>
}
</DataListCell>
)))
}
return (
<React.Fragment>
<PageSection variant={PageSectionVariants.light}>
<Title headingLevel="h1" size='2xl' className="pf-c-title">
<React.Fragment>
<span> Profile </span>
{user && user.is_superadmin &&
<Label className="super-admin-label" variant="filled" color="blue">Administrator</Label>
}
</React.Fragment>
</Title>
</PageSection>
<PageSection>
{!user && <Alert variant="danger" title="Error fetching user details" />}
{user &&
<DataList selectedDataListItemId={null} aria-label="User profile">
<DataListItem aria-labelledby="Name">
<DataListItemRow>
{!this.state.isEditing &&
<DataListItemCells
dataListCells={[
<DataListCell key={1} width={2}><strong>Name:</strong></DataListCell>,
<DataListCell key={2} width={4}>{user.name} <Button variant="link" icon={<PencilAltIcon />} onClick={this.onEditButtonClicked} isInline isSmall ouiaId="edit-profile-button">Edit</Button></DataListCell>
]}
/>
}
{this.state.isEditing &&
<DataListItemCells
dataListCells={[
<DataListCell key={1} width={2}><strong>Name:</strong></DataListCell>,
<DataListCell key={2} width={4}>
<InputGroup>
<TextInput value={this.state.tempName} type="text" onChange={value => this.setState({tempName: value})} aria-label="User name" />
<Button variant="control" icon={<CheckIcon />} onClick={this.onSaveButtonClicked} ouiaId="edit-save-button">Save</Button>
<Button variant="control" icon={<TimesIcon />} onClick={this.onCancelButtonClicked} ouiaId="edit-cancel-button">Cancel</Button>
</InputGroup>
</DataListCell>
]}
/>
}
</DataListItemRow>
</DataListItem>
<DataListItem aria-labelledby="E-mail">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1} width={2}><strong>E-mail:</strong></DataListCell>,
<DataListCell key={2} width={4}>{user.email}</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
<DataListItem aria-labelledby="Projects">
<DataListItemRow>
<DataListItemCells
dataListCells={[
<DataListCell key={1} width={2}><strong>My Projects:</strong></DataListCell>,
<DataListCell key={2} width={4} style={{paddingTop: 0, paddingBottom: 0}}>
<DataList aria-lable="projects" style={{borderTop: "none"}}>
{projects &&
projectInfo
}
</DataList>
</DataListCell>
]}
/>
</DataListItemRow>
</DataListItem>
</DataList>
}
</PageSection>
</React.Fragment>
);
}
Example #10
Source File: reset-password.js From ibutsu-server with MIT License | 4 votes |
render() {
const loginMessage = (
<LoginMainFooterBandItem>
Already registered? <NavLink to="/login">Log in.</NavLink>
</LoginMainFooterBandItem>
);
const forgotCredentials = (
<LoginMainFooterBandItem>
<NavLink to="/forgot-password">Forgot username or password?</NavLink>
</LoginMainFooterBandItem>
);
const backgroundImages = {
lg: '/images/pfbg_1200.jpg',
sm: '/images/pfbg_768.jpg',
sm2x: '/images/[email protected]',
xs: '/images/pfbg_576.jpg',
xs2x: '/images/[email protected]'
};
return (
<LoginPage
footerListVariants="inline"
brandImgSrc="/images/ibutsu-wordart-164.png"
brandImgAlt="Ibutsu"
backgroundImgSrc={backgroundImages}
backgroundImgAlt="Background image"
textContent="Ibutsu is an open source test result aggregation. Collect and display your test results, view artifacts, and monitor tests."
loginTitle="Reset your password"
loginSubtitle="Please type in a secure password"
signUpForAccountMessage={loginMessage}
forgotCredentials={forgotCredentials}
>
<Form>
{this.state.showAlert &&
<FormAlert>
<Alert variant={this.state.alertType} title={this.state.alertText} aria-live="polite" isInline/>
</FormAlert>
}
<FormGroup
label="Password"
isRequired
fieldId="password"
validated={this.state.isValidPassword ? 'default' : 'error'}
>
<InputGroup>
{!this.state.isPasswordVisible &&
<TextInput
isRequired
type="password"
id="password"
name="password"
validated={this.state.isValidPassword ? 'default' : 'error'}
aria-describedby="password-helper"
value={this.state.passwordValue}
onChange={this.onPasswordChange} />
}
{this.state.isPasswordVisible &&
<TextInput
isRequired
type="text"
id="password"
name="password"
validated={this.state.isValidPassword ? 'default' : 'error'}
aria-describedby="password-helper"
value={this.state.passwordValue}
onChange={this.onPasswordChange} />}
<Button variant="control" aria-label="Show password" onClick={this.onPasswordVisibleClick}>
{!this.state.isPasswordVisible && <EyeIcon/>}
{this.state.isPasswordVisible && <EyeSlashIcon/>}
</Button>
</InputGroup>
<PasswordErrorBoundary>
<Suspense fallback={""}>
<PasswordStrengthBar password={this.state.passwordValue}/>
</Suspense>
</PasswordErrorBoundary>
</FormGroup>
<FormGroup
label="Confirm password"
isRequired
fieldId="confirm-password"
helperText={this.state.confirmPasswordHelpText}
helperTextInvalid="Passwords do not match"
validated={this.state.confirmPasswordValidation}
>
<InputGroup>
{!this.state.isConfirmPasswordVisible && <TextInput isRequired type="password" id="confirm-password" name="confirm-password" aria-describedby="confirm-password-helper" value={this.state.confirmPasswordValue} onChange={this.onConfirmPasswordChange} validated={this.state.confirmPasswordValidation} />}
{this.state.isConfirmPasswordVisible && <TextInput isRequired type="text" id="confirm-password" name="confirm-password" aria-describedby="confirm-password-helper" value={this.state.confirmPasswordValue} onChange={this.onConfirmPasswordChange} validated={this.state.confirmPasswordValidation} />}
<Button variant="control" aria-label="Show password" onClick={this.onConfirmPasswordVisibleClick}>
{!this.state.isConfirmPasswordVisible && <EyeIcon/>}
{this.state.isConfirmPasswordVisible && <EyeSlashIcon/>}
</Button>
</InputGroup>
</FormGroup>
<ActionGroup>
<Button variant="primary" isBlock onClick={this.onResetButtonClick}>Reset Password</Button>
</ActionGroup>
</Form>
</LoginPage>
);
}
Example #11
Source File: sign-up.js From ibutsu-server with MIT License | 4 votes |
render() {
const loginMessage = (
<LoginMainFooterBandItem>
Already registered? <NavLink to="/login">Log in.</NavLink>
</LoginMainFooterBandItem>
);
const forgotCredentials = (
<LoginMainFooterBandItem>
<NavLink to="/forgot-password">Forgot username or password?</NavLink>
</LoginMainFooterBandItem>
);
const backgroundImages = {
lg: '/images/pfbg_1200.jpg',
sm: '/images/pfbg_768.jpg',
sm2x: '/images/[email protected]',
xs: '/images/pfbg_576.jpg',
xs2x: '/images/[email protected]'
};
return (
<LoginPage
footerListVariants="inline"
brandImgSrc="/images/ibutsu-wordart-164.png"
brandImgAlt="Ibutsu"
backgroundImgSrc={backgroundImages}
backgroundImgAlt="Background image"
textContent="Ibutsu is an open source test result aggregation. Collect and display your test results, view artifacts, and monitor tests."
loginTitle="Register a new account"
loginSubtitle="Please type in your e-mail address and a secure password"
signUpForAccountMessage={loginMessage}
forgotCredentials={forgotCredentials}
>
<Form>
{this.state.showAlert &&
<FormAlert>
<Alert variant={this.state.alertType} title={this.state.alertText} aria-live="polite" isInline/>
</FormAlert>
}
<FormGroup
label="Email address"
isRequired
fieldId="email"
validated={this.state.isValidEmail ? 'default' : 'error'}
helperText="The e-mail address you want to use to log in"
>
<TextInput
isRequired
type="email"
id="email"
name="email"
validated={this.state.isValidEmail ? 'default' : 'error'}
aria-describedby="email-helper"
value={this.state.emailValue}
onChange={this.onEmailChange}
/>
</FormGroup>
<FormGroup
label="Password"
isRequired
fieldId="password"
validated={this.state.isValidPassword ? 'default' : 'error'}
>
<InputGroup>
{!this.state.isPasswordVisible &&
<TextInput
isRequired
type="password"
id="password"
name="password"
validated={this.state.isValidPassword ? 'default' : 'error'}
aria-describedby="password-helper"
value={this.state.passwordValue}
onChange={this.onPasswordChange} />
}
{this.state.isPasswordVisible &&
<TextInput
isRequired
type="text"
id="password"
name="password"
validated={this.state.isValidPassword ? 'default' : 'error'}
aria-describedby="password-helper"
value={this.state.passwordValue}
onChange={this.onPasswordChange} />}
<Button variant="control" aria-label="Show password" onClick={this.onPasswordVisibleClick}>
{!this.state.isPasswordVisible && <EyeIcon/>}
{this.state.isPasswordVisible && <EyeSlashIcon/>}
</Button>
</InputGroup>
<PasswordErrorBoundary>
<Suspense fallback={""}>
<PasswordStrengthBar password={this.state.passwordValue}/>
</Suspense>
</PasswordErrorBoundary>
</FormGroup>
<FormGroup
label="Confirm password"
isRequired
fieldId="confirm-password"
helperText={this.state.confirmPasswordHelpText}
helperTextInvalid="Passwords do not match"
validated={this.state.confirmPasswordValidation}
>
<InputGroup>
{!this.state.isConfirmPasswordVisible && <TextInput isRequired type="password" id="confirm-password" name="confirm-password" aria-describedby="confirm-password-helper" value={this.state.confirmPasswordValue} onChange={this.onConfirmPasswordChange} validated={this.state.confirmPasswordValidation} />}
{this.state.isConfirmPasswordVisible && <TextInput isRequired type="text" id="confirm-password" name="confirm-password" aria-describedby="confirm-password-helper" value={this.state.confirmPasswordValue} onChange={this.onConfirmPasswordChange} validated={this.state.confirmPasswordValidation} />}
<Button variant="control" aria-label="Show password" onClick={this.onConfirmPasswordVisibleClick}>
{!this.state.isConfirmPasswordVisible && <EyeIcon/>}
{this.state.isConfirmPasswordVisible && <EyeSlashIcon/>}
</Button>
</InputGroup>
</FormGroup>
<ActionGroup>
<Button variant="primary" isBlock onClick={this.onRegisterButtonClick}>Register</Button>
</ActionGroup>
</Form>
</LoginPage>
);
}