diff --git a/console/packages/starwhale-core/src/datastore/hooks/useDatastoreMixedSchema.tsx b/console/packages/starwhale-core/src/datastore/hooks/useDatastoreMixedSchema.tsx index 9d25f07cca..28bc1d8d38 100644 --- a/console/packages/starwhale-core/src/datastore/hooks/useDatastoreMixedSchema.tsx +++ b/console/packages/starwhale-core/src/datastore/hooks/useDatastoreMixedSchema.tsx @@ -4,53 +4,7 @@ import { RecordListSchemaT, RecordSchemaT } from '../types' import { SwType } from '../model' import _ from 'lodash' import { DataTypes } from '../constants' - -class LRUCache { - private maxSize: number - - private cache: Map - - private accessedKeys: Set - - constructor(maxSize: number) { - this.maxSize = maxSize - this.cache = new Map() - this.accessedKeys = new Set() - } - - has(key: Key): boolean { - return this.cache.has(key) - } - - get(key: Key): Value | undefined { - if (this.cache.has(key)) { - // Move the key to the front of the accessedKeys set - this.accessedKeys.delete(key) - this.accessedKeys.add(key) - return this.cache.get(key) - } - return undefined - } - - put(key: Key, value: Value) { - if (this.cache.has(key)) { - // Move the key to the front of the accessedKeys set - this.accessedKeys.delete(key) - this.accessedKeys.add(key) - this.cache.set(key, value) - } else { - if (this.cache.size >= this.maxSize) { - // Remove the least recently used key from the cache and accessedKeys set - const lruKey = this.accessedKeys.values().next().value - this.accessedKeys.delete(lruKey) - this.cache.delete(lruKey) - } - // Add the new key to the front of the accessedKeys set - this.accessedKeys.add(key) - this.cache.set(key, value) - } - } -} +import { LRUCache } from '../utils' export function useDatastoreWithSchema(records: RecordListSchemaT, columnTypes: ColumnSchemaDesc[]) { const getSchema = React.useCallback( diff --git a/console/packages/starwhale-core/src/datastore/utils.ts b/console/packages/starwhale-core/src/datastore/utils.ts index c5bdd13d09..e1a72a8416 100644 --- a/console/packages/starwhale-core/src/datastore/utils.ts +++ b/console/packages/starwhale-core/src/datastore/utils.ts @@ -110,3 +110,50 @@ export const isSearchColumns = (v: string) => { return true } + +export class LRUCache { + private maxSize: number + + private cache: Map + + private accessedKeys: Set + + constructor(maxSize: number) { + this.maxSize = maxSize + this.cache = new Map() + this.accessedKeys = new Set() + } + + has(key: Key): boolean { + return this.cache.has(key) + } + + get(key: Key): Value | undefined { + if (this.cache.has(key)) { + // Move the key to the front of the accessedKeys set + this.accessedKeys.delete(key) + this.accessedKeys.add(key) + return this.cache.get(key) + } + return undefined + } + + put(key: Key, value: Value) { + if (this.cache.has(key)) { + // Move the key to the front of the accessedKeys set + this.accessedKeys.delete(key) + this.accessedKeys.add(key) + this.cache.set(key, value) + } else { + if (this.cache.size >= this.maxSize) { + // Remove the least recently used key from the cache and accessedKeys set + const lruKey = this.accessedKeys.values().next().value + this.accessedKeys.delete(lruKey) + this.cache.delete(lruKey) + } + // Add the new key to the front of the accessedKeys set + this.accessedKeys.add(key) + this.cache.set(key, value) + } + } +} diff --git a/console/packages/starwhale-core/src/utils/useCachedMap.tsx b/console/packages/starwhale-core/src/utils/useCachedMap.tsx new file mode 100644 index 0000000000..f10d1e4899 --- /dev/null +++ b/console/packages/starwhale-core/src/utils/useCachedMap.tsx @@ -0,0 +1,51 @@ +import React from 'react' +import { useLocalStorage } from 'react-use' + +const defaultMap = {} +const defaultKeys: any[] = [] + +function useCachedMap(storeKey = 'cache', maxCacheSize = 100) { + const [cachedMap, setCachedMap] = useLocalStorage>(`cache-${storeKey}`, defaultMap) + const [cachedKeys, setCachedKeys] = useLocalStorage(`cache-keys-${storeKey}`, defaultKeys) + + const has = React.useCallback( + (key: string) => { + return cachedMap?.[key] !== undefined + }, + [cachedMap] + ) + const get = React.useCallback( + (key: string) => { + return cachedMap?.[key] + }, + [cachedMap] + ) + const put = React.useCallback( + (key: string, value: DOMRect) => { + if (!cachedMap || !cachedKeys) return + + cachedMap[key] = value + if (cachedKeys.length > maxCacheSize) { + const first = cachedKeys.shift() + if (first) delete cachedMap[first] + } else { + cachedKeys.push(key) + } + + setCachedMap({ ...cachedMap }) + setCachedKeys([...cachedKeys]) + }, + [cachedMap, cachedKeys, maxCacheSize, setCachedMap, setCachedKeys] + ) + + return React.useMemo(() => { + return { + has, + get, + put, + } + }, [has, get, put]) +} + +export { useCachedMap } +export default useCachedMap diff --git a/console/src/components/Card/index.module.scss b/console/src/components/Card/index.module.scss index 1d2808d03d..edc5360598 100644 --- a/console/src/components/Card/index.module.scss +++ b/console/src/components/Card/index.module.scss @@ -7,18 +7,21 @@ font-variant: tabular-nums; line-height: 1.5715; list-style: none; - -webkit-font-feature-settings: "tnum","tnum"; - font-feature-settings: "tnum","tnum"; + -webkit-font-feature-settings: 'tnum', 'tnum'; + font-feature-settings: 'tnum', 'tnum'; position: relative; border-radius: 2px; - -webkit-transition: transform 270ms cubic-bezier(0.1, 0.9, 0.2, 1),opacity 300ms cubic-bezier(0.1, 0.9, 0.2, 1) 0.05s,-webkit-transform 300ms cubic-bezier(0.1, 0.9, 0.2, 1); - transition: transform 270ms cubic-bezier(0.1, 0.9, 0.2, 1),opacity 300ms cubic-bezier(0.1, 0.9, 0.2, 1) 0.05s,-webkit-transform 300ms cubic-bezier(0.1, 0.9, 0.2, 1); - transform: translate3d(0,48px,0); + -webkit-transition: transform 270ms cubic-bezier(0.1, 0.9, 0.2, 1), + opacity 300ms cubic-bezier(0.1, 0.9, 0.2, 1) 0.05s, -webkit-transform 300ms cubic-bezier(0.1, 0.9, 0.2, 1); + transition: transform 270ms cubic-bezier(0.1, 0.9, 0.2, 1), opacity 300ms cubic-bezier(0.1, 0.9, 0.2, 1) 0.05s, + -webkit-transform 300ms cubic-bezier(0.1, 0.9, 0.2, 1); + transform: translate3d(0, 48px, 0); transition-delay: 0.4s; margin-bottom: 10px; display: flex; border-radius: 8px; flex-direction: column; + overflow: hidden; .card { box-shadow: none; @@ -29,7 +32,7 @@ .card:nth-child(#{$i}) { transition-delay: 0.05s * ($i - 1); } - } +} .cardHeadWrapper { // padding: 0 18px; @@ -62,6 +65,7 @@ flex: 1; display: flex; flex-direction: column; + overflow: auto; } .cardHeadTail { diff --git a/console/src/components/Table/index.tsx b/console/src/components/Table/index.tsx index 4623c8c456..9c4fc83b5e 100644 --- a/console/src/components/Table/index.tsx +++ b/console/src/components/Table/index.tsx @@ -96,7 +96,7 @@ export default function Table({ isLoading, columns, data, overrides, paginationP style={{ display: 'flex', alignItems: 'center', - marginTop: 20, + marginTop: 5, }} >
({ ...column, renderCell: ({ value }) => { - return {formatTimestampDateTime(value.value)} + return ( + + {formatTimestampDateTime(value.value)} + + ) }, }) } diff --git a/console/src/pages/Job/JobListCard.tsx b/console/src/pages/Job/JobListCard.tsx index df60fd2a03..0b27197212 100644 --- a/console/src/pages/Job/JobListCard.tsx +++ b/console/src/pages/Job/JobListCard.tsx @@ -59,212 +59,200 @@ export default function JobListCard() { ) return ( - <> - - - - } - > - - {t('Job ID')} - , - t('Resource Pool'), - t('sth name', [t('Model')]), - t('Version'), - t('Owner'), - t('Created'), - t('Elapsed Time'), - t('End Time'), - t('Status'), - t('Action'), - ]} - data={ - jobsInfo.data?.list.map((job) => { - const actions: Partial> = { - [JobStatusType.CREATED]: ( - <> + + + + } + style={{ + marginBottom: 0, + }} + > +
+ {t('Job ID')} + , + t('Resource Pool'), + t('sth name', [t('Model')]), + t('Version'), + t('Owner'), + t('Created'), + t('Elapsed Time'), + t('End Time'), + t('Status'), + t('Action'), + ]} + data={ + jobsInfo.data?.list.map((job) => { + const actions: Partial> = { + [JobStatusType.CREATED]: ( + <> + + - - - - - ), - [JobStatusType.RUNNING]: ( - <> + + + ), + [JobStatusType.RUNNING]: ( + <> + + - - - - - ), - [JobStatusType.PAUSED]: ( - <> + + + ), + [JobStatusType.PAUSED]: ( + <> + + - - - - - ), - [JobStatusType.FAIL]: ( - <> - - - - - ), - [JobStatusType.SUCCESS]: ( - - ), - } + + + ), + [JobStatusType.FAIL]: ( + <> + + + + + ), + [JobStatusType.SUCCESS]: ( + + ), + } - const pinBtnStyle: ConfigurationOverride = { - 'position': 'absolute', - 'top': 0, - 'bottom': 0, - 'left': '-8px', - 'display': job.pinnedTime ? 'block' : 'none', - '& .iconfont': { - color: '#666', - }, + const pinBtnStyle: ConfigurationOverride = { + 'position': 'absolute', + 'top': 0, + 'bottom': 0, + 'left': '-8px', + 'display': job.pinnedTime ? 'block' : 'none', + '& .iconfont': { + color: '#666', + }, + } + if (canPinOrUnpin) { + pinBtnStyle[':hover .iconfont'] = { + color: '#FFB23D !important', } - if (canPinOrUnpin) { - pinBtnStyle[':hover .iconfont'] = { - color: '#FFB23D !important', - } - pinBtnStyle[':active .iconfont'] = { - color: '#F29200 !important', - } + pinBtnStyle[':active .iconfont'] = { + color: '#F29200 !important', } + } - return [ -
- - - {job.id} - -
, - job.resourcePool, - job.modelName, - {job.modelVersion}, - job.owner && , - job?.createdTime && job?.createdTime > 0 && formatTimestampDateTime(job?.createdTime), - typeof job.duration === 'string' ? '-' : durationToStr(job.duration), - job?.stopTime && job?.stopTime > 0 ? formatTimestampDateTime(job?.stopTime) : '-', - , -
- {actions[job.jobStatus] ?? ''} - {job.exposedLinks?.map((link) => { - return ( - - - - ) - })} -
, - ] - }) ?? [] - } - paginationProps={{ - start: jobsInfo.data?.pageNum, - count: jobsInfo.data?.pageSize, - total: jobsInfo.data?.total, - afterPageChange: () => { - jobsInfo.refetch() - }, - }} - /> - setIsCreateJobOpen(false)} closeable animate autoFocus> - {t('create sth', [t('Job')])} - - - - - - + style: pinBtnStyle, + }, + }} + > + {(canPinOrUnpin || job.pinnedTime) && ( + + )} + + + {job.id} + + , + job.resourcePool, + job.modelName, + {job.modelVersion}, + job.owner && , + job?.createdTime && job?.createdTime > 0 && formatTimestampDateTime(job?.createdTime), + typeof job.duration === 'string' ? '-' : durationToStr(job.duration), + job?.stopTime && job?.stopTime > 0 ? formatTimestampDateTime(job?.stopTime) : '-', + , +
+ {actions[job.jobStatus] ?? ''} + {job.exposedLinks?.map((link) => { + return ( + + + + ) + })} +
, + ] + }) ?? [] + } + paginationProps={{ + start: jobsInfo.data?.pageNum, + count: jobsInfo.data?.pageSize, + total: jobsInfo.data?.total, + afterPageChange: () => { + jobsInfo.refetch() + }, + }} + /> + setIsCreateJobOpen(false)} closeable animate autoFocus> + {t('create sth', [t('Job')])} + + + + + ) }