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:
@@ -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)
|
||||
}
|
||||
Reference in New Issue
Block a user