mirror of
https://github.com/fluxscape/fluxscape.git
synced 2026-01-11 14:52:54 +01:00
Merge branch 'main' into feature/store-cloudservices-in-project-folder
This commit is contained in:
@@ -6,7 +6,7 @@ import { ITemplateProvider, ProgressCallback, TemplateItem, TemplateListFilter }
|
|||||||
*/
|
*/
|
||||||
export class NoodlDocsTemplateProvider implements ITemplateProvider {
|
export class NoodlDocsTemplateProvider implements ITemplateProvider {
|
||||||
get name(): string {
|
get name(): string {
|
||||||
return 'https://docs.noodl.net';
|
return this.getDocsEndpoint() || 'https://docs.fluxscape.io';
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(private readonly getDocsEndpoint: () => string) {}
|
constructor(private readonly getDocsEndpoint: () => string) {}
|
||||||
|
|||||||
@@ -5,6 +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 } from '@noodl-utils/universal-search';
|
||||||
|
|
||||||
@@ -54,7 +56,7 @@ export function SearchPanel() {
|
|||||||
}
|
}
|
||||||
}, [debouncedSearchTerm]);
|
}, [debouncedSearchTerm]);
|
||||||
|
|
||||||
function onSearchItemClicked(searchResult) {
|
function onSearchItemClicked(searchResult: SearchResultItem) {
|
||||||
if (searchResult.type === 'Component') {
|
if (searchResult.type === 'Component') {
|
||||||
NodeGraphContextTmp.switchToComponent(searchResult.componentTarget, {
|
NodeGraphContextTmp.switchToComponent(searchResult.componentTarget, {
|
||||||
breadcrumbs: false,
|
breadcrumbs: false,
|
||||||
@@ -85,29 +87,7 @@ export function SearchPanel() {
|
|||||||
|
|
||||||
<div className={css.SearchResults}>
|
<div className={css.SearchResults}>
|
||||||
{searchResults.map((component) => (
|
{searchResults.map((component) => (
|
||||||
<Section
|
<SearchItem key={component.componentId} component={component} onSearchItemClicked={onSearchItemClicked} />
|
||||||
title={`${component.componentName} (${component.results.length} result${
|
|
||||||
component.results.length > 1 ? 's' : ''
|
|
||||||
})`}
|
|
||||||
key={component.componentId}
|
|
||||||
variant={SectionVariant.Panel}
|
|
||||||
>
|
|
||||||
{component.results.map((result, index) => (
|
|
||||||
<div
|
|
||||||
className={classNames(
|
|
||||||
css.SearchResultItem
|
|
||||||
// lastActiveComponentId === result.componentTarget.id && css['is-active']
|
|
||||||
)}
|
|
||||||
key={index}
|
|
||||||
onClick={() => onSearchItemClicked(result)}
|
|
||||||
>
|
|
||||||
<Label variant={TextType.Proud}>
|
|
||||||
{result.userLabel ? result.type + ' - ' + result.userLabel : result.type}
|
|
||||||
</Label>
|
|
||||||
<Text>{result.label}</Text>
|
|
||||||
</div>
|
|
||||||
))}
|
|
||||||
</Section>
|
|
||||||
))}
|
))}
|
||||||
{searchResults.length === 0 && debouncedSearchTerm.length > 0 && (
|
{searchResults.length === 0 && debouncedSearchTerm.length > 0 && (
|
||||||
<Container hasXSpacing hasYSpacing>
|
<Container hasXSpacing hasYSpacing>
|
||||||
@@ -118,3 +98,51 @@ export function SearchPanel() {
|
|||||||
</BasePanel>
|
</BasePanel>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type SearchResultItem = {
|
||||||
|
componentTarget: ComponentModel;
|
||||||
|
label: string;
|
||||||
|
nodeTarget: NodeGraphNode;
|
||||||
|
type: string;
|
||||||
|
userLabel: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
type SearchItemProps = {
|
||||||
|
component: {
|
||||||
|
componentName: string;
|
||||||
|
componentId: string;
|
||||||
|
results: SearchResultItem[];
|
||||||
|
};
|
||||||
|
onSearchItemClicked: (item: SearchResultItem) => void;
|
||||||
|
};
|
||||||
|
|
||||||
|
function SearchItem({ component, onSearchItemClicked }: SearchItemProps) {
|
||||||
|
const resultCountText = `${component.results.length} result${component.results.length > 1 ? 's' : ''}`;
|
||||||
|
let titleText = `${component.componentName} (${resultCountText})`;
|
||||||
|
|
||||||
|
// We expect there to always be at least one result, to get the full component name.
|
||||||
|
const isInCloudFunctions = component.results[0].componentTarget.name.startsWith('/#__cloud__/');
|
||||||
|
if (isInCloudFunctions) {
|
||||||
|
titleText += ' (Cloud Function)';
|
||||||
|
}
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Section title={titleText} variant={SectionVariant.Panel}>
|
||||||
|
{component.results.map((result, index) => (
|
||||||
|
<div
|
||||||
|
className={classNames(
|
||||||
|
css.SearchResultItem
|
||||||
|
// lastActiveComponentId === result.componentTarget.id && css['is-active']
|
||||||
|
)}
|
||||||
|
key={index}
|
||||||
|
onClick={() => onSearchItemClicked(result)}
|
||||||
|
>
|
||||||
|
<Label variant={TextType.Proud}>
|
||||||
|
{result.userLabel ? result.type + ' - ' + result.userLabel : result.type}
|
||||||
|
</Label>
|
||||||
|
<Text>{result.label}</Text>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
</Section>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ function createRecordsAPI(modelScope) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
async query(className, query, options) {
|
async query(className, query, options) {
|
||||||
|
if (typeof className === "undefined") throw new Error("'className' is undefined");
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
cloudstore().query({
|
cloudstore().query({
|
||||||
collection: className,
|
collection: className,
|
||||||
@@ -39,6 +40,7 @@ function createRecordsAPI(modelScope) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async count(className, query) {
|
async count(className, query) {
|
||||||
|
if (typeof className === "undefined") throw new Error("'className' is undefined");
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
cloudstore().count({
|
cloudstore().count({
|
||||||
collection: className,
|
collection: className,
|
||||||
@@ -60,6 +62,7 @@ function createRecordsAPI(modelScope) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async distinct(className, property, query) {
|
async distinct(className, property, query) {
|
||||||
|
if (typeof className === "undefined") throw new Error("'className' is undefined");
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
cloudstore().distinct({
|
cloudstore().distinct({
|
||||||
collection: className,
|
collection: className,
|
||||||
@@ -82,6 +85,7 @@ function createRecordsAPI(modelScope) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async aggregate(className, group, query) {
|
async aggregate(className, group, query) {
|
||||||
|
if (typeof className === "undefined") throw new Error("'className' is undefined");
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
cloudstore().aggregate({
|
cloudstore().aggregate({
|
||||||
collection: className,
|
collection: className,
|
||||||
@@ -104,6 +108,7 @@ function createRecordsAPI(modelScope) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async fetch(objectOrId, options) {
|
async fetch(objectOrId, options) {
|
||||||
|
if (typeof objectOrId === 'undefined') return Promise.reject(new Error("'objectOrId' is undefined."));
|
||||||
if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId();
|
if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId();
|
||||||
const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class;
|
const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class;
|
||||||
|
|
||||||
@@ -126,6 +131,7 @@ function createRecordsAPI(modelScope) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async increment(objectOrId, properties, options) {
|
async increment(objectOrId, properties, options) {
|
||||||
|
if (typeof objectOrId === 'undefined') return Promise.reject(new Error("'objectOrId' is undefined."));
|
||||||
if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId();
|
if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId();
|
||||||
const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class;
|
const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class;
|
||||||
|
|
||||||
@@ -149,6 +155,7 @@ function createRecordsAPI(modelScope) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async save(objectOrId, properties, options) {
|
async save(objectOrId, properties, options) {
|
||||||
|
if (typeof objectOrId === 'undefined') return Promise.reject(new Error("'objectOrId' is undefined."));
|
||||||
if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId();
|
if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId();
|
||||||
const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class;
|
const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class;
|
||||||
|
|
||||||
@@ -179,6 +186,7 @@ function createRecordsAPI(modelScope) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async create(className, properties, options) {
|
async create(className, properties, options) {
|
||||||
|
if (typeof className === "undefined") throw new Error("'className' is undefined");
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
cloudstore().create({
|
cloudstore().create({
|
||||||
collection: className,
|
collection: className,
|
||||||
@@ -197,6 +205,7 @@ function createRecordsAPI(modelScope) {
|
|||||||
},
|
},
|
||||||
|
|
||||||
async delete(objectOrId, options) {
|
async delete(objectOrId, options) {
|
||||||
|
if (typeof objectOrId === 'undefined') return Promise.reject(new Error("'objectOrId' is undefined."));
|
||||||
if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId();
|
if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId();
|
||||||
const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class;
|
const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class;
|
||||||
|
|
||||||
@@ -265,7 +274,7 @@ function createRecordsAPI(modelScope) {
|
|||||||
resolve();
|
resolve();
|
||||||
},
|
},
|
||||||
error: (err) => {
|
error: (err) => {
|
||||||
reject(Error(rr || 'Failed to add relation.'));
|
reject(Error(err || 'Failed to add relation.'));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -72,8 +72,10 @@ const Navigate = {
|
|||||||
backCallback: (action, results) => {
|
backCallback: (action, results) => {
|
||||||
this._internal.backResults = results;
|
this._internal.backResults = results;
|
||||||
|
|
||||||
for (var key in results) {
|
for (const key in results) {
|
||||||
if (this.hasOutput('backResult-' + key)) this.flagOutputDirty('backResult-' + key);
|
if (this.hasOutput('backResult-' + key)) {
|
||||||
|
this.flagOutputDirty('backResult-' + key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (action !== undefined) this.sendSignalOnOutput(action);
|
if (action !== undefined) this.sendSignalOnOutput(action);
|
||||||
@@ -114,22 +116,23 @@ const Navigate = {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (name === 'target')
|
if (name === 'target') {
|
||||||
return this.registerInput(name, {
|
return this.registerInput(name, {
|
||||||
set: this.setTargetPageId.bind(this)
|
set: this.setTargetPageId.bind(this)
|
||||||
});
|
});
|
||||||
else if (name === 'transition')
|
} else if (name === 'transition') {
|
||||||
return this.registerInput(name, {
|
return this.registerInput(name, {
|
||||||
set: this.setTransition.bind(this)
|
set: this.setTransition.bind(this)
|
||||||
});
|
});
|
||||||
else if (name.startsWith('tr-'))
|
} else if (name.startsWith('tr-')) {
|
||||||
return this.registerInput(name, {
|
return this.registerInput(name, {
|
||||||
set: this.setTransitionParam.bind(this, name.substring('tr-'.length))
|
set: this.setTransitionParam.bind(this, name.substring('tr-'.length))
|
||||||
});
|
});
|
||||||
else if (name.startsWith('pm-'))
|
} else if (name.startsWith('pm-')) {
|
||||||
return this.registerInput(name, {
|
return this.registerInput(name, {
|
||||||
set: this.setPageParam.bind(this, name.substring('pm-'.length))
|
set: this.setPageParam.bind(this, name.substring('pm-'.length))
|
||||||
});
|
});
|
||||||
|
}
|
||||||
},
|
},
|
||||||
registerOutputIfNeeded: function (name) {
|
registerOutputIfNeeded: function (name) {
|
||||||
if (this.hasOutput(name)) {
|
if (this.hasOutput(name)) {
|
||||||
@@ -174,18 +177,24 @@ function setup(context, graphModel) {
|
|||||||
if (Transitions[transition]) ports = ports.concat(Transitions[transition].ports(node.parameters));
|
if (Transitions[transition]) ports = ports.concat(Transitions[transition].ports(node.parameters));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if(node.parameters['stack'] !== undefined) {
|
const pageStacks = graphModel.getNodesWithType('Page Stack');
|
||||||
var pageStacks = graphModel.getNodesWithType('Page Stack');
|
const pageStack = pageStacks.find(
|
||||||
var pageStack = pageStacks.find(
|
|
||||||
(ps) => (ps.parameters['name'] || 'Main') === (node.parameters['stack'] || 'Main')
|
(ps) => (ps.parameters['name'] || 'Main') === (node.parameters['stack'] || 'Main')
|
||||||
);
|
);
|
||||||
|
|
||||||
if (pageStack !== undefined) {
|
if (pageStack !== undefined) {
|
||||||
var pages = pageStack.parameters['pages'];
|
const pages = pageStack.parameters['pages'];
|
||||||
if (pages !== undefined && pages.length > 0) {
|
if (pages !== undefined && pages.length > 0) {
|
||||||
ports.push({
|
ports.push({
|
||||||
plug: 'input',
|
plug: 'input',
|
||||||
type: { name: 'enum', enums: pages.map((p) => ({ label: p.label, value: p.id })), allowEditOnly: true },
|
type: {
|
||||||
|
name: 'enum',
|
||||||
|
enums: pages.map((p) => ({
|
||||||
|
label: p.label,
|
||||||
|
value: p.id
|
||||||
|
})),
|
||||||
|
allowEditOnly: true
|
||||||
|
},
|
||||||
group: 'General',
|
group: 'General',
|
||||||
displayName: 'Target Page',
|
displayName: 'Target Page',
|
||||||
name: 'target',
|
name: 'target',
|
||||||
@@ -193,14 +202,14 @@ function setup(context, graphModel) {
|
|||||||
});
|
});
|
||||||
|
|
||||||
// See if there is a target page with component
|
// See if there is a target page with component
|
||||||
var targetPageId = node.parameters['target'] || pages[0].id;
|
const targetPageId = node.parameters['target'] || pages[0].id;
|
||||||
var targetComponentName = pageStack.parameters['pageComp-' + targetPageId];
|
const targetComponentName = pageStack.parameters['pageComp-' + targetPageId];
|
||||||
if (targetComponentName !== undefined) {
|
if (targetComponentName !== undefined) {
|
||||||
const component = graphModel.components[targetComponentName];
|
const component = graphModel.components[targetComponentName];
|
||||||
|
|
||||||
if (component !== undefined) {
|
if (component !== undefined) {
|
||||||
// Make all inputs of the component to inputs of this navigation node
|
// Make all inputs of the component to inputs of this navigation node
|
||||||
for (var inputName in component.inputPorts) {
|
for (const inputName in component.inputPorts) {
|
||||||
ports.push({
|
ports.push({
|
||||||
name: 'pm-' + inputName,
|
name: 'pm-' + inputName,
|
||||||
displayName: inputName,
|
displayName: inputName,
|
||||||
@@ -245,7 +254,6 @@ function setup(context, graphModel) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// }
|
|
||||||
|
|
||||||
context.editorConnection.sendDynamicPorts(node.id, ports);
|
context.editorConnection.sendDynamicPorts(node.id, ports);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user