aboutsummaryrefslogtreecommitdiff
path: root/src/client/northstar/operations
diff options
context:
space:
mode:
Diffstat (limited to 'src/client/northstar/operations')
-rw-r--r--src/client/northstar/operations/BaseOperation.ts178
-rw-r--r--src/client/northstar/operations/HistogramOperation.ts124
2 files changed, 302 insertions, 0 deletions
diff --git a/src/client/northstar/operations/BaseOperation.ts b/src/client/northstar/operations/BaseOperation.ts
new file mode 100644
index 000000000..f545b2c58
--- /dev/null
+++ b/src/client/northstar/operations/BaseOperation.ts
@@ -0,0 +1,178 @@
+import { FilterModel } from '../core/filter/FilterModel'
+import { ErrorResult, Exception, OperationParameters, OperationReference, Result, ResultParameters } from '../model/idea/idea';
+import { action, computed, observable } from "mobx";
+import { Gateway } from '../manager/Gateway';
+
+export abstract class BaseOperation {
+ private _interactionTimeoutId: number = 0;
+ private static _currentOperations: Map<number, PollPromise> = new Map<number, PollPromise>();
+ //public InteractionTimeout: EventDelegate<InteractionTimeoutEventArgs> = new EventDelegate<InteractionTimeoutEventArgs>();
+
+ @observable public Error: string = "";
+ @observable public OverridingFilters: FilterModel[] = [];
+ //@observable
+ @observable public Result?: Result = undefined;
+ @observable public ComputationStarted: boolean = false;
+ public OperationReference?: OperationReference = undefined;
+
+ private static _nextId = 0;
+ public RequestSalt: string = "";
+ public Id: number;
+
+ constructor() {
+ this.Id = BaseOperation._nextId++;
+ }
+
+ @computed
+ public get FilterString(): string {
+
+ // let filterModels: FilterModel[] = [];
+ // return FilterModel.GetFilterModelsRecursive(this, new Set<GraphNode<BaseOperationViewModel, FilterLinkViewModel>>(), filterModels, true)
+ // if (this.OverridingFilters.length > 0) {
+ // return "(" + this.OverridingFilters.filter(fm => fm != null).map(fm => fm.ToPythonString()).join(" || ") + ")";
+ // }
+ // let rdg = MainManager.Instance.MainViewModel.FilterReverseDependencyGraph;
+ // let sliceModel = this.TypedViewModel.IncomingSliceModel;
+ // if (sliceModel != null && sliceModel.Source != null && instanceOfIBaseFilterProvider(sliceModel.Source) && rdg.has(sliceModel.Source)) {
+ // let filterModels = sliceModel.Source.FilterModels.map(f => f);
+ // return FilterModel.GetFilterModelsRecursive(rdg.get(sliceModel.Source), new Set<GraphNode<BaseOperationViewModel, FilterLinkViewModel>>(), filterModels, false);
+ // }
+
+ // if (rdg.has(this.TypedViewModel)) {
+ // let filterModels = [];
+ // return FilterModel.GetFilterModelsRecursive(rdg.get(this.TypedViewModel), new Set<GraphNode<BaseOperationViewModel, FilterLinkViewModel>>(), filterModels, true)
+ // }
+ return "";
+ }
+
+
+ @action
+ public SetResult(result: Result): void {
+ this.Result = result;
+ }
+
+ public async Update(): Promise<void> {
+
+ try {
+ if (BaseOperation._currentOperations.has(this.Id)) {
+ BaseOperation._currentOperations.get(this.Id)!.Cancel();
+ if (this.OperationReference) {
+ Gateway.Instance.PauseOperation(this.OperationReference.toJSON());
+ }
+ }
+
+ let operationParameters = this.CreateOperationParameters();
+ if (this.Result)
+ this.Result.progress = 0; // bcz: used to set Result to undefined, but that causes the display to blink
+ this.Error = "";
+ let salt = Math.random().toString();
+ this.RequestSalt = salt;
+
+ if (!operationParameters) {
+ this.ComputationStarted = false;
+ return;
+ }
+
+ this.ComputationStarted = true;
+ //let start = performance.now();
+ let promise = Gateway.Instance.StartOperation(operationParameters.toJSON());
+ promise.catch(err => {
+ action(() => {
+ this.Error = err;
+ console.error(err);
+ });
+ });
+ let operationReference = await promise;
+
+
+ if (operationReference) {
+ this.OperationReference = operationReference;
+
+ let resultParameters = new ResultParameters();
+ resultParameters.operationReference = operationReference;
+
+ let pollPromise = new PollPromise(salt, operationReference);
+ BaseOperation._currentOperations.set(this.Id, pollPromise);
+
+ pollPromise.Start(async () => {
+ let result = await Gateway.Instance.GetResult(resultParameters.toJSON());
+ if (result instanceof ErrorResult) {
+ throw new Error((result as ErrorResult).message);
+ }
+ if (this.RequestSalt == pollPromise.RequestSalt) {
+ if (result && (!this.Result || this.Result.progress != result.progress)) {
+ /*if (operationViewModel.Result !== null && operationViewModel.Result !== undefined) {
+ let t1 = performance.now();
+ console.log((t1 - start) + " milliseconds.");
+ start = performance.now();
+ }*/
+ this.SetResult(result);
+ }
+
+ if (!result || result.progress! < 1) {
+ return true;
+ }
+ }
+ return false;
+ }, 100).catch((err: Error) => action(() => {
+ this.Error = err.message;
+ console.error(err.message);
+ })()
+ );
+ }
+ }
+ catch (err) {
+ console.error(err as Exception);
+ // ErrorDialog.Instance.HandleError(err, operationViewModel);
+ }
+ }
+
+ public CreateOperationParameters(): OperationParameters | undefined { return undefined; }
+
+ private interactionTimeout() {
+ // clearTimeout(this._interactionTimeoutId);
+ // this.InteractionTimeout.Fire(new InteractionTimeoutEventArgs(this.TypedViewModel, InteractionTimeoutType.Timeout));
+ }
+}
+
+export class PollPromise {
+ public RequestSalt: string;
+ public OperationReference: OperationReference;
+
+ private _notCanceled: boolean = true;
+ private _poll: undefined | (() => Promise<boolean>);
+ private _delay: number = 0;
+
+ public constructor(requestKey: string, operationReference: OperationReference) {
+ this.RequestSalt = requestKey;
+ this.OperationReference = operationReference;
+ }
+
+ public Cancel(): void {
+ this._notCanceled = false;
+ }
+
+ public Start(poll: () => Promise<boolean>, delay: number): Promise<void> {
+ this._poll = poll;
+ this._delay = delay;
+ return this.pollRecursive();
+ }
+
+ private pollRecursive = (): Promise<void> => {
+ return Promise.resolve().then(this._poll).then((flag) => {
+ this._notCanceled && flag && new Promise((res) => (setTimeout(res, this._delay)))
+ .then(this.pollRecursive);
+ });
+ }
+}
+
+
+export class InteractionTimeoutEventArgs {
+ constructor(public Sender: object, public Type: InteractionTimeoutType) {
+ }
+}
+
+export enum InteractionTimeoutType {
+ Reset = 0,
+ Timeout = 1
+}
diff --git a/src/client/northstar/operations/HistogramOperation.ts b/src/client/northstar/operations/HistogramOperation.ts
new file mode 100644
index 000000000..e63de1632
--- /dev/null
+++ b/src/client/northstar/operations/HistogramOperation.ts
@@ -0,0 +1,124 @@
+import { action, computed, observable, trace } from "mobx";
+import { Document } from "../../../fields/Document";
+import { FieldWaiting } from "../../../fields/Field";
+import { KeyStore } from "../../../fields/KeyStore";
+import { CurrentUserUtils } from "../../../server/authentication/models/current_user_utils";
+import { ColumnAttributeModel } from "../core/attribute/AttributeModel";
+import { AttributeTransformationModel } from "../core/attribute/AttributeTransformationModel";
+import { CalculatedAttributeManager } from "../core/attribute/CalculatedAttributeModel";
+import { FilterModel } from "../core/filter/FilterModel";
+import { FilterOperand } from "../core/filter/FilterOperand";
+import { IBaseFilterConsumer } from "../core/filter/IBaseFilterConsumer";
+import { IBaseFilterProvider } from "../core/filter/IBaseFilterProvider";
+import { HistogramField } from "../dash-fields/HistogramField";
+import { SETTINGS_SAMPLE_SIZE, SETTINGS_X_BINS, SETTINGS_Y_BINS } from "../model/binRanges/VisualBinRangeHelper";
+import { AggregateFunction, AggregateParameters, Attribute, AverageAggregateParameters, Bin, DataType, DoubleValueAggregateResult, HistogramOperationParameters, HistogramResult, QuantitativeBinRange } from "../model/idea/idea";
+import { ModelHelpers } from "../model/ModelHelpers";
+import { ArrayUtil } from "../utils/ArrayUtil";
+import { BaseOperation } from "./BaseOperation";
+
+export class HistogramOperation extends BaseOperation implements IBaseFilterConsumer, IBaseFilterProvider {
+ public static Empty = new HistogramOperation("-empty schema-", new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())), new AttributeTransformationModel(new ColumnAttributeModel(new Attribute())));
+ @observable public FilterOperand: FilterOperand = FilterOperand.AND;
+ @observable public Links: Document[] = [];
+ @observable public BrushLinks: { l: Document, b: Document }[] = [];
+ @observable public BrushColors: number[] = [];
+ @observable public FilterModels: FilterModel[] = [];
+
+ @observable public Normalization: number = -1;
+ @observable public X: AttributeTransformationModel;
+ @observable public Y: AttributeTransformationModel;
+ @observable public V: AttributeTransformationModel;
+ @observable public SchemaName: string;
+ @observable public QRange: QuantitativeBinRange | undefined;
+ @computed public get Schema() { return CurrentUserUtils.GetNorthstarSchema(this.SchemaName); }
+
+ constructor(schemaName: string, x: AttributeTransformationModel, y: AttributeTransformationModel, v: AttributeTransformationModel, normalized?: number) {
+ super();
+ this.X = x;
+ this.Y = y;
+ this.V = v;
+ this.Normalization = normalized ? normalized : -1;
+ this.SchemaName = schemaName;
+ }
+
+ Equals(other: Object): boolean {
+ throw new Error("Method not implemented.");
+ }
+
+ @action
+ public AddFilterModels(filterModels: FilterModel[]): void {
+ filterModels.filter(f => f !== null).forEach(fm => this.FilterModels.push(fm));
+ }
+ @action
+ public RemoveFilterModels(filterModels: FilterModel[]): void {
+ ArrayUtil.RemoveMany(this.FilterModels, filterModels);
+ }
+
+ @computed
+ public get FilterString(): string {
+ let filterModels: FilterModel[] = [];
+ return FilterModel.GetFilterModelsRecursive(this, new Set<IBaseFilterProvider>(), filterModels, true)
+ }
+
+ @computed
+ public get BrushString(): string[] {
+ trace();
+ let brushes: string[] = [];
+ this.BrushLinks.map(brushLink => {
+ let brushHistogram = brushLink.b.GetT(KeyStore.Data, HistogramField);
+ if (brushHistogram && brushHistogram != FieldWaiting) {
+ let filterModels: FilterModel[] = [];
+ brushes.push(FilterModel.GetFilterModelsRecursive(brushHistogram.Data, new Set<IBaseFilterProvider>(), filterModels, false));
+ }
+ });
+ return brushes;
+ }
+
+ private getAggregateParameters(histoX: AttributeTransformationModel, histoY: AttributeTransformationModel, histoValue: AttributeTransformationModel) {
+ let allAttributes = new Array<AttributeTransformationModel>(histoX, histoY, histoValue);
+ allAttributes = ArrayUtil.Distinct(allAttributes.filter(a => a.AggregateFunction !== AggregateFunction.None));
+
+ let numericDataTypes = [DataType.Int, DataType.Double, DataType.Float];
+ let perBinAggregateParameters: AggregateParameters[] = ModelHelpers.GetAggregateParametersWithMargins(this.Schema!.distinctAttributeParameters, allAttributes);
+ let globalAggregateParameters: AggregateParameters[] = [];
+ [histoX, histoY]
+ .filter(a => a.AggregateFunction === AggregateFunction.None && ArrayUtil.Contains(numericDataTypes, a.AttributeModel.DataType))
+ .forEach(a => {
+ let avg = new AverageAggregateParameters();
+ avg.attributeParameters = ModelHelpers.GetAttributeParameters(a.AttributeModel);
+ globalAggregateParameters.push(avg);
+ });
+ return [perBinAggregateParameters, globalAggregateParameters];
+ }
+
+ public CreateOperationParameters(): HistogramOperationParameters | undefined {
+ if (this.X && this.Y && this.V) {
+ let [perBinAggregateParameters, globalAggregateParameters] = this.getAggregateParameters(this.X, this.Y, this.V);
+ return new HistogramOperationParameters({
+ enableBrushComputation: true,
+ adapterName: this.SchemaName,
+ filter: this.FilterString,
+ brushes: this.BrushString,
+ binningParameters: [ModelHelpers.GetBinningParameters(this.X, SETTINGS_X_BINS, this.QRange ? this.QRange.minValue : undefined, this.QRange ? this.QRange.maxValue : undefined),
+ ModelHelpers.GetBinningParameters(this.Y, SETTINGS_Y_BINS)],
+ sampleStreamBlockSize: SETTINGS_SAMPLE_SIZE,
+ perBinAggregateParameters: perBinAggregateParameters,
+ globalAggregateParameters: globalAggregateParameters,
+ sortPerBinAggregateParameter: undefined,
+ attributeCalculatedParameters: CalculatedAttributeManager
+ .AllCalculatedAttributes.map(a => ModelHelpers.GetAttributeParametersFromAttributeModel(a)),
+ degreeOfParallism: 1, // Settings.Instance.DegreeOfParallelism,
+ isCachable: false
+ });
+ }
+ }
+
+ @action
+ public async Update(): Promise<void> {
+ this.BrushColors = this.BrushLinks.map(e => e.l.GetNumber(KeyStore.BackgroundColor, 0));
+ return super.Update();
+ }
+}
+
+