diff --git a/packages/noodl-editor/src/editor/src/utils/forge/template/providers/noodl-docs-template-provider.ts b/packages/noodl-editor/src/editor/src/utils/forge/template/providers/noodl-docs-template-provider.ts index e9c06ed..c65eaec 100644 --- a/packages/noodl-editor/src/editor/src/utils/forge/template/providers/noodl-docs-template-provider.ts +++ b/packages/noodl-editor/src/editor/src/utils/forge/template/providers/noodl-docs-template-provider.ts @@ -6,7 +6,7 @@ import { ITemplateProvider, ProgressCallback, TemplateItem, TemplateListFilter } */ export class NoodlDocsTemplateProvider implements ITemplateProvider { get name(): string { - return 'https://docs.noodl.net'; + return this.getDocsEndpoint() || 'https://docs.fluxscape.io'; } constructor(private readonly getDocsEndpoint: () => string) {} diff --git a/packages/noodl-editor/src/editor/src/views/panels/search-panel/search-panel.tsx b/packages/noodl-editor/src/editor/src/views/panels/search-panel/search-panel.tsx index 303c75d..e9d3298 100644 --- a/packages/noodl-editor/src/editor/src/views/panels/search-panel/search-panel.tsx +++ b/packages/noodl-editor/src/editor/src/views/panels/search-panel/search-panel.tsx @@ -5,6 +5,8 @@ import { useSidePanelKeyboardCommands } from '@noodl-hooks/useKeyboardCommands'; import classNames from 'classnames'; 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 { performSearch } from '@noodl-utils/universal-search'; @@ -54,7 +56,7 @@ export function SearchPanel() { } }, [debouncedSearchTerm]); - function onSearchItemClicked(searchResult) { + function onSearchItemClicked(searchResult: SearchResultItem) { if (searchResult.type === 'Component') { NodeGraphContextTmp.switchToComponent(searchResult.componentTarget, { breadcrumbs: false, @@ -85,29 +87,7 @@ export function SearchPanel() {
{searchResults.map((component) => ( -
1 ? 's' : '' - })`} - key={component.componentId} - variant={SectionVariant.Panel} - > - {component.results.map((result, index) => ( -
onSearchItemClicked(result)} - > - - {result.label} -
- ))} -
+ ))} {searchResults.length === 0 && debouncedSearchTerm.length > 0 && ( @@ -118,3 +98,51 @@ export function SearchPanel() { ); } + +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 ( +
+ {component.results.map((result, index) => ( +
onSearchItemClicked(result)} + > + + {result.label} +
+ ))} +
+ ); +} diff --git a/packages/noodl-runtime/src/api/records.js b/packages/noodl-runtime/src/api/records.js index 7cc72cb..bd4d69c 100644 --- a/packages/noodl-runtime/src/api/records.js +++ b/packages/noodl-runtime/src/api/records.js @@ -12,6 +12,7 @@ function createRecordsAPI(modelScope) { return { async query(className, query, options) { + if (typeof className === "undefined") throw new Error("'className' is undefined"); return new Promise((resolve, reject) => { cloudstore().query({ collection: className, @@ -39,6 +40,7 @@ function createRecordsAPI(modelScope) { }, async count(className, query) { + if (typeof className === "undefined") throw new Error("'className' is undefined"); return new Promise((resolve, reject) => { cloudstore().count({ collection: className, @@ -60,6 +62,7 @@ function createRecordsAPI(modelScope) { }, async distinct(className, property, query) { + if (typeof className === "undefined") throw new Error("'className' is undefined"); return new Promise((resolve, reject) => { cloudstore().distinct({ collection: className, @@ -82,6 +85,7 @@ function createRecordsAPI(modelScope) { }, async aggregate(className, group, query) { + if (typeof className === "undefined") throw new Error("'className' is undefined"); return new Promise((resolve, reject) => { cloudstore().aggregate({ collection: className, @@ -104,6 +108,7 @@ function createRecordsAPI(modelScope) { }, async fetch(objectOrId, options) { + if (typeof objectOrId === 'undefined') return Promise.reject(new Error("'objectOrId' is undefined.")); if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId(); const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class; @@ -126,6 +131,7 @@ function createRecordsAPI(modelScope) { }, async increment(objectOrId, properties, options) { + if (typeof objectOrId === 'undefined') return Promise.reject(new Error("'objectOrId' is undefined.")); if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId(); const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class; @@ -149,6 +155,7 @@ function createRecordsAPI(modelScope) { }, async save(objectOrId, properties, options) { + if (typeof objectOrId === 'undefined') return Promise.reject(new Error("'objectOrId' is undefined.")); if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId(); const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class; @@ -179,6 +186,7 @@ function createRecordsAPI(modelScope) { }, async create(className, properties, options) { + if (typeof className === "undefined") throw new Error("'className' is undefined"); return new Promise((resolve, reject) => { cloudstore().create({ collection: className, @@ -197,6 +205,7 @@ function createRecordsAPI(modelScope) { }, async delete(objectOrId, options) { + if (typeof objectOrId === 'undefined') return Promise.reject(new Error("'objectOrId' is undefined.")); if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId(); const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class; @@ -265,7 +274,7 @@ function createRecordsAPI(modelScope) { resolve(); }, error: (err) => { - reject(Error(rr || 'Failed to add relation.')); + reject(Error(err || 'Failed to add relation.')); } }); }); diff --git a/packages/noodl-viewer-react/src/nodes/navigation/navigate.js b/packages/noodl-viewer-react/src/nodes/navigation/navigate.js index 0fb202a..8090044 100644 --- a/packages/noodl-viewer-react/src/nodes/navigation/navigate.js +++ b/packages/noodl-viewer-react/src/nodes/navigation/navigate.js @@ -72,8 +72,10 @@ const Navigate = { backCallback: (action, results) => { this._internal.backResults = results; - for (var key in results) { - if (this.hasOutput('backResult-' + key)) this.flagOutputDirty('backResult-' + key); + for (const key in results) { + if (this.hasOutput('backResult-' + key)) { + this.flagOutputDirty('backResult-' + key); + } } if (action !== undefined) this.sendSignalOnOutput(action); @@ -114,22 +116,23 @@ const Navigate = { return; } - if (name === 'target') + if (name === 'target') { return this.registerInput(name, { set: this.setTargetPageId.bind(this) }); - else if (name === 'transition') + } else if (name === 'transition') { return this.registerInput(name, { set: this.setTransition.bind(this) }); - else if (name.startsWith('tr-')) + } else if (name.startsWith('tr-')) { return this.registerInput(name, { set: this.setTransitionParam.bind(this, name.substring('tr-'.length)) }); - else if (name.startsWith('pm-')) + } else if (name.startsWith('pm-')) { return this.registerInput(name, { set: this.setPageParam.bind(this, name.substring('pm-'.length)) }); + } }, registerOutputIfNeeded: function (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(node.parameters['stack'] !== undefined) { - var pageStacks = graphModel.getNodesWithType('Page Stack'); - var pageStack = pageStacks.find( + const pageStacks = graphModel.getNodesWithType('Page Stack'); + const pageStack = pageStacks.find( (ps) => (ps.parameters['name'] || 'Main') === (node.parameters['stack'] || 'Main') ); if (pageStack !== undefined) { - var pages = pageStack.parameters['pages']; + const pages = pageStack.parameters['pages']; if (pages !== undefined && pages.length > 0) { ports.push({ 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', displayName: 'Target Page', name: 'target', @@ -193,14 +202,14 @@ function setup(context, graphModel) { }); // See if there is a target page with component - var targetPageId = node.parameters['target'] || pages[0].id; - var targetComponentName = pageStack.parameters['pageComp-' + targetPageId]; + const targetPageId = node.parameters['target'] || pages[0].id; + const targetComponentName = pageStack.parameters['pageComp-' + targetPageId]; if (targetComponentName !== undefined) { const component = graphModel.components[targetComponentName]; if (component !== undefined) { // 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({ name: 'pm-' + inputName, displayName: inputName, @@ -245,7 +254,6 @@ function setup(context, graphModel) { } } } - // } context.editorConnection.sendDynamicPorts(node.id, ports); }