diff --git a/ui/src/components/template/UserDropdown.tsx b/ui/src/components/template/UserDropdown.tsx index 06541ff..18c6aa4 100644 --- a/ui/src/components/template/UserDropdown.tsx +++ b/ui/src/components/template/UserDropdown.tsx @@ -6,22 +6,31 @@ import withHeaderItem from '@/utils/hoc/withHeaderItem' import useAuth from '@/utils/hooks/useAuth' import { useLocalization } from '@/utils/hooks/useLocalization' import classNames from 'classnames' +import type { ReactElement } from 'react' import { Link } from 'react-router-dom' import { Avatar } from '../ui' -import { FcEngineering, FcNext, FcNfcSign, FcVoicePresentation } from 'react-icons/fc' +import { + FcEngineering, + FcNext, + FcNfcSign, + FcSynchronize, + FcVoicePresentation, +} from 'react-icons/fc' +import { useManualUpdateCheck } from '@/views/version/ChangeLog' type DropdownList = { label: string path: string - icon: JSX.Element + icon: ReactElement } -const _UserDropdown = ({ className }: CommonProps) => { +const UserDropdownBase = ({ className }: CommonProps) => { const { setPanelExpand } = useStoreActions((actions) => actions.theme) const { userName, name, email, avatar } = useStoreState((state) => state.auth.user) const tenant = useStoreState((state) => state.abpConfig.config?.currentTenant) const { translate } = useLocalization() const { signOut } = useAuth() + const { isCheckingUpdate, checkForUpdate } = useManualUpdateCheck() const displayName = name || userName const tenantName = tenant?.name @@ -113,6 +122,23 @@ const _UserDropdown = ({ className }: CommonProps) => { ) })} + + + + + + + {isCheckingUpdate + ? translate('::App.CheckUpdate') + : translate('::App.CheckForUpdates')} + + + + {/* */} @@ -124,6 +150,6 @@ const _UserDropdown = ({ className }: CommonProps) => { ) } -const UserDropdown = withHeaderItem(_UserDropdown) +const UserDropdown = withHeaderItem(UserDropdownBase) export default UserDropdown diff --git a/ui/src/components/ui/StatusIcon/StatusIcon.tsx b/ui/src/components/ui/StatusIcon/StatusIcon.tsx index e843dc5..d3265a4 100644 --- a/ui/src/components/ui/StatusIcon/StatusIcon.tsx +++ b/ui/src/components/ui/StatusIcon/StatusIcon.tsx @@ -1,10 +1,10 @@ import { FaCheckCircle, FaInfoCircle, FaExclamation, FaTimesCircle } from 'react-icons/fa'; import type { TypeAttributes, CommonProps } from '../@types/common' -import type { ReactNode } from 'react' +import type { ReactElement, ReactNode } from 'react' export interface StatusIconProps extends CommonProps { type: TypeAttributes.Status - custom?: ReactNode | JSX.Element + custom?: ReactNode | ReactElement iconColor?: string } @@ -12,7 +12,7 @@ const ICONS: Record< TypeAttributes.Status, { color: string - icon: JSX.Element + icon: ReactElement } > = { success: { diff --git a/ui/src/proxy/routes/routes.tsx b/ui/src/proxy/routes/routes.tsx index b42cacb..4ba094f 100644 --- a/ui/src/proxy/routes/routes.tsx +++ b/ui/src/proxy/routes/routes.tsx @@ -1,11 +1,11 @@ import { LayoutType } from '../theme/models' -import type { LazyExoticComponent, ReactNode } from 'react' +import type { LazyExoticComponent, ReactElement, ReactNode } from 'react' export interface Meta { pageContainerType?: 'default' | 'gutterless' | 'contained' header?: string | ReactNode headerContainer?: boolean - extraHeader?: LazyExoticComponent<() => JSX.Element> + extraHeader?: LazyExoticComponent<() => ReactElement> footer?: boolean layout?: LayoutType } @@ -13,7 +13,7 @@ export interface Meta { export type Route = { key: string path: string - component: LazyExoticComponent<(props: T) => JSX.Element> + component: LazyExoticComponent<(props: T) => ReactElement> authority: string[] meta?: Meta } diff --git a/ui/src/store/store.ts b/ui/src/store/store.ts index c464ac3..aa33c72 100644 --- a/ui/src/store/store.ts +++ b/ui/src/store/store.ts @@ -45,6 +45,7 @@ export const store = createStore( }, { allow: ['auth', 'theme', 'locale', 'client', 'admin'], + storage: 'localStorage', }, ), { diff --git a/ui/src/utils/hooks/useCurrentMenuIcon.tsx b/ui/src/utils/hooks/useCurrentMenuIcon.tsx index f629226..a91cf58 100644 --- a/ui/src/utils/hooks/useCurrentMenuIcon.tsx +++ b/ui/src/utils/hooks/useCurrentMenuIcon.tsx @@ -3,6 +3,7 @@ import { useLocation } from 'react-router-dom' import { FaUser } from 'react-icons/fa' import navigationIcon from '@/proxy/menus/navigation-icon.config' import { navigationTreeToFlat } from '@/utils/navigation' +import { ReactElement } from 'react' const extractListFormCode = (path: string): string | null => { const p = (path ?? '').toLowerCase() @@ -14,7 +15,7 @@ const extractListFormCode = (path: string): string | null => { return null } -export function useCurrentMenuIcon(className = 'w-6 h-6'): JSX.Element { +export function useCurrentMenuIcon(className = 'w-6 h-6'): ReactElement { const mainMenu = useStoreState((state) => state.abpConfig.menu.mainMenu) const location = useLocation() const menus = navigationTreeToFlat(mainMenu) diff --git a/ui/src/views/list/useListFormColumns.ts b/ui/src/views/list/useListFormColumns.ts index da30ad2..784b4e2 100644 --- a/ui/src/views/list/useListFormColumns.ts +++ b/ui/src/views/list/useListFormColumns.ts @@ -1073,6 +1073,7 @@ const useListFormColumns = ({ dataField: item.dataField, visible: false, showInColumnChooser: false, + allowSearch: false }) insertedColumns.push(item.dataField) } diff --git a/ui/src/views/shared/DialogContext/DialogShowComponent.tsx b/ui/src/views/shared/DialogContext/DialogShowComponent.tsx index f3574a6..aef6f25 100644 --- a/ui/src/views/shared/DialogContext/DialogShowComponent.tsx +++ b/ui/src/views/shared/DialogContext/DialogShowComponent.tsx @@ -6,8 +6,9 @@ import AuditLogDetail from '@/views/admin/auditLog/AuditLogDetail' import RolesPermission from '@/views/admin/role-management/RolesPermission' import UsersPermission from '@/views/admin/user-management/UsersPermission' import BranchSeed from '@/views/branch/BranchSeed' +import { ReactElement } from 'react' -const DialogShowComponent = (): JSX.Element => { +const DialogShowComponent = (): ReactElement => { const dialogContext: any = useDialogContext() const handleDialogClose = () => { diff --git a/ui/src/views/shared/TableNoRecords.tsx b/ui/src/views/shared/TableNoRecords.tsx index ea64438..969d0df 100644 --- a/ui/src/views/shared/TableNoRecords.tsx +++ b/ui/src/views/shared/TableNoRecords.tsx @@ -4,12 +4,13 @@ import Tr from '@/components/ui/Table/Tr' import { useLocalization } from '@/utils/hooks/useLocalization' import useThemeClass from '@/utils/hooks/useThemeClass' import classNames from 'classnames' +import { ReactElement } from 'react' interface TableNoRecordsProps extends CommonProps { show: boolean } -const TableNoRecords = (props: TableNoRecordsProps): JSX.Element => { +const TableNoRecords = (props: TableNoRecordsProps): ReactElement => { const { show, children, className, ...rest } = props const { textTheme } = useThemeClass() diff --git a/ui/src/views/version/ChangeLog.tsx b/ui/src/views/version/ChangeLog.tsx index 3b052e7..fc8805f 100644 --- a/ui/src/views/version/ChangeLog.tsx +++ b/ui/src/views/version/ChangeLog.tsx @@ -14,47 +14,13 @@ type Release = { changeLog: string[] } -const Log = ({ - version, - date, - children, -}: { - version: string - date: string - children?: React.ReactNode -}) => { - return ( -
-
- -
- v{version} -
-
-
{children}
-
- ) -} - -const Changelog = () => { +// User dropdown reuses the exact update-check flow owned by this component. +// eslint-disable-next-line react-refresh/only-export-components +export const useManualUpdateCheck = () => { const { translate } = useLocalization() - const [releases, setReleases] = useState([]) const [isCheckingUpdate, setIsCheckingUpdate] = useState(false) - useEffect(() => { - fetch('/version.json?ts=' + Date.now()) - .then((res) => res.json()) - .then((data) => { - if (data?.releases) { - setReleases(data.releases) - } - }) - .catch(() => setReleases([])) - }, []) - - const handleManualUpdate = async () => { + const checkForUpdate = async () => { if (isCheckingUpdate) return setIsCheckingUpdate(true) @@ -96,6 +62,49 @@ const Changelog = () => { } } + return { isCheckingUpdate, checkForUpdate } +} + +const Log = ({ + version, + date, + children, +}: { + version: string + date: string + children?: React.ReactNode +}) => { + return ( +
+
+ +
+ v{version} +
+
+
{children}
+
+ ) +} + +const Changelog = () => { + const { translate } = useLocalization() + const [releases, setReleases] = useState([]) + const { isCheckingUpdate, checkForUpdate } = useManualUpdateCheck() + + useEffect(() => { + fetch('/version.json?ts=' + Date.now()) + .then((res) => res.json()) + .then((data) => { + if (data?.releases) { + setReleases(data.releases) + } + }) + .catch(() => setReleases([])) + }, []) + return ( { icon={} loading={isCheckingUpdate} variant="solid" - onClick={handleManualUpdate} + onClick={checkForUpdate} > {isCheckingUpdate ? translate('::App.CheckUpdate')