Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: advanced search filter builder for HCMS #3604

Merged
merged 134 commits into from
Oct 25, 2023
Merged
Changes from 2 commits
Commits
Show all changes
134 commits
Select commit Hold shift + click to select a range
5f1bbec
wip: add advanced search drawer
leopuleo Aug 28, 2023
3c7d1e9
wip: improve filter manager
leopuleo Aug 29, 2023
93eeb78
wip: add input fields
leopuleo Aug 30, 2023
19e016a
wip: improve drawer ui
leopuleo Sep 1, 2023
1ec46a0
wip: improve Advanced Search ui
leopuleo Sep 1, 2023
57ab6da
wip: various fixes
leopuleo Sep 6, 2023
ce2a066
wip: various fixes
leopuleo Sep 7, 2023
52cf584
wip: add SearchConfiguration and presenter
leopuleo Sep 7, 2023
1843e83
wip: make it work with form
leopuleo Sep 7, 2023
945b0c7
wip: add presenter and controller
leopuleo Sep 11, 2023
5fd7ede
wip: add tests file
leopuleo Sep 11, 2023
5504c20
wip: simplify data management
Pavel910 Sep 12, 2023
84a5c30
Merge remote-tracking branch 'origin/leo/feat/advanced-search-filter'…
leopuleo Sep 12, 2023
b02b3fb
wip: refactor data flow and domain objects
Pavel910 Sep 12, 2023
e8bcafe
Merge remote-tracking branch 'origin/leo/feat/advanced-search-filter'…
leopuleo Sep 12, 2023
81bbb4a
chore: fix build
leopuleo Sep 12, 2023
8cd839f
Merge branch 'next' into leo/feat/advanced-search-filter
leopuleo Sep 15, 2023
3e876a8
wip: create Field class
leopuleo Sep 19, 2023
b079b7a
Merge branch 'next' into leo/feat/advanced-search-filter
leopuleo Sep 20, 2023
a5fe721
test: add QueryBuilderPresenter tests
leopuleo Sep 20, 2023
7327728
wip: various
leopuleo Sep 20, 2023
5c14a55
feat: return graphql query
leopuleo Sep 20, 2023
ed4c824
refactor: change Field definition and DTO mapper
leopuleo Sep 20, 2023
333d764
wip: add tests and file organisation
leopuleo Sep 21, 2023
d03bfe0
fix(form): check invalidFields prop regardless of the data prop
Pavel910 Sep 21, 2023
14ee0e1
test: add GraphQLInputMapper test
leopuleo Sep 22, 2023
db6d7a0
test(form): add Form component tests
Pavel910 Sep 22, 2023
bce6abc
feat: various UI
leopuleo Sep 22, 2023
fea9182
Merge remote-tracking branch 'origin/leo/feat/advanced-search-filter'…
leopuleo Sep 22, 2023
13f3590
chore: run eslint
leopuleo Sep 22, 2023
9677081
feat: add ACO filter private model
leopuleo Sep 26, 2023
28336f5
fix: fix DateWithoutTimezone value format
leopuleo Sep 26, 2023
274139b
fix: remove Observer from Drawer component
leopuleo Sep 26, 2023
851b7c7
fix: set presenter without useEffect
leopuleo Sep 26, 2023
9ec6a2e
fix: remove QueryBuilderViewModel class
leopuleo Sep 26, 2023
8339036
chore: rename TypeDTO into FieldType
leopuleo Sep 26, 2023
dd9cc4c
feat: move field definition to FieldsMapper
leopuleo Sep 26, 2023
c410c5a
refactor: filter model definition
leopuleo Sep 27, 2023
c9280e1
feat: add filter gql query and mutation
leopuleo Sep 27, 2023
9bc6e01
Merge branch 'leo/feat/advanced-search-filter' into leo/feat/advanced…
leopuleo Sep 27, 2023
c4ed22f
fix: viewModel assignment
leopuleo Sep 27, 2023
d8f5278
Merge branch 'leo/feat/advanced-search-filter' into leo/feat/advanced…
leopuleo Sep 27, 2023
c183ffa
test: fix presenter.getViewModel()
leopuleo Sep 27, 2023
467500d
Merge branch 'leo/feat/advanced-search-filter' into leo/feat/advanced…
leopuleo Sep 27, 2023
45fcb38
feat: add model field
leopuleo Sep 28, 2023
6f7052c
feat: add new JSON type
leopuleo Sep 28, 2023
32fb934
wip: add QueryManager component
leopuleo Sep 29, 2023
2170493
wip: connect QueryManager and QueryBuilder
leopuleo Oct 2, 2023
c3deb65
wip: add runInAction
leopuleo Oct 2, 2023
c25e621
wip: add todo
leopuleo Oct 2, 2023
89bc626
refactor: set gateway as repository dependency
leopuleo Oct 3, 2023
f6a5612
refactor: rename main components
leopuleo Oct 3, 2023
ca07d60
refactor: add presenter and repository to AdvancedSearch component
leopuleo Oct 3, 2023
d1eff04
feat: handle queryObject persist to database
leopuleo Oct 4, 2023
87fa064
test: fix QueryBuilderPresenter tests
leopuleo Oct 4, 2023
409e08f
test: mode test
leopuleo Oct 4, 2023
fcc3391
feat: add QuerySaver dialog validation messages
leopuleo Oct 4, 2023
3d90457
test: add QuerySaver dialog tests
leopuleo Oct 5, 2023
7018c45
feat: add load function
leopuleo Oct 6, 2023
aebcda4
fix: QueryManager dialog and tests
leopuleo Oct 6, 2023
b2d01b7
fix: import SelectedFilter.styled
leopuleo Oct 6, 2023
df4e7f0
refactor: rename Chip into Selected
leopuleo Oct 6, 2023
43aacbf
fix: move Save button to left
leopuleo Oct 6, 2023
292bd84
fix: rename default filter name
leopuleo Oct 6, 2023
19efcfd
refactor: MultipleValues renders select
leopuleo Oct 6, 2023
8eec311
fix: export selected filter component
leopuleo Oct 6, 2023
b7afa23
refactor: advancedsearch presenter
leopuleo Oct 6, 2023
f625222
chore: fix sort state types
leopuleo Oct 9, 2023
932d818
chore: main viewModel management
leopuleo Oct 9, 2023
e538d44
feat: style QueryBuilder
leopuleo Oct 10, 2023
e23b954
fix: various
leopuleo Oct 10, 2023
1ae7781
test: fix testMatch
leopuleo Oct 10, 2023
55a1be8
refactor: various UI fixes
leopuleo Oct 10, 2023
6bfa1c7
fix: update selected filter
leopuleo Oct 10, 2023
8fe45d6
fix: filter invalidFields + spcific vm
leopuleo Oct 10, 2023
843f0e8
feat: add Loading and Feedback
leopuleo Oct 11, 2023
5f32176
chore: remove debug
leopuleo Oct 11, 2023
edccf1b
fix: set storage id on filter creation
leopuleo Oct 11, 2023
630ef69
feat: add empty view
leopuleo Oct 11, 2023
1ec8c2a
feat: add filter details
leopuleo Oct 11, 2023
1789388
chore: various files moves
leopuleo Oct 11, 2023
2ba58ff
chore: various files moves
leopuleo Oct 11, 2023
f52d51d
fix: field change
leopuleo Oct 12, 2023
6609978
fix: remove Mode
leopuleo Oct 12, 2023
f038868
chore: add readonly
leopuleo Oct 12, 2023
cb2e26a
fix: queryBuilderDrawer object init
leopuleo Oct 12, 2023
41bb31d
feat: add validation error snackbar
leopuleo Oct 12, 2023
d503849
refactor: loading management
leopuleo Oct 12, 2023
86e2e92
test: add presenters test
leopuleo Oct 12, 2023
dea4e13
test: add empty state and error tests
leopuleo Oct 13, 2023
d81322e
feat: open all groups by default
leopuleo Oct 13, 2023
c2883e6
fix: make filters private inside repository
leopuleo Oct 13, 2023
3c37bb5
refactor: move loading into repository
leopuleo Oct 13, 2023
6296597
refactor: create new filter with id
leopuleo Oct 13, 2023
e11c4fe
refactor: create new Filter domain
leopuleo Oct 16, 2023
132cc25
refactor: change presenter methods
leopuleo Oct 16, 2023
f4ddc50
chore: add interfaces to presenters
leopuleo Oct 16, 2023
9db0438
chore: various
leopuleo Oct 16, 2023
af58ec1
feat: add rename menu action
leopuleo Oct 16, 2023
986a2bb
feat: add clone menu action
leopuleo Oct 16, 2023
ed5b03b
fix: filter validation
leopuleo Oct 16, 2023
f10bcf2
refactor: add Sorter
leopuleo Oct 17, 2023
e3b6be8
fix: manager height while loading
leopuleo Oct 17, 2023
b9df5c7
chore: remove docs
leopuleo Oct 17, 2023
0d961ee
chore: fix imports
leopuleo Oct 17, 2023
1b7dbb8
test: add filter id to tests
leopuleo Oct 17, 2023
d7e2570
test: add app-aco package test
leopuleo Oct 17, 2023
d771e97
test: fix filter hook tests
leopuleo Oct 17, 2023
af93d38
Merge branch 'next' into leo/feat/advanced-search-filter-be
leopuleo Oct 17, 2023
e6fe383
refactor: use AutoComplete to render Field select
leopuleo Oct 19, 2023
c6ff6f3
Merge remote-tracking branch 'origin/leo/feat/advanced-search-filter-…
leopuleo Oct 19, 2023
cf54c1a
refactor: change modelId to namespace
leopuleo Oct 23, 2023
3782c13
fix: unset filter when delete filter
leopuleo Oct 24, 2023
821344c
test: check isLoading status
leopuleo Oct 24, 2023
889cc7d
refactor: remove applyQueryObject
leopuleo Oct 24, 2023
2886e56
refactor: rename styles to styled
leopuleo Oct 24, 2023
9832964
refactor: rename FiltersGatewayInterface.ts
leopuleo Oct 24, 2023
afaab92
refactor: use filterCallback
leopuleo Oct 24, 2023
74468fb
refactor: remove dashes as private
leopuleo Oct 24, 2023
a55451a
chore: fix QueryManagerDialogProps name
leopuleo Oct 24, 2023
2eaf5b2
chore: fix QueryBuilderDrawerPresenter get vm type
leopuleo Oct 24, 2023
bc0ffbb
refactor: remove QueryObject definition
leopuleo Oct 24, 2023
015d266
fix: remove filter as dependency of QuerySaverDialog
leopuleo Oct 24, 2023
1e1faa1
fix: remove filter as dependency of QueryBuilderDrawerPresenter
leopuleo Oct 24, 2023
3aa5b05
fix: missing createdOn
leopuleo Oct 24, 2023
af74b41
fix: remove createdOn from Filter validation
leopuleo Oct 24, 2023
080ab77
refactor: remove namespace from Filter
leopuleo Oct 25, 2023
66fa30a
fix: should not be able to remove first filter and group
leopuleo Oct 25, 2023
e0d5556
refactor: move types next to gateway
leopuleo Oct 25, 2023
1ea618a
Merge branch 'next' into leo/feat/advanced-search-filter-be
leopuleo Oct 25, 2023
cb701e9
fix: headless cms import
leopuleo Oct 25, 2023
414b41f
feat: use object in filter definition
leopuleo Oct 25, 2023
21e4ff3
feat: remove revision from id
leopuleo Oct 25, 2023
2a48f1b
Merge branch 'next' into leo/feat/advanced-search-filter-be
leopuleo Oct 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Empty file.
Empty file.
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
// @ts-nocheck
export const BuilderCompositionRoot = (props) => {
const [repository] = useState(() => new BuilderRepository());
const [controller] = useState(() => new BuilderController(repository));
const [presenter] = useState(() => new BuilderPresenter(repository));

return <Builder {...props} controller={controller} presenter={presenter}/>
}
Empty file.
Empty file.
Empty file.
101 changes: 68 additions & 33 deletions packages/app-aco/src/components/AdvancedSearch/Drawer.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// @ts-nocheck
import React from "react";

