@ansible/ansible-ui-framework 0.0.232 → 0.0.234

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/cjs/BulkActionDialog.js +2 -2
  2. package/cjs/PageBody.js +1 -1
  3. package/cjs/PageDataList.js +1 -2
  4. package/cjs/PageHeader.js +2 -2
  5. package/cjs/PageTable.js +32 -8
  6. package/cjs/PageTableCard.js +87 -0
  7. package/cjs/PageTableCards.js +38 -0
  8. package/cjs/PageTableList.js +79 -0
  9. package/cjs/PageTableViewType.js +9 -0
  10. package/cjs/PageToolbar.js +25 -1
  11. package/cjs/TypedActions/TypedActions.js +13 -4
  12. package/cjs/components/Details.js +2 -1
  13. package/cjs/components/patternfly-colors.js +11 -1
  14. package/cjs/index.js +1 -1
  15. package/mjs/BulkActionDialog.js +2 -2
  16. package/mjs/PageBody.d.ts +1 -0
  17. package/mjs/PageBody.js +1 -1
  18. package/mjs/PageDataList.js +1 -2
  19. package/mjs/PageHeader.d.ts +1 -0
  20. package/mjs/PageHeader.js +2 -2
  21. package/mjs/PageTable.d.ts +10 -1
  22. package/mjs/PageTable.js +28 -7
  23. package/mjs/PageTableCard.d.ts +33 -0
  24. package/mjs/PageTableCard.js +69 -0
  25. package/mjs/PageTableCards.d.ts +4 -0
  26. package/mjs/PageTableCards.js +23 -0
  27. package/mjs/PageTableList.d.ts +6 -0
  28. package/mjs/PageTableList.js +62 -0
  29. package/mjs/PageTableViewType.d.ts +6 -0
  30. package/mjs/PageTableViewType.js +6 -0
  31. package/mjs/PageToolbar.d.ts +3 -0
  32. package/mjs/PageToolbar.js +27 -3
  33. package/mjs/TypedActions/TypedActions.d.ts +3 -0
  34. package/mjs/TypedActions/TypedActions.js +14 -5
  35. package/mjs/components/Details.d.ts +1 -1
  36. package/mjs/components/Details.js +2 -2
  37. package/mjs/components/patternfly-colors.d.ts +10 -0
  38. package/mjs/components/patternfly-colors.js +10 -0
  39. package/mjs/index.d.ts +1 -1
  40. package/mjs/index.js +1 -1
  41. package/package.json +1 -1
  42. package/cjs/PageCatalog.js +0 -178
  43. package/mjs/PageCatalog.d.ts +0 -113
  44. package/mjs/PageCatalog.js +0 -140
