Skip to content

Commit

Permalink
Merge branch 'main' into release
Browse files Browse the repository at this point in the history
  • Loading branch information
acoffman committed Oct 31, 2024
2 parents 1ef4eaf + 838e3ef commit f6656bd
Show file tree
Hide file tree
Showing 30 changed files with 641 additions and 246 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -114,39 +114,10 @@
filterTitle;
context: { $implicit: 'Participating User', value: userId() }
"></ng-container>
<nz-select
nzPlaceHolder="Select User"
nzMode="multiple"
[ngModel]="userId()"
(ngModelChange)="userId.set($event)"
[nzCustomTemplate]="userLabel"
[nzOptionOverflowSize]="12"
[nzOptionHeightPx]="28">
<nz-option
*ngFor="let user of cvcFilterOptions().uniqueParticipants"
nzCustomContent
[nzLabel]="user.displayName"
[nzValue]="user.id">
<ng-container
*ngTemplateOutlet="
userLabel;
context: {
$implicit: { nzLabel: user.displayName, nzValue: user.id },
}
">
</ng-container>
</nz-option>
<ng-template
#userLabel
let-selected>
<span
nz-icon
[nzType]="'civic-curator'"
nzTheme="twotone"
[nzTwotoneColor]="'Curator' | entityColor"></span>
{{ selected.nzLabel }}
</ng-template>
</nz-select>
<cvc-user-filter-select
[cvcUniqueParticipants]="cvcFilterOptions().uniqueParticipants"
[cvcUserId]="userId()"
(cvcUserIdChange)="userId.set($event)"></cvc-user-filter-select>
</nz-col>
}

Expand All @@ -160,43 +131,14 @@
value: organizationId(),
}
"></ng-container>
<nz-select
nzPlaceHolder="Select Organization"
nzMode="multiple"
[ngModel]="organizationId()"
(ngModelChange)="organizationId.set($event)"
[nzCustomTemplate]="organizationLabel"
[nzOptionHeightPx]="28">
<nz-option
*ngFor="
let organization of cvcFilterOptions().participatingOrganizations
"
nzCustomContent
[nzLabel]="organization.name"
[nzValue]="organization.id">
<ng-container
*ngTemplateOutlet="
organizationLabel;
context: {
$implicit: {
nzLabel: organization.name,
nzValue: organization.id,
},
}
">
</ng-container>
</nz-option>
<ng-template
#organizationLabel
let-selected>
<span
nz-icon
[nzType]="'civic-organization'"
nzTheme="twotone"
[nzTwotoneColor]="'Organization' | entityColor"></span>
{{ selected.nzLabel }}
</ng-template>
</nz-select>
<cvc-org-filter-select
[cvcParticipatingOrganizations]="
cvcFilterOptions().participatingOrganizations
"
[cvcOrganizationId]="organizationId()"
(cvcOrganizationIdChange)="
organizationId.set($event)
"></cvc-org-filter-select>
</nz-col>
}
<nz-col
Expand Down Expand Up @@ -237,11 +179,15 @@ <h4>Sort Direction</h4>
</nz-option>
</nz-select>
</nz-col>
<!-- <nz-col nzSpan="24">
<!-- <nz-col
nzSpan="24"
style="max-height: 200px; overflow-y: auto">
<h4>Filters</h4>
<pre>{{ cvcFilters() | json }}</pre>
<h4>Filter Options</h4>
<pre>{{ cvcFilterOptions() | json }}</pre>
<h4>
Unique Participants ({{ cvcFilterOptions().uniqueParticipants.length }})$
</h4>
<pre>{{ cvcFilterOptions().uniqueParticipants | json }}</pre>
</nz-col> -->
</nz-row>
<!-- TEMPLATES -->
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ import {
DateSortColumns,
Maybe,
SortDirection,
UserFilterSearchGQL,
UserFilterSearchQuery,
UserFilterSearchQueryVariables,
} from '@app/generated/civic.apollo'
import { CommonModule, KeyValuePipe } from '@angular/common'
import { FormsModule } from '@angular/forms'
Expand All @@ -40,12 +43,19 @@ import { disableDates } from '../activity-feed.functions'
import { toObservable, toSignal } from '@angular/core/rxjs-interop'
import { UntilDestroy, untilDestroyed } from '@ngneat/until-destroy'
import { tag } from 'rxjs-spy/operators'
import { distinctUntilChanged, map, startWith, switchMap } from 'rxjs/operators'
import { timer, filter, of } from 'rxjs'
import { isNonNullObject } from '@apollo/client/utilities'
import {
distinctUntilChanged,
map,
skip,
startWith,
switchMap,
} from 'rxjs/operators'
import { timer, filter, of, Subject, from } from 'rxjs'
import { isNonNulled } from 'rxjs-etc'
import { NzButtonModule } from 'ng-zorro-antd/button'
import { NzAlertModule } from 'ng-zorro-antd/alert'
import { CvcUserFilterSelect } from './user-filter-select/user-filter-select.component'
import { CvcOrgFilterSelect } from './org-filter-select/org-filter-select.component'

export const defaultFilters = {}

Expand All @@ -65,6 +75,8 @@ export const defaultFilters = {}
NzSelectModule,
NzDatePickerModule,
CvcPipesModule,
CvcUserFilterSelect,
CvcOrgFilterSelect,
],
templateUrl: './feed-filters.component.html',
styleUrls: ['./feed-filters.component.less'],
Expand Down Expand Up @@ -118,7 +130,17 @@ export class CvcActivityFeedFilterSelects implements OnInit {
sortByDirection: this.sortByDirection(),
})
})

