mirror of
https://github.com/hcengineering/platform.git
synced 2025-04-23 08:48:01 +00:00
[UBER-329] Remove "Project" filter from a single project view (#3345)
Signed-off-by: Sergei Ogorelkov <sergei.ogorelkov@icloud.com>
This commit is contained in:
parent
36b7014327
commit
34147e980f
@ -1467,7 +1467,8 @@ export function createModel (builder: Builder): void {
|
|||||||
showNested: false
|
showNested: false
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
ignoreKeys: ['number', 'estimation', 'attachedTo']
|
ignoreKeys: ['number', 'estimation', 'attachedTo'],
|
||||||
|
getVisibleFilters: tracker.function.GetVisibleFilters
|
||||||
})
|
})
|
||||||
|
|
||||||
builder.mixin(tracker.class.IssueTemplate, core.class.Class, view.mixin.ClassFilters, {
|
builder.mixin(tracker.class.IssueTemplate, core.class.Class, view.mixin.ClassFilters, {
|
||||||
|
@ -52,6 +52,7 @@ import {
|
|||||||
IgnoreActions,
|
IgnoreActions,
|
||||||
InlineAttributEditor,
|
InlineAttributEditor,
|
||||||
KeyBinding,
|
KeyBinding,
|
||||||
|
KeyFilter,
|
||||||
KeyFilterPreset,
|
KeyFilterPreset,
|
||||||
LinkPresenter,
|
LinkPresenter,
|
||||||
LinkProvider,
|
LinkProvider,
|
||||||
@ -153,6 +154,7 @@ export class TClassFilters extends TClass implements ClassFilters {
|
|||||||
filters!: (string | KeyFilterPreset)[]
|
filters!: (string | KeyFilterPreset)[]
|
||||||
ignoreKeys?: string[] | undefined
|
ignoreKeys?: string[] | undefined
|
||||||
strict?: boolean | undefined
|
strict?: boolean | undefined
|
||||||
|
getVisibleFilters?: Resource<(filters: KeyFilter[], space?: Ref<Space>) => Promise<KeyFilter[]>>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Mixin(view.mixin.AttributeFilter, core.class.Class)
|
@Mixin(view.mixin.AttributeFilter, core.class.Class)
|
||||||
|
@ -117,7 +117,8 @@ import {
|
|||||||
issueStatusSort,
|
issueStatusSort,
|
||||||
moveIssuesToAnotherMilestone,
|
moveIssuesToAnotherMilestone,
|
||||||
milestoneSort,
|
milestoneSort,
|
||||||
subIssueQuery
|
subIssueQuery,
|
||||||
|
getVisibleFilters
|
||||||
} from './utils'
|
} from './utils'
|
||||||
|
|
||||||
import { EmployeeAccount } from '@hcengineering/contact'
|
import { EmployeeAccount } from '@hcengineering/contact'
|
||||||
@ -497,7 +498,8 @@ export default async (): Promise<Resources> => ({
|
|||||||
SubIssueQuery: subIssueQuery,
|
SubIssueQuery: subIssueQuery,
|
||||||
GetAllPriority: getAllPriority,
|
GetAllPriority: getAllPriority,
|
||||||
GetAllComponents: getAllComponents,
|
GetAllComponents: getAllComponents,
|
||||||
GetAllMilestones: getAllMilestones
|
GetAllMilestones: getAllMilestones,
|
||||||
|
GetVisibleFilters: getVisibleFilters
|
||||||
},
|
},
|
||||||
actionImpl: {
|
actionImpl: {
|
||||||
Move: move,
|
Move: move,
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
//
|
//
|
||||||
import { Client, Doc, Ref } from '@hcengineering/core'
|
import { Client, Doc, Ref, Space } from '@hcengineering/core'
|
||||||
import type { Asset, IntlString, Metadata, Resource } from '@hcengineering/platform'
|
import type { Asset, IntlString, Metadata, Resource } from '@hcengineering/platform'
|
||||||
import { mergeIds } from '@hcengineering/platform'
|
import { mergeIds } from '@hcengineering/platform'
|
||||||
import { IssueDraft } from '@hcengineering/tracker'
|
import { IssueDraft } from '@hcengineering/tracker'
|
||||||
@ -24,7 +24,8 @@ import {
|
|||||||
SortFunc,
|
SortFunc,
|
||||||
Viewlet,
|
Viewlet,
|
||||||
ViewletDescriptor,
|
ViewletDescriptor,
|
||||||
ViewQueryAction
|
ViewQueryAction,
|
||||||
|
KeyFilter
|
||||||
} from '@hcengineering/view'
|
} from '@hcengineering/view'
|
||||||
import tracker, { trackerId } from '../../tracker/lib'
|
import tracker, { trackerId } from '../../tracker/lib'
|
||||||
|
|
||||||
@ -392,7 +393,8 @@ export default mergeIds(trackerId, tracker, {
|
|||||||
SubIssueQuery: '' as ViewQueryAction,
|
SubIssueQuery: '' as ViewQueryAction,
|
||||||
GetAllPriority: '' as GetAllValuesFunc,
|
GetAllPriority: '' as GetAllValuesFunc,
|
||||||
GetAllComponents: '' as GetAllValuesFunc,
|
GetAllComponents: '' as GetAllValuesFunc,
|
||||||
GetAllMilestones: '' as GetAllValuesFunc
|
GetAllMilestones: '' as GetAllValuesFunc,
|
||||||
|
GetVisibleFilters: '' as Resource<(filters: KeyFilter[], space?: Ref<Space>) => Promise<KeyFilter[]>>
|
||||||
},
|
},
|
||||||
aggregation: {
|
aggregation: {
|
||||||
CreateComponentAggregationManager: '' as CreateAggregationManagerFunc,
|
CreateComponentAggregationManager: '' as CreateAggregationManagerFunc,
|
||||||
|
@ -25,6 +25,7 @@ import core, {
|
|||||||
DocumentUpdate,
|
DocumentUpdate,
|
||||||
Ref,
|
Ref,
|
||||||
SortingOrder,
|
SortingOrder,
|
||||||
|
Space,
|
||||||
Status,
|
Status,
|
||||||
StatusCategory,
|
StatusCategory,
|
||||||
StatusManager,
|
StatusManager,
|
||||||
@ -58,7 +59,7 @@ import {
|
|||||||
MILLISECONDS_IN_WEEK,
|
MILLISECONDS_IN_WEEK,
|
||||||
PaletteColorIndexes
|
PaletteColorIndexes
|
||||||
} from '@hcengineering/ui'
|
} from '@hcengineering/ui'
|
||||||
import { ViewletDescriptor } from '@hcengineering/view'
|
import { KeyFilter, ViewletDescriptor } from '@hcengineering/view'
|
||||||
import { CategoryQuery, groupBy, ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources'
|
import { CategoryQuery, groupBy, ListSelectionProvider, SelectDirection } from '@hcengineering/view-resources'
|
||||||
import tracker from './plugin'
|
import tracker from './plugin'
|
||||||
import { defaultPriorities, defaultMilestoneStatuses } from './types'
|
import { defaultPriorities, defaultMilestoneStatuses } from './types'
|
||||||
@ -654,3 +655,8 @@ export const IssuePriorityColor = {
|
|||||||
[IssuePriority.Medium]: PaletteColorIndexes.Ocean,
|
[IssuePriority.Medium]: PaletteColorIndexes.Ocean,
|
||||||
[IssuePriority.Low]: PaletteColorIndexes.Cloud
|
[IssuePriority.Low]: PaletteColorIndexes.Cloud
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function getVisibleFilters (filters: KeyFilter[], space?: Ref<Space>): Promise<KeyFilter[]> {
|
||||||
|
// Removes the "Project" filter if a specific space is provided
|
||||||
|
return space === undefined ? filters : filters.filter((f) => f.key !== 'space')
|
||||||
|
}
|
||||||
|
@ -17,6 +17,7 @@
|
|||||||
import { getClient } from '@hcengineering/presentation'
|
import { getClient } from '@hcengineering/presentation'
|
||||||
import { Label, Scroller, Submenu, closePopup, closeTooltip, resizeObserver, showPopup } from '@hcengineering/ui'
|
import { Label, Scroller, Submenu, closePopup, closeTooltip, resizeObserver, showPopup } from '@hcengineering/ui'
|
||||||
import { ClassFilters, Filter, KeyFilter, KeyFilterPreset } from '@hcengineering/view'
|
import { ClassFilters, Filter, KeyFilter, KeyFilterPreset } from '@hcengineering/view'
|
||||||
|
import { getResource } from '@hcengineering/platform'
|
||||||
import { createEventDispatcher } from 'svelte'
|
import { createEventDispatcher } from 'svelte'
|
||||||
import { FilterQuery, buildFilterKey } from '../../filter'
|
import { FilterQuery, buildFilterKey } from '../../filter'
|
||||||
import view from '../../plugin'
|
import view from '../../plugin'
|
||||||
@ -101,12 +102,12 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function getTypes (_class: Ref<Class<Doc>>, nestedFrom: KeyFilter | undefined): KeyFilter[] {
|
async function getTypes (_class: Ref<Class<Doc>>, nestedFrom: KeyFilter | undefined): Promise<KeyFilter[]> {
|
||||||
let res: KeyFilter[] = []
|
let res: KeyFilter[] = []
|
||||||
if (nestedFrom !== undefined) {
|
if (nestedFrom !== undefined) {
|
||||||
res = getNestedTypes(nestedFrom)
|
res = await getNestedTypes(nestedFrom)
|
||||||
} else {
|
} else {
|
||||||
res = getOwnTypes(_class)
|
res = await getOwnTypes(_class)
|
||||||
}
|
}
|
||||||
res.sort((a, b) => {
|
res.sort((a, b) => {
|
||||||
if (a.group === b.group) return 0
|
if (a.group === b.group) return 0
|
||||||
@ -119,20 +120,23 @@
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
function getNestedTypes (type: KeyFilter): KeyFilter[] {
|
async function getNestedTypes (type: KeyFilter): Promise<KeyFilter[]> {
|
||||||
const targetClass = (hierarchy.getAttribute(type._class, type.key).type as RefTo<Doc>).to
|
const targetClass = (hierarchy.getAttribute(type._class, type.key).type as RefTo<Doc>).to
|
||||||
return getOwnTypes(targetClass)
|
return await getOwnTypes(targetClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
function getOwnTypes (_class: Ref<Class<Doc>>): KeyFilter[] {
|
async function getOwnTypes (_class: Ref<Class<Doc>>): Promise<KeyFilter[]> {
|
||||||
const mixin = hierarchy.classHierarchyMixin(_class, view.mixin.ClassFilters)
|
const mixin = hierarchy.classHierarchyMixin(_class, view.mixin.ClassFilters)
|
||||||
if (mixin === undefined) return []
|
if (mixin === undefined) return []
|
||||||
_class = hierarchy.getBaseClass(_class)
|
_class = hierarchy.getBaseClass(_class)
|
||||||
const result = getFilters(_class, mixin)
|
const result = getFilters(_class, mixin)
|
||||||
|
const getVisibleFilters = mixin.getVisibleFilters
|
||||||
|
? await getResource(mixin.getVisibleFilters)
|
||||||
|
: async (filters: KeyFilter[]) => filters
|
||||||
|
|
||||||
if (mixin.strict) {
|
if (mixin.strict) {
|
||||||
// Attributes not specified in "mixing.filters" are ignored
|
// Attributes not specified in "mixin.filters" are ignored in "strict" mode
|
||||||
return result
|
return await getVisibleFilters(result, space)
|
||||||
}
|
}
|
||||||
|
|
||||||
const allAttributes = hierarchy.getAllAttributes(_class)
|
const allAttributes = hierarchy.getAllAttributes(_class)
|
||||||
@ -166,7 +170,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return result
|
return await getVisibleFilters(result, space)
|
||||||
}
|
}
|
||||||
|
|
||||||
const actionElements: HTMLButtonElement[] = []
|
const actionElements: HTMLButtonElement[] = []
|
||||||
@ -260,8 +264,6 @@
|
|||||||
|
|
||||||
const elements: HTMLElement[] = []
|
const elements: HTMLElement[] = []
|
||||||
|
|
||||||
$: types = getTypes(_class, nestedFrom)
|
|
||||||
|
|
||||||
function nextDiffCat (types: KeyFilter[], i: number): boolean {
|
function nextDiffCat (types: KeyFilter[], i: number): boolean {
|
||||||
if (types[i + 1] === undefined) return false
|
if (types[i + 1] === undefined) return false
|
||||||
return types[i].group !== types[i + 1].group
|
return types[i].group !== types[i + 1].group
|
||||||
@ -289,45 +291,47 @@
|
|||||||
</button>
|
</button>
|
||||||
<div class="divider" />
|
<div class="divider" />
|
||||||
{/if}
|
{/if}
|
||||||
{#each types as type, i}
|
{#await getTypes(_class, nestedFrom) then types}
|
||||||
{#if filter === undefined && hasNested(type)}
|
{#each types as type, i}
|
||||||
<Submenu
|
{#if filter === undefined && hasNested(type)}
|
||||||
bind:element={elements[i]}
|
<Submenu
|
||||||
on:keydown={(event) => keyDown(event, i)}
|
bind:element={elements[i]}
|
||||||
on:mouseover={() => {
|
on:keydown={(event) => keyDown(event, i)}
|
||||||
elements[i]?.focus()
|
on:mouseover={() => {
|
||||||
}}
|
elements[i]?.focus()
|
||||||
label={type.label}
|
}}
|
||||||
props={{
|
label={type.label}
|
||||||
_class,
|
props={{
|
||||||
space,
|
_class,
|
||||||
index,
|
space,
|
||||||
target,
|
index,
|
||||||
onChange,
|
target,
|
||||||
nestedFrom: type
|
onChange,
|
||||||
}}
|
nestedFrom: type
|
||||||
options={{ component: view.component.FilterTypePopup }}
|
}}
|
||||||
withHover
|
options={{ component: view.component.FilterTypePopup }}
|
||||||
/>
|
withHover
|
||||||
{:else}
|
/>
|
||||||
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
{:else}
|
||||||
<button
|
<!-- svelte-ignore a11y-mouse-events-have-key-events -->
|
||||||
class="menu-item"
|
<button
|
||||||
on:keydown={(event) => keyDown(event, i)}
|
class="menu-item"
|
||||||
on:mouseover={(event) => {
|
on:keydown={(event) => keyDown(event, i)}
|
||||||
event.currentTarget.focus()
|
on:mouseover={(event) => {
|
||||||
}}
|
event.currentTarget.focus()
|
||||||
on:click={() => {
|
}}
|
||||||
click(type)
|
on:click={() => {
|
||||||
}}
|
click(type)
|
||||||
>
|
}}
|
||||||
<div class="overflow-label pr-1"><Label label={type.label} /></div>
|
>
|
||||||
</button>
|
<div class="overflow-label pr-1"><Label label={type.label} /></div>
|
||||||
{/if}
|
</button>
|
||||||
{#if nextDiffCat(types, i)}
|
{/if}
|
||||||
<div class="menu-separator" />
|
{#if nextDiffCat(types, i)}
|
||||||
{/if}
|
<div class="menu-separator" />
|
||||||
{/each}
|
{/if}
|
||||||
|
{/each}
|
||||||
|
{/await}
|
||||||
</Scroller>
|
</Scroller>
|
||||||
<div class="menu-space" />
|
<div class="menu-space" />
|
||||||
</div>
|
</div>
|
||||||
|
@ -128,6 +128,8 @@ export interface ClassFilters extends Class<Doc> {
|
|||||||
|
|
||||||
// Ignore attributes not specified in the "filters" array
|
// Ignore attributes not specified in the "filters" array
|
||||||
strict?: boolean
|
strict?: boolean
|
||||||
|
// Allows to filter out the provided keys, leaving only the necessary ones
|
||||||
|
getVisibleFilters?: Resource<(filters: KeyFilter[], space?: Ref<Space>) => Promise<KeyFilter[]>>
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user