improve fixed column (#2491)

Signed-off-by: Denis Bykhov <bykhov.denis@gmail.com>
This commit is contained in:
Denis Bykhov 2023-01-05 12:09:30 +06:00 committed by GitHub
parent 396dd3e7f4
commit e32e977b72
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
9 changed files with 36 additions and 150 deletions

View File

@ -220,7 +220,6 @@ export async function getWorkspaces (): Promise<Workspace[]> {
body: serialize(request) body: serialize(request)
}) })
const result: Response<any> = await response.json() const result: Response<any> = await response.json()
console.log(result)
if (result.error != null) { if (result.error != null) {
throw new PlatformError(result.error) throw new PlatformError(result.error)
} }

View File

@ -86,8 +86,6 @@
let currentTeam: Team | undefined let currentTeam: Team | undefined
let personPresenter: AttributeModel let personPresenter: AttributeModel
let isCollapsedMap: Record<any, boolean> = {} let isCollapsedMap: Record<any, boolean> = {}
let varsStyle: string = ''
let propsWidth: Record<string, number> = { groupBy: 0 }
let itemModels: AttributeModel[] let itemModels: AttributeModel[]
let isFilterUpdate = false let isFilterUpdate = false
let groupedIssuesBeforeFilter = groupedIssues let groupedIssuesBeforeFilter = groupedIssues
@ -196,20 +194,9 @@
personPresenter = p personPresenter = p
}) })
$: buildModel({ client, _class, keys: itemsConfig, lookup: options.lookup }).then((res) => (itemModels = res)) $: buildModel({ client, _class, keys: itemsConfig, lookup: options.lookup }).then((res) => (itemModels = res))
$: if (itemModels) {
for (const item of itemModels) if (item.props?.fixed !== undefined) propsWidth[item.key] = 0
}
$: if (propsWidth) {
varsStyle = ''
for (const key in propsWidth) varsStyle += `--fixed-${key}: ${propsWidth[key]}px;`
}
const checkWidth = (key: string, result: CustomEvent): void => {
if (result !== undefined) propsWidth[key] = result.detail
}
</script> </script>
<div class="issueslist-container" style={varsStyle}> <div class="issueslist-container">
{#each categories as category} {#each categories as category}
{@const items = groupedIssues[category] ?? []} {@const items = groupedIssues[category] ?? []}
{@const limited = limitGroup(category, groupedIssues, categoryLimit) ?? []} {@const limited = limitGroup(category, groupedIssues, categoryLimit) ?? []}
@ -217,12 +204,7 @@
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<div class="flex-between categoryHeader row" on:click={() => handleCollapseCategory(toCat(category))}> <div class="flex-between categoryHeader row" on:click={() => handleCollapseCategory(toCat(category))}>
<div class="flex-row-center gap-2 clear-mins"> <div class="flex-row-center gap-2 clear-mins">
<FixedColumn <FixedColumn key={'issuelist_groupBy'} justify={'left'}>
width={propsWidth.groupBy}
key={'groupBy'}
justify={'left'}
on:update={(result) => checkWidth('groupBy', result)}
>
{#if groupByKey === 'assignee' && personPresenter} {#if groupByKey === 'assignee' && personPresenter}
<svelte:component <svelte:component
this={personPresenter.presenter} this={personPresenter.presenter}
@ -256,12 +238,7 @@
/> />
{/if} {/if}
</FixedColumn> </FixedColumn>
<FixedColumn <FixedColumn key={'issuelist_statistics'} justify={'left'}>
width={propsWidth.statistics}
key={'statistics'}
justify={'left'}
on:update={(result) => checkWidth('statistics', result)}
>
<IssueStatistics issues={groupedIssues[category]} /> <IssueStatistics issues={groupedIssues[category]} />
</FixedColumn> </FixedColumn>
{#if limited.length < items.length} {#if limited.length < items.length}
@ -303,10 +280,6 @@
checked={selectedObjectIdsSet.has(docObject._id)} checked={selectedObjectIdsSet.has(docObject._id)}
{statuses} {statuses}
{currentTeam} {currentTeam}
{propsWidth}
on:fitting={(ev) => {
if (ev.detail !== undefined) propsWidth = ev.detail
}}
on:check={(ev) => dispatch('check', { docs: ev.detail.docs, value: ev.detail.value })} on:check={(ev) => dispatch('check', { docs: ev.detail.docs, value: ev.detail.value })}
on:contextmenu={(event) => on:contextmenu={(event) =>
handleMenuOpened( handleMenuOpened(

View File

@ -32,17 +32,9 @@
export let selected: boolean export let selected: boolean
export let statuses: WithLookup<IssueStatus>[] export let statuses: WithLookup<IssueStatus>[]
export let currentTeam: Team | undefined export let currentTeam: Team | undefined
export let propsWidth: Record<string, number>
const dispatch = createEventDispatcher() const dispatch = createEventDispatcher()
const checkWidth = (key: string, result: CustomEvent): void => {
if (result !== undefined) {
propsWidth[key] = result.detail
dispatch('fitting', propsWidth)
}
}
$: compactMode = $deviceInfo.twoRows $: compactMode = $deviceInfo.twoRows
</script> </script>
@ -78,12 +70,7 @@
<svelte:component this={attributeModel.presenter} /> <svelte:component this={attributeModel.presenter} />
{:else if (!groupByKey || attributeModel.props?.excludeByKey !== groupByKey) && !(attributeModel.props?.optional && compactMode)} {:else if (!groupByKey || attributeModel.props?.excludeByKey !== groupByKey) && !(attributeModel.props?.optional && compactMode)}
{#if attributeModel.props?.fixed} {#if attributeModel.props?.fixed}
<FixedColumn <FixedColumn key={`issue_${attributeModel.key}`} justify={attributeModel.props.fixed}>
width={propsWidth[attributeModel.key]}
key={attributeModel.key}
justify={attributeModel.props.fixed}
on:update={(result) => checkWidth(attributeModel.key, result)}
>
<svelte:component <svelte:component
this={attributeModel.presenter} this={attributeModel.presenter}
value={getObjectValue(attributeModel.key, docObject) ?? ''} value={getObjectValue(attributeModel.key, docObject) ?? ''}

View File

@ -70,16 +70,6 @@
function showContextMenu (ev: MouseEvent, object: Issue) { function showContextMenu (ev: MouseEvent, object: Issue) {
showPopup(ContextMenu, { object }, getEventPositionElement(ev)) showPopup(ContextMenu, { object }, getEventPositionElement(ev))
} }
let varsStyle: string = ''
const propsWidth: Record<string, number> = { issue: 0 }
$: if (propsWidth) {
varsStyle = ''
for (const key in propsWidth) varsStyle += `--fixed-${key}: ${propsWidth[key]}px;`
}
const checkWidth = (key: string, result: CustomEvent): void => {
if (result !== undefined) propsWidth[key] = result.detail
}
</script> </script>
<ActionContext <ActionContext
@ -96,7 +86,6 @@
class:is-dragging={index === draggingIndex} class:is-dragging={index === draggingIndex}
class:is-dragged-over-up={draggingIndex !== null && index < draggingIndex && index === hoveringIndex} class:is-dragged-over-up={draggingIndex !== null && index < draggingIndex && index === hoveringIndex}
class:is-dragged-over-down={draggingIndex !== null && index > draggingIndex && index === hoveringIndex} class:is-dragged-over-down={draggingIndex !== null && index > draggingIndex && index === hoveringIndex}
style={varsStyle}
animate:flip={{ duration: 400 }} animate:flip={{ duration: 400 }}
draggable={true} draggable={true}
on:click|self={openIssueCall} on:click|self={openIssueCall}
@ -113,12 +102,7 @@
<div class="flex-row-center ml-6 clear-mins gap-2"> <div class="flex-row-center ml-6 clear-mins gap-2">
<PriorityEditor value={issue} isEditable kind={'list'} size={'small'} justify={'center'} /> <PriorityEditor value={issue} isEditable kind={'list'} size={'small'} justify={'center'} />
<span class="issuePresenter" on:click={openIssueCall}> <span class="issuePresenter" on:click={openIssueCall}>
<FixedColumn <FixedColumn key={'subissue_issue'} justify={'left'}>
width={propsWidth.issue}
key={'issue'}
justify={'left'}
on:update={(result) => checkWidth('issue', result)}
>
{#if currentTeam} {#if currentTeam}
{getIssueId(currentTeam, issue)} {getIssueId(currentTeam, issue)}
{/if} {/if}

View File

@ -32,16 +32,6 @@
} }
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {}) const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {})
let varsStyle: string = ''
const propsWidth: Record<string, number> = { issue: 0, estimation: 0, assignee: 0 }
$: if (propsWidth) {
varsStyle = ''
for (const key in propsWidth) varsStyle += `--fixed-${key}: ${propsWidth[key]}px;`
}
const checkWidth = (key: string, result: CustomEvent): void => {
if (result !== undefined) propsWidth[key] = result.detail
}
</script> </script>
<ListView count={issues.length}> <ListView count={issues.length}>
@ -50,7 +40,6 @@
{@const currentTeam = teams.get(issue.space)} {@const currentTeam = teams.get(issue.space)}
<div <div
class="flex-between row" class="flex-between row"
style={varsStyle}
on:contextmenu|preventDefault={(ev) => showContextMenu(ev, issue)} on:contextmenu|preventDefault={(ev) => showContextMenu(ev, issue)}
on:mouseover={() => { on:mouseover={() => {
listProvider.updateFocus(issue) listProvider.updateFocus(issue)
@ -61,12 +50,7 @@
> >
<div class="flex-row-center clear-mins gap-2 p-2 flex-grow"> <div class="flex-row-center clear-mins gap-2 p-2 flex-grow">
<span class="issuePresenter"> <span class="issuePresenter">
<FixedColumn <FixedColumn key={'estimation_issue'} justify={'left'}>
width={propsWidth.issue}
key={'issue'}
justify={'left'}
on:update={(result) => checkWidth('issue', result)}
>
{#if currentTeam} {#if currentTeam}
{getIssueId(currentTeam, issue)} {getIssueId(currentTeam, issue)}
{/if} {/if}
@ -77,12 +61,7 @@
</span> </span>
</div> </div>
<FixedColumn <FixedColumn key={'estimation_issue_assignee'} justify={'right'}>
width={propsWidth.assignee}
key={'assignee'}
justify={'right'}
on:update={(result) => checkWidth('assignee', result)}
>
<UserBox <UserBox
width={'100%'} width={'100%'}
label={tracker.string.Assignee} label={tracker.string.Assignee}
@ -92,12 +71,7 @@
showNavigate={false} showNavigate={false}
/> />
</FixedColumn> </FixedColumn>
<FixedColumn <FixedColumn key={'estimation'} justify={'left'}>
width={propsWidth.estimation}
key={'estimation'}
justify={'left'}
on:update={(result) => checkWidth('estimation', result)}
>
<EstimationEditor value={issue} kind={'list'} /> <EstimationEditor value={issue} kind={'list'} />
</FixedColumn> </FixedColumn>
</div> </div>

View File

@ -35,15 +35,6 @@
const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {}) const listProvider = new ListSelectionProvider((offset: 1 | -1 | 0, of?: Doc, dir?: SelectDirection) => {})
let varsStyle: string = ''
const propsWidth: Record<string, number> = { issue: 0, assignee: 0, reported: 0, date: 0 }
$: if (propsWidth) {
varsStyle = ''
for (const key in propsWidth) varsStyle += `--fixed-${key}: ${propsWidth[key]}px;`
}
const checkWidth = (key: string, result: CustomEvent): void => {
if (result !== undefined) propsWidth[key] = result.detail
}
const toTeamId = (ref: Ref<Space>) => ref as Ref<Team> const toTeamId = (ref: Ref<Space>) => ref as Ref<Team>
function editSpendReport ( function editSpendReport (
@ -72,7 +63,6 @@
{@const currentTeam = teams.get(toTeamId(report.space))} {@const currentTeam = teams.get(toTeamId(report.space))}
<div <div
class="flex-between row" class="flex-between row"
style={varsStyle}
on:contextmenu|preventDefault={(ev) => showContextMenu(ev, report)} on:contextmenu|preventDefault={(ev) => showContextMenu(ev, report)}
on:mouseover={() => { on:mouseover={() => {
listProvider.updateFocus(report) listProvider.updateFocus(report)
@ -84,12 +74,7 @@
> >
<div class="flex-row-center clear-mins gap-2 p-2 flex-grow"> <div class="flex-row-center clear-mins gap-2 p-2 flex-grow">
<span class="issuePresenter"> <span class="issuePresenter">
<FixedColumn <FixedColumn key={'tmiespend_issue'} justify={'left'}>
width={propsWidth.issue}
key={'issue'}
justify={'left'}
on:update={(result) => checkWidth('issue', result)}
>
{#if currentTeam && report.$lookup?.attachedTo} {#if currentTeam && report.$lookup?.attachedTo}
{getIssueId(currentTeam, report.$lookup?.attachedTo)} {getIssueId(currentTeam, report.$lookup?.attachedTo)}
{/if} {/if}
@ -101,12 +86,7 @@
</span> </span>
{/if} {/if}
</div> </div>
<FixedColumn <FixedColumn key={'timespend_assignee'} justify={'left'}>
width={propsWidth.assignee}
key={'assignee'}
justify={'left'}
on:update={(result) => checkWidth('assignee', result)}
>
<UserBox <UserBox
width={'100%'} width={'100%'}
label={tracker.string.Assignee} label={tracker.string.Assignee}
@ -117,22 +97,12 @@
/> />
</FixedColumn> </FixedColumn>
<FixedColumn <FixedColumn key={'timespend_reported'} justify={'center'}>
width={propsWidth.reported}
key={'reported'}
justify={'center'}
on:update={(result) => checkWidth('reported', result)}
>
<div class="p-1"> <div class="p-1">
<TimePresenter value={report.value} workDayLength={currentTeam?.workDayLength} /> <TimePresenter value={report.value} workDayLength={currentTeam?.workDayLength} />
</div> </div>
</FixedColumn> </FixedColumn>
<FixedColumn <FixedColumn key={'timespend_date'} justify={'left'}>
width={propsWidth.date}
key={'date'}
justify={'left'}
on:update={(result) => checkWidth('date', result)}
>
<DatePresenter value={report.date} /> <DatePresenter value={report.date} />
</FixedColumn> </FixedColumn>
</div> </div>

View File

@ -86,16 +86,6 @@
// showPopup(ContextMenu, { object }, getEventPositionElement(ev)) // showPopup(ContextMenu, { object }, getEventPositionElement(ev))
} }
let varsStyle: string = ''
const propsWidth: Record<string, number> = { issue: 0 }
$: if (propsWidth) {
varsStyle = ''
for (const key in propsWidth) varsStyle += `--fixed-${key}: ${propsWidth[key]}px;`
}
const checkWidth = (key: string, result: CustomEvent): void => {
if (result !== undefined) propsWidth[key] = result.detail
}
export function getIssueTemplateId (team: string, issue: IssueTemplateChild): string { export function getIssueTemplateId (team: string, issue: IssueTemplateChild): string {
return `${team}-${issues.findIndex((it) => it.id === issue.id)}` return `${team}-${issues.findIndex((it) => it.id === issue.id)}`
} }
@ -114,7 +104,6 @@
class:is-dragging={index === draggingIndex} class:is-dragging={index === draggingIndex}
class:is-dragged-over-up={draggingIndex !== null && index < draggingIndex && index === hoveringIndex} class:is-dragged-over-up={draggingIndex !== null && index < draggingIndex && index === hoveringIndex}
class:is-dragged-over-down={draggingIndex !== null && index > draggingIndex && index === hoveringIndex} class:is-dragged-over-down={draggingIndex !== null && index > draggingIndex && index === hoveringIndex}
style={varsStyle}
animate:flip={{ duration: 400 }} animate:flip={{ duration: 400 }}
draggable={true} draggable={true}
on:click|self={(evt) => openIssue(evt, issue)} on:click|self={(evt) => openIssue(evt, issue)}
@ -142,12 +131,7 @@
/> />
<!-- svelte-ignore a11y-click-events-have-key-events --> <!-- svelte-ignore a11y-click-events-have-key-events -->
<span class="issuePresenter" on:click={(evt) => openIssue(evt, issue)}> <span class="issuePresenter" on:click={(evt) => openIssue(evt, issue)}>
<FixedColumn <FixedColumn key={'issue_template_issue'} justify={'left'}>
width={propsWidth.issue}
key={'issue'}
justify={'left'}
on:update={(result) => checkWidth('issue', result)}
>
{getIssueTemplateId(teamId, issue)} {getIssueTemplateId(teamId, issue)}
</FixedColumn> </FixedColumn>
</span> </span>

View File

@ -15,24 +15,34 @@
--> -->
<script lang="ts"> <script lang="ts">
import { resizeObserver } from '@hcengineering/ui' import { resizeObserver } from '@hcengineering/ui'
import { createEventDispatcher } from 'svelte' import { afterUpdate, onDestroy } from 'svelte'
import { fixedWidthStore } from '../utils'
export let width: number | undefined = 0
export let key: string export let key: string
export let justify: string = '' export let justify: string = ''
let prevKey = key
const dispatch = createEventDispatcher()
let cWidth: number = 0 let cWidth: number = 0
$: if (cWidth > (width ?? 0)) {
width = cWidth afterUpdate(() => {
dispatch('update', cWidth) if (prevKey !== key) {
$fixedWidthStore[prevKey] = 0
prevKey = key
} }
})
$: if (cWidth > ($fixedWidthStore[key] ?? 0)) {
$fixedWidthStore[key] = cWidth
}
onDestroy(() => {
$fixedWidthStore[key] = 0
})
</script> </script>
<div <div
class="flex-no-shrink" class="flex-no-shrink"
style="{justify !== '' ? `text-align: ${justify}; ` : ''} min-width: var(--fixed-{key});" style="{justify !== '' ? `text-align: ${justify}; ` : ''} min-width: {$fixedWidthStore[key] ?? 0}px;"
use:resizeObserver={(element) => { use:resizeObserver={(element) => {
if (element.clientWidth > cWidth) { if (element.clientWidth > cWidth) {
cWidth = element.clientWidth cWidth = element.clientWidth

View File

@ -39,6 +39,7 @@ import {
} from '@hcengineering/ui' } from '@hcengineering/ui'
import type { BuildModelOptions, Viewlet } from '@hcengineering/view' import type { BuildModelOptions, Viewlet } from '@hcengineering/view'
import view, { AttributeModel, BuildModelKey } from '@hcengineering/view' import view, { AttributeModel, BuildModelKey } from '@hcengineering/view'
import { writable } from 'svelte/store'
import plugin from './plugin' import plugin from './plugin'
/** /**
@ -492,3 +493,7 @@ export function getActiveViewletId (): Ref<Viewlet> | null {
const key = makeViewletKey() const key = makeViewletKey()
return localStorage.getItem(key) as Ref<Viewlet> | null return localStorage.getItem(key) as Ref<Viewlet> | null
} }
export type FixedWidthStore = Record<string, number>
export const fixedWidthStore = writable<FixedWidthStore>({})