Merge branch 'feat/dict-table-default-hide-extras' into 'main'
feat(dict): таблица справочника — hide tail columns по умолчанию (без H-scroll) See merge request 2-6/2-6-4/terravault/ordinis!287
This commit is contained in:
@@ -28,11 +28,20 @@ const DEFAULT_STATE: DictTableState = { sort: null, hidden: [] }
|
||||
|
||||
const storageKey = (dictName: string): string => `ord-dict-table:${dictName}`
|
||||
|
||||
const readState = (dictName: string): DictTableState => {
|
||||
if (typeof window === 'undefined') return DEFAULT_STATE
|
||||
/**
|
||||
* Прочитать persisted state. Если в storage пусто (юзер ни разу не
|
||||
* взаимодействовал с этим dict) → используем `fallbackHidden` как initial
|
||||
* visibility (для info-dense schemas: hide tail columns по умолчанию,
|
||||
* чтобы таблица помещалась в viewport без H-scroll). Любой toggle/setHidden
|
||||
* запишет state в storage → дальнейшие посещения respect юзерский выбор
|
||||
* вне зависимости от fallback.
|
||||
*/
|
||||
const readState = (dictName: string, fallbackHidden: string[]): DictTableState => {
|
||||
const fallback: DictTableState = { sort: null, hidden: fallbackHidden }
|
||||
if (typeof window === 'undefined') return fallback
|
||||
try {
|
||||
const raw = window.localStorage.getItem(storageKey(dictName))
|
||||
if (!raw) return DEFAULT_STATE
|
||||
if (!raw) return fallback
|
||||
const parsed = JSON.parse(raw) as Partial<DictTableState>
|
||||
return {
|
||||
sort:
|
||||
@@ -46,7 +55,7 @@ const readState = (dictName: string): DictTableState => {
|
||||
: [],
|
||||
}
|
||||
} catch {
|
||||
return DEFAULT_STATE
|
||||
return fallback
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,13 +69,19 @@ const writeState = (dictName: string, state: DictTableState): void => {
|
||||
}
|
||||
}
|
||||
|
||||
export function useDictTableState(dictName: string) {
|
||||
const [state, setState] = useState<DictTableState>(() => readState(dictName))
|
||||
export function useDictTableState(dictName: string, defaultHidden: string[] = []) {
|
||||
// Stable key для defaultHidden чтобы useEffect не зацикливался на каждый
|
||||
// render (массив literal каждый раз new reference). Caller обычно строит
|
||||
// defaultHidden из useMemo, но guard всё равно нужен.
|
||||
const defaultKey = defaultHidden.join(',')
|
||||
const [state, setState] = useState<DictTableState>(() => readState(dictName, defaultHidden))
|
||||
|
||||
// Перечитать когда смена dictName (navigation между справочниками).
|
||||
// Перечитать когда смена dictName (navigation между справочниками) или
|
||||
// когда меняется набор defaultHidden (schema reload → новые extra columns).
|
||||
useEffect(() => {
|
||||
setState(readState(dictName))
|
||||
}, [dictName])
|
||||
setState(readState(dictName, defaultHidden))
|
||||
// eslint-disable-next-line react-hooks/exhaustive-deps -- defaultKey stable
|
||||
}, [dictName, defaultKey])
|
||||
|
||||
useEffect(() => {
|
||||
writeState(dictName, state)
|
||||
|
||||
@@ -372,9 +372,28 @@ function DictionaryDetail() {
|
||||
setPage(0)
|
||||
}, [search, scopeFilter, aoi])
|
||||
|
||||
// First-visit defaults: с info-dense schemas (10+ scalar полей) полная
|
||||
// таблица не помещается в viewport → H-scroll. Hide хвост по умолчанию
|
||||
// — показываем businessKey, name, scope, validFrom + первые 2 extra
|
||||
// (обычно самые важные ключи). Юзер открывает menu Колонки и сам
|
||||
// добавляет нужные — выбор persisted в localStorage и при следующем
|
||||
// визите fallback уже не применяется.
|
||||
const defaultHiddenExtras = useMemo<string[]>(() => {
|
||||
const props = detailQuery.data?.schemaJson?.properties ?? {}
|
||||
const eligible: string[] = []
|
||||
for (const [key, prop] of Object.entries(props)) {
|
||||
if (key === 'name' || key === 'code' || key === 'businessKey') continue
|
||||
if (Boolean(prop['x-localized'])) continue
|
||||
const t = prop.type
|
||||
if (t === 'array' || t === 'object') continue
|
||||
eligible.push(key)
|
||||
}
|
||||
return eligible.slice(2) // первые 2 видны, остальные default-hidden
|
||||
}, [detailQuery.data?.schemaJson])
|
||||
|
||||
// Table state — sort (cycle none→asc→desc) + hidden columns persisted в
|
||||
// localStorage per dict через useDictTableState.
|
||||
const dictTable = useDictTableState(name)
|
||||
const dictTable = useDictTableState(name, defaultHiddenExtras)
|
||||
|
||||
// Getter для applySort — извлекает значение по col key из record.
|
||||
// Изолирован чтобы sort работал унифицировано для всех типов колонок.
|
||||
|
||||
Reference in New Issue
Block a user