package/mjs/PageHeader.js CHANGED
@@ -59,7 +59,7 @@ export function PageHeader(props) {
59
59
  borderTop: settings.theme !== 'light' && settings.borders
60
60
  ? 'thin solid var(--pf-global--BorderColor--100)'
61
61
  : undefined,
62
- borderBottom: settings.borders
62
+ borderBottom: !props.disableBorderBottom && settings.borders
63
63
  ? 'thin solid var(--pf-global--BorderColor--100)'
64
64
  : undefined,
65
65
  backgroundColor: 'var(--pf-global--BackgroundColor--100)',
@@ -69,7 +69,7 @@ export function PageHeader(props) {
69
69
  borderTop: !navigation && settings.theme !== 'light' && settings.borders
70
70
  ? 'thin solid var(--pf-global--BorderColor--100)'
71
71
  : undefined,
72
- borderBottom: settings.borders
72
+ borderBottom: !props.disableBorderBottom && settings.borders
73
73
  ? 'thin solid var(--pf-global--BorderColor--100)'
74
74
  : undefined,
75
75
  backgroundColor: settings.theme === 'dark'
@@ -1,5 +1,6 @@
1
1
  import { Dispatch, ReactNode, SetStateAction } from 'react';
2
2
  import { PageHeaderProps } from './PageHeader';
3
+ import { PageTableViewType } from './PageTableViewType';
3
4
  import { IToolbarFilter } from './PageToolbar';
4
5
  import { ITypedAction } from './TypedActions';
5
6
  export declare type TablePageProps<T extends object> = PageHeaderProps & PageTableProps<T> & {
@@ -43,7 +44,12 @@ export declare type PageTableProps<T extends object> = {
43
44
  emptyStateButtonClick?: () => void;
44
45
  t?: (t: string) => string;
45
46
  showSelect?: boolean;
46
- ColumnManagement?: boolean;
47
+ disableTableView?: boolean;
48
+ disableListView?: boolean;
49
+ disableCardView?: boolean;
50
+ defaultTableView?: PageTableViewType;
51
+ disableBodyPadding?: boolean;
52
+ defaultCardSubtitle?: ReactNode;
47
53
  };
48
54
  export declare function PageTable<T extends object>(props: PageTableProps<T>): JSX.Element;
49
55
  declare type CellFn<T extends object> = (item: T) => ReactNode;
@@ -64,5 +70,8 @@ export interface ITableColumn<T extends object> {
64
70
  * @deprecated The method should not be used
65
71
  */
66
72
  sortFn?: (l: T, r: T) => number;
73
+ card?: 'description' | 'hidden';
74
+ list?: 'primary' | 'secondary';
75
+ hideLabel?: boolean;
67
76
  }
68
77
  export {};
package/mjs/PageTable.js CHANGED
@@ -4,19 +4,41 @@ import { ExclamationCircleIcon, PlusCircleIcon, SearchIcon } from '@patternfly/r
4
4
  import { ActionsColumn, TableComposable, Tbody, Td, Th, Thead, Tr, } from '@patternfly/react-table';
5
5
  import useResizeObserver from '@react-hook/resize-observer';
6
6
  import { Fragment, useCallback, useEffect, useRef, useState, } from 'react';
7
+ import { Scrollable } from './components/Scrollable';
7
8
  import { useBreakpoint } from './components/useBreakPoint';
8
9
  import { PageBody } from './PageBody';
9
10
  import { useColumnModal } from './PageColumnModal';
10
11
  import { PageHeader } from './PageHeader';
11
12
  import { PageLayout } from './PageLayout';
12
13
  import { PagePagination } from './PagePagination';
14
+ import { PageTableCards } from './PageTableCards';
15
+ import { PageTableList } from './PageTableList';
16
+ import { PageTableViewTypeE } from './PageTableViewType';
13
17
  import { PageTableToolbar } from './PageToolbar';
14
18
  import { useSettings } from './Settings';
15
19
  import { TypedActionType, useTypedActionsToTableActions } from './TypedActions';
16
20
  export function TablePage(props) {
17
- return (_jsx(_Fragment, { children: _jsxs(PageLayout, { children: [_jsx(PageHeader, { ...props }), _jsx(PageBody, { children: _jsx(PageTable, { ...props }) })] }) }));
21
+ return (_jsxs(PageLayout, { children: [_jsx(PageHeader, { ...props }), _jsx(PageTable, { ...props })] }));
18
22
  }
19
23
  export function PageTable(props) {
24
+ let { disableBodyPadding } = props;
25
+ disableBodyPadding = true;
26
+ const { toolbarActions } = props;
27
+ const { openColumnModal, columnModal, managedColumns } = useColumnModal(props.tableColumns);
28
+ const showSelect = toolbarActions?.find((toolbarAction) => TypedActionType.bulk === toolbarAction.type) !==
29
+ undefined;
30
+ const hasTableViewType = !props.disableTableView;
31
+ const hasListViewType = !props.disableListView;
32
+ // const hasCardViewType = !props.disableCardView
33
+ const [viewType, setViewType] = useState(() => props.defaultTableView ??
34
+ (hasTableViewType
35
+ ? PageTableViewTypeE.Table
36
+ : hasListViewType
37
+ ? PageTableViewTypeE.List
38
+ : PageTableViewTypeE.Cards));
39
+ return (_jsxs(_Fragment, { children: [_jsx(PageTableToolbar, { ...props, openColumnModal: openColumnModal, showSelect: showSelect, viewType: viewType, setViewType: setViewType }), viewType === PageTableViewTypeE.Table && (_jsx(PageBody, { disablePadding: disableBodyPadding, children: _jsx(PageTableView, { ...props, tableColumns: managedColumns }) })), viewType === PageTableViewTypeE.List && (_jsx(PageBody, { disablePadding: true, children: _jsx(Scrollable, { children: _jsx(PageTableList, { ...props, showSelect: showSelect }) }) })), viewType === PageTableViewTypeE.Cards && (_jsx(Scrollable, { children: _jsx(PageTableCards, { ...props, showSelect: showSelect }) })), (!props.autoHidePagination || (props.itemCount ?? 0) > props.perPage) && (_jsx(PagePagination, { ...props })), columnModal] }));
40
+ }
41
+ function PageTableView(props) {
20
42
  const { tableColumns, pageItems, selectItem, unselectItem, isSelected, keyFn, rowActions, toolbarActions, itemCount, perPage, clearAllFilters, filters, error, onSelect, unselectAll, } = props;
21
43
  let { t } = props;
22
44
  t = t ? t : (t) => t;
@@ -44,7 +66,6 @@ export function PageTable(props) {
44
66
  useResizeObserver(containerRef, () => updateScroll(containerRef.current));
45
67
  useEffect(() => updateScroll(containerRef.current), [updateScroll]);
46
68
  const settings = useSettings();
47
- const { openColumnModal, columnModal, managedColumns } = useColumnModal(tableColumns);
48
69
  if (error) {
49
70
  return (_jsx("div", { style: {
50
71
  backgroundColor: settings.theme === 'dark' ? 'var(--pf-global--BackgroundColor--300)' : undefined,
@@ -56,11 +77,11 @@ export function PageTable(props) {
56
77
  if (itemCount === 0 && Object.keys(filters ?? {}).length === 0) {
57
78
  return (_jsxs(EmptyState, { variant: EmptyStateVariant.large, style: { paddingTop: 64 }, children: [_jsx(EmptyStateIcon, { icon: PlusCircleIcon }), _jsx(Title, { headingLevel: "h4", size: "lg", children: props.emptyStateTitle }), props.emptyStateDescription && (_jsx(EmptyStateBody, { children: props.emptyStateDescription })), props.emptyStateButtonClick && (_jsx(Button, { variant: "primary", onClick: props.emptyStateButtonClick, children: props.emptyStateButtonText }))] }));
58
79
  }
59
- return (_jsxs(Fragment, { children: [columnModal, _jsx(PageTableToolbar, { ...props, openColumnModal: openColumnModal, showSelect: showSelect }), _jsxs("div", { className: "pf-c-scroll-inner-wrapper", style: { height: '100%' }, ref: containerRef, onScroll: onScroll, children: [_jsxs(TableComposable, { "aria-label": "Simple table", variant: props.compact ? 'compact' : settings.tableLayout === 'compact' ? 'compact' : undefined, gridBreakPoint: "", isStickyHeader: true, children: [itemCount === undefined ? (_jsx(Thead, { children: _jsx(Tr, { children: _jsx(Th, { children: _jsx(Skeleton, {}) }) }) })) : (_jsx(TableHead, { ...props, showSelect: showSelect, scrollLeft: scroll.left > 0, scrollRight: scroll.right > 1, tableColumns: managedColumns, onSelect: onSelect })), _jsx(Tbody, { children: itemCount === undefined
60
- ? new Array(perPage).fill(0).map((_, index) => (_jsx(Tr, { children: _jsx(Td, { children: _jsx("div", { style: { paddingTop: 5, paddingBottom: 5 }, children: _jsx(Skeleton, { height: "27px" }) }) }) }, index)))
61
- : pageItems === undefined
62
- ? new Array(Math.min(perPage, itemCount)).fill(0).map((_, index) => (_jsxs(Tr, { children: [showSelect && _jsx(Td, {}), _jsx(Td, { colSpan: managedColumns.length, children: _jsx("div", { style: { paddingTop: 5, paddingBottom: 5 }, children: _jsx(Skeleton, { height: "27px" }) }) })] }, index)))
63
- : pageItems?.map((item, rowIndex) => (_jsx(TableRow, { columns: managedColumns, item: item, isItemSelected: isSelected?.(item), selectItem: selectItem, unselectItem: unselectItem, rowActions: rowActions, rowIndex: rowIndex, showSelect: showSelect, scrollLeft: scroll.left > 0, scrollRight: scroll.right > 1, unselectAll: unselectAll, onSelect: onSelect }, keyFn ? keyFn(item) : rowIndex))) })] }), itemCount === 0 && (_jsx("div", { style: { margin: 'auto' }, children: _jsxs(EmptyState, { children: [_jsx(EmptyStateIcon, { icon: SearchIcon }), _jsx(Title, { headingLevel: "h2", size: "lg", children: t('No results found') }), _jsx(EmptyStateBody, { children: t('No results match this filter criteria. Adjust your filters and try again.') }), clearAllFilters && (_jsx(EmptyStateSecondaryActions, { children: _jsx(Button, { variant: "link", onClick: clearAllFilters, children: t('Clear all filters') }) }))] }) }))] }), (!props.autoHidePagination || (itemCount ?? 0) > perPage) && _jsx(PagePagination, { ...props })] }));
80
+ return (_jsxs("div", { className: "pf-c-scroll-inner-wrapper", style: { height: '100%', marginBottom: -1 }, ref: containerRef, onScroll: onScroll, children: [_jsxs(TableComposable, { "aria-label": "Simple table", variant: props.compact ? 'compact' : settings.tableLayout === 'compact' ? 'compact' : undefined, gridBreakPoint: "", isStickyHeader: true, children: [itemCount === undefined ? (_jsx(Thead, { children: _jsx(Tr, { children: _jsx(Th, { children: _jsx(Skeleton, {}) }) }) })) : (_jsx(TableHead, { ...props, showSelect: showSelect, scrollLeft: scroll.left > 0, scrollRight: scroll.right > 1, tableColumns: tableColumns, onSelect: onSelect })), _jsx(Tbody, { children: itemCount === undefined
81
+ ? new Array(perPage).fill(0).map((_, index) => (_jsx(Tr, { children: _jsx(Td, { children: _jsx("div", { style: { paddingTop: 5, paddingBottom: 5 }, children: _jsx(Skeleton, { height: "27px" }) }) }) }, index)))
82
+ : pageItems === undefined
83
+ ? new Array(Math.min(perPage, itemCount)).fill(0).map((_, index) => (_jsxs(Tr, { children: [showSelect && _jsx(Td, {}), _jsx(Td, { colSpan: tableColumns.length, children: _jsx("div", { style: { paddingTop: 5, paddingBottom: 5 }, children: _jsx(Skeleton, { height: "27px" }) }) })] }, index)))
84
+ : pageItems?.map((item, rowIndex) => (_jsx(TableRow, { columns: tableColumns, item: item, isItemSelected: isSelected?.(item), selectItem: selectItem, unselectItem: unselectItem, rowActions: rowActions, rowIndex: rowIndex, showSelect: showSelect, scrollLeft: scroll.left > 0, scrollRight: scroll.right > 1, unselectAll: unselectAll, onSelect: onSelect }, keyFn ? keyFn(item) : rowIndex))) })] }), itemCount === 0 && (_jsx("div", { style: { margin: 'auto' }, children: _jsxs(EmptyState, { children: [_jsx(EmptyStateIcon, { icon: SearchIcon }), _jsx(Title, { headingLevel: "h2", size: "lg", children: t('No results found') }), _jsx(EmptyStateBody, { children: t('No results match this filter criteria. Adjust your filters and try again.') }), clearAllFilters && (_jsx(EmptyStateSecondaryActions, { children: _jsx(Button, { variant: "link", onClick: clearAllFilters, children: t('Clear all filters') }) }))] }) }))] }));
64
85
  }
65
86
  function TableHead(props) {
66
87
  const { tableColumns: columns, rowActions: itemActions, sort, setSort, sortDirection, setSortDirection, showSelect, onSelect, } = props;
@@ -0,0 +1,33 @@
1
+ import { ReactNode } from 'react';
2
+ import { LabelColor } from './components/patternfly-colors';
3
+ import { ITableColumn } from './PageTable';
4
+ import { ITypedAction } from './TypedActions';
5
+ export interface IPageTableCard {
6
+ id: string | number;
7
+ icon?: ReactNode;
8
+ title: ReactNode;
9
+ description?: ReactNode;
10
+ cardBody: ReactNode;
11
+ labels?: {
12
+ label: string;
13
+ color?: LabelColor;
14
+ }[];
15
+ badge?: string;
16
+ badgeColor?: LabelColor;
17
+ badgeTooltip?: string;
18
+ badgeTooltipTitle?: string;
19
+ alertTitle?: string;
20
+ alertContent?: ReactNode;
21
+ alertVariant?: 'success' | 'danger' | 'warning' | 'info' | 'default';
22
+ }
23
+ export declare function PageTableCard<T extends object>(props: {
24
+ item: T;
25
+ itemToCardFn: (item: T) => IPageTableCard;
26
+ isSelected?: (item: T) => boolean;
27
+ selectItem?: (item: T) => void;
28
+ unselectItem?: (item: T) => void;
29
+ itemActions?: ITypedAction<T>[];
30
+ showSelect?: boolean;
31
+ defaultCardSubtitle?: ReactNode;
32
+ }): JSX.Element;
33
+ export declare function useColumnsToTableCardFn<T extends object>(columns: ITableColumn<T>[], keyFn: (item: T) => string | number): (item: T) => IPageTableCard;
@@ -0,0 +1,69 @@
1
+ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ /* eslint-disable @typescript-eslint/no-non-null-assertion */
3
+ /* eslint-disable @typescript-eslint/no-empty-function */
4
+ import { Alert, Card, CardActions, CardBody, CardFooter, CardHeader, CardTitle, Checkbox, DescriptionList, DropdownPosition, Label, LabelGroup, Popover, Split, SplitItem, Stack, Text, Truncate, } from '@patternfly/react-core';
5
+ import { useCallback, useMemo } from 'react';
6
+ import { Detail } from './components/Details';
7
+ import { IconWrapper } from './components/IconWrapper';
8
+ import { TypedActions } from './TypedActions';
9
+ export function PageTableCard(props) {
10
+ const { item, itemToCardFn, isSelected, selectItem, unselectItem, itemActions, showSelect, defaultCardSubtitle, } = props;
11
+ const card = useMemo(() => itemToCardFn(item), [item, itemToCardFn]);
12
+ const isItemSelected = !!isSelected?.(item);
13
+ const onSelectClick = useCallback(() => {
14
+ if (isSelected?.(item)) {
15
+ unselectItem?.(item);
16
+ }
17
+ else {
18
+ selectItem?.(item);
19
+ }
20
+ }, [isSelected, item, selectItem, unselectItem]);
21
+ const showDropdown = itemActions !== undefined && itemActions.length > 0;
22
+ const showActions = showSelect || showDropdown;
23
+ return (_jsxs(Card, { id: card.id, isFlat: true, isLarge: true, isRounded: true, isSelectable: isItemSelected, isSelected: isItemSelected, style: {
24
+ transition: 'box-shadow 0.25s',
25
+ cursor: 'default',
26
+ }, children: [_jsxs(CardHeader, { children: [_jsxs(Split, { hasGutter: true, style: { width: '100%' }, children: [_jsx(SplitItem, { isFilled: true, children: _jsxs("div", { style: { display: 'flex', alignItems: 'center' }, children: [card.icon && (_jsx("div", { style: {
27
+ display: 'flex',
28
+ height: 40,
29
+ width: 40,
30
+ marginTop: -20,
31
+ marginBottom: -20,
32
+ marginRight: 12,
33
+ alignItems: 'center',
34
+ justifyItems: 'stretch',
35
+ }, children: _jsx(IconWrapper, { size: "lg", children: card.icon }) })), _jsxs(Stack, { children: [_jsx(CardTitle, { children: card.title }), card.description ? (_jsx(Text, { component: "small", style: { opacity: 0.7 }, children: card.description })) : (defaultCardSubtitle && _jsx(Text, { component: "small", children: defaultCardSubtitle }))] })] }) }), card.badge && card.badgeTooltip && (_jsx(SplitItem, { children: _jsx("div", { onClick: (e) => e.stopPropagation(), children: _jsx(Popover, { headerContent: card.badgeTooltipTitle, bodyContent: card.badgeTooltip, removeFindDomNode: true, children: _jsx(Label, { color: card.badgeColor, children: card.badge }) }) }) })), card.badge && !card.badgeTooltip && (_jsx(SplitItem, { children: _jsx(Label, { color: card.badgeColor, children: card.badge }) }))] }), showActions && (_jsxs(CardActions, { children: [itemActions && itemActions.length && (_jsx(TypedActions, { actions: itemActions, position: DropdownPosition.right, selectedItem: item })), showSelect && (_jsx(Checkbox, { isChecked: isSelected?.(item), onChange: onSelectClick,
36
+ // aria-label="card checkbox example"
37
+ id: "check-1" }))] }))] }), card.cardBody, card.labels && (_jsx(CardFooter, { children: _jsx("div", { style: {
38
+ display: 'flex',
39
+ flexDirection: 'row',
40
+ alignItems: 'end',
41
+ gap: 16,
42
+ }, children: _jsx("div", { style: { flexGrow: 1 }, children: card.labels && (_jsx(LabelGroup, { children: card.labels.map((item) => (_jsx(Label, { color: item.color, children: _jsx(Truncate, { content: item.label, style: { minWidth: 0 } }) }, item.label))) })) }) }) })), card.alertTitle && (_jsx(Alert, { title: card.alertTitle, isInline: true, variant: card.alertVariant, children: card.alertContent }))] }, card.id ?? card.title));
43
+ }
44
+ export function useColumnsToTableCardFn(columns, keyFn) {
45
+ const cardData = useMemo(() => {
46
+ let cols = columns.filter((column) => column.card !== 'hidden');
47
+ const nameColumn = cols.shift();
48
+ const descriptionColumn = cols.find((column) => column.card === 'description');
49
+ if (descriptionColumn) {
50
+ cols = cols.filter((column) => column !== descriptionColumn);
51
+ }
52
+ return {
53
+ nameColumn: nameColumn,
54
+ descriptionColumn: descriptionColumn,
55
+ columns: cols,
56
+ };
57
+ }, [columns]);
58
+ return useMemo(() => {
59
+ return (item) => {
60
+ const pageTableCard = {
61
+ id: keyFn(item),
62
+ title: cardData.nameColumn?.cell(item),
63
+ description: cardData.descriptionColumn?.cell(item),
64
+ cardBody: (_jsx(CardBody, { children: _jsx(DescriptionList, { isCompact: true, children: cardData.columns.map((column) => (_jsx(Detail, { label: column.hideLabel ? undefined : column.header, children: column.cell(item) }, column.id))) }) })),
65
+ };
66
+ return pageTableCard;
67
+ };
68
+ }, [cardData.columns, cardData.descriptionColumn, cardData.nameColumn, keyFn]);
69
+ }
@@ -0,0 +1,4 @@
1
+ /// <reference types="react" />
2
+ import { PageTableProps } from './PageTable';
3
+ export declare type PageTableCardsProps<T extends object> = PageTableProps<T>;
4
+ export declare function PageTableCards<T extends object>(props: PageTableCardsProps<T>): JSX.Element;
@@ -0,0 +1,23 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { PageSection } from '@patternfly/react-core';
3
+ import { useMemo } from 'react';
4
+ import { Grid } from './components/Grid';
5
+ import { PageTableCard, useColumnsToTableCardFn } from './PageTableCard';
6
+ export function PageTableCards(props) {
7
+ const { keyFn, pageItems: items, tableColumns, isSelected, selectItem, unselectItem, rowActions, showSelect, defaultCardSubtitle, } = props;
8
+ const itemToCardFn = useColumnsToTableCardFn(tableColumns, keyFn);
9
+ const catalogCards = useMemo(() => {
10
+ return (_jsx(Grid, { size: 470, children: items?.map((item) => (_jsx(PageTableCard, { item: item, itemToCardFn: itemToCardFn, isSelected: isSelected, selectItem: selectItem, unselectItem: unselectItem, itemActions: rowActions, showSelect: showSelect, defaultCardSubtitle: defaultCardSubtitle }, keyFn(item)))) }));
11
+ }, [
12
+ items,
13
+ keyFn,
14
+ itemToCardFn,
15
+ isSelected,
16
+ selectItem,
17
+ unselectItem,
18
+ rowActions,
19
+ showSelect,
20
+ defaultCardSubtitle,
21
+ ]);
22
+ return _jsx(PageSection, { style: { flexGrow: 1 }, children: catalogCards });
23
+ }
@@ -0,0 +1,6 @@
1
+ import { ReactNode } from 'react';
2
+ import { ITableColumn, PageTableProps } from './PageTable';
3
+ import { ITypedAction } from './TypedActions';
4
+ export declare type PageTableListProps<T extends object> = PageTableProps<T>;
5
+ export declare function PageTableList<T extends object>(props: PageTableListProps<T>): JSX.Element;
6
+ export declare function useColumnsToDataList<T extends object>(tableColumns: ITableColumn<T>[], keyFn: (item: T) => string | number, isSelected?: (item: T) => boolean, selectItem?: (item: T) => void, unselectItem?: (item: T) => void, rowActions?: ITypedAction<T>[], defaultCardSubtitle?: ReactNode, showSelect?: boolean): (item: T) => ReactNode;
@@ -0,0 +1,62 @@
1
+ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
+ import { DataList, DataListAction, DataListCell, DataListCheck, DataListItem, DataListItemCells, DataListItemRow, DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm, DropdownPosition, Flex, Stack, Text, Title, } from '@patternfly/react-core';
3
+ import { useCallback, useMemo } from 'react';
4
+ import { TypedActions } from './TypedActions';
5
+ export function PageTableList(props) {
6
+ const { keyFn, pageItems, tableColumns, isSelected, selectItem, unselectItem, rowActions, defaultCardSubtitle, showSelect, } = props;
7
+ const columnsToDataList = useColumnsToDataList(tableColumns, keyFn, isSelected, selectItem, unselectItem, rowActions, defaultCardSubtitle, showSelect);
8
+ return (_jsx(DataList, { "aria-label": "TODO", style: { marginTop: -1 }, children: pageItems?.map(columnsToDataList) }));
9
+ }
10
+ export function useColumnsToDataList(tableColumns, keyFn, isSelected, selectItem, unselectItem, rowActions, defaultCardSubtitle, showSelect) {
11
+ const data = useMemo(() => {
12
+ let cols = tableColumns.filter((column) => column.card !== 'hidden');
13
+ const nameColumn = cols.shift();
14
+ const descriptionColumn = cols.find((column) => column.card === 'description');
15
+ if (descriptionColumn) {
16
+ cols = cols.filter((column) => column !== descriptionColumn);
17
+ }
18
+ return {
19
+ nameColumn: nameColumn,
20
+ descriptionColumn: descriptionColumn,
21
+ columns: cols.filter((column) => column.list !== 'secondary'),
22
+ secondary: cols.filter((column) => column.list === 'secondary'),
23
+ };
24
+ }, [tableColumns]);
25
+ const onSelectClick = useCallback((item) => {
26
+ if (isSelected?.(item)) {
27
+ unselectItem?.(item);
28
+ }
29
+ else {
30
+ selectItem?.(item);
31
+ }
32
+ }, [isSelected, selectItem, unselectItem]);
33
+ return useCallback((item) => {
34
+ const key = keyFn(item);
35
+ const isItemSelected = isSelected?.(item);
36
+ return (_jsx(DataListItem, { "aria-labelledby": `data-list-${key}`, isExpanded: isItemSelected, children: _jsxs(DataListItemRow, { children: [showSelect && (_jsx(DataListCheck, { "aria-labelledby": `data-list-check-${key}`, name: `data-list-check-${key}`, isChecked: isSelected?.(item), onClick: () => onSelectClick(item) })), _jsx(DataListItemCells, { dataListCells: [
37
+ _jsx(DataListCell, { children: _jsx(Flex, { children: _jsxs(Stack, { hasGutter: true, children: [_jsxs(Stack, { children: [_jsx(Title, { headingLevel: "h2", style: { marginTop: -4 }, children: _jsx("span", { id: `data-list-${key}`, children: data.nameColumn?.cell(item) }) }), data.descriptionColumn ? (_jsx(Text, { component: "small", style: { opacity: 0.7 }, children: data.descriptionColumn.cell(item) })) : (defaultCardSubtitle && (_jsx(Text, { component: "small", style: { opacity: 0.7 }, children: defaultCardSubtitle })))] }), _jsx(DescriptionList, { isCompact: true, children: data.columns.map((column) => {
38
+ const value = column.cell(item);
39
+ if (!value)
40
+ return _jsx(_Fragment, {});
41
+ return (_jsxs(DescriptionListGroup, { children: [!column.hideLabel && (_jsx(DescriptionListTerm, { children: _jsx(Text, { component: "small", style: { opacity: 0.7 }, children: column.header }) })), _jsx(DescriptionListDescription, { children: column.cell(item) })] }, column.header));
42
+ }) })] }) }) }, "primary"),
43
+ _jsx(DataListCell, { children: _jsx(Flex, { children: _jsx(DescriptionList, { isCompact: true, children: data.secondary.map((column) => {
44
+ const value = column.cell(item);
45
+ if (!value)
46
+ return _jsx(_Fragment, {});
47
+ return (_jsxs(DescriptionListGroup, { children: [!column.hideLabel && (_jsx(DescriptionListTerm, { children: _jsx(Text, { component: "small", style: { opacity: 0.7 }, children: column.header }) })), _jsx(DescriptionListDescription, { children: column.cell(item) })] }, column.header));
48
+ }) }) }) }, "secondary"),
49
+ ] }), rowActions && (_jsx(DataListAction, { "aria-labelledby": "check-action-item1 check-action-action1", id: "check-action-action1", "aria-label": "Actions", isPlainButtonAction: true, style: { whiteSpace: 'nowrap' }, children: _jsx(TypedActions, { actions: rowActions, position: DropdownPosition.right, selectedItem: item }) }))] }) }, key));
50
+ }, [
51
+ data.columns,
52
+ data.descriptionColumn,
53
+ data.nameColumn,
54
+ data.secondary,
55
+ defaultCardSubtitle,
56
+ isSelected,
57
+ keyFn,
58
+ onSelectClick,
59
+ rowActions,
60
+ showSelect,
61
+ ]);
62
+ }
@@ -0,0 +1,6 @@
1
+ export declare enum PageTableViewTypeE {
2
+ Table = "table",
3
+ List = "list",
4
+ Cards = "cards"
5
+ }
6
+ export declare type PageTableViewType = 'table' | 'list' | 'cards';
@@ -0,0 +1,6 @@
1
+ export var PageTableViewTypeE;
2
+ (function (PageTableViewTypeE) {
3
+ PageTableViewTypeE["Table"] = "table";
4
+ PageTableViewTypeE["List"] = "list";
5
+ PageTableViewTypeE["Cards"] = "cards";
6
+ })(PageTableViewTypeE || (PageTableViewTypeE = {}));
@@ -1,4 +1,5 @@
1
1
  import { Dispatch, SetStateAction } from 'react';
2
+ import { PageTableViewType } from './PageTableViewType';
2
3
  import { ITypedAction } from './TypedActions';
3
4
  export interface IItemFilter<T extends object> {
4
5
  label: string;
@@ -53,5 +54,7 @@ export declare type PagetableToolbarProps<T extends object> = {
53
54
  onSelect?: (item: T) => void;
54
55
  disableBorderBottom?: boolean;
55
56
  showSelect?: boolean;
57
+ viewType: PageTableViewType;
58
+ setViewType: (viewType: PageTableViewType) => void;
56
59
  };
57
60
  export declare function PageTableToolbar<T extends object>(props: PagetableToolbarProps<T>): JSX.Element;
@@ -1,11 +1,12 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
2
- import { Button, Flex, FlexItem, InputGroup, Pagination, PaginationVariant, Select, SelectOption, SelectVariant, Skeleton, TextInputGroup, TextInputGroupMain, TextInputGroupUtilities, Toolbar, ToolbarContent, ToolbarFilter, ToolbarGroup, ToolbarItem, ToolbarToggleGroup, Tooltip, } from '@patternfly/react-core';
3
- import { ArrowRightIcon, ColumnsIcon, FilterIcon, TimesIcon } from '@patternfly/react-icons';
2
+ import { Button, Flex, FlexItem, InputGroup, Pagination, PaginationVariant, Select, SelectOption, SelectVariant, Skeleton, TextInputGroup, TextInputGroupMain, TextInputGroupUtilities, ToggleGroup, ToggleGroupItem, Toolbar, ToolbarContent, ToolbarFilter, ToolbarGroup, ToolbarItem, ToolbarToggleGroup, Tooltip, } from '@patternfly/react-core';
3
+ import { ArrowRightIcon, ColumnsIcon, FilterIcon, ListIcon, TableIcon, ThLargeIcon, TimesIcon, } from '@patternfly/react-icons';
4
4
  import { Fragment, useCallback, useState } from 'react';
5
5
  import { useTranslation } from 'react-i18next';
6
6
  import { BulkSelector } from './components/BulkSelector';
7
7
  import { SingleSelect2 } from './components/SingleSelect';
8
8
  import { useBreakpoint } from './components/useBreakPoint';
9
+ import { PageTableViewTypeE } from './PageTableViewType';
9
10
  import { useSettings } from './Settings';
10
11
  import { TypedActions, TypedActionType } from './TypedActions';
11
12
  export function toolbarActionsHaveBulkActions(actions) {
@@ -20,6 +21,7 @@ export function toolbarActionsHaveBulkActions(actions) {
20
21
  export function PageTableToolbar(props) {
21
22
  const { itemCount, page, perPage, setPage, setPerPage, toolbarFilters, selectedItems, filters, setFilters, clearAllFilters, openColumnModal, disableBorderBottom, } = props;
22
23
  const sm = useBreakpoint('md');
24
+ const { viewType, setViewType } = props;
23
25
  let { toolbarActions } = props;
24
26
  toolbarActions = toolbarActions ?? [];
25
27
  const onSetPage = useCallback((_event, page) => setPage(page), [setPage]);
@@ -96,7 +98,29 @@ export function PageTableToolbar(props) {
96
98
  return newState;
97
99
  });
98
100
  }, showToolbarItem: false, children: _jsx(_Fragment, {}) }, filter.label));
99
- })] }) })), _jsx(ToolbarGroup, { variant: "button-group", style: { zIndex: 302 }, children: _jsx(ToolbarItem, { children: _jsx(TypedActions, { actions: toolbarActions, selectedItems: selectedItems, wrapper: ToolbarItem }) }) }), _jsx(ToolbarGroup, { variant: "button-group", style: { zIndex: 302 }, children: openColumnModal && (_jsx(ToolbarItem, { children: _jsx(Tooltip, { content: 'Manage columns', children: _jsx(Button, { variant: "plain", icon: _jsx(ColumnsIcon, {}), onClick: openColumnModal }) }) })) }), _jsx(ToolbarItem, { variant: "pagination", visibility: { default: 'hidden', '2xl': 'visible' }, children: _jsx(Pagination, { variant: PaginationVariant.top, isCompact: true, itemCount: itemCount, perPage: perPage, page: page, onSetPage: onSetPage, onPerPageSelect: onPerPageSelect, style: { marginTop: -8, marginBottom: -8 } }) })] }) }));
101
+ })] }) })), _jsx(ToolbarGroup, { variant: "button-group", style: { zIndex: 302 }, children: _jsx(ToolbarItem, { children: _jsx(TypedActions, { actions: toolbarActions, selectedItems: selectedItems, wrapper: ToolbarItem }) }) }), _jsx("div", { style: { flexGrow: 1 } }), _jsxs(ToolbarGroup, { variant: "button-group", style: { zIndex: 302 }, children: [openColumnModal && viewType === 'table' && (_jsx(ToolbarItem, { children: _jsx(Tooltip, { content: 'Manage columns', children: _jsx(Button, { variant: "plain", icon: _jsx(ColumnsIcon, {}), onClick: openColumnModal }) }) })), _jsx(ToolbarItem, { children: _jsx(ToggleGroup, { children: [PageTableViewTypeE.Table, PageTableViewTypeE.List, PageTableViewTypeE.Cards]
102
+ // .filter((vt) => {
103
+ // switch (vt) {
104
+ // case PageTableViewTypeE.Cards:
105
+ // return props.itemToCardFn !== undefined
106
+ // case PageTableViewTypeE.list:
107
+ // return false
108
+ // case PageTableViewTypeE.table:
109
+ // return props.tableColumns !== undefined
110
+ // default:
111
+ // return false
112
+ // }
113
+ // })
114
+ .map((vt) => {
115
+ switch (vt) {
116
+ case PageTableViewTypeE.Cards:
117
+ return (_jsx(Tooltip, { content: 'Card view', position: "top-end", enableFlip: false, children: _jsx(ToggleGroupItem, { icon: _jsx(ThLargeIcon, {}), isSelected: viewType === PageTableViewTypeE.Cards, onClick: () => setViewType?.(PageTableViewTypeE.Cards) }) }, vt));
118
+ case PageTableViewTypeE.List:
119
+ return (_jsx(Tooltip, { content: 'List view', position: "top-end", enableFlip: false, children: _jsx(ToggleGroupItem, { icon: _jsx(ListIcon, {}), isSelected: viewType === PageTableViewTypeE.List, onClick: () => setViewType?.(PageTableViewTypeE.List) }) }));
120
+ case PageTableViewTypeE.Table:
121
+ return (_jsx(Tooltip, { content: 'Table view', position: "top-end", enableFlip: false, children: _jsx(ToggleGroupItem, { icon: _jsx(TableIcon, {}), isSelected: viewType === PageTableViewTypeE.Table, onClick: () => setViewType?.(PageTableViewTypeE.Table) }) }));
122
+ }
123
+ }) }) })] }), _jsx(ToolbarItem, { visibility: { default: 'hidden', '2xl': 'visible' }, children: _jsx(Pagination, { variant: PaginationVariant.top, isCompact: true, itemCount: itemCount, perPage: perPage, page: page, onSetPage: onSetPage, onPerPageSelect: onPerPageSelect, style: { marginTop: -8, marginBottom: -8 } }) })] }) }));
100
124
  }
