import { ChangeDetectorRef, Component, OnDestroy } from "@angular/core";
import { merge, ReplaySubject, Subject } from "rxjs";
import * as uriTemplates_ from "uri-templates";
import { FormWidgetField } from "./advanced/search-advanced.component";
import { Attribute } from "../../components/edit-attribute/attribute";
import {
DeletionMode,
Scope,
} from "../../components/local-storage/local-storage-constants";
import {
LocalStorageEntry,
LocalStorageService,
} from "../../components/local-storage/local-storage.service";
import {
WidgetComponent,
WidgetConfiguration,
WidgetConfigure,
WidgetInput,
WidgetOutput,
} from "../widget.metadata";
import { NgUnsubscribe } from "../../ng-unsubscribe";
import { getOrDefault, WidgetConfig } from "../widget.configuration";
import { WidgetframeService } from "../widgetframe/widgetframe.service";
import { SelectFilterParams } from "../interfaces/list.interfaces";
import { AppContext } from "../../components/app-context/app.context";
import { filter, map, takeUntil } from "rxjs/operators";
import { TranslateService } from "@ngx-translate/core";
import { NodeLoader } from "../worklist-select/node-loader";
import { AppdataStore } from "../../components/appdata/appdata.store";
import { Selectors } from "../../components/app-context/api";
const uriTemplates = uriTemplates_;
export interface RatingSearchConfiguration {
title: string;
header: string;
infoTitle: string;
infoText: string;
wikiLink: string;
isCollapsible: boolean;
searchMode: string;
lookups: any;
fields: FormWidgetField[];
searchInputLabel: string;
directSearch: boolean;
localstoragePrefix: string;
staticFolders: any[];
attributeUrl: string;
advancedSearch: boolean;
selectFilterParams: SelectFilterParams;
searchFavorites: boolean;
searchTemplatesUri: string;
searchmodeSelect: boolean;
withHeader: boolean;
searchOnFieldsChanged: boolean;
selectors: {
nodeMenu?: Selectors;
nodeIcons?: Selectors;
// fallback, used, when the more specific selectors are not defined
menu: Selectors;
icons: Selectors;
};
}
export interface RatingSearchData {
searchMode?: string;
productNo?: string;
worklist?: string;
fields?: any;
attributes?: Attribute[];
parameter?: string;
list?: string;
}
const SEARCHMODE_STANDARD = "number";
const SEARCHMODE_LIST = "list";
const SEARCHMODE_WORKLIST = "worklist";
@WidgetComponent("nm-rating-search")
@Component({
selector: "nm-rating-search",
templateUrl: "./rating-search-widget.component.html",
styleUrls: ["./rating-search-widget.component.scss"],
})
export class RatingSearchWidgetComponent implements OnDestroy {
public searchmodeSelect = true;
public advancedSearch: boolean = false;
public searchFavorites: boolean = false;
public searchTemplatesUri: string;
public staticFolders: any[];
public searchmodes = [
{
identifier: SEARCHMODE_STANDARD,
label: "product-search",
},
{
identifier: SEARCHMODE_WORKLIST,
label: "worklist",
},
{
identifier: SEARCHMODE_LIST,
label: "list-search",
},
];
public searchInputLabel: string;
@WidgetConfiguration()
public configuration: WidgetConfig<RatingSearchConfiguration>;
@WidgetInput()
public locale = new Subject();
@WidgetInput()
public reloadLookups = new ReplaySubject<string[]>();
@WidgetOutput()
public bulkEdit = new Subject<any>();
@WidgetOutput("term")
public termOutput = new ReplaySubject(1);
@WidgetOutput()
public resetPressed = new Subject();
@WidgetOutput("attributes")
public attributesOutput = new Subject<Attribute[]>();
@WidgetOutput("data")
public dataOutput = new Subject();
//Same as data, but will only output when search is pressed so we know the data-set that was used to perform the last executed search
@WidgetOutput("searchingData")
public searchingDataOutput = new Subject();
private searchStringEntry: LocalStorageEntry;
private searchModeEntry: LocalStorageEntry;
private searchListEntry: LocalStorageEntry;
private unsubscribe = NgUnsubscribe.create();
public data: RatingSearchData = {
searchMode: SEARCHMODE_STANDARD,
};
public withHeader: boolean;
searchOnFieldsChanged: any;
public prefix: string;
public nodeMenuSelectors: Selectors;
public nodeIconsSelectors: Selectors;
private advancedData: any;
constructor(
private translateService: TranslateService,
private appDataStore: AppdataStore,
private localstorageService: LocalStorageService,
private widgetframeService: WidgetframeService,
private appContext: AppContext,
private cd: ChangeDetectorRef
) {}
@WidgetConfigure()
public configureWidget(config: WidgetConfig<RatingSearchConfiguration>) {
this.searchInputLabel = getOrDefault(
this.configuration.configuration.searchInputLabel,
"product.or.article.number"
);
this.advancedSearch = getOrDefault(
this.configuration.configuration.advancedSearch,
false
);
this.searchFavorites = getOrDefault(
this.configuration.configuration.searchFavorites,
false
);
this.searchTemplatesUri = getOrDefault(
this.configuration.configuration.searchTemplatesUri,
"/api/core/search-templates"
);
this.searchmodeSelect = getOrDefault(
this.configuration.configuration.searchmodeSelect,
true
);
let prefix = getOrDefault(
this.configuration.configuration.localstoragePrefix,
"rating-"
);
this.staticFolders = getOrDefault(
this.configuration.configuration.staticFolders,
NodeLoader.defaultStaticFolders()
);
this.searchStringEntry = this.localstorageService.getLocalStorageEntry(
prefix + "search",
Scope.GLOBAL,
DeletionMode.RESET
);
this.searchModeEntry = this.localstorageService.getLocalStorageEntry(
prefix + "searchmode",
Scope.GLOBAL,
DeletionMode.RESET
);
this.searchListEntry = this.localstorageService.getLocalStorageEntry(
prefix + "list-search",
Scope.GLOBAL,
DeletionMode.RESET
);
this.withHeader = getOrDefault(
this.configuration.configuration.withHeader,
true
);
this.searchOnFieldsChanged = getOrDefault(
this.configuration.configuration.searchOnFieldsChanged,
true
);
this.prefix = prefix;
const selectors: any = this.configuration.configuration.selectors || {};
this.nodeMenuSelectors = getOrDefault(
selectors.nodeMenu || selectors.menu,
{
target: ["nm-worklist-tree-selector", "nm-worklist-tree-selector-node"],
type: "menu",
}
);
this.nodeIconsSelectors = getOrDefault(
selectors.nodeIcons || selectors.icons,
{
target: ["nm-worklist-tree-selector", "nm-worklist-tree-selector-node"],
type: "icons",
}
);
if (this.searchModeEntry.exists()) {
this.data.searchMode = this.searchModeEntry.value;
}
if (this.searchStringEntry.exists()) {
this.data.productNo = this.searchStringEntry.value;
if (this.data.searchMode === SEARCHMODE_STANDARD && this.data.productNo) {
this.termOutput.next(this.data.productNo);
if (this.searchOnFieldsChanged) {
this.doSearch();
}
}
}
if (this.searchListEntry.exists()) {
this.data.list = this.searchListEntry.value;
}
this.initToolboxEdits();
this.dataOutput.next(this.data);
}
ngOnDestroy(): void {
this.unsubscribe.destroy();
}
doSearch() {
this.searchingDataOutput.next(this.data);
}
searchStringChange() {
this.searchStringEntry.value = this.data.productNo;
this.dataOutput.next(this.data);
this.termOutput.next(this.data.productNo);
}
searchListStringChange() {
this.searchListEntry.value = this.data.list;
this.dataOutput.next(this.data);
}
onModeChange() {
this.searchModeEntry.value = this.data.searchMode;
if (this.data.searchMode === SEARCHMODE_STANDARD) {
delete this.data.list;
delete this.data.parameter;
delete this.data.worklist;
} else if (
this.data.searchMode === SEARCHMODE_LIST ||
this.data.searchMode === SEARCHMODE_WORKLIST
) {
delete this.data.productNo;
if (this.data.searchMode === SEARCHMODE_LIST) {
delete this.data.worklist;
} else {
delete this.data.list;
}
}
this.dataOutput.next(this.data);
}
onWorklistSelect(worklist) {
if (worklist !== null && worklist.isNode) {
this.data.worklist = worklist.id;
}
this.dataOutput.next(this.data);
}
reset() {
this.data = {
searchMode: SEARCHMODE_STANDARD,
};
this.searchStringEntry.clear();
this.searchListEntry.clear();
this.resetPressed.next();
//this.dataOutput.next(this.data);
}
onAdvancedSearchChanged(data: any) {
if (this.advancedSearch) {
this.advancedData = data;
this.data.fields = Object.assign(
{},
this.data.fields || {},
this.advancedData
);
} else {
this.data.fields = {};
}
this.dataOutput.next(this.data);
if (!this.searchOnFieldsChanged) {
return;
}
this.doSearch();
}
onExpandToggle($event: boolean) {
this.advancedSearch = $event;
this.onAdvancedSearchChanged(this.advancedData);
}
onAttributesChanged(attributes: Attribute[]) {
this.attributesOutput.next(attributes);
this.data.attributes = attributes;
this.dataOutput.next(this.data);
}
private initToolboxEdits() {
const filterer = filter(
(data) => data && (data as any).length !== 0 && data[0].current
);
merge(
this.appContext.userContext.subscribe({
"@toolbox-active-context": "single",
}),
this.appContext.userContext.subscribe({
"@toolbox-active-context": "sequential",
})
)
.pipe(
filterer,
map((data) => data[0].current.identifier),
takeUntil(this.unsubscribe)
)
.subscribe((number) => {
this.data = {
searchMode: "number",
};
this.onModeChange();
this.data.productNo = number + "";
this.searchStringEntry.value = this.data.productNo;
this.resetPressed.next();
});
this.appContext.userContext
.subscribe({ "@toolbox-active-context": "bulk" })
.pipe(
filterer,
map((data) => data[0].current || []),
takeUntil(this.unsubscribe)
)
.subscribe((data) => {
if (this.searchmodeSelect) {
this.data.searchMode = "list";
this.reset();
this.data.list = data.join("\n");
this.searchListEntry.value = this.data.list;
this.onModeChange();
this.doSearch();
} else {
this.data.productNo = "";
this.searchStringEntry.clear();
this.bulkEdit.next(data);
}
});
}
}