mirror of
https://github.com/fluxscape/fluxscape.git
synced 2026-01-11 23:02:55 +01:00
Compare commits
15 Commits
fix/close-
...
v1.2.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
307a13f7be | ||
|
|
4e96d23585 | ||
|
|
2fd4b67a08 | ||
|
|
50e266e3e4 | ||
|
|
7ca69b809a | ||
|
|
80c7c01805 | ||
|
|
fc89bd9ce1 | ||
|
|
2cfd36147a | ||
|
|
0e13a8b033 | ||
|
|
680bd58442 | ||
|
|
95db9f6528 | ||
|
|
6205d08451 | ||
|
|
14786b2144 | ||
|
|
e25155556f | ||
|
|
016837f466 |
2
package-lock.json
generated
2
package-lock.json
generated
@@ -48981,7 +48981,7 @@
|
|||||||
},
|
},
|
||||||
"packages/noodl-editor": {
|
"packages/noodl-editor": {
|
||||||
"name": "fluxscape-editor",
|
"name": "fluxscape-editor",
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@electron/remote": "^2.1.2",
|
"@electron/remote": "^2.1.2",
|
||||||
"@jaames/iro": "^5.5.2",
|
"@jaames/iro": "^5.5.2",
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
"description": "Node-Based App Builder for Scalability & Rapid Development, a fork of Noodl",
|
"description": "Node-Based App Builder for Scalability & Rapid Development, a fork of Noodl",
|
||||||
"author": "Fluxscape <contact@fluxscape.io>",
|
"author": "Fluxscape <contact@fluxscape.io>",
|
||||||
"homepage": "https://fluxscape.io",
|
"homepage": "https://fluxscape.io",
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"main": "src/main/main.js",
|
"main": "src/main/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "npx ts-node -P ./tsconfig.build.json ./scripts/build.ts",
|
"build": "npx ts-node -P ./tsconfig.build.json ./scripts/build.ts",
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import { EventDispatcher } from '../../shared/utils/EventDispatcher';
|
|||||||
import ProjectModules from '../../shared/utils/projectmodules';
|
import ProjectModules from '../../shared/utils/projectmodules';
|
||||||
import { NodeLibrary } from './models/nodelibrary';
|
import { NodeLibrary } from './models/nodelibrary';
|
||||||
import { ProjectModel } from './models/projectmodel';
|
import { ProjectModel } from './models/projectmodel';
|
||||||
import { WarningsModel } from './models/warningsmodel';
|
import { WarningRef, WarningsModel } from './models/warningsmodel';
|
||||||
import DebugInspector from './utils/debuginspector';
|
import DebugInspector from './utils/debuginspector';
|
||||||
import * as Exporter from './utils/exporter';
|
import * as Exporter from './utils/exporter';
|
||||||
|
|
||||||
@@ -112,7 +112,7 @@ export class ViewerConnection extends Model {
|
|||||||
} else if (request.cmd === 'showwarning' && request.type === 'viewer') {
|
} else if (request.cmd === 'showwarning' && request.type === 'viewer') {
|
||||||
const content = JSON.parse(request.content);
|
const content = JSON.parse(request.content);
|
||||||
if (ProjectModel.instance !== undefined) {
|
if (ProjectModel.instance !== undefined) {
|
||||||
const ref = {
|
const ref: WarningRef = {
|
||||||
component: ProjectModel.instance.getComponentWithName(content.componentName),
|
component: ProjectModel.instance.getComponentWithName(content.componentName),
|
||||||
node: ProjectModel.instance.findNodeWithId(content.nodeId),
|
node: ProjectModel.instance.findNodeWithId(content.nodeId),
|
||||||
key: content.key,
|
key: content.key,
|
||||||
@@ -124,7 +124,7 @@ export class ViewerConnection extends Model {
|
|||||||
}
|
}
|
||||||
} else if (request.cmd === 'clearwarnings' && request.type === 'viewer') {
|
} else if (request.cmd === 'clearwarnings' && request.type === 'viewer') {
|
||||||
const content = JSON.parse(request.content);
|
const content = JSON.parse(request.content);
|
||||||
const ref = {
|
const ref: WarningRef = {
|
||||||
component: ProjectModel.instance.getComponentWithName(content.componentName),
|
component: ProjectModel.instance.getComponentWithName(content.componentName),
|
||||||
node: ProjectModel.instance.findNodeWithId(content.nodeId)
|
node: ProjectModel.instance.findNodeWithId(content.nodeId)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,72 @@
|
|||||||
|
import { CloudService } from '@noodl-models/CloudServices';
|
||||||
|
import { ProjectModel } from '@noodl-models/projectmodel';
|
||||||
|
import { setCloudServices } from '@noodl-models/projectmodel.editor';
|
||||||
|
|
||||||
|
import { ToastLayer } from '../../../views/ToastLayer';
|
||||||
|
|
||||||
|
export type Command = {
|
||||||
|
kind: 'cloud-service';
|
||||||
|
use?: boolean;
|
||||||
|
|
||||||
|
name: string;
|
||||||
|
description?: string;
|
||||||
|
endpoint: string;
|
||||||
|
appId: string;
|
||||||
|
masterKey: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function execute(command: Command, _event: MessageEvent) {
|
||||||
|
const environment = await getOrCreate(command);
|
||||||
|
|
||||||
|
if (command.use) {
|
||||||
|
setCloudServices(ProjectModel.instance, environment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function getOrCreate(command: Command) {
|
||||||
|
const cloudServices = await CloudService.instance.backend.fetch();
|
||||||
|
const environment = cloudServices.find((c) => c.url === command.endpoint);
|
||||||
|
if (environment) {
|
||||||
|
if (
|
||||||
|
environment.name !== command.name ||
|
||||||
|
environment.description !== command.description ||
|
||||||
|
environment.appId !== command.appId ||
|
||||||
|
environment.masterKey !== command.masterKey
|
||||||
|
) {
|
||||||
|
await CloudService.instance.backend.update({
|
||||||
|
id: environment.id,
|
||||||
|
url: environment.url,
|
||||||
|
|
||||||
|
// Update the existing environment
|
||||||
|
name: command.name,
|
||||||
|
description: command.description,
|
||||||
|
appId: command.appId,
|
||||||
|
masterKey: command.masterKey
|
||||||
|
});
|
||||||
|
|
||||||
|
ToastLayer.showSuccess(`Cloud service "${command.name}" updated.`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: environment.id,
|
||||||
|
endpoint: environment.url,
|
||||||
|
appId: command.appId
|
||||||
|
};
|
||||||
|
} else {
|
||||||
|
const create = await CloudService.instance.backend.create({
|
||||||
|
name: command.name,
|
||||||
|
description: command.description,
|
||||||
|
appId: command.appId,
|
||||||
|
url: command.endpoint,
|
||||||
|
masterKey: command.masterKey
|
||||||
|
});
|
||||||
|
|
||||||
|
ToastLayer.showSuccess(`Cloud service "${command.name}" added successfully.`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
id: create.id,
|
||||||
|
endpoint: create.url,
|
||||||
|
appId: create.appId
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,11 +1,13 @@
|
|||||||
|
import * as CloudService from './commands/cloud-service';
|
||||||
import * as Notify from './commands/notify';
|
import * as Notify from './commands/notify';
|
||||||
import * as UploadAwsS3 from './commands/upload-aws-s3';
|
import * as UploadAwsS3 from './commands/upload-aws-s3';
|
||||||
|
|
||||||
type IFrameCommand = Notify.Command | UploadAwsS3.Command;
|
type IFrameCommand = Notify.Command | UploadAwsS3.Command | CloudService.Command;
|
||||||
|
|
||||||
const commands: Record<IFrameCommand['kind'], (command: IFrameCommand, event: MessageEvent) => Promise<void>> = {
|
const commands: Record<IFrameCommand['kind'], (command: IFrameCommand, event: MessageEvent) => Promise<void>> = {
|
||||||
notify: Notify.execute,
|
notify: Notify.execute,
|
||||||
'upload-aws-s3': UploadAwsS3.execute
|
'upload-aws-s3': UploadAwsS3.execute,
|
||||||
|
'cloud-service': CloudService.execute
|
||||||
};
|
};
|
||||||
|
|
||||||
export function commandEventHandler(event: MessageEvent) {
|
export function commandEventHandler(event: MessageEvent) {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { NodeGraphNode } from '@noodl-models/nodegraphmodel';
|
import { NodeGraphNode } from '@noodl-models/nodegraphmodel';
|
||||||
import { WarningsModel } from '@noodl-models/warningsmodel';
|
import { type Warning, WarningsModel } from '@noodl-models/warningsmodel';
|
||||||
|
|
||||||
import { ProjectModel } from '../projectmodel';
|
import { ProjectModel } from '../projectmodel';
|
||||||
import NodeTypeAdapter from './NodeTypeAdapter';
|
import NodeTypeAdapter from './NodeTypeAdapter';
|
||||||
@@ -103,7 +103,7 @@ export class RouterNavigateAdapter extends NodeTypeAdapter {
|
|||||||
|
|
||||||
const hasValidTarget = target && pageComponents.includes(target);
|
const hasValidTarget = target && pageComponents.includes(target);
|
||||||
|
|
||||||
const warning =
|
const warning: Warning =
|
||||||
hasValidTarget === false
|
hasValidTarget === false
|
||||||
? {
|
? {
|
||||||
message: "The target page doesn't belong to the target router",
|
message: "The target page doesn't belong to the target router",
|
||||||
|
|||||||
@@ -458,11 +458,11 @@ export class VariantModel extends Model {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
} else if (c.type === 'defaultStateTransition') {
|
} else if (c.type === 'defaultStateTransition') {
|
||||||
var state =
|
const state =
|
||||||
this.getType().visualStates !== undefined
|
this.getType().visualStates !== undefined
|
||||||
? this.getType().visualStates.find((s) => s.name === c.state)
|
? this.getType().visualStates.find((s) => s.name === c.state)
|
||||||
: undefined;
|
: undefined;
|
||||||
var stateName = state !== undefined ? state.label : c.state;
|
const stateName = state !== undefined ? state.label : c.state;
|
||||||
|
|
||||||
WarningsModel.instance.setWarning(
|
WarningsModel.instance.setWarning(
|
||||||
{ key: 'variant-dst-conflict-' + this.name + '-' + this.getType().fullName + '-' + c.state },
|
{ key: 'variant-dst-conflict-' + this.name + '-' + this.getType().fullName + '-' + c.state },
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ export class NodeGraphNode extends Model {
|
|||||||
metadata?: Record<string, any>;
|
metadata?: Record<string, any>;
|
||||||
|
|
||||||
private _variant: TSFixme;
|
private _variant: TSFixme;
|
||||||
private _label: TSFixme;
|
_label: TSFixme;
|
||||||
private _type: TSFixme;
|
private _type: TSFixme;
|
||||||
private _ports: TSFixme;
|
private _ports: TSFixme;
|
||||||
|
|
||||||
|
|||||||
@@ -1167,6 +1167,28 @@ EventDispatcher.instance.on(
|
|||||||
null
|
null
|
||||||
);
|
);
|
||||||
|
|
||||||
|
NodeLibrary.instance.on('libraryUpdated', () => {
|
||||||
|
const library = NodeLibrary.instance.library;
|
||||||
|
|
||||||
|
// Check if we have any data from the browser
|
||||||
|
if (Object.keys(library?.nodeIndex || {}).length > 0) {
|
||||||
|
const filepath = filesystem.join(ProjectModel.instance._retainedProjectDirectory, 'nodelibrary.json');
|
||||||
|
|
||||||
|
const compactLibrary = {
|
||||||
|
typecasts: library.typecasts,
|
||||||
|
dynamicports: library.dynamicports,
|
||||||
|
nodetypes: library.nodetypes,
|
||||||
|
// NOTE: Let's save the node index for now, most likely this is something we will just ignore.
|
||||||
|
nodeIndex: library.nodeIndex,
|
||||||
|
projectsettings: library.projectsettings
|
||||||
|
};
|
||||||
|
|
||||||
|
filesystem.writeJson(filepath, compactLibrary).then(() => {
|
||||||
|
console.log('saved nodelibrary.json');
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
function saveProject() {
|
function saveProject() {
|
||||||
if (!ProjectModel.instance) return;
|
if (!ProjectModel.instance) return;
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,42 @@
|
|||||||
import { ComponentModel } from '@noodl-models/componentmodel';
|
|
||||||
import { ProjectModel } from '@noodl-models/projectmodel';
|
|
||||||
import { toArray } from 'underscore';
|
import { toArray } from 'underscore';
|
||||||
|
|
||||||
|
import type { ComponentModel } from '@noodl-models/componentmodel';
|
||||||
|
|
||||||
import Model from '../../../shared/model';
|
import Model from '../../../shared/model';
|
||||||
|
import type { NodeGraphNode } from './nodegraphmodel';
|
||||||
import { NodeLibrary } from './nodelibrary';
|
import { NodeLibrary } from './nodelibrary';
|
||||||
|
|
||||||
|
export type WarningLabel = 'warning' | 'error';
|
||||||
|
|
||||||
|
export type Warning =
|
||||||
|
| {
|
||||||
|
type?: string;
|
||||||
|
level?: WarningLabel;
|
||||||
|
message: string;
|
||||||
|
showGlobally?: boolean;
|
||||||
|
}
|
||||||
|
| {
|
||||||
|
type: 'conflict' | 'conflict-source-code';
|
||||||
|
level?: WarningLabel;
|
||||||
|
message: string;
|
||||||
|
showGlobally?: boolean;
|
||||||
|
conflictMetadata: {
|
||||||
|
parameter: string;
|
||||||
|
ours: string;
|
||||||
|
theirs: string;
|
||||||
|
};
|
||||||
|
onDismiss: () => void;
|
||||||
|
onUseTheirs: () => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type WarningRef = {
|
||||||
|
key?: string;
|
||||||
|
component?: ComponentModel;
|
||||||
|
connection?: TSFixme;
|
||||||
|
node?: NodeGraphNode;
|
||||||
|
isFromViewer?: boolean;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The first level of the warnings object is component name
|
* The first level of the warnings object is component name
|
||||||
* Second is the connection / node identifier
|
* Second is the connection / node identifier
|
||||||
@@ -14,7 +47,7 @@ interface Warnings {
|
|||||||
[node_connection_id: string]: {
|
[node_connection_id: string]: {
|
||||||
[warningKey: string]: {
|
[warningKey: string]: {
|
||||||
ref: TSFixme;
|
ref: TSFixme;
|
||||||
warning: TSFixme;
|
warning: Warning;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -24,7 +57,7 @@ export class WarningsModel extends Model {
|
|||||||
public static instance = new WarningsModel();
|
public static instance = new WarningsModel();
|
||||||
|
|
||||||
private warnings: Warnings = {};
|
private warnings: Warnings = {};
|
||||||
private notifyChangedScheduled: boolean = false;
|
private notifyChangedScheduled = false;
|
||||||
|
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
@@ -35,10 +68,12 @@ export class WarningsModel extends Model {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public setWarning(ref, warning) {
|
public setWarning(ref: WarningRef, warning: Warning) {
|
||||||
var w = this.getWarningsForRef(ref, warning !== undefined);
|
const w = this.getWarningsForRef(ref, warning !== undefined);
|
||||||
if (!warning) {
|
if (!warning) {
|
||||||
if (w) delete w[ref.key];
|
if (w) {
|
||||||
|
delete w[ref.key];
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
warning.level = warning.level || 'warning';
|
warning.level = warning.level || 'warning';
|
||||||
w[ref.key] = { ref: ref, warning: warning };
|
w[ref.key] = { ref: ref, warning: warning };
|
||||||
@@ -47,31 +82,34 @@ export class WarningsModel extends Model {
|
|||||||
this.scheduleNotifyChanged();
|
this.scheduleNotifyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public clearWarningsForRef(ref) {
|
public clearWarningsForRef(ref: WarningRef) {
|
||||||
var w = this.getWarningsForRef(ref);
|
const w = this.getWarningsForRef(ref);
|
||||||
if (!w) return;
|
if (!w) return;
|
||||||
|
|
||||||
for (var i in w) delete w[i];
|
for (const i in w) {
|
||||||
|
delete w[i];
|
||||||
|
}
|
||||||
|
|
||||||
this.scheduleNotifyChanged();
|
this.scheduleNotifyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public clearAllWarningsForComponent(component) {
|
public clearAllWarningsForComponent(component: ComponentModel) {
|
||||||
const warnings = this.warnings[component.name];
|
const warnings = this.warnings[component.name];
|
||||||
|
|
||||||
if (!warnings) return;
|
if (!warnings) return;
|
||||||
|
|
||||||
for (let i in warnings) delete warnings[i];
|
for (const i in warnings) {
|
||||||
|
delete warnings[i];
|
||||||
|
}
|
||||||
|
|
||||||
this.scheduleNotifyChanged();
|
this.scheduleNotifyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public clearWarningsForRefMatching(matchCb) {
|
public clearWarningsForRefMatching(matchFn: (ref: TSFixme) => boolean) {
|
||||||
for (const cw of Object.values(this.warnings)) {
|
for (const cw of Object.values(this.warnings)) {
|
||||||
for (const ws of Object.values(cw)) {
|
for (const ws of Object.values(cw)) {
|
||||||
for (const key in ws) {
|
for (const key in ws) {
|
||||||
const w = ws[key];
|
const w = ws[key];
|
||||||
if (matchCb(w.ref)) {
|
if (matchFn(w.ref)) {
|
||||||
delete ws[key];
|
delete ws[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -87,15 +125,14 @@ export class WarningsModel extends Model {
|
|||||||
this.scheduleNotifyChanged();
|
this.scheduleNotifyChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
public getWarnings(ref) {
|
public getWarnings(ref: WarningRef) {
|
||||||
var w = this.getWarningsForRef(ref);
|
const w = this.getWarningsForRef(ref);
|
||||||
if (!w) return;
|
if (!w) return;
|
||||||
|
|
||||||
if (Object.keys(w).length === 0) return;
|
if (Object.keys(w).length === 0) return;
|
||||||
|
|
||||||
// Create short message for hover
|
// Create short message for hover
|
||||||
var messages = [];
|
const messages = [];
|
||||||
for (var k in w) {
|
for (const k in w) {
|
||||||
if (w[k].warning) messages.push(w[k].warning.message);
|
if (w[k].warning) messages.push(w[k].warning.message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -106,13 +143,13 @@ export class WarningsModel extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public forEachWarningInComponent(c, callback, args) {
|
public forEachWarningInComponent(c, callback, args) {
|
||||||
var cw = this.warnings[c ? c.name : '/'];
|
const cw = this.warnings[c ? c.name : '/'];
|
||||||
if (!cw) return;
|
if (!cw) return;
|
||||||
|
|
||||||
for (var ref in cw) {
|
for (const ref in cw) {
|
||||||
var ws = cw[ref];
|
const ws = cw[ref];
|
||||||
|
|
||||||
for (var w in ws) {
|
for (const w in ws) {
|
||||||
if (!args || !args.levels || args.levels.indexOf(ws[w].warning.level) !== -1) {
|
if (!args || !args.levels || args.levels.indexOf(ws[w].warning.level) !== -1) {
|
||||||
callback(ws[w]);
|
callback(ws[w]);
|
||||||
}
|
}
|
||||||
@@ -121,7 +158,7 @@ export class WarningsModel extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getAllWarningsForComponent(c, args) {
|
public getAllWarningsForComponent(c, args) {
|
||||||
var warnings = [];
|
const warnings = [];
|
||||||
this.forEachWarningInComponent(
|
this.forEachWarningInComponent(
|
||||||
c,
|
c,
|
||||||
function (warning) {
|
function (warning) {
|
||||||
@@ -152,15 +189,15 @@ export class WarningsModel extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public getTotalNumberOfWarnings(args) {
|
public getTotalNumberOfWarnings(args) {
|
||||||
var total = 0;
|
let total = 0;
|
||||||
for (var key in this.warnings) {
|
for (const key in this.warnings) {
|
||||||
total += this.getNumberOfWarningsForComponent({ name: key }, args);
|
total += this.getNumberOfWarningsForComponent({ name: key }, args);
|
||||||
}
|
}
|
||||||
return total;
|
return total;
|
||||||
}
|
}
|
||||||
|
|
||||||
public getTotalNumberOfWarningsMatching(matchCb) {
|
public getTotalNumberOfWarningsMatching(matchCb) {
|
||||||
var total = 0;
|
let total = 0;
|
||||||
this.forEachWarning((c, ref, key, warning) => {
|
this.forEachWarning((c, ref, key, warning) => {
|
||||||
if (matchCb(key, ref, warning)) total++;
|
if (matchCb(key, ref, warning)) total++;
|
||||||
});
|
});
|
||||||
@@ -168,16 +205,16 @@ export class WarningsModel extends Model {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public forEachWarning(callback: (c: string, ref, key, warning) => void) {
|
public forEachWarning(callback: (c: string, ref, key, warning) => void) {
|
||||||
var w = this.warnings;
|
const w = this.warnings;
|
||||||
for (const c in w) {
|
for (const c in w) {
|
||||||
// Loop over all components
|
// Loop over all components
|
||||||
var _w = w[c];
|
const _w = w[c];
|
||||||
for (const ref in _w) {
|
for (const ref in _w) {
|
||||||
// Loop over all refs
|
// Loop over all refs
|
||||||
var __w = _w[ref];
|
const __w = _w[ref];
|
||||||
for (const key in __w) {
|
for (const key in __w) {
|
||||||
// Loop over all keys
|
// Loop over all keys
|
||||||
var warning = __w[key];
|
const warning = __w[key];
|
||||||
|
|
||||||
callback(c, ref, key, warning);
|
callback(c, ref, key, warning);
|
||||||
}
|
}
|
||||||
@@ -195,12 +232,12 @@ export class WarningsModel extends Model {
|
|||||||
// node: nodeRef,
|
// node: nodeRef,
|
||||||
// connection: connectionRef,
|
// connection: connectionRef,
|
||||||
// key: key of warning as string}
|
// key: key of warning as string}
|
||||||
private getWarningsForRef(ref, create?) {
|
private getWarningsForRef(ref: WarningRef, create?) {
|
||||||
var componentName = ref.component ? ref.component.name : '/';
|
const componentName = ref.component ? ref.component.name : '/';
|
||||||
if (!this.warnings[componentName]) this.warnings[componentName] = {};
|
if (!this.warnings[componentName]) this.warnings[componentName] = {};
|
||||||
var cw = this.warnings[componentName];
|
const cw = this.warnings[componentName];
|
||||||
|
|
||||||
var key;
|
let key;
|
||||||
if (ref.node) key = 'node/' + ref.node.id;
|
if (ref.node) key = 'node/' + ref.node.id;
|
||||||
else if (ref.connection)
|
else if (ref.connection)
|
||||||
key =
|
key =
|
||||||
@@ -220,7 +257,8 @@ export class WarningsModel extends Model {
|
|||||||
|
|
||||||
/** Batch changed notifications so listeners don't get peppered */
|
/** Batch changed notifications so listeners don't get peppered */
|
||||||
private scheduleNotifyChanged() {
|
private scheduleNotifyChanged() {
|
||||||
var _this = this;
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
||||||
|
const _this = this;
|
||||||
|
|
||||||
if (this.notifyChangedScheduled) return;
|
if (this.notifyChangedScheduled) return;
|
||||||
this.notifyChangedScheduled = true;
|
this.notifyChangedScheduled = true;
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import { clearFolders } from './cleanup';
|
|||||||
|
|
||||||
export async function copyProjectFilesToFolder(projectPath: string, direntry: string): Promise<void> {
|
export async function copyProjectFilesToFolder(projectPath: string, direntry: string): Promise<void> {
|
||||||
// TODO: Load something like .noodlignore file list
|
// TODO: Load something like .noodlignore file list
|
||||||
const ignoreFiles = ['.DS_Store', '.gitignore', '.gitattributes', 'project.json', 'Dockerfile'];
|
const ignoreFiles = ['.DS_Store', '.gitignore', '.gitattributes', 'project.json', 'Dockerfile', 'nodelibrary.json'];
|
||||||
|
|
||||||
// Copy everything from the project folder
|
// Copy everything from the project folder
|
||||||
if (!projectPath) {
|
if (!projectPath) {
|
||||||
|
|||||||
@@ -1,22 +1,32 @@
|
|||||||
const { ProjectModel } = require('../models/projectmodel');
|
import type { ComponentModel } from '@noodl-models/componentmodel';
|
||||||
|
import type { NodeGraphNode } from '@noodl-models/nodegraphmodel';
|
||||||
|
|
||||||
function matchStrings(string1, string2) {
|
import { ProjectModel } from '../models/projectmodel';
|
||||||
|
|
||||||
|
export type SearchResult = {
|
||||||
|
componentTarget: ComponentModel;
|
||||||
|
nodeTarget?: NodeGraphNode;
|
||||||
|
type?: string;
|
||||||
|
userLabel?: string;
|
||||||
|
label: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
function matchStrings(string1: string, string2: string) {
|
||||||
return string1.toLowerCase().indexOf(string2.toLowerCase()) !== -1;
|
return string1.toLowerCase().indexOf(string2.toLowerCase()) !== -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchInNodeRecursive(node, searchTerms, component) {
|
function searchInNodeRecursive(node: NodeGraphNode, searchTerms: string, component: ComponentModel) {
|
||||||
var results = [];
|
let results: SearchResult[] = [];
|
||||||
var matchLabel = null;
|
let matchLabel: string | null = null;
|
||||||
var i = 0;
|
|
||||||
|
|
||||||
if (node._label !== undefined && matchStrings(node._label, searchTerms)) {
|
if (node._label !== undefined && matchStrings(node._label, searchTerms)) {
|
||||||
matchLabel = node.label;
|
matchLabel = node.label;
|
||||||
} else if (matchStrings(node.id, searchTerms)) {
|
} else if (node.id === searchTerms) {
|
||||||
matchLabel = node.id;
|
matchLabel = node.id;
|
||||||
} else if (matchStrings(node.type.displayName || node.type.name, searchTerms)) {
|
} else if (matchStrings(node.type.displayName || node.type.name, searchTerms)) {
|
||||||
matchLabel = node.label;
|
matchLabel = node.label;
|
||||||
} else {
|
} else {
|
||||||
let parameterNames = Object.keys(node.parameters);
|
const parameterNames = Object.keys(node.parameters);
|
||||||
for (const parameterNameIndex in parameterNames) {
|
for (const parameterNameIndex in parameterNames) {
|
||||||
const parameterName = parameterNames[parameterNameIndex];
|
const parameterName = parameterNames[parameterNameIndex];
|
||||||
|
|
||||||
@@ -25,7 +35,7 @@ function searchInNodeRecursive(node, searchTerms, component) {
|
|||||||
matchStrings(node.parameters[parameterName], searchTerms)
|
matchStrings(node.parameters[parameterName], searchTerms)
|
||||||
) {
|
) {
|
||||||
let displayLabel = parameterName;
|
let displayLabel = parameterName;
|
||||||
let connectionPort = node.type.ports?.find((port) => port.name === parameterName);
|
const connectionPort = node.type.ports?.find((port) => port.name === parameterName);
|
||||||
if (connectionPort) {
|
if (connectionPort) {
|
||||||
displayLabel = connectionPort.displayName;
|
displayLabel = connectionPort.displayName;
|
||||||
}
|
}
|
||||||
@@ -51,9 +61,9 @@ function searchInNodeRecursive(node, searchTerms, component) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (matchLabel === null) {
|
if (matchLabel === null) {
|
||||||
var ports = node.dynamicports;
|
const ports = node.dynamicports;
|
||||||
for (i = 0; i < ports.length; ++i) {
|
for (let i = 0; i < ports.length; ++i) {
|
||||||
var port = ports[i];
|
const port = ports[i];
|
||||||
if (matchStrings(port.name, searchTerms)) {
|
if (matchStrings(port.name, searchTerms)) {
|
||||||
matchLabel = node.label + ' : ' + port.name;
|
matchLabel = node.label + ' : ' + port.name;
|
||||||
break;
|
break;
|
||||||
@@ -62,9 +72,9 @@ function searchInNodeRecursive(node, searchTerms, component) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (matchLabel === null) {
|
if (matchLabel === null) {
|
||||||
var ports = node.ports;
|
const ports = node.ports;
|
||||||
for (i = 0; i < ports.length; ++i) {
|
for (let i = 0; i < ports.length; ++i) {
|
||||||
var port = ports[i];
|
const port = ports[i];
|
||||||
if (matchStrings(port.name, searchTerms)) {
|
if (matchStrings(port.name, searchTerms)) {
|
||||||
matchLabel = node.label + ' : ' + port.name;
|
matchLabel = node.label + ' : ' + port.name;
|
||||||
break;
|
break;
|
||||||
@@ -83,17 +93,17 @@ function searchInNodeRecursive(node, searchTerms, component) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i = 0; i < node.children.length; ++i) {
|
for (let i = 0; i < node.children.length; ++i) {
|
||||||
var child = node.children[i];
|
const child = node.children[i];
|
||||||
var childResults = searchInNodeRecursive(child, searchTerms, component);
|
const childResults = searchInNodeRecursive(child, searchTerms, component);
|
||||||
results = results.concat(childResults);
|
results = results.concat(childResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
}
|
}
|
||||||
|
|
||||||
function searchInComponent(component, searchTerms) {
|
function searchInComponent(component: ComponentModel, searchTerms: string) {
|
||||||
var results = [];
|
let results: SearchResult[] = [];
|
||||||
if (matchStrings(component.displayName, searchTerms)) {
|
if (matchStrings(component.displayName, searchTerms)) {
|
||||||
results.push({
|
results.push({
|
||||||
componentTarget: component,
|
componentTarget: component,
|
||||||
@@ -102,14 +112,14 @@ function searchInComponent(component, searchTerms) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for (var i = 0; i < component.graph.roots.length; ++i) {
|
for (let i = 0; i < component.graph.roots.length; ++i) {
|
||||||
var node = component.graph.roots[i];
|
const node = component.graph.roots[i];
|
||||||
var nodeResults = searchInNodeRecursive(node, searchTerms, component);
|
const nodeResults = searchInNodeRecursive(node, searchTerms, component);
|
||||||
results = results.concat(nodeResults);
|
results = results.concat(nodeResults);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (component.graph.commentsModel.comments) {
|
if (component.graph.commentsModel.comments) {
|
||||||
for (var i = 0; i < component.graph.commentsModel.comments.length; ++i) {
|
for (let i = 0; i < component.graph.commentsModel.comments.length; ++i) {
|
||||||
const comment = component.graph.commentsModel.comments[i];
|
const comment = component.graph.commentsModel.comments[i];
|
||||||
if (matchStrings(comment.text, searchTerms)) {
|
if (matchStrings(comment.text, searchTerms)) {
|
||||||
results.push({
|
results.push({
|
||||||
@@ -132,17 +142,17 @@ function searchInComponent(component, searchTerms) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function performSearch(searchTerms) {
|
export function performSearch(searchTerms: string) {
|
||||||
var results = [];
|
const results: ReturnType<typeof searchInComponent>[] = [];
|
||||||
var root = ProjectModel.instance.getRootNode();
|
const root = ProjectModel.instance.getRootNode();
|
||||||
if (root === undefined) return;
|
if (root === undefined) return;
|
||||||
|
|
||||||
var components = ProjectModel.instance.components;
|
const components = ProjectModel.instance.components;
|
||||||
|
|
||||||
for (var i = 0; i < components.length; ++i) {
|
for (let i = 0; i < components.length; ++i) {
|
||||||
var component = components[i];
|
const component = components[i];
|
||||||
|
|
||||||
var componentResults = searchInComponent(component, searchTerms);
|
const componentResults = searchInComponent(component, searchTerms);
|
||||||
if (componentResults !== null) {
|
if (componentResults !== null) {
|
||||||
//limit the label length (it can search in markdown, css, etc)
|
//limit the label length (it can search in markdown, css, etc)
|
||||||
for (const result of componentResults.results) {
|
for (const result of componentResults.results) {
|
||||||
@@ -211,7 +211,7 @@ export default function Clippy() {
|
|||||||
aiAssistantModel.removeActivity(id);
|
aiAssistantModel.removeActivity(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
const initialPlaceholder = isInputOpen ? 'Select (or type) a command below' : 'Ask Noodl AI';
|
const initialPlaceholder = isInputOpen ? 'Select (or type) a command below' : 'Ask FluxScape AI';
|
||||||
const isPromptInWrongOrder = Boolean(!selectedOption) && Boolean(secondInputValue);
|
const isPromptInWrongOrder = Boolean(!selectedOption) && Boolean(secondInputValue);
|
||||||
const isFullBeta = ['full-beta', 'enterprise'].includes(version);
|
const isFullBeta = ['full-beta', 'enterprise'].includes(version);
|
||||||
const isLimitedBeta = false; // TODO: version === 'limited-beta';
|
const isLimitedBeta = false; // TODO: version === 'limited-beta';
|
||||||
@@ -412,8 +412,8 @@ export default function Clippy() {
|
|||||||
<Text hasBottomSpacing>4. Click the "Verify API Key" button</Text>
|
<Text hasBottomSpacing>4. Click the "Verify API Key" button</Text>
|
||||||
|
|
||||||
<Text hasBottomSpacing>
|
<Text hasBottomSpacing>
|
||||||
If you dont have an API key with GPT-4 access, you can set the Noodl AI to use the Limited Beta in the
|
If you dont have an API key with GPT-4 access, you can set the FluxScape AI to use the Limited Beta in
|
||||||
editor settings.
|
the editor settings.
|
||||||
</Text>
|
</Text>
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
size={PrimaryButtonSize.Small}
|
size={PrimaryButtonSize.Small}
|
||||||
@@ -597,8 +597,8 @@ export default function Clippy() {
|
|||||||
</Label>
|
</Label>
|
||||||
|
|
||||||
<Text hasBottomSpacing size={TextSize.Medium}>
|
<Text hasBottomSpacing size={TextSize.Medium}>
|
||||||
You are running the limited beta of Noodl AI. If features fewer commands and a less capable AI. Get full
|
You are running the limited beta of FluxScape AI. If features fewer commands and a less capable AI. Get
|
||||||
beta access by bringing your own GPT-4 API key.
|
full beta access by bringing your own GPT-4 API key.
|
||||||
</Text>
|
</Text>
|
||||||
|
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { RefObject } from 'react';
|
import React, { RefObject } from 'react';
|
||||||
|
import { platform } from '@noodl/platform';
|
||||||
|
|
||||||
import { ProjectModel } from '@noodl-models/projectmodel';
|
import { ProjectModel } from '@noodl-models/projectmodel';
|
||||||
|
|
||||||
@@ -64,7 +65,9 @@ export function DeployPopup(props: DeployPopupProps) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function FluxscapeDeployTab() {
|
function FluxscapeDeployTab() {
|
||||||
const params = {};
|
const params = {
|
||||||
|
version: platform.getVersion()
|
||||||
|
};
|
||||||
|
|
||||||
const projectId = ProjectModel.instance.id;
|
const projectId = ProjectModel.instance.id;
|
||||||
if (projectId) {
|
if (projectId) {
|
||||||
|
|||||||
@@ -6,8 +6,6 @@ import { CloudService } from '@noodl-models/CloudServices';
|
|||||||
import { ActivityIndicator } from '@noodl-core-ui/components/common/ActivityIndicator';
|
import { ActivityIndicator } from '@noodl-core-ui/components/common/ActivityIndicator';
|
||||||
import { IconName, IconSize } from '@noodl-core-ui/components/common/Icon';
|
import { IconName, IconSize } from '@noodl-core-ui/components/common/Icon';
|
||||||
import { IconButton } from '@noodl-core-ui/components/inputs/IconButton';
|
import { IconButton } from '@noodl-core-ui/components/inputs/IconButton';
|
||||||
import { PrimaryButton } from '@noodl-core-ui/components/inputs/PrimaryButton';
|
|
||||||
import { Box } from '@noodl-core-ui/components/layout/Box';
|
|
||||||
import { ConditionalContainer } from '@noodl-core-ui/components/layout/ConditionalContainer';
|
import { ConditionalContainer } from '@noodl-core-ui/components/layout/ConditionalContainer';
|
||||||
import { Container } from '@noodl-core-ui/components/layout/Container';
|
import { Container } from '@noodl-core-ui/components/layout/Container';
|
||||||
import { VStack } from '@noodl-core-ui/components/layout/Stack';
|
import { VStack } from '@noodl-core-ui/components/layout/Stack';
|
||||||
|
|||||||
@@ -44,7 +44,7 @@ export function OpenAiSection() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<CollapsableSection title="Noodl AI (Beta)">
|
<CollapsableSection title="FluxScape AI (Beta)">
|
||||||
<Box hasXSpacing>
|
<Box hasXSpacing>
|
||||||
<VStack>
|
<VStack>
|
||||||
<PropertyPanelRow label="Version" isChanged={false}>
|
<PropertyPanelRow label="Version" isChanged={false}>
|
||||||
@@ -66,7 +66,7 @@ export function OpenAiSection() {
|
|||||||
|
|
||||||
{enabledState === 'disabled' && (
|
{enabledState === 'disabled' && (
|
||||||
<Box hasYSpacing>
|
<Box hasYSpacing>
|
||||||
<Text>Noodl AI is currently disabled.</Text>
|
<Text>FluxScape AI is currently disabled.</Text>
|
||||||
</Box>
|
</Box>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
@@ -157,16 +157,16 @@ export function OpenAiSection() {
|
|||||||
UNSAFE_style={{ borderRadius: '2px', background: 'var(--theme-color-bg-3)' }}
|
UNSAFE_style={{ borderRadius: '2px', background: 'var(--theme-color-bg-3)' }}
|
||||||
>
|
>
|
||||||
<Title size={TitleSize.Medium} hasBottomSpacing>
|
<Title size={TitleSize.Medium} hasBottomSpacing>
|
||||||
Noodl AI docs
|
FluxScape AI docs
|
||||||
</Title>
|
</Title>
|
||||||
<Text hasBottomSpacing>See setup instructions and guides for how to use Noodl AI on our docs.</Text>
|
<Text hasBottomSpacing>See setup instructions and guides for how to use FluxScape AI on our docs.</Text>
|
||||||
<PrimaryButton
|
<PrimaryButton
|
||||||
variant={PrimaryButtonVariant.Muted}
|
variant={PrimaryButtonVariant.Muted}
|
||||||
size={PrimaryButtonSize.Small}
|
size={PrimaryButtonSize.Small}
|
||||||
isGrowing
|
isGrowing
|
||||||
label="Open docs"
|
label="Open docs"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
platform.openExternal('https://docs.noodl.net/#/docs/getting-started/noodl-ai/');
|
platform.openExternal('https://docs.fluxscape.io/docs/getting-started/noodl-ai');
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|||||||
@@ -991,7 +991,7 @@ export class ComponentsPanelView extends View {
|
|||||||
|
|
||||||
// Find references
|
// Find references
|
||||||
const nodeReference = HACK_findNodeReference(scope.comp.name);
|
const nodeReference = HACK_findNodeReference(scope.comp.name);
|
||||||
const nodeReferencesText = `Used in ${nodeReference?.referenaces?.length || 0} places`;
|
const nodeReferencesText = `Used in ~${nodeReference?.referenaces?.length || 0} places`;
|
||||||
|
|
||||||
items = items.concat([
|
items = items.concat([
|
||||||
{
|
{
|
||||||
@@ -1122,7 +1122,7 @@ export class ComponentsPanelView extends View {
|
|||||||
if (scope.canBecomeRoot) {
|
if (scope.canBecomeRoot) {
|
||||||
// Find references
|
// Find references
|
||||||
const nodeReference = HACK_findNodeReference(scope.folder.component.name);
|
const nodeReference = HACK_findNodeReference(scope.folder.component.name);
|
||||||
const nodeReferencesText = `Used in ${nodeReference?.referenaces?.length || 0} places`;
|
const nodeReferencesText = `Used in ~${nodeReference?.referenaces?.length || 0} places`;
|
||||||
|
|
||||||
items = items.concat([{
|
items = items.concat([{
|
||||||
label: nodeReferencesText
|
label: nodeReferencesText
|
||||||
|
|||||||
@@ -182,7 +182,7 @@ function AiNodeChat({ context, onUpdated }: AiNodeChatProps) {
|
|||||||
footer={
|
footer={
|
||||||
version === 'disabled' ? (
|
version === 'disabled' ? (
|
||||||
<Center>
|
<Center>
|
||||||
<Text textType={TextType.Shy}>Noodl AI is currently disabled.</Text>
|
<Text textType={TextType.Shy}>FluxScape AI is currently disabled.</Text>
|
||||||
</Center>
|
</Center>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -5,10 +5,8 @@ import { useSidePanelKeyboardCommands } from '@noodl-hooks/useKeyboardCommands';
|
|||||||
import classNames from 'classnames';
|
import classNames from 'classnames';
|
||||||
import React, { useEffect, useRef, useState } from 'react';
|
import React, { useEffect, useRef, useState } from 'react';
|
||||||
|
|
||||||
import { ComponentModel } from '@noodl-models/componentmodel';
|
|
||||||
import { NodeGraphNode } from '@noodl-models/nodegraphmodel';
|
|
||||||
import { KeyCode, KeyMod } from '@noodl-utils/keyboard/KeyCode';
|
import { KeyCode, KeyMod } from '@noodl-utils/keyboard/KeyCode';
|
||||||
import { performSearch } from '@noodl-utils/universal-search';
|
import { performSearch, SearchResult } from '@noodl-utils/universal-search';
|
||||||
|
|
||||||
import { SearchInput } from '@noodl-core-ui/components/inputs/SearchInput';
|
import { SearchInput } from '@noodl-core-ui/components/inputs/SearchInput';
|
||||||
import { Container } from '@noodl-core-ui/components/layout/Container';
|
import { Container } from '@noodl-core-ui/components/layout/Container';
|
||||||
@@ -21,7 +19,7 @@ import css from './search-panel.module.scss';
|
|||||||
|
|
||||||
export function SearchPanel() {
|
export function SearchPanel() {
|
||||||
const [searchTerm, setSearchTerm] = useState('');
|
const [searchTerm, setSearchTerm] = useState('');
|
||||||
const [searchResults, setSearchResults] = useState([]);
|
const [searchResults, setSearchResults] = useState<ReturnType<typeof performSearch>>([]);
|
||||||
const inputRef = useRef<HTMLInputElement>(null);
|
const inputRef = useRef<HTMLInputElement>(null);
|
||||||
|
|
||||||
// TODO: Not same context
|
// TODO: Not same context
|
||||||
@@ -56,7 +54,7 @@ export function SearchPanel() {
|
|||||||
}
|
}
|
||||||
}, [debouncedSearchTerm]);
|
}, [debouncedSearchTerm]);
|
||||||
|
|
||||||
function onSearchItemClicked(searchResult: SearchResultItem) {
|
function onSearchItemClicked(searchResult: SearchResult) {
|
||||||
if (searchResult.type === 'Component') {
|
if (searchResult.type === 'Component') {
|
||||||
NodeGraphContextTmp.switchToComponent(searchResult.componentTarget, {
|
NodeGraphContextTmp.switchToComponent(searchResult.componentTarget, {
|
||||||
breadcrumbs: false,
|
breadcrumbs: false,
|
||||||
@@ -99,21 +97,9 @@ export function SearchPanel() {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
type SearchResultItem = {
|
|
||||||
componentTarget: ComponentModel;
|
|
||||||
label: string;
|
|
||||||
nodeTarget: NodeGraphNode;
|
|
||||||
type: string;
|
|
||||||
userLabel: string;
|
|
||||||
};
|
|
||||||
|
|
||||||
type SearchItemProps = {
|
type SearchItemProps = {
|
||||||
component: {
|
component: ReturnType<typeof performSearch>[0];
|
||||||
componentName: string;
|
onSearchItemClicked: (item: SearchResult) => void;
|
||||||
componentId: string;
|
|
||||||
results: SearchResultItem[];
|
|
||||||
};
|
|
||||||
onSearchItemClicked: (item: SearchResultItem) => void;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
function SearchItem({ component, onSearchItemClicked }: SearchItemProps) {
|
function SearchItem({ component, onSearchItemClicked }: SearchItemProps) {
|
||||||
@@ -130,11 +116,11 @@ function SearchItem({ component, onSearchItemClicked }: SearchItemProps) {
|
|||||||
<Section title={titleText} variant={SectionVariant.Panel}>
|
<Section title={titleText} variant={SectionVariant.Panel}>
|
||||||
{component.results.map((result, index) => (
|
{component.results.map((result, index) => (
|
||||||
<div
|
<div
|
||||||
|
key={index}
|
||||||
className={classNames(
|
className={classNames(
|
||||||
css.SearchResultItem
|
css.SearchResultItem
|
||||||
// lastActiveComponentId === result.componentTarget.id && css['is-active']
|
// lastActiveComponentId === result.componentTarget.id && css['is-active']
|
||||||
)}
|
)}
|
||||||
key={index}
|
|
||||||
onClick={() => onSearchItemClicked(result)}
|
onClick={() => onSearchItemClicked(result)}
|
||||||
>
|
>
|
||||||
<Label variant={TextType.Proud}>
|
<Label variant={TextType.Proud}>
|
||||||
|
|||||||
@@ -263,7 +263,9 @@ class CloudStore {
|
|||||||
* @param {{
|
* @param {{
|
||||||
* objectId: string;
|
* objectId: string;
|
||||||
* collection: string;
|
* collection: string;
|
||||||
|
* keys?: string[] | string;
|
||||||
* include?: string[] | string;
|
* include?: string[] | string;
|
||||||
|
* excludeKeys?: string[] | string;
|
||||||
* success: (data: unknown) => void;
|
* success: (data: unknown) => void;
|
||||||
* error: (error: unknown) => void;
|
* error: (error: unknown) => void;
|
||||||
* }} options
|
* }} options
|
||||||
@@ -275,6 +277,16 @@ class CloudStore {
|
|||||||
args.push('include=' + (Array.isArray(options.include) ? options.include.join(',') : options.include));
|
args.push('include=' + (Array.isArray(options.include) ? options.include.join(',') : options.include));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (options.keys) {
|
||||||
|
args.push('keys=' + (Array.isArray(options.keys) ? options.keys.join(',') : options.keys));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (options.excludeKeys) {
|
||||||
|
args.push(
|
||||||
|
'excludeKeys=' + (Array.isArray(options.excludeKeys) ? options.excludeKeys.join(',') : options.excludeKeys)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
this._makeRequest(
|
this._makeRequest(
|
||||||
'/classes/' + options.collection + '/' + options.objectId + (args.length > 0 ? '?' + args.join('&') : ''),
|
'/classes/' + options.collection + '/' + options.objectId + (args.length > 0 ? '?' + args.join('&') : ''),
|
||||||
{
|
{
|
||||||
@@ -459,8 +471,15 @@ class CloudStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function _isArrayOfObjects(a) {
|
function _isArrayOfObjects(a) {
|
||||||
if (!Array.isArray(a)) return false;
|
if (!Array.isArray(a)) {
|
||||||
for (var i = 0; i < a.length; i++) if (typeof a[i] !== 'object' || a[i] === null) return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (let i = 0; i < a.length; i++) {
|
||||||
|
if (typeof a[i] !== 'object' || a[i] === null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -532,54 +551,86 @@ function _serializeObject(data, collectionName, modelScope) {
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {unknown} data
|
||||||
|
* @param {string} type
|
||||||
|
* @param {*} modelScope
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
function _deserializeJSON(data, type, modelScope) {
|
function _deserializeJSON(data, type, modelScope) {
|
||||||
if (data === undefined) return;
|
if (data === undefined) return undefined;
|
||||||
if (data === null) return null;
|
if (data === null) return null;
|
||||||
|
|
||||||
if (type === 'Relation' && data.__type === 'Relation') {
|
if (type === 'Relation' && data.__type === 'Relation') {
|
||||||
return undefined; // Ignore relation fields
|
return undefined; // Ignore relation fields
|
||||||
} else if (type === 'Pointer' && data.__type === 'Pointer') {
|
}
|
||||||
|
|
||||||
// This is a pointer type, resolve into id
|
// This is a pointer type, resolve into id
|
||||||
|
if (type === 'Pointer' && data.__type === 'Pointer') {
|
||||||
return data.objectId;
|
return data.objectId;
|
||||||
} else if (type === 'Date' && data.__type === 'Date') {
|
}
|
||||||
|
|
||||||
|
if (type === 'Date' && data.__type === 'Date') {
|
||||||
return new Date(data.iso);
|
return new Date(data.iso);
|
||||||
} else if (type === 'Date' && typeof data === 'string') {
|
}
|
||||||
|
|
||||||
|
if (type === 'Date' && typeof data === 'string') {
|
||||||
return new Date(data);
|
return new Date(data);
|
||||||
} else if (type === 'File' && data.__type === 'File') {
|
}
|
||||||
|
|
||||||
|
if (type === 'File' && data.__type === 'File') {
|
||||||
return new CloudFile(data);
|
return new CloudFile(data);
|
||||||
} else if (type === 'GeoPoint' && data.__type === 'GeoPoint') {
|
}
|
||||||
|
|
||||||
|
if (type === 'GeoPoint' && data.__type === 'GeoPoint') {
|
||||||
return {
|
return {
|
||||||
latitude: data.latitude,
|
latitude: data.latitude,
|
||||||
longitude: data.longitude
|
longitude: data.longitude
|
||||||
};
|
};
|
||||||
} else if (_isArrayOfObjects(data)) {
|
}
|
||||||
var a = [];
|
|
||||||
for (var i = 0; i < data.length; i++) {
|
if (_isArrayOfObjects(data)) {
|
||||||
|
const a = [];
|
||||||
|
for (let i = 0; i < data.length; i++) {
|
||||||
a.push(_deserializeJSON(data[i], undefined, modelScope));
|
a.push(_deserializeJSON(data[i], undefined, modelScope));
|
||||||
}
|
}
|
||||||
var c = Collection.get();
|
const c = Collection.get();
|
||||||
c.set(a);
|
c.set(a);
|
||||||
return c;
|
return c;
|
||||||
} else if (Array.isArray(data)) return data;
|
}
|
||||||
|
|
||||||
|
// An array with mixed types
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
// This is an array with mixed data, just return it
|
// This is an array with mixed data, just return it
|
||||||
else if (data && data.__type === 'Object' && data.className !== undefined && data.objectId !== undefined) {
|
if (data && data.__type === 'Object' && data.className !== undefined && data.objectId !== undefined) {
|
||||||
const _data = Object.assign({}, data);
|
const _data = Object.assign({}, data);
|
||||||
delete _data.className;
|
delete _data.className;
|
||||||
delete _data.__type;
|
delete _data.__type;
|
||||||
return _fromJSON(_data, data.className, modelScope);
|
return _fromJSON(_data, data.className, modelScope);
|
||||||
} else if (typeof data === 'object' && data !== null) {
|
|
||||||
var m = (modelScope || Model).get();
|
|
||||||
for (var key in data) {
|
|
||||||
m.set(key, _deserializeJSON(data[key], undefined, modelScope));
|
|
||||||
}
|
}
|
||||||
return m;
|
|
||||||
} else return data;
|
if (typeof data === 'object' && data !== null) {
|
||||||
|
// Try to get the model by id, if it is defined, otherwise we create a new unique id.
|
||||||
|
const model = (modelScope || Model).get(data.id);
|
||||||
|
for (const key in data) {
|
||||||
|
const nestedValue = _deserializeJSON(data[key], undefined, modelScope);
|
||||||
|
model.set(key, nestedValue);
|
||||||
|
}
|
||||||
|
return model;
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
function _fromJSON(item, collectionName, modelScope) {
|
function _fromJSON(item, collectionName, modelScope) {
|
||||||
const modelStore = modelScope || Model;
|
const modelStore = modelScope || Model;
|
||||||
|
|
||||||
const model = modelStore.get(item.objectId);
|
// Try to get the model by the object id (record) or id, otherwise we create a new unique id.
|
||||||
|
const model = modelStore.get(item.objectId || item.id);
|
||||||
model._class = collectionName;
|
model._class = collectionName;
|
||||||
|
|
||||||
let schema = undefined;
|
let schema = undefined;
|
||||||
@@ -593,7 +644,8 @@ function _fromJSON(item, collectionName, modelScope) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const _type = schema && schema.properties && schema.properties[key] ? schema.properties[key].type : undefined;
|
const _type = schema && schema.properties && schema.properties[key] ? schema.properties[key].type : undefined;
|
||||||
model.set(key, _deserializeJSON(item[key], _type, modelScope));
|
const nestedValue = _deserializeJSON(item[key], _type, modelScope);
|
||||||
|
model.set(key, nestedValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
return model;
|
return model;
|
||||||
|
|||||||
@@ -112,7 +112,9 @@ function createRecordsAPI(modelScope) {
|
|||||||
* @param {string | { getId(): string; }} objectOrId
|
* @param {string | { getId(): string; }} objectOrId
|
||||||
* @param {{
|
* @param {{
|
||||||
* className: string;
|
* className: string;
|
||||||
|
* keys?: string[] | string;
|
||||||
* include?: string[] | string;
|
* include?: string[] | string;
|
||||||
|
* excludeKeys?: string[] | string;
|
||||||
* }} options
|
* }} options
|
||||||
* @returns {Promise<unknown>}
|
* @returns {Promise<unknown>}
|
||||||
*/
|
*/
|
||||||
@@ -129,7 +131,9 @@ function createRecordsAPI(modelScope) {
|
|||||||
cloudstore().fetch({
|
cloudstore().fetch({
|
||||||
collection: className,
|
collection: className,
|
||||||
objectId: objectOrId,
|
objectId: objectOrId,
|
||||||
include: options ? options.include : undefined,
|
keys: options?.keys,
|
||||||
|
include: options?.include,
|
||||||
|
excludeKeys: options?.excludeKeys,
|
||||||
success: function (response) {
|
success: function (response) {
|
||||||
const record = cloudstore()._fromJSON(response, className);
|
const record = cloudstore()._fromJSON(response, className);
|
||||||
resolve(record);
|
resolve(record);
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
"use strict";
|
'use strict';
|
||||||
|
|
||||||
var Model = require("./model");
|
var Model = require('./model');
|
||||||
|
|
||||||
// Get and set proxy
|
// Get and set proxy
|
||||||
/*const proxies = {}
|
/*const proxies = {}
|
||||||
@@ -221,48 +221,48 @@ Collection.prototype.toJSON = function() {
|
|||||||
}*/
|
}*/
|
||||||
|
|
||||||
// ----
|
// ----
|
||||||
Object.defineProperty(Array.prototype, "items", {
|
Object.defineProperty(Array.prototype, 'items', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
get() {
|
get() {
|
||||||
return this;
|
return this;
|
||||||
},
|
},
|
||||||
set(data) {
|
set(data) {
|
||||||
this.set(data);
|
this.set(data);
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
Object.defineProperty(Array.prototype, "each", {
|
Object.defineProperty(Array.prototype, 'each', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: Array.prototype.forEach,
|
value: Array.prototype.forEach
|
||||||
});
|
});
|
||||||
Object.defineProperty(Array.prototype, "size", {
|
Object.defineProperty(Array.prototype, 'size', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: function () {
|
value: function () {
|
||||||
return this.length;
|
return this.length;
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
Object.defineProperty(Array.prototype, "get", {
|
Object.defineProperty(Array.prototype, 'get', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: function (index) {
|
value: function (index) {
|
||||||
return this[index];
|
return this[index];
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
Object.defineProperty(Array.prototype, "getId", {
|
Object.defineProperty(Array.prototype, 'getId', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: function () {
|
value: function () {
|
||||||
return this._id;
|
return this._id;
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
Object.defineProperty(Array.prototype, "id", {
|
Object.defineProperty(Array.prototype, 'id', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
get() {
|
get() {
|
||||||
return this.getId();
|
return this.getId();
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
Object.defineProperty(Array.prototype, "set", {
|
Object.defineProperty(Array.prototype, 'set', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: function (src) {
|
value: function (src) {
|
||||||
@@ -323,10 +323,10 @@ Object.defineProperty(Array.prototype, "set", {
|
|||||||
for (i = aItems.length; i < bItems.length; i++) {
|
for (i = aItems.length; i < bItems.length; i++) {
|
||||||
this.add(bItems[i]);
|
this.add(bItems[i]);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(Array.prototype, "notify", {
|
Object.defineProperty(Array.prototype, 'notify', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: async function (event, args) {
|
value: async function (event, args) {
|
||||||
@@ -337,80 +337,80 @@ Object.defineProperty(Array.prototype, "notify", {
|
|||||||
for (var i = 0; i < l.length; i++) {
|
for (var i = 0; i < l.length; i++) {
|
||||||
await l[i](args);
|
await l[i](args);
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(Array.prototype, "contains", {
|
Object.defineProperty(Array.prototype, 'contains', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: function (item) {
|
value: function (item) {
|
||||||
return this.indexOf(item) !== -1;
|
return this.indexOf(item) !== -1;
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(Array.prototype, "add", {
|
Object.defineProperty(Array.prototype, 'add', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: async function (item) {
|
value: async function (item) {
|
||||||
if (this.contains(item)) return; // Already contains item
|
if (this.contains(item)) return; // Already contains item
|
||||||
|
|
||||||
this.items.push(item);
|
this.items.push(item);
|
||||||
await this.notify("add", { item: item, index: this.items.length - 1 });
|
await this.notify('add', { item: item, index: this.items.length - 1 });
|
||||||
await this.notify("change");
|
await this.notify('change');
|
||||||
await item.notify("add", { collection: this });
|
await item.notify('add', { collection: this });
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(Array.prototype, "remove", {
|
Object.defineProperty(Array.prototype, 'remove', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: function (item) {
|
value: function (item) {
|
||||||
var idx = this.items.indexOf(item);
|
var idx = this.items.indexOf(item);
|
||||||
if (idx !== -1) this.removeAtIndex(idx);
|
if (idx !== -1) this.removeAtIndex(idx);
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(Array.prototype, "addAtIndex", {
|
Object.defineProperty(Array.prototype, 'addAtIndex', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: async function (item, index) {
|
value: async function (item, index) {
|
||||||
if (this.contains(item)) return; // Already contains item
|
if (this.contains(item)) return; // Already contains item
|
||||||
|
|
||||||
this.items.splice(index, 0, item);
|
this.items.splice(index, 0, item);
|
||||||
await this.notify("add", { item: item, index: index });
|
await this.notify('add', { item: item, index: index });
|
||||||
await this.notify("change");
|
await this.notify('change');
|
||||||
await item.notify("add", { collection: this, index: index });
|
await item.notify('add', { collection: this, index: index });
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(Array.prototype, "removeAtIndex", {
|
Object.defineProperty(Array.prototype, 'removeAtIndex', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: async function (idx) {
|
value: async function (idx) {
|
||||||
var item = this.items[idx];
|
var item = this.items[idx];
|
||||||
this.items.splice(idx, 1);
|
this.items.splice(idx, 1);
|
||||||
await this.notify("remove", { item: item, index: idx });
|
await this.notify('remove', { item: item, index: idx });
|
||||||
await this.notify("change");
|
await this.notify('change');
|
||||||
await item.notify("remove", { collection: this });
|
await item.notify('remove', { collection: this });
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(Array.prototype, "on", {
|
Object.defineProperty(Array.prototype, 'on', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: function (event, listener) {
|
value: function (event, listener) {
|
||||||
if (!this._listeners)
|
if (!this._listeners)
|
||||||
Object.defineProperty(this, "_listeners", {
|
Object.defineProperty(this, '_listeners', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: {},
|
value: {}
|
||||||
});
|
});
|
||||||
if (!this._listeners[event]) this._listeners[event] = [];
|
if (!this._listeners[event]) this._listeners[event] = [];
|
||||||
this._listeners[event].push(listener);
|
this._listeners[event].push(listener);
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
Object.defineProperty(Array.prototype, "off", {
|
Object.defineProperty(Array.prototype, 'off', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: function (event, listener) {
|
value: function (event, listener) {
|
||||||
@@ -418,20 +418,20 @@ Object.defineProperty(Array.prototype, "off", {
|
|||||||
if (!this._listeners[event]) return;
|
if (!this._listeners[event]) return;
|
||||||
var idx = this._listeners[event].indexOf(listener);
|
var idx = this._listeners[event].indexOf(listener);
|
||||||
if (idx !== -1) this._listeners[event].splice(idx, 1);
|
if (idx !== -1) this._listeners[event].splice(idx, 1);
|
||||||
},
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
class Collection extends Array {}
|
class Collection extends Array {}
|
||||||
|
|
||||||
var collections = (Collection._collections = {});
|
const collections = (Collection._collections = {});
|
||||||
|
|
||||||
Collection.create = function (items) {
|
Collection.create = function (items) {
|
||||||
const name = Model.guid();
|
const name = Model.guid();
|
||||||
collections[name] = new Collection();
|
collections[name] = new Collection();
|
||||||
Object.defineProperty(collections[name], "_id", {
|
Object.defineProperty(collections[name], '_id', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: name,
|
value: name
|
||||||
});
|
});
|
||||||
if (items) {
|
if (items) {
|
||||||
collections[name].set(items);
|
collections[name].set(items);
|
||||||
@@ -439,14 +439,18 @@ Collection.create = function (items) {
|
|||||||
return collections[name];
|
return collections[name];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name
|
||||||
|
* @returns {Collection}
|
||||||
|
*/
|
||||||
Collection.get = function (name) {
|
Collection.get = function (name) {
|
||||||
if (name === undefined) name = Model.guid();
|
if (name === undefined) name = Model.guid();
|
||||||
if (!collections[name]) {
|
if (!collections[name]) {
|
||||||
collections[name] = new Collection();
|
collections[name] = new Collection();
|
||||||
Object.defineProperty(collections[name], "_id", {
|
Object.defineProperty(collections[name], '_id', {
|
||||||
enumerable: false,
|
enumerable: false,
|
||||||
writable: false,
|
writable: false,
|
||||||
value: name,
|
value: name
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -35,6 +35,11 @@ const _modelProxyHandler = {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @param {*} id
|
||||||
|
* @returns {Model}
|
||||||
|
*/
|
||||||
Model.get = function (id) {
|
Model.get = function (id) {
|
||||||
if (id === undefined) id = Model.guid();
|
if (id === undefined) id = Model.guid();
|
||||||
if (!models[id]) {
|
if (!models[id]) {
|
||||||
@@ -122,13 +127,22 @@ Model.prototype.fill = function (value = null) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name
|
||||||
|
* @param {unknown} value
|
||||||
|
* @param {{
|
||||||
|
* resolve?: boolean;
|
||||||
|
* forceChange?: boolean;
|
||||||
|
* silent?: boolean;
|
||||||
|
* }} args
|
||||||
|
*/
|
||||||
Model.prototype.set = function (name, value, args) {
|
Model.prototype.set = function (name, value, args) {
|
||||||
if (args && args.resolve && name.indexOf('.') !== -1) {
|
if (args && args.resolve && name.indexOf('.') !== -1) {
|
||||||
// We should resolve path references
|
// We should resolve path references
|
||||||
var path = name.split('.');
|
const path = name.split('.');
|
||||||
var model = this;
|
let model = this;
|
||||||
for (var i = 0; i < path.length - 1; i++) {
|
for (let i = 0; i < path.length - 1; i++) {
|
||||||
var v = model.get(path[i]);
|
const v = model.get(path[i]);
|
||||||
if (Model.instanceOf(v)) model = v;
|
if (Model.instanceOf(v)) model = v;
|
||||||
else return; // Path resolve failed
|
else return; // Path resolve failed
|
||||||
}
|
}
|
||||||
@@ -138,24 +152,35 @@ Model.prototype.set = function (name, value, args) {
|
|||||||
|
|
||||||
const forceChange = args && args.forceChange;
|
const forceChange = args && args.forceChange;
|
||||||
|
|
||||||
var oldValue = this.data[name];
|
const oldValue = this.data[name];
|
||||||
this.data[name] = value;
|
this.data[name] = value;
|
||||||
(forceChange || oldValue !== value) &&
|
|
||||||
(!args || !args.silent) &&
|
if ((forceChange || oldValue !== value) && (!args || !args.silent)) {
|
||||||
this.notify('change', { name: name, value: value, old: oldValue });
|
this.notify('change', { name: name, value: value, old: oldValue });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
Model.prototype.getId = function () {
|
Model.prototype.getId = function () {
|
||||||
return this.id;
|
return this.id;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} name
|
||||||
|
* @param {{
|
||||||
|
* resolve?: boolean;
|
||||||
|
* }} args
|
||||||
|
* @returns {unknown}
|
||||||
|
*/
|
||||||
Model.prototype.get = function (name, args) {
|
Model.prototype.get = function (name, args) {
|
||||||
if (args && args.resolve && name.indexOf('.') !== -1) {
|
if (args && args.resolve && name.indexOf('.') !== -1) {
|
||||||
// We should resolve path references
|
// We should resolve path references
|
||||||
var path = name.split('.');
|
const path = name.split('.');
|
||||||
var model = this;
|
let model = this;
|
||||||
for (var i = 0; i < path.length - 1; i++) {
|
for (let i = 0; i < path.length - 1; i++) {
|
||||||
var v = model.get(path[i]);
|
const v = model.get(path[i]);
|
||||||
if (Model.instanceOf(v)) model = v;
|
if (Model.instanceOf(v)) model = v;
|
||||||
else return; // Path resolve failed
|
else return; // Path resolve failed
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -230,7 +230,7 @@ NodeContext.prototype.deregisterComponentModel = function (componentModel) {
|
|||||||
|
|
||||||
NodeContext.prototype.fetchComponentBundle = async function (name) {
|
NodeContext.prototype.fetchComponentBundle = async function (name) {
|
||||||
const fetchBundle = async (name) => {
|
const fetchBundle = async (name) => {
|
||||||
let baseUrl = Noodl.Env["BaseUrl"] || '/';
|
let baseUrl = Noodl.Env['BaseUrl'] || '/';
|
||||||
let bundleUrl = `${baseUrl}noodl_bundles/${name}.json`;
|
let bundleUrl = `${baseUrl}noodl_bundles/${name}.json`;
|
||||||
|
|
||||||
const response = await fetch(bundleUrl);
|
const response = await fetch(bundleUrl);
|
||||||
@@ -455,6 +455,15 @@ NodeContext.prototype.setPopupCallbacks = function ({ onShow, onClose }) {
|
|||||||
this.onClosePopup = onClose;
|
this.onClosePopup = onClose;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} popupComponent
|
||||||
|
* @param {Record<string, unknown>} params
|
||||||
|
* @param {{
|
||||||
|
* senderNode?: unknown;
|
||||||
|
* onClosePopup?: (action?: string, results: object) => void;
|
||||||
|
* }} args
|
||||||
|
* @returns
|
||||||
|
*/
|
||||||
NodeContext.prototype.showPopup = async function (popupComponent, params, args) {
|
NodeContext.prototype.showPopup = async function (popupComponent, params, args) {
|
||||||
if (!this.onShowPopup) return;
|
if (!this.onShowPopup) return;
|
||||||
|
|
||||||
|
|||||||
@@ -227,6 +227,9 @@ declare namespace Noodl {
|
|||||||
objectOrId: string | { getId(): string; },
|
objectOrId: string | { getId(): string; },
|
||||||
options?: {
|
options?: {
|
||||||
className?: RecordClassName;
|
className?: RecordClassName;
|
||||||
|
keys?: string[] | string;
|
||||||
|
include?: string[] | string;
|
||||||
|
excludeKeys?: string[] | string;
|
||||||
}
|
}
|
||||||
): Promise<any>;
|
): Promise<any>;
|
||||||
|
|
||||||
|
|||||||
@@ -2,12 +2,18 @@ const { RouterHandler } = require('../nodes/navigation/router-handler');
|
|||||||
const NoodlRuntime = require('@noodl/runtime');
|
const NoodlRuntime = require('@noodl/runtime');
|
||||||
|
|
||||||
const navigation = {
|
const navigation = {
|
||||||
|
/**
|
||||||
|
* This is set by "packages/noodl-viewer-react/src/noodl-js-api.js"
|
||||||
|
* @type {NoodlRuntime}
|
||||||
|
*/
|
||||||
|
_noodlRuntime: undefined,
|
||||||
|
|
||||||
async showPopup(componentPath, params) {
|
async showPopup(componentPath, params) {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
navigation._noodlRuntime.context.showPopup(componentPath, params, {
|
navigation._noodlRuntime.context.showPopup(componentPath, params, {
|
||||||
onClosePopup: (action, results) => {
|
onClosePopup: (action, results) => {
|
||||||
resolve({
|
resolve({
|
||||||
action: action.replace('closeAction-', ''),
|
action: action?.replace('closeAction-', ''),
|
||||||
parameters: results
|
parameters: results
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,8 +40,8 @@ const ClosePopupNode = {
|
|||||||
this._internal.closeCallback = cb;
|
this._internal.closeCallback = cb;
|
||||||
},
|
},
|
||||||
scheduleClose: function () {
|
scheduleClose: function () {
|
||||||
var _this = this;
|
const _this = this;
|
||||||
var internal = this._internal;
|
const internal = this._internal;
|
||||||
if (!internal.hasScheduledClose) {
|
if (!internal.hasScheduledClose) {
|
||||||
internal.hasScheduledClose = true;
|
internal.hasScheduledClose = true;
|
||||||
this.scheduleAfterInputsHaveUpdated(function () {
|
this.scheduleAfterInputsHaveUpdated(function () {
|
||||||
@@ -113,9 +113,8 @@ module.exports = {
|
|||||||
var closeActions = node.parameters['closeActions'];
|
var closeActions = node.parameters['closeActions'];
|
||||||
if (closeActions) {
|
if (closeActions) {
|
||||||
closeActions = closeActions ? closeActions.split(',') : undefined;
|
closeActions = closeActions ? closeActions.split(',') : undefined;
|
||||||
for (var i in closeActions) {
|
for (const i in closeActions) {
|
||||||
var p = closeActions[i];
|
const p = closeActions[i];
|
||||||
|
|
||||||
ports.push({
|
ports.push({
|
||||||
type: 'signal',
|
type: 'signal',
|
||||||
plug: 'input',
|
plug: 'input',
|
||||||
|
|||||||
@@ -3,6 +3,17 @@ const CloudStore = require('@noodl/runtime/src/api/cloudstore');
|
|||||||
|
|
||||||
('use strict');
|
('use strict');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param {string} path
|
||||||
|
* @param {{
|
||||||
|
* endpoint: string;
|
||||||
|
* method: string;
|
||||||
|
* appId: string;
|
||||||
|
* content: any;
|
||||||
|
* success: (json: object) => void;
|
||||||
|
* error: (json: object | undefined) => void;
|
||||||
|
* }} options
|
||||||
|
*/
|
||||||
function _makeRequest(path, options) {
|
function _makeRequest(path, options) {
|
||||||
var xhr = new XMLHttpRequest();
|
var xhr = new XMLHttpRequest();
|
||||||
|
|
||||||
@@ -15,7 +26,9 @@ function _makeRequest(path, options) {
|
|||||||
|
|
||||||
if (xhr.status === 200 || xhr.status === 201) {
|
if (xhr.status === 200 || xhr.status === 201) {
|
||||||
options.success(json);
|
options.success(json);
|
||||||
} else options.error(json);
|
} else {
|
||||||
|
options.error(json);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -191,7 +204,7 @@ var CloudFunctionNode = {
|
|||||||
this.sendSignalOnOutput('success');
|
this.sendSignalOnOutput('success');
|
||||||
},
|
},
|
||||||
error: (e) => {
|
error: (e) => {
|
||||||
const error = typeof e === 'string' ? e : e.error || 'Failed running cloud function.';
|
const error = typeof e === 'string' ? e : e?.error || 'Failed running cloud function.';
|
||||||
this._internal.lastCallResult = {
|
this._internal.lastCallResult = {
|
||||||
status: 'failure',
|
status: 'failure',
|
||||||
error
|
error
|
||||||
|
|||||||
@@ -1,21 +1,25 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const { Node } = require('@noodl/runtime');
|
|
||||||
|
|
||||||
const Model = require('@noodl/runtime/src/model');
|
const Model = require('@noodl/runtime/src/model');
|
||||||
const Collection = require('@noodl/runtime/src/collection');
|
const Collection = require('@noodl/runtime/src/collection');
|
||||||
|
|
||||||
var SetVariableNodeDefinition = {
|
const SetVariableNodeDefinition = {
|
||||||
name: 'Set Variable',
|
name: 'Set Variable',
|
||||||
docs: 'https://docs.noodl.net/nodes/data/variable/set-variable',
|
docs: 'https://docs.noodl.net/nodes/data/variable/set-variable',
|
||||||
category: 'Data',
|
category: 'Data',
|
||||||
usePortAsLabel: 'name',
|
usePortAsLabel: 'name',
|
||||||
color: 'data',
|
color: 'data',
|
||||||
initialize: function () {
|
initialize: function () {
|
||||||
var internal = this._internal;
|
const internal = this._internal;
|
||||||
|
|
||||||
internal.variablesModel = Model.get('--ndl--global-variables');
|
internal.variablesModel = Model.get('--ndl--global-variables');
|
||||||
},
|
},
|
||||||
|
getInspectInfo() {
|
||||||
|
if (this._internal.name) {
|
||||||
|
return this._internal.variablesModel.get(this._internal.name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return '[No value set]';
|
||||||
|
},
|
||||||
outputs: {
|
outputs: {
|
||||||
done: {
|
done: {
|
||||||
type: 'signal',
|
type: 'signal',
|
||||||
@@ -74,17 +78,22 @@ var SetVariableNodeDefinition = {
|
|||||||
if (this.hasScheduledStore) return;
|
if (this.hasScheduledStore) return;
|
||||||
this.hasScheduledStore = true;
|
this.hasScheduledStore = true;
|
||||||
|
|
||||||
var internal = this._internal;
|
const internal = this._internal;
|
||||||
this.scheduleAfterInputsHaveUpdated(function () {
|
this.scheduleAfterInputsHaveUpdated(function () {
|
||||||
this.hasScheduledStore = false;
|
this.hasScheduledStore = false;
|
||||||
|
|
||||||
var value = internal.setWith === 'emptyString' ? '' : internal.value;
|
let value = internal.setWith === 'emptyString' ? '' : internal.value;
|
||||||
|
|
||||||
|
// Can set arrays with "id" or array
|
||||||
|
if (internal.setWith === 'object' && typeof value === 'string') value = Model.get(value);
|
||||||
|
|
||||||
|
// Can set arrays with "id" or array
|
||||||
|
if (internal.setWith === 'array' && typeof value === 'string') value = Collection.get(value);
|
||||||
|
|
||||||
if (internal.setWith === 'object' && typeof value === 'string') value = Model.get(value); // Can set arrays with "id" or array
|
|
||||||
if (internal.setWith === 'array' && typeof value === 'string') value = Collection.get(value); // Can set arrays with "id" or array
|
|
||||||
if (internal.setWith === 'boolean') value = !!value;
|
if (internal.setWith === 'boolean') value = !!value;
|
||||||
|
|
||||||
//use forceChange to always trigger Variable nodes to send the value on their output, even if it's the same value twice
|
// use forceChange to always trigger Variable nodes to send the value on
|
||||||
|
// their output, even if it's the same value twice
|
||||||
internal.variablesModel.set(internal.name, value, {
|
internal.variablesModel.set(internal.name, value, {
|
||||||
forceChange: true
|
forceChange: true
|
||||||
});
|
});
|
||||||
@@ -96,12 +105,13 @@ var SetVariableNodeDefinition = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name === 'value')
|
if (name === 'value') {
|
||||||
this.registerInput(name, {
|
this.registerInput(name, {
|
||||||
set: this.setValue.bind(this)
|
set: this.setValue.bind(this)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
|||||||
@@ -274,6 +274,9 @@ declare namespace Noodl {
|
|||||||
objectOrId: string | { getId(): string; },
|
objectOrId: string | { getId(): string; },
|
||||||
options?: {
|
options?: {
|
||||||
className?: RecordClassName;
|
className?: RecordClassName;
|
||||||
|
keys?: string[] | string;
|
||||||
|
include?: string[] | string;
|
||||||
|
excludeKeys?: string[] | string;
|
||||||
}
|
}
|
||||||
): Promise<any>;
|
): Promise<any>;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user