101
125
  function ToolbarFilterInput(props) {
102
126
  const { filter } = props;
@@ -45,17 +45,20 @@ export declare function TypedActionsDropdown<T extends object>(props: {
45
45
  label?: string;
46
46
  isPrimary?: boolean;
47
47
  selectedItems?: T[];
48
+ selectedItem?: T;
48
49
  position?: DropdownPosition;
49
50
  }): JSX.Element;
50
51
  export declare function DropdownActionItem<T extends object>(props: {
51
52
  action: ITypedAction<T>;
52
53
  selectedItems: T[];
54
+ selectedItem?: T;
53
55
  hasIcons: boolean;
54
56
  index: number;
55
57
  }): JSX.Element;
56
58
  export declare function TypedActions<T extends object>(props: {
57
59
  actions: ITypedAction<T>[];
58
60
  selectedItems?: T[];
61
+ selectedItem?: T;
59
62
  wrapper?: ComponentClass | FunctionComponent;
60
63
  collapse?: WindowSize;
61
64
  noPrimary?: boolean;
@@ -3,7 +3,7 @@ import { ButtonVariant, Dropdown, DropdownItem, DropdownSeparator, DropdownToggl
3
3
  import { CircleIcon } from '@patternfly/react-icons';
4
4
  import { useCallback, useMemo, useState } from 'react';
5
5
  import { useBreakpoint } from '../components/useBreakPoint';
6
- import { TypedActionsButtons, TypedActionButton } from './TypedActionsButtons';
6
+ import { TypedActionButton, TypedActionsButtons } from './TypedActionsButtons';
7
7
  export var TypedActionType;
8
8
  (function (TypedActionType) {
9
9
  TypedActionType["seperator"] = "seperator";
@@ -13,7 +13,7 @@ export var TypedActionType;
13
13
  TypedActionType["dropdown"] = "dropdown";
14
14
  })(TypedActionType || (TypedActionType = {}));
15
15
  export function TypedActionsDropdown(props) {
16
- const { actions, label, isPrimary = false, selectedItems } = props;
16
+ const { actions, label, isPrimary = false, selectedItems, selectedItem } = props;
17
17
  const [dropdownOpen, setDropdownOpen] = useState(false);
18
18
  const hasItemActions = useMemo(() => !actions.every((action) => action.type !== TypedActionType.bulk), [actions]);
19
19
  const hasIcons = useMemo(() => actions.find((action) => action.type !== TypedActionType.seperator && action.icon !== undefined) !== undefined, [actions]);
@@ -24,12 +24,21 @@ export function TypedActionsDropdown(props) {
24
24
  ? {
25
25
  color: 'var(--pf-global--Color--light-100)',
26
26
  }
27
- : {}, children: label }), isOpen: dropdownOpen, isPlain: !label, dropdownItems: actions.map((action, index) => (_jsx(DropdownActionItem, { action: action, selectedItems: selectedItems ?? [], hasIcons: hasIcons, index: index }, 'label' in action ? action.label : `action-${index}`))), position: props.position, style: { zIndex: 201 } }));
27
+ : {}, children: label }), isOpen: dropdownOpen, isPlain: !label, dropdownItems: actions.map((action, index) => (_jsx(DropdownActionItem, { action: action, selectedItems: selectedItems ?? [], selectedItem: selectedItem, hasIcons: hasIcons, index: index }, 'label' in action ? action.label : `action-${index}`))), position: props.position, style: { zIndex: 201 } }));
28
28
  }
