Frontend logic for filters

This commit is contained in:
Brieuc Dubois 2024-01-10 16:39:28 +01:00
parent bb479c45ef
commit c725d5154e
4 changed files with 225 additions and 6 deletions

View File

@ -0,0 +1,62 @@
import api, { processError } from '$lib/utils/api';
import status from '$lib/utils/status';
async function create(
viewId: number,
projectTagId: number,
filterType: number,
tagOptionId: number
): Promise<number | null> {
const response = await api.post(`/v1/filters`, {
view_id: viewId,
tag_id: projectTagId,
filter_type: filterType,
option_id: tagOptionId
});
if (response.status !== status.Created) {
processError(response, 'Failed to create filter');
return null;
}
return response.data.id;
}
async function update(
filterId: number,
viewId: number,
projectTagId: number,
filterType: number,
tagOptionId: number
): Promise<boolean> {
const response = await api.put(`/v1/filters/${filterId}`, {
view_id: viewId,
tag_id: projectTagId,
filter_type: filterType,
option_id: tagOptionId
});
if (response.status !== status.NoContent) {
processError(response, 'Failed to update filter');
return false;
}
return true;
}
async function delete_(filterId: number): Promise<boolean> {
const response = await api.delete(`/v1/filters/${filterId}`);
if (response.status !== status.NoContent) {
processError(response, 'Failed to delete filter');
return false;
}
return true;
}
export default {
create,
update,
delete: delete_
};

View File

@ -1,5 +1,5 @@
import Filter from '$lib/types/Filter';
import type Project from '$lib/types/Project';
import type View from '$lib/types/View';
import api, { processError } from '$lib/utils/api';
import status from '$lib/utils/status';
@ -53,8 +53,20 @@ async function delete_(viewId: number): Promise<boolean> {
return true;
}
async function getFilters(viewId: number): Promise<Filter[]> {
const response = await api.get(`/v1/views/${viewId}/filters`);
if (response.status !== status.OK) {
processError(response, 'Failed to get view filters');
return [];
}
return Filter.parseAll(response.data);
}
export default {
create,
update,
delete: delete_
delete: delete_,
getFilters
};

View File

@ -0,0 +1,110 @@
import { writable } from 'svelte/store';
import View from './View';
import ProjectTag from './ProjectTag';
import TagOption from './TagOption';
import { toastAlert } from '$lib/utils/toasts';
import filtersApi from '$lib/api/filtersApi';
export default class Filter {
private _id: number;
private _view: View;
private _projectTag: ProjectTag;
private _filterType: number;
private _tagOption: TagOption;
private constructor(
id: number,
view: View,
projectTag: ProjectTag,
filterType: number,
tagOption: TagOption
) {
this._id = id;
this._view = view;
this._projectTag = projectTag;
this._filterType = filterType;
this._tagOption = tagOption;
}
get id(): number {
return this._id;
}
get view(): View {
return this._view;
}
get projectTag(): ProjectTag {
return this._projectTag;
}
get filterType(): number {
return this._filterType;
}
get tagOption(): TagOption {
return this._tagOption;
}
static async create(
view: View,
projectTag: ProjectTag,
filterType: number,
tagOption: TagOption
): Promise<Filter | null> {
const id = await filtersApi.create(view.id, projectTag.id, filterType, tagOption.id);
if (!id) return null;
return new Filter(id, view, projectTag, filterType, tagOption);
}
async delete(): Promise<boolean> {
return await filtersApi.delete(this.id);
}
static parseAll(json: any): Filter[];
static parseAll(json: any, view: View | null): Filter[];
static parseAll(json: any[], view?: View | null): Filter[] {
if (!json) return [];
const filters: Filter[] = [];
for (const filter of json) {
const parsed = Filter.parse(filter, view);
if (parsed) filters.push(parsed);
}
return filters;
}
static parse(json: any): Filter | null;
static parse(json: any, view: View | null | undefined): Filter | null;
static parse(json: any, view?: View | null | undefined): Filter | null {
if (!json) {
toastAlert('Failed to parse filter: json is null');
return null;
}
if (!view) view = View.fromId(json.view_id);
if (!view) {
toastAlert('Failed to parse filter: view not found');
return null;
}
const projectTag = ProjectTag.fromId(json.tag_id);
if (!projectTag) {
toastAlert('Failed to parse filter: projectTag not found');
return null;
}
const tagOption = projectTag.options.find((option) => option.id === json.option_id);
if (!tagOption) {
toastAlert('Failed to parse filter: tagOption not found');
return null;
}
return new Filter(json.id, view, projectTag, json.filter_type, tagOption);
}
}

View File

@ -1,8 +1,10 @@
import { writable } from 'svelte/store';
import { get, writable } from 'svelte/store';
import Project from './Project';
import ProjectTag from './ProjectTag';
import viewsApi from '$lib/api/viewsApi';
import { toastAlert } from '$lib/utils/toasts';
import Filter from './Filter';
import type TagOption from './TagOption';
export const views = writable([] as View[]);
@ -14,6 +16,7 @@ export default class View {
private _title: string;
private _sortTag: ProjectTag | null;
private _sortDirection: number | null;
private _filters: Filter[];
private constructor(
id: number,
@ -22,7 +25,8 @@ export default class View {
secondaryTag: ProjectTag | null,
title: string,
sortTag: ProjectTag | null,
sortDirection: number | null
sortDirection: number | null,
filters: Filter[]
) {
this._id = id;
this._project = project;
@ -31,6 +35,7 @@ export default class View {
this._title = title;
this._sortTag = sortTag;
this._sortDirection = sortDirection;
this._filters = filters;
}
get id(): number {
@ -61,6 +66,16 @@ export default class View {
return this._sortDirection;
}
static fromId(id: number): View | null {
for (const view of get(views)) {
if (view.id === id) {
return view;
}
}
return null;
}
async setPrimaryTag(projectTag: ProjectTag): Promise<boolean> {
const response = await viewsApi.update(
this.id,
@ -103,7 +118,7 @@ export default class View {
if (!id) return null;
const view = new View(id, project, null, null, 'New view', null, null);
const view = new View(id, project, null, null, 'New view', null, null, []);
views.update((views) => [...views, view]);
@ -137,6 +152,23 @@ export default class View {
return true;
}
async addFilter(projectTag: ProjectTag, filterType: number, option: TagOption): Promise<boolean> {
const filter = await Filter.create(this, projectTag, filterType, option);
if (!filter) return false;
this._filters = [...this._filters, filter];
return true;
}
async removeFilter(filter: Filter): Promise<boolean> {
if (!(await filter.delete())) return false;
this._filters = this._filters.filter((f) => f.id !== filter.id);
return true;
}
static parse(json: any): View | null;
static parse(json: any, project: Project | null | undefined): View | null;
@ -163,9 +195,12 @@ export default class View {
secondaryTag,
json.title,
sortTag,
json.sort_direction
json.sort_direction,
[]
);
view._filters = Filter.parseAll(json.filters, view);
views.update((views) => {
if (!views.find((view) => view.id === json.id)) {
return [...views, view];