Frontend logic for filters
This commit is contained in:
parent
bb479c45ef
commit
c725d5154e
|
@ -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_
|
||||||
|
};
|
|
@ -1,5 +1,5 @@
|
||||||
|
import Filter from '$lib/types/Filter';
|
||||||
import type Project from '$lib/types/Project';
|
import type Project from '$lib/types/Project';
|
||||||
import type View from '$lib/types/View';
|
|
||||||
import api, { processError } from '$lib/utils/api';
|
import api, { processError } from '$lib/utils/api';
|
||||||
import status from '$lib/utils/status';
|
import status from '$lib/utils/status';
|
||||||
|
|
||||||
|
@ -53,8 +53,20 @@ async function delete_(viewId: number): Promise<boolean> {
|
||||||
return true;
|
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 {
|
export default {
|
||||||
create,
|
create,
|
||||||
update,
|
update,
|
||||||
delete: delete_
|
delete: delete_,
|
||||||
|
getFilters
|
||||||
};
|
};
|
||||||
|
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,8 +1,10 @@
|
||||||
import { writable } from 'svelte/store';
|
import { get, writable } from 'svelte/store';
|
||||||
import Project from './Project';
|
import Project from './Project';
|
||||||
import ProjectTag from './ProjectTag';
|
import ProjectTag from './ProjectTag';
|
||||||
import viewsApi from '$lib/api/viewsApi';
|
import viewsApi from '$lib/api/viewsApi';
|
||||||
import { toastAlert } from '$lib/utils/toasts';
|
import { toastAlert } from '$lib/utils/toasts';
|
||||||
|
import Filter from './Filter';
|
||||||
|
import type TagOption from './TagOption';
|
||||||
|
|
||||||
export const views = writable([] as View[]);
|
export const views = writable([] as View[]);
|
||||||
|
|
||||||
|
@ -14,6 +16,7 @@ export default class View {
|
||||||
private _title: string;
|
private _title: string;
|
||||||
private _sortTag: ProjectTag | null;
|
private _sortTag: ProjectTag | null;
|
||||||
private _sortDirection: number | null;
|
private _sortDirection: number | null;
|
||||||
|
private _filters: Filter[];
|
||||||
|
|
||||||
private constructor(
|
private constructor(
|
||||||
id: number,
|
id: number,
|
||||||
|
@ -22,7 +25,8 @@ export default class View {
|
||||||
secondaryTag: ProjectTag | null,
|
secondaryTag: ProjectTag | null,
|
||||||
title: string,
|
title: string,
|
||||||
sortTag: ProjectTag | null,
|
sortTag: ProjectTag | null,
|
||||||
sortDirection: number | null
|
sortDirection: number | null,
|
||||||
|
filters: Filter[]
|
||||||
) {
|
) {
|
||||||
this._id = id;
|
this._id = id;
|
||||||
this._project = project;
|
this._project = project;
|
||||||
|
@ -31,6 +35,7 @@ export default class View {
|
||||||
this._title = title;
|
this._title = title;
|
||||||
this._sortTag = sortTag;
|
this._sortTag = sortTag;
|
||||||
this._sortDirection = sortDirection;
|
this._sortDirection = sortDirection;
|
||||||
|
this._filters = filters;
|
||||||
}
|
}
|
||||||
|
|
||||||
get id(): number {
|
get id(): number {
|
||||||
|
@ -61,6 +66,16 @@ export default class View {
|
||||||
return this._sortDirection;
|
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> {
|
async setPrimaryTag(projectTag: ProjectTag): Promise<boolean> {
|
||||||
const response = await viewsApi.update(
|
const response = await viewsApi.update(
|
||||||
this.id,
|
this.id,
|
||||||
|
@ -103,7 +118,7 @@ export default class View {
|
||||||
|
|
||||||
if (!id) return null;
|
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]);
|
views.update((views) => [...views, view]);
|
||||||
|
|
||||||
|
@ -137,6 +152,23 @@ export default class View {
|
||||||
return true;
|
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): View | null;
|
||||||
static parse(json: any, project: Project | null | undefined): View | null;
|
static parse(json: any, project: Project | null | undefined): View | null;
|
||||||
|
|
||||||
|
@ -163,9 +195,12 @@ export default class View {
|
||||||
secondaryTag,
|
secondaryTag,
|
||||||
json.title,
|
json.title,
|
||||||
sortTag,
|
sortTag,
|
||||||
json.sort_direction
|
json.sort_direction,
|
||||||
|
[]
|
||||||
);
|
);
|
||||||
|
|
||||||
|
view._filters = Filter.parseAll(json.filters, view);
|
||||||
|
|
||||||
views.update((views) => {
|
views.update((views) => {
|
||||||
if (!views.find((view) => view.id === json.id)) {
|
if (!views.find((view) => view.id === json.id)) {
|
||||||
return [...views, view];
|
return [...views, view];
|
||||||
|
|
Loading…
Reference in New Issue