/**
* Observable that emits the count of new activities since the last refresh.
*
* Behavior:
* - Only activates if cvcCheckInterval > 0, else emits 0
* - Polls the API at the specified interval (cvcCheckInterval in seconds)
* - Uses the current filter settings but only looks for activities after the last refresh
* - Emits 0 initially and then the count of new activities
* - Only emits when the count changes (uses distinctUntilChanged)
* - Resets to 0 when filters change via cvcRefreshChanges
*/
const newActivities$ = toObservable(this.cvcRefreshChanges).pipe(
filter(isNonNulled),
switchMap((refetchEvent) => {
Expand Down Expand Up @@ -151,6 +173,7 @@ export class CvcActivityFeedFilterSelects implements OnInit {
)
this.newActivities = toSignal(newActivities$, { initialValue: 0 })
}

ngOnInit(): void {
this.eventType = signal(this.cvcFilters().activityType)
this.subjectType = signal(this.cvcFilters().subjectType)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
<nz-select
nzPlaceHolder="Select Organization"
nzMode="multiple"
nzAllowClear
[(ngModel)]="cvcOrganizationId"
(nzOnSearch)="onSearch$.next($event)"
[nzCustomTemplate]="organizationLabel"
[nzNotFoundContent]="notFound"
[nzOptionHeightPx]="28">
<nz-option
*ngFor="let organization of filteredOrganizations()"
nzCustomContent
[nzLabel]="organization.name"
[nzValue]="organization.id">
<ng-container
*ngTemplateOutlet="
organizationLabel;
context: {
$implicit: {
nzLabel: organization.name,
nzValue: organization.id,
},
}
">
</ng-container>
</nz-option>
</nz-select>

<ng-template
#organizationLabel
let-selected>
<span
nz-icon
[nzType]="'civic-organization'"
nzTheme="twotone"
[nzTwotoneColor]="'Organization' | entityColor"></span>
{{ selected.nzLabel }}
</ng-template>

<ng-template #notFound>
<span>No organizationsfound matching "{{ onSearch() }}"</span>
</ng-template>
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Component, input, model, Signal } from '@angular/core'
import { ActivityFeedFilterOptions } from '../../activity-feed.types'
import { CvcPipesModule } from '@app/core/pipes/pipes.module'
import { CommonModule } from '@angular/common'
import { NzSelectModule } from 'ng-zorro-antd/select'
import { NzIconModule } from 'ng-zorro-antd/icon'
import { FormsModule } from '@angular/forms'
import {
BrowseOrganization,
Organization,
OrgFilterSearchGQL,
OrgFilterSearchQuery,
OrgFilterSearchQueryVariables,
} from '@app/generated/civic.apollo'
import { from, map, Subject, switchMap } from 'rxjs'
import { QueryRef } from 'apollo-angular'
import { tag } from 'rxjs-spy/operators'
import { toSignal } from '@angular/core/rxjs-interop'

@Component({
selector: 'cvc-org-filter-select',
standalone: true,
imports: [
CommonModule,
FormsModule,
NzIconModule,
NzSelectModule,
CvcPipesModule,
],
templateUrl: './org-filter-select.component.html',
styleUrl: './org-filter-select.component.less',
})
export class CvcOrgFilterSelect {
cvcParticipatingOrganizations =
input.required<ActivityFeedFilterOptions['participatingOrganizations']>()
cvcOrganizationId = model.required<number[]>()

onSearch$: Subject<string>
onSearch: Signal<string>
queryRef!: QueryRef<OrgFilterSearchQuery, OrgFilterSearchQueryVariables>
filteredOrganizations: Signal<BrowseOrganization[]>

constructor(private gql: OrgFilterSearchGQL) {
this.onSearch$ = new Subject<string>()
const filteredOrganizations$ = this.onSearch$.pipe(
tag(`filteredOrganizations$`),
switchMap((nameStr) => {
const query = { name: nameStr, first: 25 }
if (this.queryRef) {
const refetch = this.queryRef.refetch({ name: nameStr })
return from(refetch)
} else {
this.queryRef = this.gql.watch({ name: nameStr })
return this.queryRef.valueChanges
}
}),
map(
(result) =>
result.data?.organizations.edges.map(
(e) => e.node! as BrowseOrganization
) ?? []
),
tag(`${this.constructor.name} filteredOrganizations$ after`)
)
this.filteredOrganizations = toSignal(filteredOrganizations$, {
initialValue: [],
})
this.onSearch = toSignal(this.onSearch$, { initialValue: '' })
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
query OrgFilterSearch($name: String) {
organizations(name: $name) {
pageInfo {
endCursor
hasNextPage
hasPreviousPage
startCursor
}
edges {
node {
id
name
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<nz-select
nzPlaceHolder="Select User"
nzMode="multiple"
nzAllowClear
[(ngModel)]="cvcUserId"
(nzOnSearch)="onSearch$.next($event)"
[nzCustomTemplate]="userLabel"
[nzNotFoundContent]="notFound"
[nzOptionOverflowSize]="12"
[nzOptionHeightPx]="28">
<nz-option
*ngFor="let user of filteredUsers()"
nzCustomContent
[nzLabel]="user.displayName"
[nzValue]="user.id">
<ng-container
*ngTemplateOutlet="
userLabel;
context: {
$implicit: {
nzLabel: user.displayName ?? user.name ?? user.username,
nzValue: user.id,
},
}
">
</ng-container>
</nz-option>
</nz-select>

<ng-template
#userLabel
let-selected>
<span
nz-icon
[nzType]="'civic-curator'"
nzTheme="twotone"
[nzTwotoneColor]="'Curator' | entityColor"></span>
{{ selected.nzLabel }}
</ng-template>

<ng-template #notFound>
<span>No users found matching "{{ onSearch() }}"</span>
</ng-template>
Loading

0 comments on commit f6656bd

Please sign in to comment.