style(usage): extract DeletedTag, unify deleted-entity tag across filters
This commit is contained in:
@@ -0,0 +1,44 @@
|
|||||||
|
/**
|
||||||
|
* Deleted-entity marker for the usage filter dropdowns (model / user / api-key
|
||||||
|
* on the Tokens tab; user / instance / volume on the resource tabs). Renders an
|
||||||
|
* outlined transparent pill "Deleted·#{id}" — the id keeps two entries sharing
|
||||||
|
* a now-stale label distinguishable. Pairs with dimming the option label to the
|
||||||
|
* tertiary text color.
|
||||||
|
*
|
||||||
|
* Presentational only: each filter resolves the entity id from its own option
|
||||||
|
* shape (Tokens tab ← ``identity.current``; resource tabs ← option ``value``)
|
||||||
|
* and passes it in. When no id is available the tag falls back to plain
|
||||||
|
* "Deleted".
|
||||||
|
*/
|
||||||
|
import { useIntl } from '@umijs/max';
|
||||||
|
import { Tag } from 'antd';
|
||||||
|
import React from 'react';
|
||||||
|
|
||||||
|
interface DeletedTagProps {
|
||||||
|
id?: string | number | null;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DeletedTag: React.FC<DeletedTagProps> = ({ id }) => {
|
||||||
|
const intl = useIntl();
|
||||||
|
const label = intl.formatMessage({ id: 'usage.table.deleted' });
|
||||||
|
return (
|
||||||
|
<Tag
|
||||||
|
variant="outlined"
|
||||||
|
style={{
|
||||||
|
margin: 0,
|
||||||
|
fontSize: 11,
|
||||||
|
borderRadius: 12,
|
||||||
|
background: 'transparent'
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{label}
|
||||||
|
{id != null && (
|
||||||
|
<span className="text-tertiary">
|
||||||
|
<span style={{ margin: '0 2px' }}>·</span>#{id}
|
||||||
|
</span>
|
||||||
|
)}
|
||||||
|
</Tag>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default DeletedTag;
|
||||||
@@ -13,6 +13,7 @@ import React from 'react';
|
|||||||
import { GroupOption } from '../config';
|
import { GroupOption } from '../config';
|
||||||
import { UsageFilterItem } from '../config/types';
|
import { UsageFilterItem } from '../config/types';
|
||||||
import FilterBarCss from '../styles/filter-bar.less';
|
import FilterBarCss from '../styles/filter-bar.less';
|
||||||
|
import DeletedTag from './deleted-tag';
|
||||||
|
|
||||||
type valueType = string | number | null;
|
type valueType = string | number | null;
|
||||||
const DefaultDateConfig = {
|
const DefaultDateConfig = {
|
||||||
@@ -156,6 +157,17 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
|
|||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// The entity id behind a deleted option, shown in the "Deleted·#{id}" tag so
|
||||||
|
// two deleted entries with the same (now-stale) label stay distinguishable.
|
||||||
|
const getEntityId = (data: any): valueType => {
|
||||||
|
const current = data?.identity?.current;
|
||||||
|
if (!current) return null;
|
||||||
|
return current.user_id ?? current.api_key_id ?? current.route_id ?? null;
|
||||||
|
};
|
||||||
|
|
||||||
|
const deletedLabelStyle = (deleted?: boolean) =>
|
||||||
|
deleted ? { color: 'var(--ant-color-text-tertiary)' } : undefined;
|
||||||
|
|
||||||
const handleOnApiKeysChange = (
|
const handleOnApiKeysChange = (
|
||||||
value: valueType[][],
|
value: valueType[][],
|
||||||
selectedOptions: any
|
selectedOptions: any
|
||||||
@@ -175,9 +187,10 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
|
|||||||
if (!data.isParent) {
|
if (!data.isParent) {
|
||||||
return (
|
return (
|
||||||
<span className="flex-center gap-4">
|
<span className="flex-center gap-4">
|
||||||
<AutoTooltip ghost>{data.label}</AutoTooltip>
|
<AutoTooltip ghost style={deletedLabelStyle(data.deleted)}>
|
||||||
{data.deleted &&
|
{data.label}
|
||||||
renderTag(intl.formatMessage({ id: 'usage.table.deleted' }))}
|
</AutoTooltip>
|
||||||
|
{data.deleted && <DeletedTag id={getEntityId(data)} />}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -193,9 +206,10 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
|
|||||||
const { data } = option;
|
const { data } = option;
|
||||||
return (
|
return (
|
||||||
<span className="flex-center gap-4">
|
<span className="flex-center gap-4">
|
||||||
<AutoTooltip ghost>{data.label}</AutoTooltip>
|
<AutoTooltip ghost style={deletedLabelStyle(data.deleted)}>
|
||||||
{data.deleted &&
|
{data.label}
|
||||||
renderTag(intl.formatMessage({ id: 'usage.table.deleted' }))}
|
</AutoTooltip>
|
||||||
|
{data.deleted && <DeletedTag id={getEntityId(data)} />}
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
@@ -214,11 +228,12 @@ const FilterBar: React.FC<FilterBarProps> = (props) => {
|
|||||||
const { data } = option;
|
const { data } = option;
|
||||||
return (
|
return (
|
||||||
<span className="flex-center gap-4">
|
<span className="flex-center gap-4">
|
||||||
<AutoTooltip ghost>{data.label}</AutoTooltip>
|
<AutoTooltip ghost style={deletedLabelStyle(data.deleted)}>
|
||||||
|
{data.label}
|
||||||
|
</AutoTooltip>
|
||||||
{data.isCurrent &&
|
{data.isCurrent &&
|
||||||
renderTag(intl.formatMessage({ id: 'usage.user.currentAccount' }))}
|
renderTag(intl.formatMessage({ id: 'usage.user.currentAccount' }))}
|
||||||
{data.deleted &&
|
{data.deleted && <DeletedTag id={getEntityId(data)} />}
|
||||||
renderTag(intl.formatMessage({ id: 'usage.table.deleted' }))}
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ import { Button, DatePicker, Dropdown, MenuProps } from 'antd';
|
|||||||
import dayjs from 'dayjs';
|
import dayjs from 'dayjs';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import FilterBarCss from '../styles/filter-bar.less';
|
import FilterBarCss from '../styles/filter-bar.less';
|
||||||
|
import DeletedTag from './deleted-tag';
|
||||||
|
|
||||||
const DefaultDateConfig = {
|
const DefaultDateConfig = {
|
||||||
maxRange: 90,
|
maxRange: 90,
|
||||||
@@ -144,15 +145,22 @@ const ResourceFilterBar: React.FC<ResourceFilterBarProps> = (props) => {
|
|||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const deletedLabelStyle = (deleted?: boolean) =>
|
||||||
|
deleted ? { color: 'var(--ant-color-text-tertiary)' } : undefined;
|
||||||
|
|
||||||
|
// The user / instance / volume filters mirror the Tokens tab: the option
|
||||||
|
// ``value`` is the entity id, so a deleted entry stays distinguishable via the
|
||||||
|
// "Deleted·#{id}" tag.
|
||||||
const userOptionRender = (option: any) => {
|
const userOptionRender = (option: any) => {
|
||||||
const { data } = option;
|
const { data } = option;
|
||||||
return (
|
return (
|
||||||
<span className="flex-center gap-4">
|
<span className="flex-center gap-4">
|
||||||
<AutoTooltip ghost>{data?.label}</AutoTooltip>
|
<AutoTooltip ghost style={deletedLabelStyle(data?.deleted)}>
|
||||||
|
{data?.label}
|
||||||
|
</AutoTooltip>
|
||||||
{data?.isCurrent &&
|
{data?.isCurrent &&
|
||||||
renderTag(intl.formatMessage({ id: 'usage.user.currentAccount' }))}
|
renderTag(intl.formatMessage({ id: 'usage.user.currentAccount' }))}
|
||||||
{data?.deleted &&
|
{data?.deleted && <DeletedTag id={data?.value} />}
|
||||||
renderTag(intl.formatMessage({ id: 'usage.table.deleted' }))}
|
|
||||||
</span>
|
</span>
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user