1
0
Fork 0
mirror of https://github.com/portainer/portainer.git synced 2025-08-05 05:45:22 +02:00

refactor(azure): migrate module to react [EE-2782] (#6689)

* refactor(azure): migrate module to react [EE-2782]

* fix(azure): remove optional chain

* feat(azure): apply new icons in dashboard

* feat(azure): apply new icons in dashboard

* feat(ui): allow single string for breadcrumbs

* refactor(azure/containers): use Table.content

* feat(azure/containers): implement new ui [EE-3538]

* fix(azure/containers): use correct icon

* chore(tests): mock svg as component

* fix(azure): fix tests

Co-authored-by: matias.spinarolli <matias.spinarolli@portainer.io>
This commit is contained in:
Chaim Lev-Ari 2022-07-26 21:44:08 +02:00 committed by GitHub
parent b059641c80
commit 82b848af0c
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
97 changed files with 1723 additions and 1430 deletions

View file

@ -10,16 +10,20 @@ export interface Crumb {
linkParams?: Record<string, unknown>;
}
interface Props {
breadcrumbs: (Crumb | string)[];
breadcrumbs: (Crumb | string)[] | string;
}
export function Breadcrumbs({ breadcrumbs }: Props) {
const breadcrumbsArray = Array.isArray(breadcrumbs)
? breadcrumbs
: [breadcrumbs];
return (
<div className="breadcrumb-links">
{breadcrumbs.map((crumb, index) => (
{breadcrumbsArray.map((crumb, index) => (
<Fragment key={index}>
{renderCrumb(crumb)}
{index !== breadcrumbs.length - 1 ? ' > ' : ''}
{index !== breadcrumbsArray.length - 1 ? ' > ' : ''}
</Fragment>
))}
</div>

View file

@ -14,7 +14,7 @@ interface Props {
reload?: boolean;
loading?: boolean;
onReload?(): Promise<void> | void;
breadcrumbs?: Crumb[];
breadcrumbs?: (Crumb | string)[] | string;
title: string;
}

View file

@ -5,10 +5,11 @@ import styles from './AddButton.module.css';
export interface Props {
className?: string;
label: string;
disabled?: boolean;
onClick: () => void;
}
export function AddButton({ label, onClick, className }: Props) {
export function AddButton({ label, onClick, className, disabled }: Props) {
return (
<button
className={clsx(
@ -20,6 +21,7 @@ export function AddButton({ label, onClick, className }: Props) {
)}
type="button"
onClick={onClick}
disabled={disabled}
>
<i className="fa fa-plus-circle space-right" aria-hidden="true" /> {label}
</button>

View file

@ -1,13 +1,11 @@
import { PropsWithChildren } from 'react';
import { Icon } from '@/react/components/Icon';
import { Icon, IconProps } from '@@/Icon';
import { useTableContext } from './TableContainer';
interface Props {
icon: string;
interface Props extends IconProps {
label: string;
featherIcon?: boolean;
}
export function TableTitle({

View file

@ -25,7 +25,7 @@ interface UseRowSelectTableInstance<D extends DefaultType = DefaultType>
isAllRowSelected: boolean;
selectSubRows: boolean;
getSubRows(row: Row<D>): Row<D>[];
isRowSelectable(row: Row<D>): boolean;
isRowSelectable?(row: Row<D>): boolean;
}
const pluginName = 'useRowSelect';
@ -73,7 +73,10 @@ function defaultGetToggleRowSelectedProps<D extends DefaultType>(
props: D,
{ instance, row }: { instance: UseRowSelectTableInstance<D>; row: Row<D> }
) {
const { manualRowSelectedKey = 'isSelected' } = instance;
const {
manualRowSelectedKey = 'isSelected',
isRowSelectable = defaultIsRowSelectable,
} = instance;
let checked = false;
if (row.original && row.original[manualRowSelectedKey]) {
@ -94,7 +97,7 @@ function defaultGetToggleRowSelectedProps<D extends DefaultType>(
checked,
title: 'Toggle Row Selected',
indeterminate: row.isSomeSelected,
disabled: !instance.isRowSelectable(row),
disabled: !isRowSelectable(row),
},
];
}
@ -317,7 +320,7 @@ function useInstance<D extends Record<string, unknown>>(
dispatch,
page,
getSubRows,
isRowSelectable,
isRowSelectable = defaultIsRowSelectable,
} = instance;
ensurePluginOrder(
@ -474,5 +477,5 @@ function getRowIsSelected<D extends Record<string, unknown>>(
}
function defaultIsRowSelectable<D extends DefaultType>(row: Row<D>) {
return !!row.original.disabled;
return !row.original.disabled;
}

View file

@ -15,6 +15,8 @@ interface Props<T> {
onChange(value: T): void;
options: Option<T>[];
size?: Size;
disabled?: boolean;
readOnly?: boolean;
}
export function ButtonSelector<T extends string | number>({
@ -22,6 +24,8 @@ export function ButtonSelector<T extends string | number>({
onChange,
size,
options,
disabled,
readOnly,
}: Props<T>) {
return (
<ButtonGroup size={size} className={styles.group}>
@ -30,6 +34,8 @@ export function ButtonSelector<T extends string | number>({
key={option.value}
selected={value === option.value}
onChange={() => onChange(option.value)}
disabled={disabled}
readOnly={readOnly}
>
{option.label || option.value.toString()}
</OptionItem>
@ -41,17 +47,32 @@ export function ButtonSelector<T extends string | number>({
interface OptionItemProps {
selected: boolean;
onChange(): void;
disabled?: boolean;
readOnly?: boolean;
}
function OptionItem({
selected,
children,
onChange,
disabled,
readOnly,
}: PropsWithChildren<OptionItemProps>) {
return (
<label className={clsx('btn btn-primary', { active: selected })}>
<label
className={clsx('btn btn-primary', {
active: selected,
disabled: readOnly || disabled,
})}
>
{children}
<input type="radio" checked={selected} onChange={onChange} />
<input
type="radio"
checked={selected}
onChange={onChange}
disabled={disabled}
readOnly={readOnly}
/>
</label>
);
}

View file

@ -1,5 +1,6 @@
import { ComponentType } from 'react';
import clsx from 'clsx';
import { FormikErrors } from 'formik';
import { AddButton, Button } from '@@/buttons';
import { Tooltip } from '@@/Tip/Tooltip';
@ -11,12 +12,12 @@ import { FormError } from '../FormError';
import styles from './InputList.module.css';
import { arrayMove } from './utils';
export type InputListError<T> = Record<keyof T, string>;
export interface ItemProps<T> {
item: T;
onChange(value: T): void;
error?: InputListError<T>;
error?: string | FormikErrors<T>;
disabled?: boolean;
readOnly?: boolean;
}
type Key = string | number;
type ChangeType = 'delete' | 'create' | 'update';
@ -36,7 +37,7 @@ type OnChangeEvent<T> =
type RenderItemFunction<T> = (
item: T,
onChange: (value: T) => void,
error?: InputListError<T>
error?: string | FormikErrors<T>
) => React.ReactNode;
interface Props<T> {
@ -50,9 +51,11 @@ interface Props<T> {
addLabel?: string;
itemKeyGetter?(item: T, index: number): Key;
movable?: boolean;
errors?: InputListError<T>[] | string;
errors?: FormikErrors<T>[] | string | string[];
textTip?: string;
isAddButtonHidden?: boolean;
disabled?: boolean;
readOnly?: boolean;
}
export function InputList<T = DefaultType>({
@ -69,6 +72,8 @@ export function InputList<T = DefaultType>({
errors,
textTip,
isAddButtonHidden = false,
disabled,
readOnly,
}: Props<T>) {
return (
<div className={clsx('form-group', styles.root)}>
@ -77,11 +82,12 @@ export function InputList<T = DefaultType>({
{label}
{tooltip && <Tooltip message={tooltip} />}
</div>
{!isAddButtonHidden && (
{!(isAddButtonHidden || readOnly) && (
<AddButton
label={addLabel}
className="space-left"
onClick={handleAdd}
disabled={disabled}
/>
)}
</div>
@ -107,6 +113,8 @@ export function InputList<T = DefaultType>({
item={item}
onChange={(value: T) => handleChangeItem(key, value)}
error={error}
disabled={disabled}
readOnly={readOnly}
/>
) : (
renderItem(
@ -116,11 +124,11 @@ export function InputList<T = DefaultType>({
)
)}
<div className={clsx(styles.itemActions, 'items-start')}>
{movable && (
{!readOnly && movable && (
<>
<Button
size="small"
disabled={index === 0}
disabled={disabled || index === 0}
onClick={() => handleMoveUp(index)}
>
<i className="fa fa-arrow-up" aria-hidden="true" />
@ -128,20 +136,23 @@ export function InputList<T = DefaultType>({
<Button
size="small"
type="button"
disabled={index === value.length - 1}
disabled={disabled || index === value.length - 1}
onClick={() => handleMoveDown(index)}
>
<i className="fa fa-arrow-down" aria-hidden="true" />
</Button>
</>
)}
<Button
color="danger"
size="small"
onClick={() => handleRemoveItem(key, item)}
>
<i className="fa fa-trash" aria-hidden="true" />
</Button>
{!readOnly && (
<Button
color="danger"
size="small"
onClick={() => handleRemoveItem(key, item)}
disabled={disabled}
>
<i className="fa fa-trash" aria-hidden="true" />
</Button>
)}
</div>
</div>
);
@ -210,13 +221,21 @@ function defaultItemBuilder(): DefaultType {
return { value: '' };
}
function DefaultItem({ item, onChange, error }: ItemProps<DefaultType>) {
function DefaultItem({
item,
onChange,
error,
disabled,
readOnly,
}: ItemProps<DefaultType>) {
return (
<>
<Input
value={item.value}
onChange={(e) => onChange({ value: e.target.value })}
className={styles.defaultItem}
disabled={disabled}
readOnly={readOnly}
/>
{error && <FormError>{error}</FormError>}
</>
@ -226,7 +245,7 @@ function DefaultItem({ item, onChange, error }: ItemProps<DefaultType>) {
function renderDefaultItem(
item: DefaultType,
onChange: (value: DefaultType) => void,
error?: InputListError<DefaultType>
error?: FormikErrors<DefaultType>
) {
return <DefaultItem item={item} onChange={onChange} error={error} />;
}