Check New Version eklendi

This commit is contained in:
Sedat ÖZTÜRK 2026-07-14 16:43:05 +03:00
parent 28ec641275
commit 4805e8c4d9
9 changed files with 92 additions and 52 deletions

View file

@ -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) => {
)
})}
<Dropdown.Item
eventKey="Check New Version"
className="mb-1 px-0"
onClick={checkForUpdate}
>
<span className="flex h-full w-full items-center gap-2 px-2">
<span className={classNames('text-xl opacity-50', isCheckingUpdate && 'animate-spin')}>
<FcSynchronize />
</span>
<span>
{isCheckingUpdate
? translate('::App.CheckUpdate')
: translate('::App.CheckForUpdates')}
</span>
</span>
</Dropdown.Item>
{/* <Dropdown.Item variant="divider" /> */}
<Dropdown.Item eventKey="Sign Out" className="mb-1 px-2" onClick={signOut}>
<span className="text-xl opacity-50">
@ -124,6 +150,6 @@ const _UserDropdown = ({ className }: CommonProps) => {
)
}
const UserDropdown = withHeaderItem(_UserDropdown)
const UserDropdown = withHeaderItem(UserDropdownBase)
export default UserDropdown

View file

@ -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: {

View file

@ -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<<T extends Meta>(props: T) => JSX.Element>
component: LazyExoticComponent<<T extends Meta>(props: T) => ReactElement>
authority: string[]
meta?: Meta
}

View file

@ -45,6 +45,7 @@ export const store = createStore<StoreModel>(
},
{
allow: ['auth', 'theme', 'locale', 'client', 'admin'],
storage: 'localStorage',
},
),
{

View file

@ -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)

View file

@ -1073,6 +1073,7 @@ const useListFormColumns = ({
dataField: item.dataField,
visible: false,
showInColumnChooser: false,
allowSearch: false
})
insertedColumns.push(item.dataField)
}

View file

@ -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 = () => {

View file

@ -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()

View file

@ -14,47 +14,13 @@ type Release = {
changeLog: string[]
}
const Log = ({
version,
date,
children,
}: {
version: string
date: string
children?: React.ReactNode
}) => {
return (
<div className="relative pl-4 sm:pl-32 py-4 group">
<div className="flex flex-col sm:flex-row items-start mb-1 group-last:before:hidden before:absolute before:left-2 sm:before:left-0 before:h-full before:px-px before:bg-slate-200 sm:before:ml-[6.5rem] before:self-start before:-translate-x-1/2 before:translate-y-3 after:absolute after:left-2 sm:after:left-0 after:w-2 after:h-2 after:bg-indigo-600 after:border-4 after:box-content after:border-slate-50 after:rounded-full sm:after:ml-[6.5rem] after:-translate-x-1/2 after:translate-y-1.5">
<time className="sm:absolute left-0 translate-y-0.5 inline-flex items-center justify-center text-xs font-semibold uppercase w-20 h-6 mb-3 sm:mb-0 text-emerald-600 bg-emerald-100 rounded-full">
{date}
</time>
<div className="flex items-center text-xl font-bold text-gray-900 dark:text-white">
<FaTag className="mr-2 text-indigo-500" />v{version}
</div>
</div>
<div className="text-slate-500">{children}</div>
</div>
)
}
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<Release[]>([])
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 (
<div className="relative pl-4 sm:pl-32 py-4 group">
<div className="flex flex-col sm:flex-row items-start mb-1 group-last:before:hidden before:absolute before:left-2 sm:before:left-0 before:h-full before:px-px before:bg-slate-200 sm:before:ml-[6.5rem] before:self-start before:-translate-x-1/2 before:translate-y-3 after:absolute after:left-2 sm:after:left-0 after:w-2 after:h-2 after:bg-indigo-600 after:border-4 after:box-content after:border-slate-50 after:rounded-full sm:after:ml-[6.5rem] after:-translate-x-1/2 after:translate-y-1.5">
<time className="sm:absolute left-0 translate-y-0.5 inline-flex items-center justify-center text-xs font-semibold uppercase w-20 h-6 mb-3 sm:mb-0 text-emerald-600 bg-emerald-100 rounded-full">
{date}
</time>
<div className="flex items-center text-xl font-bold text-gray-900 dark:text-white">
<FaTag className="mr-2 text-indigo-500" />v{version}
</div>
</div>
<div className="text-slate-500">{children}</div>
</div>
)
}
const Changelog = () => {
const { translate } = useLocalization()
const [releases, setReleases] = useState<Release[]>([])
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 (
<Container>
<Helmet
@ -114,7 +123,7 @@ const Changelog = () => {
icon={<FaSyncAlt />}
loading={isCheckingUpdate}
variant="solid"
onClick={handleManualUpdate}
onClick={checkForUpdate}
>
{isCheckingUpdate
? translate('::App.CheckUpdate')