29
29
  export function DropdownActionItem(props) {
30
- const { action, selectedItems, hasIcons, index } = props;
31
- // TODO case TypedActionType.single?
30
+ const { action, selectedItems, selectedItem, hasIcons, index } = props;
32
31
  switch (action.type) {
32
+ case TypedActionType.single: {
33
+ let Icon = action.icon;
34
+ if (!Icon && hasIcons)
35
+ Icon = TransparentIcon;
36
+ const tooltip = action.tooltip;
37
+ const isDisabled = false;
38
+ return (_jsx(Tooltip, { content: tooltip, trigger: tooltip ? undefined : 'manual', children: _jsx(DropdownItem, { onClick: () => selectedItem && action.onClick(selectedItem), isAriaDisabled: isDisabled, icon: Icon ? (_jsx("span", { style: { paddingRight: 4 }, children: _jsx(Icon, {}) })) : undefined, style: {
39
+ color: action.isDanger && !isDisabled ? 'var(--pf-global--danger-color--100)' : undefined,
40
+ }, children: action.label }) }, action.label));
41
+ }
33
42
  case TypedActionType.button:
34
43
  case TypedActionType.bulk: {
35
44
  let Icon = action.icon;
@@ -32,7 +32,7 @@ export declare function DetailsList(props: {
32
32
  children?: ReactNode;
33
33
  }): JSX.Element;
34
34
  export declare function Detail(props: {
35
- label: string;
35
+ label?: string;
36
36
  children?: ReactNode;
37
37
  }): JSX.Element;
38
38
  export declare function DetailsSkeleton(): JSX.Element;
@@ -1,5 +1,5 @@
1
1
  import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm, Skeleton, Split, SplitItem, Stack, } from '@patternfly/react-core';
2
+ import { DescriptionList, DescriptionListDescription, DescriptionListGroup, DescriptionListTerm, Skeleton, Split, SplitItem, Stack, Text, } from '@patternfly/react-core';
3
3
  import { Link } from 'react-router-dom';
4
4
  import { CopyCell, SinceCell } from '../PageCells';
5
5
  import { useSettings } from '../Settings';
@@ -61,7 +61,7 @@ export function DetailsList(props) {
61
61
  export function Detail(props) {
62
62
  if (!props.children)
63
63
  return _jsx(_Fragment, {});
64
- return (_jsxs(DescriptionListGroup, { children: [_jsx(DescriptionListTerm, { children: props.label }), _jsx(DescriptionListDescription, { id: props.label.toLowerCase().split(' ').join('-'), children: props.children })] }));
64
+ return (_jsxs(DescriptionListGroup, { children: [props.label && (_jsx(DescriptionListTerm, { children: _jsx(Text, { component: "small", style: { opacity: 0.7 }, children: props.label }) })), _jsx(DescriptionListDescription, { id: props.label?.toLowerCase().split(' ').join('-'), children: props.children })] }));
65
65
  }
66
66
  export function DetailsSkeleton() {
67
67
  return (_jsxs(Stack, { hasGutter: true, children: [_jsx(Skeleton, {}), _jsx(Skeleton, {}), _jsx(Skeleton, {}), _jsx(Skeleton, {})] }));
@@ -11,3 +11,13 @@ export declare const pfDanger = "var(--pf-global--danger-color--100)";
11
11
  export declare const pfWarning = "var(--pf-global--warning-color--100)";
12
12
  export declare const pfInfo = "var(--pf-global--info-color--100)";
13
13
  export declare const pfDisabled = "var(--pf-global--disabled-color--100)";
14
+ export declare enum LabelColorE {
15
+ blue = "blue",
16
+ cyan = "cyan",
17
+ green = "green",
18
+ orange = "orange",
19
+ purple = "purple",
20
+ red = "red",
21
+ grey = "grey"
22
+ }
23
+ export declare type LabelColor = 'blue' | 'cyan' | 'green' | 'orange' | 'purple' | 'red' | 'grey';
@@ -26,3 +26,13 @@ export const pfDanger = 'var(--pf-global--danger-color--100)';
26
26
  export const pfWarning = 'var(--pf-global--warning-color--100)';
27
27
  export const pfInfo = 'var(--pf-global--info-color--100)';
28
28
  export const pfDisabled = 'var(--pf-global--disabled-color--100)';
29
+ export var LabelColorE;
30
+ (function (LabelColorE) {
31
+ LabelColorE["blue"] = "blue";
32
+ LabelColorE["cyan"] = "cyan";
33
+ LabelColorE["green"] = "green";
34
+ LabelColorE["orange"] = "orange";
35
+ LabelColorE["purple"] = "purple";
36
+ LabelColorE["red"] = "red";
37
+ LabelColorE["grey"] = "grey";
38
+ })(LabelColorE || (LabelColorE = {}));
package/mjs/index.d.ts CHANGED
@@ -6,7 +6,6 @@ export * from './components/Help';
6
6
  export * from './components/patternfly-colors';
7
7
  export * from './components/useBreakPoint';
8
8
  export * from './PageBody';
9
- export * from './PageCatalog';
10
9
  export * from './PageCells';
11
10
  export * from './PageDataList';
12
11
  export * from './PageDialog';
@@ -15,6 +14,7 @@ export * from './PageFramework';
15
14
  export * from './PageHeader';
16
15
  export * from './PageLayout';
17
16
  export * from './PageTable';
17
+ export * from './PageTableCards';
18
18
  export * from './PageTabs';
19
19
  export * from './PageToolbar';
20
20
  export * from './TypedActions';
package/mjs/index.js CHANGED
@@ -6,7 +6,6 @@ export * from './components/Help';
6
6
  export * from './components/patternfly-colors';
7
7
  export * from './components/useBreakPoint';
8
8
  export * from './PageBody';
9
- export * from './PageCatalog';
10
9
  export * from './PageCells';
11
10
  export * from './PageDataList';
12
11
  export * from './PageDialog';
@@ -15,6 +14,7 @@ export * from './PageFramework';
15
14
  export * from './PageHeader';
16
15
  export * from './PageLayout';
17
16
  export * from './PageTable';
17
+ export * from './PageTableCards';
18
18
  export * from './PageTabs';
19
19
  export * from './PageToolbar';
20
20
  export * from './TypedActions';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@ansible/ansible-ui-framework",
3
3
  "description": "Framework for building consistent responsive web applications using PatternFly.",
4
- "version": "0.0.232",
4
+ "version": "0.0.234",
5
5
  "author": "Red Hat",
6
6
  "license": "MIT",
7
7
  "repository": {