import { ReactComponent as AddIcon } from "@material-design-icons/svg/round/add_circle_outline.svg";
import { ReactComponent as DeleteIcon } from "@material-design-icons/svg/round/delete.svg";
import { Bind, Form } from "@webiny/form";
@@ -13,13 +13,13 @@ import { useHotkeys } from "react-hotkeyz";

import { Footer } from "./Footer";
import { Header } from "./Header";
import { Filter } from "./Filter";
import { Filter as FilterComponent } from "./Filter";

import { CellInner, Content, DrawerContainer, GroupContainer } from "./styled";

import { Field, FilterOperation } from "./types";

import { Group, SearchConfiguration } from "./SearchConfiguration";
import { Group, Filter, SearchConfiguration } from "./SearchConfiguration";
import { SearchConfigurationController } from "./SearchConfigurationController";
import { SearchConfigurationPresenter } from "./SearchConfigurationPresenter";
import { Radio, RadioGroup } from "@webiny/ui/Radio";
@@ -40,14 +40,11 @@ interface FormProps {

export const Drawer: React.VFC<DrawerProps> = observer(
({ presenter, controller, open, onClose, fields, onSubmit }) => {
const { groups, operation, operations, toGraphql } = presenter.viewModel;
const { configuration, operations, toObject } = presenter.viewModel;

const onChange = (data: SearchConfiguration) => {
console.log("SearchConfiguration", data);

for (const group of data.groups) {
controller.updateGroup(group);
}
controller.updateConfiguration(data);
};

useHotkeys({
@@ -59,16 +56,55 @@ export const Drawer: React.VFC<DrawerProps> = observer(
});

const onFormSubmit = () => {
const output = toGraphql();
const output = toObject();
console.log("output", output);
onSubmit(output);
// onSubmit(output);
};

const addGroup = () => {
controller.updateConfiguration({
...configuration,
groups: [
...configuration.groups,
{
operation: FilterOperation.AND,
filters: [{ field: "", value: "", condition: "" }]
}
]
});
};

const addFilter = (group: Group) => {
const index = configuration.groups.findIndex(g => g.id === group.id);
if (index <= -1) {
return;
}

configuration.groups[index].filters.push({ field: "", value: "", condition: "" });

controller.updateConfiguration(configuration);
};

const deleteGroup = (groupToDelete: Group) => {
controller.updateConfiguration({
...configuration,
groups: configuration.groups.filter(group => groupToDelete.id !== group.id)
});
};

const deleteFilter = (group: Group, filter: Filter) => {
const groupIndex = configuration.groups.findIndex(g => g.id === group.id);
const newFilters = configuration.groups[groupIndex].filters.filter(f => f.id !== filter.id);
configuration.groups[groupIndex].filters = newFilters;

controller.updateConfiguration(configuration);
};

return (
<DrawerContainer modal open={open} onClose={onClose} dir="rtl">
<DrawerContent dir="ltr">
<Form<FormProps>
data={{ groups, operation }}
data={configuration}
onChange={data => onChange(data)}
onSubmit={onFormSubmit}
>
@@ -89,12 +125,9 @@ export const Drawer: React.VFC<DrawerProps> = observer(
key={option}
label={option}
value={getValue(option)}
onChange={() => {
onChange(option);
controller.setOperation(
option as FilterOperation
);
}}
onChange={onChange(
option
)}
/>
))}
</>
@@ -125,14 +158,9 @@ export const Drawer: React.VFC<DrawerProps> = observer(
value={getValue(
option
)}
onChange={() => {
onChange(
option
);
group.setOperation(
option as FilterOperation
);
}}
onChange={onChange(
option
)}
/>
)
)}
@@ -147,23 +175,28 @@ export const Drawer: React.VFC<DrawerProps> = observer(
<IconButton
label={"Delete group"}
icon={<DeleteIcon />}
onClick={() =>
controller.deleteGroup(group)
}
onClick={() => {
console.log(
"Delete group",
group
);
deleteGroup(group);
}}
/>
</CellInner>
</Cell>
</Grid>

{group.filters.map((filter, filterIndex) => (
<Filter
key={filter.id}
<FilterComponent
key={filterIndex}
groupIndex={groupIndex}
filterIndex={filterIndex}
filter={filter}
fields={fields}
onRemove={() => {
group.deleteFilter(filter);
console.log("Delete filter", filter);
deleteFilter(group, filter);
}}
/>
))}
@@ -178,7 +211,8 @@ export const Drawer: React.VFC<DrawerProps> = observer(
label={"Add field"}
icon={<AddIcon />}
onClick={() => {
group.addFilter();
console.log("Add filter");
addFilter(group);
}}
/>
</Tooltip>
@@ -199,7 +233,8 @@ export const Drawer: React.VFC<DrawerProps> = observer(
label={"Add group"}
icon={<AddIcon />}
onClick={() => {
controller.addGroup();
console.log("Add group");
addGroup();
}}
/>
</Tooltip>
6 changes: 1 addition & 5 deletions packages/app-aco/src/components/AdvancedSearch/Filter.tsx
Original file line number Diff line number Diff line change
@@ -186,10 +186,6 @@ export const Filter: React.VFC<FilterProps> = observer(

return (
<FilterWrapper>
<Bind
name={`groups.${groupIndex}.filters.${filterIndex}.id`}
defaultValue={filter.id}
></Bind>
<Grid>
<Cell span={4}>
<Bind
@@ -224,7 +220,7 @@ export const Filter: React.VFC<FilterProps> = observer(
</Cell>
<Cell span={1} align={"middle"}>
<CellInner align={"center"}>
<IconButton icon={<DeleteIcon />} onClick={() => onRemove(filter.id)} />
<IconButton icon={<DeleteIcon />} onClick={() => onRemove(filter)} />
</CellInner>
</Cell>
</Grid>
204 changes: 63 additions & 141 deletions packages/app-aco/src/components/AdvancedSearch/SearchConfiguration.ts
Original file line number Diff line number Diff line change
@@ -2,62 +2,59 @@ import { FilterOperation } from "~/components/AdvancedSearch/types";
import { generateId } from "@webiny/utils";
import { makeAutoObservable } from "mobx";

interface FilterInput {
field: string;
condition: string;
value: string;
}

interface GroupInput {
operation: FilterOperation;
filters: FilterInput[];
}

export interface SearchConfigurationDTO {
operation: FilterOperation;
groups: GroupInput[];
}

export class SearchConfiguration {
public readonly operations = FilterOperation;
private id = generateId();
private name = "Untitled";
private _operation = FilterOperation.AND;
private _groups = [new Group()];

constructor() {
makeAutoObservable(this);
}

// static createFrom(rawData) {
// const configuration = new SearchConfiguration();
//
// configuration.setOperation(rawData.operation);
//
// return configuration;
// }

validate() {
for (const group of this.groups) {
group.validate();
}
}

get operation() {
return this._operation;
}

setOperation(operation: FilterOperation) {
this._operation = operation;
}

get groups() {
return this._groups;
}

addGroup() {
this._groups = [...this.groups, new Group()];
public readonly operation: FilterOperation;
public readonly groups: Group[];

static createFrom(rawData: SearchConfigurationDTO) {
return new SearchConfiguration(
rawData.operation,
rawData.groups.map(groupDTO => {
return new Group(
groupDTO.operation,
groupDTO.filters.map(filterDTO => {
return new Filter(
filterDTO.field,
filterDTO.condition,
filterDTO.value
);
})
);
})
);
}

updateGroup(group: Group) {
const index = this.groups.findIndex(item => item.id === group.id);

if (index === -1) {
return;
}

this._groups = [...this.groups.slice(0, index), group, ...this.groups.slice(index + 1)];
static createEmpty() {
return new SearchConfiguration(FilterOperation.AND, [
new Group(FilterOperation.AND, [new Filter()])
]);
}

deleteGroup(group: Group) {
this._groups = this.groups.filter(item => item.id !== group.id);
private constructor(operation: FilterOperation, groups: Group[]) {
this.operation = operation;
this.groups = groups;
}

toGraphql() {
toObject() {
return {
[this.operation]: this.groups.map(group => {
return {
@@ -75,122 +72,47 @@ export class SearchConfiguration {

export class Group {
public readonly id = generateId();
private _operation = FilterOperation.AND;
private _filters = [new Filter()];
public readonly operation: FilterOperation;
public readonly filters: Filter[];

constructor() {
makeAutoObservable(this);
}

validate() {
//TODO: handle the last filter deletion
for (const filter of this._filters) {
filter.validate();
}
}

get filters() {
return this._filters;
}

addFilter() {
this._filters = [...this.filters, new Filter()];
}

deleteFilter(filter: Filter) {
this._filters = this.filters.filter(item => item.id !== filter.id);
}

updateFilter(filter: Filter) {
const index = this.filters.findIndex(item => item.id === filter.id);

if (index === -1) {
return;
}

this._filters = [...this.filters.slice(0, index), filter, ...this.filters.slice(index + 1)];
}

get operation() {
return this._operation;
}

setOperation(operation: FilterOperation) {
this._operation = operation;
constructor(operation: FilterOperation, filters: Filter[]) {
this.operation = operation;
this.filters = filters;
}
}

export class Filter {
public readonly id = generateId();
public field?: string = undefined;
public condition?: string = undefined;
public value?: string = undefined;

constructor() {
makeAutoObservable(this);
}
public readonly field?: string;
public readonly condition?: string;
public readonly value?: string;

validate() {
if (!this.field || !this.condition || !this.value) {
throw Error(`Field ${this.id} is not valid`);
}
constructor(field?: string, condition?: string, value?: string) {
this.field = field;
this.condition = condition;
this.value = value;
}
}

export interface ISearchConfigurationRepository {
getOperations(): string[];
getOperation(): string;
setOperation(operation: FilterOperation): void;
addGroup(): void;
getGroups(): Group[];
updateGroup(group: Group): void;
deleteGroup(group: Group): void;
toGraphql(): any;
validate(): void;
getSearchConfiguration(): SearchConfiguration;
setSearchConfiguration(configuration: SearchConfiguration): void;
}

class CurrentSearchConfigurationRepository {
private readonly searchConfiguration: SearchConfiguration;
private searchConfiguration: SearchConfiguration;

constructor() {
this.searchConfiguration = new SearchConfiguration();
this.searchConfiguration = SearchConfiguration.createEmpty();
makeAutoObservable(this);
}

getOperations() {
return Object.values(this.searchConfiguration.operations);
}

getOperation() {
return this.searchConfiguration.operation;
}

setOperation(operation: FilterOperation) {
return this.searchConfiguration.setOperation(operation);
}

addGroup() {
this.searchConfiguration.addGroup();
}

getGroups() {
return this.searchConfiguration.groups;
}

updateGroup(group: Group) {
this.searchConfiguration.updateGroup(group);
}

deleteGroup(group: Group) {
this.searchConfiguration.deleteGroup(group);
}

toGraphql() {
return this.searchConfiguration.toGraphql();
getSearchConfiguration() {
return this.searchConfiguration;
}

validate() {
this.searchConfiguration.validate();
setSearchConfiguration(configuration: SearchConfiguration) {
this.searchConfiguration = configuration;
}
}
export const currentSearchConfigurationRepository = new CurrentSearchConfigurationRepository();
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import { makeAutoObservable } from "mobx";

import { Group, ISearchConfigurationRepository } from "./SearchConfiguration";
import { FilterOperation } from "~/components/AdvancedSearch/types";
import {
ISearchConfigurationRepository,
SearchConfiguration,
SearchConfigurationDTO
} from "./SearchConfiguration";

export class SearchConfigurationController {
private readonly repository: ISearchConfigurationRepository;
@@ -11,19 +13,9 @@ export class SearchConfigurationController {
makeAutoObservable(this);
}

setOperation(operation: FilterOperation) {
this.repository.setOperation(operation);
}

addGroup() {
this.repository.addGroup();
}

updateGroup(group: Group) {
this.repository.updateGroup(group);
}
updateConfiguration(configuration: SearchConfigurationDTO) {
const config = SearchConfiguration.createFrom(configuration);

deleteGroup(group: Group) {
this.repository.deleteGroup(group);
this.repository.setSearchConfiguration(config);
}
}
Original file line number Diff line number Diff line change
@@ -1,35 +1,34 @@
import { makeAutoObservable } from "mobx";

import { Filter, ISearchConfigurationRepository } from "./SearchConfiguration";
import { FilterOperation } from "~/components/AdvancedSearch/types";
import { ISearchConfigurationRepository } from "./SearchConfiguration";

export class SearchConfigurationPresenter {
private readonly searchConfiguration: ISearchConfigurationRepository;
private readonly repository: ISearchConfigurationRepository;

constructor(repository: ISearchConfigurationRepository) {
this.searchConfiguration = repository;
this.repository = repository;
makeAutoObservable(this);
}

get viewModel() {
const configuration = this.repository.getSearchConfiguration();

return {
operations: this.searchConfiguration.getOperations(),
operation: this.searchConfiguration.getOperation(),
toGraphql: () => this.searchConfiguration.toGraphql(),
groups: this.searchConfiguration.getGroups().map(group => ({
id: group.id,
operation: group.operation,
setOperation: (operation: FilterOperation) => group.setOperation(operation),
addFilter: () => group.addFilter(),
deleteFilter: (filter: Filter) => group.deleteFilter(filter),
updateFilter: (filter: Filter) => group.updateFilter(filter),
filters: group.filters.map(filter => ({
id: filter.id,
field: filter.field,
value: filter.value,
condition: filter.condition
toObject: () => configuration.toObject(),
operations: Object.values(configuration.operations),
configuration: {
operation: configuration.operation,
groups: configuration.groups.map(group => ({
id: group.id,
operation: group.operation,
filters: group.filters.map(filter => ({
id: filter.id,
field: filter.field,
value: filter.value,
condition: filter.condition
}))
}))
}))
}
};
}
}