feat: saved board views and richer board filters
The board now filters by text, type, priority and unassigned tickets as well. Any combination can be saved as a named view, private or shared with the project, and opened again with one click. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -52,6 +52,13 @@ export class GraphqlIssuesGateway extends IssuesGateway {
|
||||
releaseId: filter.releaseId ?? null,
|
||||
assigneeId: filter.assigneeId ?? null,
|
||||
area: filter.area ?? null,
|
||||
types: filter.types?.length ? filter.types : null,
|
||||
priorities: filter.priorities?.length
|
||||
? (filter.priorities as never)
|
||||
: null,
|
||||
labels: filter.labels?.length ? filter.labels : null,
|
||||
search: filter.search?.trim() || null,
|
||||
unassigned: filter.unassigned ?? null,
|
||||
})
|
||||
.pipe(
|
||||
map((d) =>
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
import { inject, Injectable } from '@angular/core';
|
||||
import {
|
||||
SavedFilter,
|
||||
SavedFilterCriteria,
|
||||
SavedFiltersGateway,
|
||||
} from '@task-stream/web/tracker/domain';
|
||||
import { map, Observable } from 'rxjs';
|
||||
import {
|
||||
DeleteSavedFilterDocument,
|
||||
SavedFiltersDocument,
|
||||
SaveFilterDocument,
|
||||
} from '../graphql/generated';
|
||||
import { GraphqlOperations } from './graphql-operations';
|
||||
|
||||
@Injectable()
|
||||
export class GraphqlSavedFiltersGateway extends SavedFiltersGateway {
|
||||
private readonly gql = inject(GraphqlOperations);
|
||||
|
||||
list(projectId: string): Observable<SavedFilter[]> {
|
||||
return this.gql
|
||||
.query(SavedFiltersDocument, { projectId })
|
||||
.pipe(map((d) => d.savedFilters as SavedFilter[]));
|
||||
}
|
||||
|
||||
save(input: {
|
||||
projectId: string;
|
||||
name: string;
|
||||
shared: boolean;
|
||||
criteria: SavedFilterCriteria;
|
||||
}): Observable<string> {
|
||||
return this.gql
|
||||
.mutate(SaveFilterDocument, { input: input as never })
|
||||
.pipe(map((d) => d.saveFilter));
|
||||
}
|
||||
|
||||
remove(id: string): Observable<void> {
|
||||
return this.gql
|
||||
.mutate(DeleteSavedFilterDocument, { id })
|
||||
.pipe(map(() => undefined));
|
||||
}
|
||||
}
|
||||
@@ -147,6 +147,25 @@ export type RankIssueInput = {
|
||||
|
||||
export type ReleaseStatus = 'ARCHIVED' | 'PLANNED' | 'RELEASED';
|
||||
|
||||
export type SaveFilterInput = {
|
||||
criteria: SavedFilterCriteriaInput;
|
||||
name: string;
|
||||
projectId: string;
|
||||
/** Visible to the whole project (members, not viewers, share) */
|
||||
shared?: boolean;
|
||||
};
|
||||
|
||||
export type SavedFilterCriteriaInput = {
|
||||
areas?: Array<string> | null | undefined;
|
||||
assigneeId?: string | null | undefined;
|
||||
labels?: Array<string> | null | undefined;
|
||||
priorities?: Array<IssuePriority> | null | undefined;
|
||||
releaseId?: string | null | undefined;
|
||||
search?: string | null | undefined;
|
||||
types?: Array<string> | null | undefined;
|
||||
unassigned?: boolean | null | undefined;
|
||||
};
|
||||
|
||||
/** What a status means, whatever each project calls it. DONE and CANCELLED are finished. */
|
||||
export type StatusCategory =
|
||||
| 'CANCELLED'
|
||||
@@ -335,6 +354,11 @@ export type BoardQueryVariables = Exact<{
|
||||
releaseId?: string | null | undefined;
|
||||
assigneeId?: string | null | undefined;
|
||||
area?: string | null | undefined;
|
||||
types?: Array<string> | string | null | undefined;
|
||||
priorities?: Array<IssuePriority> | IssuePriority | null | undefined;
|
||||
labels?: Array<string> | string | null | undefined;
|
||||
search?: string | null | undefined;
|
||||
unassigned?: boolean | null | undefined;
|
||||
}>;
|
||||
|
||||
export type BoardQuery = {
|
||||
@@ -1138,6 +1162,62 @@ export type ReleaseBurnupQuery = {
|
||||
};
|
||||
};
|
||||
|
||||
export type SavedFilterFieldsFragment = {
|
||||
id: string;
|
||||
projectId: string;
|
||||
name: string;
|
||||
shared: boolean;
|
||||
createdAt: string;
|
||||
owner: { id: string; name: string };
|
||||
criteria: {
|
||||
types: Array<string> | null;
|
||||
areas: Array<string> | null;
|
||||
priorities: Array<IssuePriority> | null;
|
||||
assigneeId: string | null;
|
||||
unassigned: boolean | null;
|
||||
releaseId: string | null;
|
||||
labels: Array<string> | null;
|
||||
search: string | null;
|
||||
};
|
||||
};
|
||||
|
||||
export type SavedFiltersQueryVariables = Exact<{
|
||||
projectId: string;
|
||||
}>;
|
||||
|
||||
export type SavedFiltersQuery = {
|
||||
savedFilters: Array<{
|
||||
id: string;
|
||||
projectId: string;
|
||||
name: string;
|
||||
shared: boolean;
|
||||
createdAt: string;
|
||||
owner: { id: string; name: string };
|
||||
criteria: {
|
||||
types: Array<string> | null;
|
||||
areas: Array<string> | null;
|
||||
priorities: Array<IssuePriority> | null;
|
||||
assigneeId: string | null;
|
||||
unassigned: boolean | null;
|
||||
releaseId: string | null;
|
||||
labels: Array<string> | null;
|
||||
search: string | null;
|
||||
};
|
||||
}>;
|
||||
};
|
||||
|
||||
export type SaveFilterMutationVariables = Exact<{
|
||||
input: SaveFilterInput;
|
||||
}>;
|
||||
|
||||
export type SaveFilterMutation = { saveFilter: string };
|
||||
|
||||
export type DeleteSavedFilterMutationVariables = Exact<{
|
||||
id: string;
|
||||
}>;
|
||||
|
||||
export type DeleteSavedFilterMutation = { deleteSavedFilter: boolean };
|
||||
|
||||
export type IssueChangedSubscriptionVariables = Exact<{
|
||||
projectId: string;
|
||||
}>;
|
||||
@@ -1949,6 +2029,74 @@ export const NotificationFieldsFragmentDoc = {
|
||||
},
|
||||
],
|
||||
} as unknown as DocumentNode<NotificationFieldsFragment, unknown>;
|
||||
export const SavedFilterFieldsFragmentDoc = {
|
||||
kind: 'Document',
|
||||
definitions: [
|
||||
{
|
||||
kind: 'FragmentDefinition',
|
||||
name: { kind: 'Name', value: 'SavedFilterFields' },
|
||||
typeCondition: {
|
||||
kind: 'NamedType',
|
||||
name: { kind: 'Name', value: 'SavedFilter' },
|
||||
},
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'projectId' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'name' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'shared' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'createdAt' } },
|
||||
{
|
||||
kind: 'Field',
|
||||
name: { kind: 'Name', value: 'owner' },
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{
|
||||
kind: 'FragmentSpread',
|
||||
name: { kind: 'Name', value: 'UserRefFields' },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'Field',
|
||||
name: { kind: 'Name', value: 'criteria' },
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'types' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'areas' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'priorities' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'assigneeId' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'unassigned' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'releaseId' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'labels' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'search' } },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'FragmentDefinition',
|
||||
name: { kind: 'Name', value: 'UserRefFields' },
|
||||
typeCondition: {
|
||||
kind: 'NamedType',
|
||||
name: { kind: 'Name', value: 'UserRef' },
|
||||
},
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'name' } },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
} as unknown as DocumentNode<SavedFilterFieldsFragment, unknown>;
|
||||
export const BoardDocument = {
|
||||
kind: 'Document',
|
||||
definitions: [
|
||||
@@ -1992,6 +2140,73 @@ export const BoardDocument = {
|
||||
variable: { kind: 'Variable', name: { kind: 'Name', value: 'area' } },
|
||||
type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } },
|
||||
},
|
||||
{
|
||||
kind: 'VariableDefinition',
|
||||
variable: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'types' },
|
||||
},
|
||||
type: {
|
||||
kind: 'ListType',
|
||||
type: {
|
||||
kind: 'NonNullType',
|
||||
type: {
|
||||
kind: 'NamedType',
|
||||
name: { kind: 'Name', value: 'String' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'VariableDefinition',
|
||||
variable: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'priorities' },
|
||||
},
|
||||
type: {
|
||||
kind: 'ListType',
|
||||
type: {
|
||||
kind: 'NonNullType',
|
||||
type: {
|
||||
kind: 'NamedType',
|
||||
name: { kind: 'Name', value: 'IssuePriority' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'VariableDefinition',
|
||||
variable: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'labels' },
|
||||
},
|
||||
type: {
|
||||
kind: 'ListType',
|
||||
type: {
|
||||
kind: 'NonNullType',
|
||||
type: {
|
||||
kind: 'NamedType',
|
||||
name: { kind: 'Name', value: 'String' },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'VariableDefinition',
|
||||
variable: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'search' },
|
||||
},
|
||||
type: { kind: 'NamedType', name: { kind: 'Name', value: 'String' } },
|
||||
},
|
||||
{
|
||||
kind: 'VariableDefinition',
|
||||
variable: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'unassigned' },
|
||||
},
|
||||
type: { kind: 'NamedType', name: { kind: 'Name', value: 'Boolean' } },
|
||||
},
|
||||
],
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
@@ -2041,6 +2256,46 @@ export const BoardDocument = {
|
||||
name: { kind: 'Name', value: 'area' },
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'Argument',
|
||||
name: { kind: 'Name', value: 'types' },
|
||||
value: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'types' },
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'Argument',
|
||||
name: { kind: 'Name', value: 'priorities' },
|
||||
value: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'priorities' },
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'Argument',
|
||||
name: { kind: 'Name', value: 'labels' },
|
||||
value: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'labels' },
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'Argument',
|
||||
name: { kind: 'Name', value: 'search' },
|
||||
value: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'search' },
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'Argument',
|
||||
name: { kind: 'Name', value: 'unassigned' },
|
||||
value: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'unassigned' },
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'Argument',
|
||||
name: { kind: 'Name', value: 'perColumn' },
|
||||
@@ -7168,6 +7423,207 @@ export const ReleaseBurnupDocument = {
|
||||
},
|
||||
],
|
||||
} as unknown as DocumentNode<ReleaseBurnupQuery, ReleaseBurnupQueryVariables>;
|
||||
export const SavedFiltersDocument = {
|
||||
kind: 'Document',
|
||||
definitions: [
|
||||
{
|
||||
kind: 'OperationDefinition',
|
||||
operation: 'query',
|
||||
name: { kind: 'Name', value: 'SavedFilters' },
|
||||
variableDefinitions: [
|
||||
{
|
||||
kind: 'VariableDefinition',
|
||||
variable: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'projectId' },
|
||||
},
|
||||
type: {
|
||||
kind: 'NonNullType',
|
||||
type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } },
|
||||
},
|
||||
},
|
||||
],
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{
|
||||
kind: 'Field',
|
||||
name: { kind: 'Name', value: 'savedFilters' },
|
||||
arguments: [
|
||||
{
|
||||
kind: 'Argument',
|
||||
name: { kind: 'Name', value: 'projectId' },
|
||||
value: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'projectId' },
|
||||
},
|
||||
},
|
||||
],
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{
|
||||
kind: 'FragmentSpread',
|
||||
name: { kind: 'Name', value: 'SavedFilterFields' },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'FragmentDefinition',
|
||||
name: { kind: 'Name', value: 'UserRefFields' },
|
||||
typeCondition: {
|
||||
kind: 'NamedType',
|
||||
name: { kind: 'Name', value: 'UserRef' },
|
||||
},
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'name' } },
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'FragmentDefinition',
|
||||
name: { kind: 'Name', value: 'SavedFilterFields' },
|
||||
typeCondition: {
|
||||
kind: 'NamedType',
|
||||
name: { kind: 'Name', value: 'SavedFilter' },
|
||||
},
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'id' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'projectId' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'name' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'shared' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'createdAt' } },
|
||||
{
|
||||
kind: 'Field',
|
||||
name: { kind: 'Name', value: 'owner' },
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{
|
||||
kind: 'FragmentSpread',
|
||||
name: { kind: 'Name', value: 'UserRefFields' },
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
{
|
||||
kind: 'Field',
|
||||
name: { kind: 'Name', value: 'criteria' },
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'types' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'areas' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'priorities' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'assigneeId' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'unassigned' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'releaseId' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'labels' } },
|
||||
{ kind: 'Field', name: { kind: 'Name', value: 'search' } },
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
} as unknown as DocumentNode<SavedFiltersQuery, SavedFiltersQueryVariables>;
|
||||
export const SaveFilterDocument = {
|
||||
kind: 'Document',
|
||||
definitions: [
|
||||
{
|
||||
kind: 'OperationDefinition',
|
||||
operation: 'mutation',
|
||||
name: { kind: 'Name', value: 'SaveFilter' },
|
||||
variableDefinitions: [
|
||||
{
|
||||
kind: 'VariableDefinition',
|
||||
variable: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'input' },
|
||||
},
|
||||
type: {
|
||||
kind: 'NonNullType',
|
||||
type: {
|
||||
kind: 'NamedType',
|
||||
name: { kind: 'Name', value: 'SaveFilterInput' },
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{
|
||||
kind: 'Field',
|
||||
name: { kind: 'Name', value: 'saveFilter' },
|
||||
arguments: [
|
||||
{
|
||||
kind: 'Argument',
|
||||
name: { kind: 'Name', value: 'input' },
|
||||
value: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'input' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
} as unknown as DocumentNode<SaveFilterMutation, SaveFilterMutationVariables>;
|
||||
export const DeleteSavedFilterDocument = {
|
||||
kind: 'Document',
|
||||
definitions: [
|
||||
{
|
||||
kind: 'OperationDefinition',
|
||||
operation: 'mutation',
|
||||
name: { kind: 'Name', value: 'DeleteSavedFilter' },
|
||||
variableDefinitions: [
|
||||
{
|
||||
kind: 'VariableDefinition',
|
||||
variable: { kind: 'Variable', name: { kind: 'Name', value: 'id' } },
|
||||
type: {
|
||||
kind: 'NonNullType',
|
||||
type: { kind: 'NamedType', name: { kind: 'Name', value: 'ID' } },
|
||||
},
|
||||
},
|
||||
],
|
||||
selectionSet: {
|
||||
kind: 'SelectionSet',
|
||||
selections: [
|
||||
{
|
||||
kind: 'Field',
|
||||
name: { kind: 'Name', value: 'deleteSavedFilter' },
|
||||
arguments: [
|
||||
{
|
||||
kind: 'Argument',
|
||||
name: { kind: 'Name', value: 'id' },
|
||||
value: {
|
||||
kind: 'Variable',
|
||||
name: { kind: 'Name', value: 'id' },
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
],
|
||||
} as unknown as DocumentNode<
|
||||
DeleteSavedFilterMutation,
|
||||
DeleteSavedFilterMutationVariables
|
||||
>;
|
||||
export const IssueChangedDocument = {
|
||||
kind: 'Document',
|
||||
definitions: [
|
||||
|
||||
@@ -1,10 +1,25 @@
|
||||
query Board($idOrKey: String!, $releaseId: ID, $assigneeId: ID, $area: String) {
|
||||
query Board(
|
||||
$idOrKey: String!
|
||||
$releaseId: ID
|
||||
$assigneeId: ID
|
||||
$area: String
|
||||
$types: [String!]
|
||||
$priorities: [IssuePriority!]
|
||||
$labels: [String!]
|
||||
$search: String
|
||||
$unassigned: Boolean
|
||||
) {
|
||||
project(idOrKey: $idOrKey) {
|
||||
id
|
||||
board(
|
||||
releaseId: $releaseId
|
||||
assigneeId: $assigneeId
|
||||
area: $area
|
||||
types: $types
|
||||
priorities: $priorities
|
||||
labels: $labels
|
||||
search: $search
|
||||
unassigned: $unassigned
|
||||
perColumn: 100
|
||||
) {
|
||||
status
|
||||
|
||||
@@ -0,0 +1,34 @@
|
||||
fragment SavedFilterFields on SavedFilter {
|
||||
id
|
||||
projectId
|
||||
name
|
||||
shared
|
||||
createdAt
|
||||
owner {
|
||||
...UserRefFields
|
||||
}
|
||||
criteria {
|
||||
types
|
||||
areas
|
||||
priorities
|
||||
assigneeId
|
||||
unassigned
|
||||
releaseId
|
||||
labels
|
||||
search
|
||||
}
|
||||
}
|
||||
|
||||
query SavedFilters($projectId: ID!) {
|
||||
savedFilters(projectId: $projectId) {
|
||||
...SavedFilterFields
|
||||
}
|
||||
}
|
||||
|
||||
mutation SaveFilter($input: SaveFilterInput!) {
|
||||
saveFilter(input: $input)
|
||||
}
|
||||
|
||||
mutation DeleteSavedFilter($id: ID!) {
|
||||
deleteSavedFilter(id: $id)
|
||||
}
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
NotificationsGateway,
|
||||
ProjectsGateway,
|
||||
ReleasesGateway,
|
||||
SavedFiltersGateway,
|
||||
TrackerRealtimeGateway,
|
||||
UsersGateway,
|
||||
} from '@task-stream/web/tracker/domain';
|
||||
@@ -24,6 +25,7 @@ import { GraphqlNotificationsGateway } from './adapters/graphql-notifications.ga
|
||||
import { HttpAttachmentsGateway } from './adapters/http-attachments.gateway';
|
||||
import { GraphqlProjectsGateway } from './adapters/graphql-projects.gateway';
|
||||
import { GraphqlRealtimeGateway } from './adapters/graphql-realtime.gateway';
|
||||
import { GraphqlSavedFiltersGateway } from './adapters/graphql-saved-filters.gateway';
|
||||
|
||||
/** Ports → GraphQL adapters (and REST for files). */
|
||||
export function provideTrackerInfrastructure(): EnvironmentProviders {
|
||||
@@ -37,5 +39,6 @@ export function provideTrackerInfrastructure(): EnvironmentProviders {
|
||||
{ provide: UsersGateway, useClass: GraphqlUsersGateway },
|
||||
{ provide: NotificationsGateway, useClass: GraphqlNotificationsGateway },
|
||||
{ provide: TrackerRealtimeGateway, useClass: GraphqlRealtimeGateway },
|
||||
{ provide: SavedFiltersGateway, useClass: GraphqlSavedFiltersGateway },
|
||||
]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user