Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion models/activity/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ export class TTxViewlet extends TDoc implements TxViewlet {
@Model(activity.class.ActivityFilter, core.class.Class, DOMAIN_MODEL)
export class TActivityFilter extends TDoc implements ActivityFilter {
label!: IntlString
filter!: Resource<(txes: DisplayTx[]) => DisplayTx[]>
filter!: Resource<(tx: DisplayTx) => boolean>
}

export function createModel (builder: Builder): void {
Expand Down
2 changes: 1 addition & 1 deletion models/attachment/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,6 @@ export default mergeIds(attachmentId, attachment, {
Attachments: '' as Ref<ActionCategory>
},
filter: {
AttachmentsFilter: '' as Resource<(txes: DisplayTx[]) => DisplayTx[]>
AttachmentsFilter: '' as Resource<(tx: DisplayTx) => boolean>
}
})
4 changes: 2 additions & 2 deletions models/chunter/src/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ export default mergeIds(chunterId, chunter, {
ChunterBrowserVisible: '' as Resource<(spaces: Space[]) => boolean>
},
filter: {
CommentsFilter: '' as Resource<(txes: DisplayTx[]) => DisplayTx[]>,
BacklinksFilter: '' as Resource<(txes: DisplayTx[]) => DisplayTx[]>
CommentsFilter: '' as Resource<(tx: DisplayTx) => boolean>,
BacklinksFilter: '' as Resource<(tx: DisplayTx) => boolean>
}
})
1 change: 1 addition & 0 deletions packages/theme/styles/_layouts.scss
Original file line number Diff line number Diff line change
Expand Up @@ -399,6 +399,7 @@ input.search {
.mr-1 { margin-right: .25rem; }
.mr-1-5 { margin-right: .375rem; }
.mr-2 { margin-right: .5rem; }
.mr-2-5 { margin-right: .625rem; }
.mr-3 { margin-right: .75rem; }
.mr-4 { margin-right: 1rem; }
.mr-6 { margin-right: 1.5rem; }
Expand Down
11 changes: 11 additions & 0 deletions packages/theme/styles/common.scss
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,17 @@
font-size: 1rem;
color: var(--caption-color);
}
&__tag {
padding: .125rem .25rem;
min-width: 0;
font-size: .8125rem;
background-color: var(--accent-bg-color);
color: var(--dark-color);
border-radius: .25rem;

&.highlight { color: var(--content-color); }
}
&__tag + &__tag { margin-left: .125rem; }
}
.invisible { display: none; }
&-empty {
Expand Down
72 changes: 50 additions & 22 deletions plugins/activity-resources/src/components/Activity.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -34,17 +34,26 @@
export let transparent: boolean = false

let txes: DisplayTx[] = []
let txesF: DisplayTx[] = []

const client = getClient()
const attrs = client.getHierarchy().getAllAttributes(object._class)

let filterLabel: IntlString = activityPlg.string.All
let labels: IntlString[] = []
const filters: ActivityFilter[] = []
const saved = localStorage.getItem('activity-filter')
let selectedFilter: Ref<Doc> | 'All' = saved !== null && saved !== undefined ? JSON.parse(saved) : 'All'
let selectedFilter: Ref<Doc>[] | 'All' =
saved !== null && saved !== undefined ? (JSON.parse(saved) as Ref<Doc>[] | 'All') : 'All'
$: localStorage.setItem('activity-filter', JSON.stringify(selectedFilter))
client.findAll(activity.class.ActivityFilter, {}).then((res) => res.map((it) => filters.push(it)))
client.findAll(activity.class.ActivityFilter, {}).then((res) => {
res.map((it) => filters.push(it))
if (saved !== null && saved !== undefined) {
const temp: Ref<Doc>[] | 'All' = JSON.parse(saved)
if (temp !== 'All' && Array.isArray(temp)) {
selectedFilter = temp.filter((it) => filters.findIndex((f) => it === f._id) > -1)
if ((selectedFilter as Ref<Doc>[]).length === 0) selectedFilter = 'All'
} else selectedFilter = 'All'
}
})

const activityQuery = newActivity(client, attrs)
getResource(notification.function.GetNotificationClient).then((res) => {
Expand Down Expand Up @@ -82,7 +91,7 @@

$: if (editableMap) updateTxes(object)

$: newTxPos = newTx(txesF, $lastViews)
$: newTxPos = newTx(filtered, $lastViews)

function newTx (txes: DisplayTx[], lastViews: Map<Ref<Doc>, number> | undefined): number {
const lastView = lastViews?.get(object._id)
Expand All @@ -96,22 +105,35 @@

let optionsBtn: HTMLButtonElement
const handleOptions = () => {
showPopup(FilterPopup, { selectedFilter, filters }, optionsBtn, (res) => {
if (res === undefined) return
if (res.action === 'select') selectedFilter = res.value as Ref<Doc> | 'All'
})
showPopup(
FilterPopup,
{ selectedFilter, filters },
optionsBtn,
() => {},
(res) => {
if (res === undefined) return
if (res.action === 'select') selectedFilter = res.value as Ref<Doc>[] | 'All'
}
)
}

$: if (selectedFilter || txes) {
const filter = filters.find((it) => it._id === selectedFilter)
if (filter) {
filterLabel = filter.label
getResource(filter.filter).then((result) => (txesF = result(txes)))
} else {
filterLabel = activityPlg.string.All
txesF = txes
let filterActions: ((tx: DisplayTx) => boolean)[] = [] // Enabled filters
const updateFiltered = () => (filtered = txes.filter((it) => filterActions.some((f) => f(it))))
async function updateFilterActions (fls: ActivityFilter[], selected: Ref<Doc>[] | 'All'): Promise<void> {
if (selected === 'All' || !Array.isArray(selected)) filterActions = [() => true]
else {
const tf = fls.filter((filter) => (selected as Ref<Doc>[]).includes(filter._id))
filterActions = []
labels = []
tf.forEach((filter) => {
labels.push(filter.label)
getResource(filter.filter).then((res) => filterActions.push(res))
})
}
setTimeout(() => updateFiltered(), 0)
}
$: updateFilterActions(filters, selectedFilter)
$: filtered = txes.filter((it) => filterActions.some((f) => f(it)))
</script>

{#if !integrate || transparent}
Expand All @@ -126,9 +148,9 @@
<div class="flex-col flex-grow min-h-0" class:background-accent-bg-color={!transparent}>
<Scroller>
<div class="p-10 select-text" id={activity.string.Activity}>
{#if txesF}
{#if filtered}
<Grid column={1} rowGap={1.5}>
{#each txesF as tx, i}
{#each filtered as tx, i}
<TxView
{tx}
{viewlets}
Expand All @@ -152,7 +174,13 @@
<div class="antiSection-header mt-6">
<div class="antiSection-header__icon"><IconActivity size={'small'} /></div>
<span class="antiSection-header__title"><Label label={activity.string.Activity} /></span>
<span class="dark-color text-md"><Label label={filterLabel} /></span>
{#if selectedFilter === 'All'}
<span class="antiSection-header__tag highlight"><Label label={activityPlg.string.All} /></span>
{:else}
{#each labels as label}
<span class="antiSection-header__tag overflow-label"><Label {label} /></span>
{/each}
{/if}
<div class="w-2 min-w-2 max-w-2" />
<Button
bind:input={optionsBtn}
Expand All @@ -168,9 +196,9 @@
</div>
{/if}
<div class="p-activity select-text" id={activity.string.Activity}>
{#if txesF}
{#if filtered}
<Grid column={1} rowGap={1.5}>
{#each txesF as tx, i}
{#each filtered as tx, i}
<TxView
{tx}
{viewlets}
Expand Down
55 changes: 46 additions & 9 deletions plugins/activity-resources/src/components/FilterPopup.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import { ActivityFilter } from '@hcengineering/activity'
import activity from '../plugin'

export let selectedFilter: Ref<Doc> | 'All' = 'All'
export let selectedFilter: Ref<Doc>[] | 'All' = 'All'
export let filters: ActivityFilter[] = []

const dispatch = createEventDispatcher()
Expand All @@ -30,22 +30,27 @@
checked: boolean
value: Ref<Doc> | 'All'
}
const menu: ActionMenu[] = [
let menu: ActionMenu[] = [
{
label: activity.string.All,
checked: selectedFilter === 'All',
checked: true,
value: 'All'
}
]
filters.map((fl) => menu.push({ label: fl.label, checked: selectedFilter === fl._id, value: fl._id }))
filters.map((fl) => menu.push({ label: fl.label, checked: false, value: fl._id }))
if (selectedFilter !== 'All') {
selectedFilter.forEach((fl) => {
const index = menu.findIndex((el) => el.value === fl)
if (index !== -1) menu[index].checked = true
})
}

let popup: HTMLElement
$: popup?.focus()

const btns: HTMLElement[] = []
let activeElement: HTMLElement
const keyDown = (ev: KeyboardEvent): void => {
console.log('[KEY]', ev.key)
const n = btns.indexOf(activeElement) ?? 0
if (ev.key === ' ' || ev.key === 'Enter') {
ev.preventDefault()
Expand All @@ -69,6 +74,40 @@
}
}

const checkAll = () => {
menu.forEach((el, i) => (el.checked = i === 0))
selectedFilter = 'All'
}
const uncheckAll = () => {
menu.forEach((el) => (el.checked = true))
const temp = filters.map((fl) => fl._id as Ref<Doc>)
selectedFilter = temp
}

const selectRow = (n: number) => {
if (n === 0) {
if (selectedFilter === 'All') uncheckAll()
else checkAll()
} else {
if (selectedFilter === 'All') {
menu[n].checked = true
selectedFilter = [menu[n].value as Ref<Doc>]
} else if (menu[n].checked) {
if (menu.filter((el) => el.checked).length === 2) checkAll()
else {
menu[n].checked = false
selectedFilter = selectedFilter.filter((fl) => fl !== menu[n].value)
}
} else {
menu[n].checked = true
selectedFilter.push(menu[n].value as Ref<Doc>)
}
}
menu = menu
dispatch('update', { action: 'select', value: selectedFilter })
setTimeout(() => dispatch('changeContent'), 0)
}

onMount(() => {
if (btns[0]) {
btns[0].focus()
Expand All @@ -95,12 +134,10 @@
on:mousemove={() => {
if (btns[i] !== activeElement) activeElement = btns[i]
}}
on:click={() => {
dispatch('close', { action: 'select', value: item.value })
}}
on:click={() => selectRow(i)}
>
<div class="flex-center justify-end mr-3 pointer-events-none">
<CheckBox checked={item.checked} />
<CheckBox checked={item.checked} symbol={selectedFilter !== 'All' && i === 0 ? 'minus' : 'check'} />
</div>
<span class="overflow-label">
<Label label={item.label} />
Expand Down
2 changes: 1 addition & 1 deletion plugins/activity-resources/src/components/TxView.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -159,7 +159,7 @@
{/if}

<div
class="flex-grow flex-col clear-mins"
class="flex-grow flex-col clear-mins mr-2-5"
class:comment={viewlet && viewlet?.editable}
class:mention={viewlet?.display === 'emphasized' || isMessageType(model[0]?.attribute)}
>
Expand Down
2 changes: 1 addition & 1 deletion plugins/activity/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export interface DisplayTx {
*/
export interface ActivityFilter extends Doc {
label: IntlString
filter: Resource<(txes: DisplayTx[]) => DisplayTx[]>
filter: Resource<(tx: DisplayTx) => boolean>
}

/**
Expand Down
4 changes: 2 additions & 2 deletions plugins/attachment-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -228,8 +228,8 @@ export async function DeleteAttachment (attach: Attachment): Promise<void> {
)
}

export function attachmentsFilter (txes: DisplayTx[]): DisplayTx[] {
return txes.filter((tx) => tx.tx.objectClass === attachment.class.Attachment)
export function attachmentsFilter (tx: DisplayTx): boolean {
return tx.tx.objectClass === attachment.class.Attachment
}

export default async (): Promise<Resources> => ({
Expand Down
8 changes: 4 additions & 4 deletions plugins/chunter-resources/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -207,12 +207,12 @@ async function update (source: Doc, key: string, target: RelatedDocument[], msg:
await updateBacklinksList(getClient(), q, backlinks)
}

export function commentsFilter (txes: DisplayTx[]): DisplayTx[] {
return txes.filter((tx) => tx.tx.objectClass === chunter.class.Comment)
export function commentsFilter (tx: DisplayTx): boolean {
return tx.tx.objectClass === chunter.class.Comment
}

export function backlinksFilter (txes: DisplayTx[]): DisplayTx[] {
return txes.filter((tx) => tx.tx.objectClass === chunter.class.Backlink)
export function backlinksFilter (tx: DisplayTx): boolean {
return tx.tx.objectClass === chunter.class.Backlink
}

export default async (): Promise<Resources> => ({
Expand Down