feat: update admin platform resource and user tables
This commit is contained in:
parent
a33474ec5f
commit
39d7e527cb
@ -46,6 +46,56 @@
|
|||||||
font-weight: 650;
|
font-weight: 650;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.selectColumn {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
overflow: visible;
|
||||||
|
padding-right: var(--space-2) !important;
|
||||||
|
padding-left: var(--space-2) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.selectColumn :global(.admin-cell__head-content) {
|
||||||
|
justify-content: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortHeader {
|
||||||
|
display: inline-flex;
|
||||||
|
max-width: 100%;
|
||||||
|
min-width: 0;
|
||||||
|
align-items: center;
|
||||||
|
gap: var(--space-1);
|
||||||
|
padding: 0;
|
||||||
|
border: 0;
|
||||||
|
background: transparent;
|
||||||
|
color: inherit;
|
||||||
|
cursor: pointer;
|
||||||
|
font: inherit;
|
||||||
|
font-weight: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortHeader:hover,
|
||||||
|
.sortHeaderActive {
|
||||||
|
color: var(--text-primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortHeader span {
|
||||||
|
min-width: 0;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortIcon {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
font-size: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sortHeaderActive .sortIcon {
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
.filters {
|
.filters {
|
||||||
display: flex;
|
display: flex;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|||||||
@ -21,6 +21,8 @@ export function useAppUsersPage() {
|
|||||||
const { countryOptions, loadingCountries } = useCountryOptions();
|
const { countryOptions, loadingCountries } = useCountryOptions();
|
||||||
const [query, setQuery] = useState("");
|
const [query, setQuery] = useState("");
|
||||||
const [status, setStatus] = useState("");
|
const [status, setStatus] = useState("");
|
||||||
|
const [sortBy, setSortBy] = useState("created_at");
|
||||||
|
const [sortDirection, setSortDirection] = useState("desc");
|
||||||
const [page, setPage] = useState(1);
|
const [page, setPage] = useState(1);
|
||||||
const [activeAction, setActiveAction] = useState("");
|
const [activeAction, setActiveAction] = useState("");
|
||||||
const [activeUser, setActiveUser] = useState(null);
|
const [activeUser, setActiveUser] = useState(null);
|
||||||
@ -33,9 +35,11 @@ export function useAppUsersPage() {
|
|||||||
const filters = useMemo(
|
const filters = useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
keyword: query,
|
keyword: query,
|
||||||
|
sort_by: sortBy,
|
||||||
|
sort_direction: sortDirection,
|
||||||
status,
|
status,
|
||||||
}),
|
}),
|
||||||
[query, status],
|
[query, sortBy, sortDirection, status],
|
||||||
);
|
);
|
||||||
const {
|
const {
|
||||||
data: queryData = emptyData,
|
data: queryData = emptyData,
|
||||||
@ -61,7 +65,7 @@ export function useAppUsersPage() {
|
|||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedUserIds([]);
|
setSelectedUserIds([]);
|
||||||
setPatchedUsers({});
|
setPatchedUsers({});
|
||||||
}, [page, query, status]);
|
}, [page, query, sortBy, sortDirection, status]);
|
||||||
|
|
||||||
const changeQuery = (value) => {
|
const changeQuery = (value) => {
|
||||||
setQuery(value);
|
setQuery(value);
|
||||||
@ -73,6 +77,12 @@ export function useAppUsersPage() {
|
|||||||
setPage(1);
|
setPage(1);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const changeSort = (field) => {
|
||||||
|
setSortDirection((current) => (sortBy === field ? (current === "asc" ? "desc" : "asc") : "desc"));
|
||||||
|
setSortBy(field);
|
||||||
|
setPage(1);
|
||||||
|
};
|
||||||
|
|
||||||
const resetFilters = () => {
|
const resetFilters = () => {
|
||||||
setQuery("");
|
setQuery("");
|
||||||
setStatus("");
|
setStatus("");
|
||||||
@ -255,7 +265,10 @@ export function useAppUsersPage() {
|
|||||||
setPage,
|
setPage,
|
||||||
setPasswordForm,
|
setPasswordForm,
|
||||||
setSelectedUserIds,
|
setSelectedUserIds,
|
||||||
|
sortBy,
|
||||||
|
sortDirection,
|
||||||
status,
|
status,
|
||||||
|
changeSort,
|
||||||
submitCountry,
|
submitCountry,
|
||||||
submitEdit,
|
submitEdit,
|
||||||
submitPassword,
|
submitPassword,
|
||||||
|
|||||||
@ -1,8 +1,11 @@
|
|||||||
import BlockOutlined from "@mui/icons-material/BlockOutlined";
|
import BlockOutlined from "@mui/icons-material/BlockOutlined";
|
||||||
import EditOutlined from "@mui/icons-material/EditOutlined";
|
import EditOutlined from "@mui/icons-material/EditOutlined";
|
||||||
|
import KeyboardArrowDownOutlined from "@mui/icons-material/KeyboardArrowDownOutlined";
|
||||||
|
import KeyboardArrowUpOutlined from "@mui/icons-material/KeyboardArrowUpOutlined";
|
||||||
import LockOpenOutlined from "@mui/icons-material/LockOpenOutlined";
|
import LockOpenOutlined from "@mui/icons-material/LockOpenOutlined";
|
||||||
import PasswordOutlined from "@mui/icons-material/PasswordOutlined";
|
import PasswordOutlined from "@mui/icons-material/PasswordOutlined";
|
||||||
import PersonOutlineOutlined from "@mui/icons-material/PersonOutlineOutlined";
|
import PersonOutlineOutlined from "@mui/icons-material/PersonOutlineOutlined";
|
||||||
|
import UnfoldMoreOutlined from "@mui/icons-material/UnfoldMoreOutlined";
|
||||||
import Autocomplete from "@mui/material/Autocomplete";
|
import Autocomplete from "@mui/material/Autocomplete";
|
||||||
import Checkbox from "@mui/material/Checkbox";
|
import Checkbox from "@mui/material/Checkbox";
|
||||||
import MenuItem from "@mui/material/MenuItem";
|
import MenuItem from "@mui/material/MenuItem";
|
||||||
@ -27,24 +30,6 @@ const columns = [
|
|||||||
width: "minmax(240px, 1.5fr)",
|
width: "minmax(240px, 1.5fr)",
|
||||||
render: (user) => <UserIdentity user={user} />,
|
render: (user) => <UserIdentity user={user} />,
|
||||||
},
|
},
|
||||||
{ key: "coin", label: "金币", width: "minmax(90px, 0.6fr)", render: (user) => formatNumber(user.coin) },
|
|
||||||
{
|
|
||||||
key: "status",
|
|
||||||
label: "状态",
|
|
||||||
width: "minmax(92px, 0.6fr)",
|
|
||||||
render: (user) => <UserStatus status={user.status} />,
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: "time",
|
|
||||||
label: "创建 / 活跃",
|
|
||||||
width: "minmax(180px, 1fr)",
|
|
||||||
render: (user) => (
|
|
||||||
<div className={styles.stack}>
|
|
||||||
<span>{formatMillis(user.createdAtMs)}</span>
|
|
||||||
<span className={styles.meta}>{formatMillis(user.lastActiveAtMs)}</span>
|
|
||||||
</div>
|
|
||||||
),
|
|
||||||
},
|
|
||||||
];
|
];
|
||||||
|
|
||||||
export function AppUserListPage() {
|
export function AppUserListPage() {
|
||||||
@ -68,6 +53,7 @@ export function AppUserListPage() {
|
|||||||
const tableColumns = [
|
const tableColumns = [
|
||||||
{
|
{
|
||||||
key: "select",
|
key: "select",
|
||||||
|
className: styles.selectColumn,
|
||||||
header: (
|
header: (
|
||||||
<Checkbox
|
<Checkbox
|
||||||
checked={allChecked}
|
checked={allChecked}
|
||||||
@ -77,7 +63,8 @@ export function AppUserListPage() {
|
|||||||
onChange={(event) => toggleAll(event.target.checked)}
|
onChange={(event) => toggleAll(event.target.checked)}
|
||||||
/>
|
/>
|
||||||
),
|
),
|
||||||
width: "52px",
|
resizable: false,
|
||||||
|
width: "64px",
|
||||||
render: (user) => {
|
render: (user) => {
|
||||||
const banned = isBannedUser(user);
|
const banned = isBannedUser(user);
|
||||||
return (
|
return (
|
||||||
@ -110,19 +97,53 @@ export function AppUserListPage() {
|
|||||||
width: "minmax(170px, 1fr)",
|
width: "minmax(170px, 1fr)",
|
||||||
render: (user) => <UserLocation page={page} user={user} />,
|
render: (user) => <UserLocation page={page} user={user} />,
|
||||||
},
|
},
|
||||||
...columns.slice(1).map((column) =>
|
{
|
||||||
column.key === "status"
|
key: "coin",
|
||||||
? {
|
header: (
|
||||||
...column,
|
<SortHeader
|
||||||
filter: createOptionsColumnFilter({
|
field="coin"
|
||||||
options: appUserStatusFilters,
|
label="金币"
|
||||||
placeholder: "搜索状态",
|
sortBy={page.sortBy}
|
||||||
value: page.status,
|
sortDirection={page.sortDirection}
|
||||||
onChange: page.changeStatus,
|
onClick={page.changeSort}
|
||||||
}),
|
/>
|
||||||
}
|
),
|
||||||
: column,
|
label: "金币",
|
||||||
),
|
width: "minmax(90px, 0.6fr)",
|
||||||
|
render: (user) => formatNumber(user.coin),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "status",
|
||||||
|
label: "状态",
|
||||||
|
width: "minmax(92px, 0.6fr)",
|
||||||
|
filter: createOptionsColumnFilter({
|
||||||
|
options: appUserStatusFilters,
|
||||||
|
placeholder: "搜索状态",
|
||||||
|
value: page.status,
|
||||||
|
onChange: page.changeStatus,
|
||||||
|
}),
|
||||||
|
render: (user) => <UserStatus status={user.status} />,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: "time",
|
||||||
|
header: (
|
||||||
|
<SortHeader
|
||||||
|
field="created_at"
|
||||||
|
label="创建 / 活跃"
|
||||||
|
sortBy={page.sortBy}
|
||||||
|
sortDirection={page.sortDirection}
|
||||||
|
onClick={page.changeSort}
|
||||||
|
/>
|
||||||
|
),
|
||||||
|
label: "创建 / 活跃",
|
||||||
|
width: "minmax(180px, 1fr)",
|
||||||
|
render: (user) => (
|
||||||
|
<div className={styles.stack}>
|
||||||
|
<span>{formatMillis(user.createdAtMs)}</span>
|
||||||
|
<span className={styles.meta}>{formatMillis(user.lastActiveAtMs)}</span>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: "actions",
|
key: "actions",
|
||||||
label: "操作",
|
label: "操作",
|
||||||
@ -335,6 +356,27 @@ function UserStatus({ status }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function SortHeader({ field, label, onClick, sortBy, sortDirection }) {
|
||||||
|
const active = sortBy === field;
|
||||||
|
const nextDirection = active && sortDirection === "desc" ? "asc" : "desc";
|
||||||
|
const Icon = !active
|
||||||
|
? UnfoldMoreOutlined
|
||||||
|
: sortDirection === "asc"
|
||||||
|
? KeyboardArrowUpOutlined
|
||||||
|
: KeyboardArrowDownOutlined;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
aria-label={`按${label}${nextDirection === "asc" ? "正序" : "倒序"}排序`}
|
||||||
|
className={[styles.sortHeader, active ? styles.sortHeaderActive : ""].filter(Boolean).join(" ")}
|
||||||
|
type="button"
|
||||||
|
onClick={() => onClick(field)}
|
||||||
|
>
|
||||||
|
<span>{label}</span>
|
||||||
|
<Icon className={styles.sortIcon} fontSize="inherit" />
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function ActionModal({ children, disabled, loading, onClose, onSubmit, open, sectionTitle = "基本信息", title }) {
|
function ActionModal({ children, disabled, loading, onClose, onSubmit, open, sectionTitle = "基本信息", title }) {
|
||||||
return (
|
return (
|
||||||
<AdminFormDialog
|
<AdminFormDialog
|
||||||
|
|||||||
@ -944,6 +944,32 @@ export function useGiftListPage() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const saveGiftSortOrder = async (gift, rawSortOrder) => {
|
||||||
|
if (!abilities.canUpdateGift || !gift?.giftId) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
const sortOrder = Number(rawSortOrder);
|
||||||
|
if (!Number.isInteger(sortOrder) || sortOrder < 0) {
|
||||||
|
showToast("排序必须是大于等于 0 的整数", "error");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (sortOrder === Number(gift.sortOrder || 0)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
setLoadingAction(`gift-sort-${gift.giftId}`);
|
||||||
|
try {
|
||||||
|
await updateGift(gift.giftId, buildGiftInlineSortPayload(gift, sortOrder));
|
||||||
|
showToast("排序已保存", "success");
|
||||||
|
await result.reload();
|
||||||
|
return true;
|
||||||
|
} catch (err) {
|
||||||
|
showToast(err.message || "保存排序失败", "error");
|
||||||
|
return false;
|
||||||
|
} finally {
|
||||||
|
setLoadingAction("");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const resetFilters = () => {
|
const resetFilters = () => {
|
||||||
setQuery("");
|
setQuery("");
|
||||||
setStatus("");
|
setStatus("");
|
||||||
@ -978,6 +1004,7 @@ export function useGiftListPage() {
|
|||||||
resetFilters,
|
resetFilters,
|
||||||
selectGiftResource,
|
selectGiftResource,
|
||||||
setForm,
|
setForm,
|
||||||
|
saveGiftSortOrder,
|
||||||
submitGiftTypes,
|
submitGiftTypes,
|
||||||
status,
|
status,
|
||||||
submitGift,
|
submitGift,
|
||||||
@ -1427,6 +1454,27 @@ function buildGiftPayload(form) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function buildGiftInlineSortPayload(gift, sortOrder) {
|
||||||
|
return {
|
||||||
|
chargeAssetType: gift.chargeAssetType || "COIN",
|
||||||
|
coinPrice: Number(gift.coinPrice || 0),
|
||||||
|
effectiveAtMs: Date.now(),
|
||||||
|
effectiveFromMs: Number(gift.effectiveFromMs || 0),
|
||||||
|
effectiveToMs: Number(gift.effectiveToMs || 0),
|
||||||
|
effectTypes: Array.isArray(gift.effectTypes) ? gift.effectTypes : [],
|
||||||
|
giftId: String(gift.giftId || "").trim(),
|
||||||
|
giftPointAmount: Number(gift.giftPointAmount ?? gift.coinPrice ?? 0),
|
||||||
|
giftTypeCode: gift.giftTypeCode || "normal",
|
||||||
|
name: String(gift.name || gift.resource?.name || gift.giftId || "").trim(),
|
||||||
|
presentationJson: String(gift.presentationJson || "{}").trim() || "{}",
|
||||||
|
priceVersion: String(gift.priceVersion || "default").trim(),
|
||||||
|
regionIds: Array.isArray(gift.regionIds) && gift.regionIds.length ? gift.regionIds.map(Number) : [0],
|
||||||
|
resourceId: Number(gift.resourceId || 0),
|
||||||
|
sortOrder,
|
||||||
|
status: gift.status || "active",
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function buildGiftTypePayload(form) {
|
function buildGiftTypePayload(form) {
|
||||||
return {
|
return {
|
||||||
displayName: form.displayName.trim(),
|
displayName: form.displayName.trim(),
|
||||||
|
|||||||
@ -11,7 +11,7 @@ import MenuItem from "@mui/material/MenuItem";
|
|||||||
import Popover from "@mui/material/Popover";
|
import Popover from "@mui/material/Popover";
|
||||||
import { AdminSwitch } from "@/shared/ui/AdminSwitch.jsx";
|
import { AdminSwitch } from "@/shared/ui/AdminSwitch.jsx";
|
||||||
import TextField from "@mui/material/TextField";
|
import TextField from "@mui/material/TextField";
|
||||||
import { useMemo, useState } from "react";
|
import { useEffect, useMemo, useState } from "react";
|
||||||
import {
|
import {
|
||||||
AdminFormDialog,
|
AdminFormDialog,
|
||||||
AdminFormFieldGrid,
|
AdminFormFieldGrid,
|
||||||
@ -81,6 +81,11 @@ const baseColumns = (giftTypeOptions) => [
|
|||||||
label: "区域",
|
label: "区域",
|
||||||
width: "minmax(160px, 0.8fr)",
|
width: "minmax(160px, 0.8fr)",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: "sortOrder",
|
||||||
|
label: "排序",
|
||||||
|
width: "minmax(96px, 0.45fr)",
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: "effects",
|
key: "effects",
|
||||||
label: "有效期 / 特效",
|
label: "有效期 / 特效",
|
||||||
@ -143,6 +148,12 @@ export function GiftListPage() {
|
|||||||
render: (gift) => <GiftStatusSwitch gift={gift} page={page} />,
|
render: (gift) => <GiftStatusSwitch gift={gift} page={page} />,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
if (column.key === "sortOrder") {
|
||||||
|
return {
|
||||||
|
...column,
|
||||||
|
render: (gift) => <GiftSortOrderCell gift={gift} page={page} />,
|
||||||
|
};
|
||||||
|
}
|
||||||
if (column.key === "gift") {
|
if (column.key === "gift") {
|
||||||
return {
|
return {
|
||||||
...column,
|
...column,
|
||||||
@ -185,7 +196,7 @@ export function GiftListPage() {
|
|||||||
<DataTable
|
<DataTable
|
||||||
columns={tableColumns}
|
columns={tableColumns}
|
||||||
items={items}
|
items={items}
|
||||||
minWidth="1480px"
|
minWidth="1560px"
|
||||||
pagination={
|
pagination={
|
||||||
total > 0
|
total > 0
|
||||||
? {
|
? {
|
||||||
@ -251,6 +262,76 @@ function GiftStatusSwitch({ gift, page }) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function GiftSortOrderCell({ gift, page }) {
|
||||||
|
const originalValue = String(gift.sortOrder ?? 0);
|
||||||
|
const saving = page.loadingAction === `gift-sort-${gift.giftId}`;
|
||||||
|
const editable = page.abilities.canUpdateGift && !saving;
|
||||||
|
const [editing, setEditing] = useState(false);
|
||||||
|
const [value, setValue] = useState(originalValue);
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
if (!editing) {
|
||||||
|
setValue(originalValue);
|
||||||
|
}
|
||||||
|
}, [editing, originalValue]);
|
||||||
|
|
||||||
|
const save = async () => {
|
||||||
|
const nextValue = String(value || "0").trim() || "0";
|
||||||
|
const saved = await page.saveGiftSortOrder(gift, nextValue);
|
||||||
|
if (saved) {
|
||||||
|
setEditing(false);
|
||||||
|
setValue(nextValue);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
setValue(originalValue);
|
||||||
|
setEditing(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
if (!editing) {
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
className={styles.inlineSortButton}
|
||||||
|
disabled={!editable}
|
||||||
|
title={editable ? "点击编辑排序" : undefined}
|
||||||
|
type="button"
|
||||||
|
onClick={() => {
|
||||||
|
if (editable) {
|
||||||
|
setEditing(true);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
{originalValue}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<TextField
|
||||||
|
autoFocus
|
||||||
|
className={styles.inlineSortInput}
|
||||||
|
disabled={saving}
|
||||||
|
inputProps={{ min: 0, step: 1 }}
|
||||||
|
size="small"
|
||||||
|
type="number"
|
||||||
|
value={value}
|
||||||
|
onBlur={save}
|
||||||
|
onChange={(event) => setValue(event.target.value)}
|
||||||
|
onKeyDown={(event) => {
|
||||||
|
if (event.key === "Enter") {
|
||||||
|
event.preventDefault();
|
||||||
|
event.currentTarget.blur();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.key === "Escape") {
|
||||||
|
event.preventDefault();
|
||||||
|
setValue(originalValue);
|
||||||
|
setEditing(false);
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
function GiftFormDialog({ disabled, form, loading, mode, onClose, onSubmit, open, page, regionOptions }) {
|
function GiftFormDialog({ disabled, form, loading, mode, onClose, onSubmit, open, page, regionOptions }) {
|
||||||
const submitDisabled =
|
const submitDisabled =
|
||||||
disabled || loading || page.resourceOptionsLoading || page.loadingRegions || page.giftTypesLoading;
|
disabled || loading || page.resourceOptionsLoading || page.loadingRegions || page.giftTypesLoading;
|
||||||
|
|||||||
@ -76,6 +76,51 @@
|
|||||||
min-height: var(--control-height);
|
min-height: var(--control-height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.inlineSortButton {
|
||||||
|
display: inline-flex;
|
||||||
|
width: 100%;
|
||||||
|
max-width: 76px;
|
||||||
|
height: 30px;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: flex-start;
|
||||||
|
padding: 0 var(--space-2);
|
||||||
|
border: 1px solid transparent;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
cursor: pointer;
|
||||||
|
font: inherit;
|
||||||
|
font-weight: 650;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inlineSortButton:hover {
|
||||||
|
border-color: var(--primary-border);
|
||||||
|
background: var(--primary-surface);
|
||||||
|
color: var(--primary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inlineSortButton:disabled {
|
||||||
|
cursor: default;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inlineSortButton:disabled:hover {
|
||||||
|
border-color: transparent;
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-tertiary);
|
||||||
|
}
|
||||||
|
|
||||||
|
.inlineSortInput {
|
||||||
|
width: 76px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.inlineSortInput :global(.MuiInputBase-input) {
|
||||||
|
padding-right: var(--space-2);
|
||||||
|
padding-left: var(--space-2);
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
|
||||||
.datePopover {
|
.datePopover {
|
||||||
display: grid;
|
display: grid;
|
||||||
width: 320px;
|
width: 320px;
|
||||||
|
|||||||
@ -29,6 +29,10 @@ export interface PageQuery {
|
|||||||
region_id?: EntityId;
|
region_id?: EntityId;
|
||||||
regionId?: EntityId;
|
regionId?: EntityId;
|
||||||
role?: string;
|
role?: string;
|
||||||
|
sort_by?: string;
|
||||||
|
sort_direction?: string;
|
||||||
|
sortBy?: string;
|
||||||
|
sortDirection?: string;
|
||||||
status?: string;
|
status?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -419,8 +419,9 @@ function displayValue(value) {
|
|||||||
|
|
||||||
function HeaderLabel({ column, onOpenFilter, trailingAction }) {
|
function HeaderLabel({ column, onOpenFilter, trailingAction }) {
|
||||||
const content = column.header || column.label;
|
const content = column.header || column.label;
|
||||||
|
const hasCustomHeader = column.header !== undefined && column.header !== null;
|
||||||
const label = !column.filter ? (
|
const label = !column.filter ? (
|
||||||
<span className="admin-cell__head-label">{content}</span>
|
<span className={hasCustomHeader ? "admin-cell__head-custom" : "admin-cell__head-label"}>{content}</span>
|
||||||
) : (
|
) : (
|
||||||
<FilterHeaderButton column={column} onOpenFilter={onOpenFilter} />
|
<FilterHeaderButton column={column} onOpenFilter={onOpenFilter} />
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1229,6 +1229,13 @@
|
|||||||
white-space: nowrap;
|
white-space: nowrap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.admin-cell__head-custom {
|
||||||
|
display: inline-flex;
|
||||||
|
min-width: 0;
|
||||||
|
align-items: center;
|
||||||
|
overflow: visible;
|
||||||
|
}
|
||||||
|
|
||||||
.admin-cell__head-filter {
|
.admin-cell__head-filter {
|
||||||
color: var(--primary);
|
color: var(--primary);
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user