Initial commit

Co-Authored-By: Eric Tuvesson <eric.tuvesson@gmail.com>
Co-Authored-By: mikaeltellhed <2311083+mikaeltellhed@users.noreply.github.com>
Co-Authored-By: kotte <14197736+mrtamagotchi@users.noreply.github.com>
Co-Authored-By: Anders Larsson <64838990+anders-topp@users.noreply.github.com>
Co-Authored-By: Johan  <4934465+joolsus@users.noreply.github.com>
Co-Authored-By: Tore Knudsen <18231882+torekndsn@users.noreply.github.com>
Co-Authored-By: victoratndl <99176179+victoratndl@users.noreply.github.com>
This commit is contained in:
Michael Cartner
2024-01-26 11:52:55 +01:00
commit b9c60b07dc
2789 changed files with 868795 additions and 0 deletions

View File

@@ -0,0 +1,9 @@
Font used by Monaco Editor for the icons.
The issue:
Monaco Editor is importing the font with CSS url.
`url('./codicon.ttf')` and since we don't transform the urls because
of the old templates this causes a problem here.
Easy solution was just to move this single font file here and everything works fine.

Binary file not shown.

View File

@@ -0,0 +1,28 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>Noodl</title>
<link href="../assets/lib/fontawesome/css/font-awesome.min.css" rel="stylesheet" />
<link href="../assets/css/style.css" rel="stylesheet" />
<!-- Libs that don't have npm packaged -->
<script type="text/javascript" src="../assets/lib/jquery-min.js"></script>
<script type="text/javascript" src="../assets/lib/jquery.autosize.min.js"></script>
<link rel="preload" href="../assets/Inter/Inter-Light.ttf" as="font" />
<link rel="preload" href="../assets/Inter/Inter-Regular.ttf" as="font" />
<link rel="preload" href="../assets/Inter/Inter-Medium.ttf" as="font" />
<link rel="preload" href="../assets/Inter/Inter-Bold.ttf" as="font" />
<link rel="preload" href="../assets/Inter/Inter-SemiBold.ttf" as="font" />
<script>
const path = process.env.devMode !== 'yes' ? '.' : 'http://localhost:8080/src/editor';
document.write(`<script defer src="${path}/index.bundle.js"><\/script>`);
</script>
</head>
<body>
<div id="root" style="position: relative; width: 100vw; height: 100vh; overflow: hidden"></div>
</body>
</html>

View File

@@ -0,0 +1,87 @@
import * as remote from '@electron/remote';
import { ipcRenderer } from 'electron';
import React from 'react';
import ReactDOM from 'react-dom';
import './process-setup';
import { EventDispatcher } from '../shared/utils/EventDispatcher';
import { NodeLibrary } from './src/models/nodelibrary';
import { ProjectModel } from './src/models/projectmodel';
//Design tokens for later
// import '../../../noodl-core-ui/src/styles/custom-properties/animations.css';
// import '../../../noodl-core-ui/src/styles/custom-properties/fonts.css';
// import '../../../noodl-core-ui/src/styles/custom-properties/colors.css';
import '../editor/src/styles/custom-properties/animations.css';
import '../editor/src/styles/custom-properties/fonts.css';
import '../editor/src/styles/custom-properties/colors.css';
import Router from './src/router';
ipcRenderer.on('open-noodl-uri', async (event, uri) => {
if (uri.startsWith('noodl:import/http')) {
console.log('import: ', uri);
EventDispatcher.instance.emit('importFromUrl', uri.substring('noodl:import/'.length));
}
});
ipcRenderer.on('import-projectmetadata', (event, data) => {
ProjectModel.instance.mergeMetadata(data);
});
function setupViewerIpc() {
ipcRenderer.on('viewer-refreshed', () => {
EventDispatcher.instance.emit('viewer-refreshed');
});
ipcRenderer.on('viewer-closed', () => {
EventDispatcher.instance.emit('viewer-closed');
});
}
window.addEventListener('DOMContentLoaded', () => {
// Register node adapters
require('./src/models/NodeTypeAdapters/registeradapters');
// Disable context menu
$('body').on('contextmenu', function () {
return false;
});
ipcRenderer.on('showAutoUpdatePopup', () => {
//@ts-expect-error
window._hasNewAutoUpdateAvailable = true;
});
setupViewerIpc();
ipcRenderer.on('window-focused', () => {
EventDispatcher.instance.notifyListeners('window-focused');
});
document.addEventListener('mousedown', () => {
remote.getCurrentWindow().focus();
});
// Activity detector
let lastActiveTime = +new Date();
document.addEventListener('mousedown', function (evt) {
const now = +new Date();
if (now > lastActiveTime + 10 * 60 * 1000) {
// Wake up after 10 minutes of inactivity
EventDispatcher.instance.notifyListeners('wakeup');
}
lastActiveTime = now;
});
EventDispatcher.instance.on('ProjectModel.instanceWillChange', () => {
//@ts-expect-error
window.NodeLibraryData = undefined;
NodeLibrary.instance.reload();
}, null);
// Create the main element
const rootElement = document.getElementById('root');
ReactDOM.render(React.createElement(Router, { uri: remote.process.env.noodlURI }), rootElement);
});

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[128],{93128:(e,n,t)=>{t.r(n),t.d(n,{c:()=>m});var i=t(96539),l=Object.defineProperty,o=(e,n)=>l(e,"name",{value:n,configurable:!0});function r(e,n){return n.forEach((function(n){n&&"string"!=typeof n&&!Array.isArray(n)&&Object.keys(n).forEach((function(t){if("default"!==t&&!(t in e)){var i=Object.getOwnPropertyDescriptor(n,t);Object.defineProperty(e,t,i.get?i:{enumerable:!0,get:function(){return n[t]}})}}))})),Object.freeze(e)}o(r,"_mergeNamespaces");var a={exports:{}};!function(e){var n={},t=/[^\s\u00a0]/,i=e.Pos,l=e.cmpPos;function r(e){var n=e.search(t);return-1==n?0:n}function a(e,n,t){return/\bstring\b/.test(e.getTokenTypeAt(i(n.line,0)))&&!/^[\'\"\`]/.test(t)}function c(e,n){var t=e.getMode();return!1!==t.useInnerComments&&t.innerMode?e.getModeAt(n):t}o(r,"firstNonWS"),e.commands.toggleComment=function(e){e.toggleComment()},e.defineExtension("toggleComment",(function(e){e||(e=n);for(var t=this,l=1/0,o=this.listSelections(),r=null,a=o.length-1;a>=0;a--){var c=o[a].from(),m=o[a].to();c.line>=l||(m.line>=l&&(m=i(l,0)),l=c.line,null==r?t.uncomment(c,m,e)?r="un":(t.lineComment(c,m,e),r="line"):"un"==r?t.uncomment(c,m,e):t.lineComment(c,m,e))}})),o(a,"probablyInsideString"),o(c,"getMode"),e.defineExtension("lineComment",(function(e,l,o){o||(o=n);var m=this,s=c(m,e),f=m.getLine(e.line);if(null!=f&&!a(m,e,f)){var g=o.lineComment||s.lineComment;if(g){var u=Math.min(0!=l.ch||l.line==e.line?l.line+1:l.line,m.lastLine()+1),d=null==o.padding?" ":o.padding,h=o.commentBlankLines||e.line==l.line;m.operation((function(){if(o.indent){for(var n=null,l=e.line;l<u;++l){var a=(c=m.getLine(l)).slice(0,r(c));(null==n||n.length>a.length)&&(n=a)}for(l=e.line;l<u;++l){var c=m.getLine(l),s=n.length;(h||t.test(c))&&(c.slice(0,s)!=n&&(s=r(c)),m.replaceRange(n+g+d,i(l,0),i(l,s)))}}else for(l=e.line;l<u;++l)(h||t.test(m.getLine(l)))&&m.replaceRange(g+d,i(l,0))}))}else(o.blockCommentStart||s.blockCommentStart)&&(o.fullLines=!0,m.blockComment(e,l,o))}})),e.defineExtension("blockComment",(function(e,o,r){r||(r=n);var a=this,m=c(a,e),s=r.blockCommentStart||m.blockCommentStart,f=r.blockCommentEnd||m.blockCommentEnd;if(s&&f){if(!/\bcomment\b/.test(a.getTokenTypeAt(i(e.line,0)))){var g=Math.min(o.line,a.lastLine());g!=e.line&&0==o.ch&&t.test(a.getLine(g))&&--g;var u=null==r.padding?" ":r.padding;e.line>g||a.operation((function(){if(0!=r.fullLines){var n=t.test(a.getLine(g));a.replaceRange(u+f,i(g)),a.replaceRange(s+u,i(e.line,0));var c=r.blockCommentLead||m.blockCommentLead;if(null!=c)for(var d=e.line+1;d<=g;++d)(d!=g||n)&&a.replaceRange(c+u,i(d,0))}else{var h=0==l(a.getCursor("to"),o),p=!a.somethingSelected();a.replaceRange(f,o),h&&a.setSelection(p?o:a.getCursor("from"),o),a.replaceRange(s,e)}}))}}else(r.lineComment||m.lineComment)&&0!=r.fullLines&&a.lineComment(e,o,r)})),e.defineExtension("uncomment",(function(e,l,o){o||(o=n);var r,a=this,m=c(a,e),s=Math.min(0!=l.ch||l.line==e.line?l.line:l.line-1,a.lastLine()),f=Math.min(e.line,s),g=o.lineComment||m.lineComment,u=[],d=null==o.padding?" ":o.padding;e:if(g){for(var h=f;h<=s;++h){var p=a.getLine(h),v=p.indexOf(g);if(v>-1&&!/comment/.test(a.getTokenTypeAt(i(h,v+1)))&&(v=-1),-1==v&&t.test(p))break e;if(v>-1&&t.test(p.slice(0,v)))break e;u.push(p)}if(a.operation((function(){for(var e=f;e<=s;++e){var n=u[e-f],t=n.indexOf(g),l=t+g.length;t<0||(n.slice(l,l+d.length)==d&&(l+=d.length),r=!0,a.replaceRange("",i(e,t),i(e,l)))}})),r)return!0}var b=o.blockCommentStart||m.blockCommentStart,C=o.blockCommentEnd||m.blockCommentEnd;if(!b||!C)return!1;var k=o.blockCommentLead||m.blockCommentLead,L=a.getLine(f),x=L.indexOf(b);if(-1==x)return!1;var O=s==f?L:a.getLine(s),y=O.indexOf(C,s==f?x+b.length:0),S=i(f,x+1),R=i(s,y+1);if(-1==y||!/comment/.test(a.getTokenTypeAt(S))||!/comment/.test(a.getTokenTypeAt(R))||a.getRange(S,R,"\n").indexOf(C)>-1)return!1;var T=L.lastIndexOf(b,e.ch),E=-1==T?-1:L.slice(0,e.ch).indexOf(C,T+b.length);if(-1!=T&&-1!=E&&E+C.length!=e.ch)return!1;E=O.indexOf(C,l.ch);var M=O.slice(l.ch).lastIndexOf(b,E-l.ch);return T=-1==E||-1==M?-1:l.ch+M,(-1==E||-1==T||T==l.ch)&&(a.operation((function(){a.replaceRange("",i(s,y-(d&&O.slice(y-d.length,y)==d?d.length:0)),i(s,y+C.length));var e=x+b.length;if(d&&L.slice(e,e+d.length)==d&&(e+=d.length),a.replaceRange("",i(f,x),i(f,e)),k)for(var n=f+1;n<=s;++n){var l=a.getLine(n),o=l.indexOf(k);if(-1!=o&&!t.test(l.slice(0,o))){var r=o+k.length;d&&l.slice(r,r+d.length)==d&&(r+=d.length),a.replaceRange("",i(n,o),i(n,r))}}})),!0)}))}(i.a.exports);var c=a.exports,m=Object.freeze(r({__proto__:null,[Symbol.toStringTag]:"Module",default:c},[a.exports]))}}]);

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[269,31],{81031:(e,o,t)=>{t.r(o),t.d(o,{a:()=>u,d:()=>l});var n=t(96539),r=Object.defineProperty,i=(e,o)=>r(e,"name",{value:o,configurable:!0});function a(e,o){return o.forEach((function(o){o&&"string"!=typeof o&&!Array.isArray(o)&&Object.keys(o).forEach((function(t){if("default"!==t&&!(t in e)){var n=Object.getOwnPropertyDescriptor(o,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:function(){return o[t]}})}}))})),Object.freeze(e)}i(a,"_mergeNamespaces");var u={exports:{}};!function(e){function o(o,t,n){var r,i=o.getWrapperElement();return(r=i.appendChild(document.createElement("div"))).className=n?"CodeMirror-dialog CodeMirror-dialog-bottom":"CodeMirror-dialog CodeMirror-dialog-top","string"==typeof t?r.innerHTML=t:r.appendChild(t),e.addClass(i,"dialog-opened"),r}function t(e,o){e.state.currentNotificationClose&&e.state.currentNotificationClose(),e.state.currentNotificationClose=o}i(o,"dialogDiv"),i(t,"closeNotification"),e.defineExtension("openDialog",(function(n,r,a){a||(a={}),t(this,null);var u=o(this,n,a.bottom),s=!1,l=this;function c(o){if("string"==typeof o)p.value=o;else{if(s)return;s=!0,e.rmClass(u.parentNode,"dialog-opened"),u.parentNode.removeChild(u),l.focus(),a.onClose&&a.onClose(u)}}i(c,"close");var f,p=u.getElementsByTagName("input")[0];return p?(p.focus(),a.value&&(p.value=a.value,!1!==a.selectValueOnOpen&&p.select()),a.onInput&&e.on(p,"input",(function(e){a.onInput(e,p.value,c)})),a.onKeyUp&&e.on(p,"keyup",(function(e){a.onKeyUp(e,p.value,c)})),e.on(p,"keydown",(function(o){a&&a.onKeyDown&&a.onKeyDown(o,p.value,c)||((27==o.keyCode||!1!==a.closeOnEnter&&13==o.keyCode)&&(p.blur(),e.e_stop(o),c()),13==o.keyCode&&r(p.value,o))})),!1!==a.closeOnBlur&&e.on(u,"focusout",(function(e){null!==e.relatedTarget&&c()}))):(f=u.getElementsByTagName("button")[0])&&(e.on(f,"click",(function(){c(),l.focus()})),!1!==a.closeOnBlur&&e.on(f,"blur",c),f.focus()),c})),e.defineExtension("openConfirm",(function(n,r,a){t(this,null);var u=o(this,n,a&&a.bottom),s=u.getElementsByTagName("button"),l=!1,c=this,f=1;function p(){l||(l=!0,e.rmClass(u.parentNode,"dialog-opened"),u.parentNode.removeChild(u),c.focus())}i(p,"close"),s[0].focus();for(var d=0;d<s.length;++d){var m=s[d];!function(o){e.on(m,"click",(function(t){e.e_preventDefault(t),p(),o&&o(c)}))}(r[d]),e.on(m,"blur",(function(){--f,setTimeout((function(){f<=0&&p()}),200)})),e.on(m,"focus",(function(){++f}))}})),e.defineExtension("openNotification",(function(n,r){t(this,c);var a,u=o(this,n,r&&r.bottom),s=!1,l=r&&void 0!==r.duration?r.duration:5e3;function c(){s||(s=!0,clearTimeout(a),e.rmClass(u.parentNode,"dialog-opened"),u.parentNode.removeChild(u))}return i(c,"close"),e.on(u,"click",(function(o){e.e_preventDefault(o),c()})),l&&(a=setTimeout(c,l)),c}))}(n.a.exports);var s=u.exports,l=Object.freeze(a({__proto__:null,[Symbol.toStringTag]:"Module",default:s},[u.exports]))},18269:(e,o,t)=>{t.r(o),t.d(o,{j:()=>c});var n=t(96539),r=t(81031),i=Object.defineProperty,a=(e,o)=>i(e,"name",{value:o,configurable:!0});function u(e,o){return o.forEach((function(o){o&&"string"!=typeof o&&!Array.isArray(o)&&Object.keys(o).forEach((function(t){if("default"!==t&&!(t in e)){var n=Object.getOwnPropertyDescriptor(o,t);Object.defineProperty(e,t,n.get?n:{enumerable:!0,get:function(){return o[t]}})}}))})),Object.freeze(e)}a(u,"_mergeNamespaces");var s={exports:{}};!function(e){function o(e,o,t,n,r){e.openDialog?e.openDialog(o,r,{value:n,selectValueOnOpen:!0,bottom:e.options.search.bottom}):r(prompt(t,n))}function t(e){return e.phrase("Jump to line:")+' <input type="text" style="width: 10em" class="CodeMirror-search-field"/> <span style="color: #888" class="CodeMirror-search-hint">'+e.phrase("(Use line:column or scroll% syntax)")+"</span>"}function n(e,o){var t=Number(o);return/^[-+]/.test(o)?e.getCursor().line+t:t-1}e.defineOption("search",{bottom:!1}),a(o,"dialog"),a(t,"getJumpDialog"),a(n,"interpretLine"),e.commands.jumpToLine=function(e){var r=e.getCursor();o(e,t(e),e.phrase("Jump to line:"),r.line+1+":"+r.ch,(function(o){var t;if(o)if(t=/^\s*([\+\-]?\d+)\s*\:\s*(\d+)\s*$/.exec(o))e.setCursor(n(e,t[1]),Number(t[2]));else if(t=/^\s*([\+\-]?\d+(\.\d+)?)\%\s*/.exec(o)){var i=Math.round(e.lineCount()*Number(t[1])/100);/^[-+]/.test(t[1])&&(i=r.line+i+1),e.setCursor(i-1,r.ch)}else(t=/^\s*\:?\s*([\+\-]?\d+)\s*/.exec(o))&&e.setCursor(n(e,t[1]),r.ch)}))},e.keyMap.default["Alt-G"]="jumpToLine"}(n.a.exports,r.a.exports);var l=s.exports,c=Object.freeze(u({__proto__:null,[Symbol.toStringTag]:"Module",default:l},[s.exports]))}}]);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[31],{81031:(e,o,n)=>{n.r(o),n.d(o,{a:()=>u,d:()=>c});var t=n(96539),r=Object.defineProperty,i=(e,o)=>r(e,"name",{value:o,configurable:!0});function a(e,o){return o.forEach((function(o){o&&"string"!=typeof o&&!Array.isArray(o)&&Object.keys(o).forEach((function(n){if("default"!==n&&!(n in e)){var t=Object.getOwnPropertyDescriptor(o,n);Object.defineProperty(e,n,t.get?t:{enumerable:!0,get:function(){return o[n]}})}}))})),Object.freeze(e)}i(a,"_mergeNamespaces");var u={exports:{}};!function(e){function o(o,n,t){var r,i=o.getWrapperElement();return(r=i.appendChild(document.createElement("div"))).className=t?"CodeMirror-dialog CodeMirror-dialog-bottom":"CodeMirror-dialog CodeMirror-dialog-top","string"==typeof n?r.innerHTML=n:r.appendChild(n),e.addClass(i,"dialog-opened"),r}function n(e,o){e.state.currentNotificationClose&&e.state.currentNotificationClose(),e.state.currentNotificationClose=o}i(o,"dialogDiv"),i(n,"closeNotification"),e.defineExtension("openDialog",(function(t,r,a){a||(a={}),n(this,null);var u=o(this,t,a.bottom),l=!1,c=this;function s(o){if("string"==typeof o)d.value=o;else{if(l)return;l=!0,e.rmClass(u.parentNode,"dialog-opened"),u.parentNode.removeChild(u),c.focus(),a.onClose&&a.onClose(u)}}i(s,"close");var f,d=u.getElementsByTagName("input")[0];return d?(d.focus(),a.value&&(d.value=a.value,!1!==a.selectValueOnOpen&&d.select()),a.onInput&&e.on(d,"input",(function(e){a.onInput(e,d.value,s)})),a.onKeyUp&&e.on(d,"keyup",(function(e){a.onKeyUp(e,d.value,s)})),e.on(d,"keydown",(function(o){a&&a.onKeyDown&&a.onKeyDown(o,d.value,s)||((27==o.keyCode||!1!==a.closeOnEnter&&13==o.keyCode)&&(d.blur(),e.e_stop(o),s()),13==o.keyCode&&r(d.value,o))})),!1!==a.closeOnBlur&&e.on(u,"focusout",(function(e){null!==e.relatedTarget&&s()}))):(f=u.getElementsByTagName("button")[0])&&(e.on(f,"click",(function(){s(),c.focus()})),!1!==a.closeOnBlur&&e.on(f,"blur",s),f.focus()),s})),e.defineExtension("openConfirm",(function(t,r,a){n(this,null);var u=o(this,t,a&&a.bottom),l=u.getElementsByTagName("button"),c=!1,s=this,f=1;function d(){c||(c=!0,e.rmClass(u.parentNode,"dialog-opened"),u.parentNode.removeChild(u),s.focus())}i(d,"close"),l[0].focus();for(var p=0;p<l.length;++p){var g=l[p];!function(o){e.on(g,"click",(function(n){e.e_preventDefault(n),d(),o&&o(s)}))}(r[p]),e.on(g,"blur",(function(){--f,setTimeout((function(){f<=0&&d()}),200)})),e.on(g,"focus",(function(){++f}))}})),e.defineExtension("openNotification",(function(t,r){n(this,s);var a,u=o(this,t,r&&r.bottom),l=!1,c=r&&void 0!==r.duration?r.duration:5e3;function s(){l||(l=!0,clearTimeout(a),e.rmClass(u.parentNode,"dialog-opened"),u.parentNode.removeChild(u))}return i(s,"close"),e.on(u,"click",(function(o){e.e_preventDefault(o),s()})),c&&(a=setTimeout(s,c)),s}))}(t.a.exports);var l=u.exports,c=Object.freeze(a({__proto__:null,[Symbol.toStringTag]:"Module",default:l},[u.exports]))}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[590],{84590:(e,o,t)=>{t.r(o);var n=t(96539),i=(t(71254),t(27378),t(31542),Object.defineProperty),r=(e,o)=>i(e,"name",{value:o,configurable:!0});function u(e){return{options:e instanceof Function?{render:e}:!0===e?{}:e}}function m(e){const o=e.state.info.options;return(null==o?void 0:o.hoverTime)||500}function s(e,o){const t=e.state.info,i=o.target||o.srcElement;if(!(i instanceof HTMLElement))return;if("SPAN"!==i.nodeName||void 0!==t.hoverTimeout)return;const u=i.getBoundingClientRect(),s=r((function(){clearTimeout(t.hoverTimeout),t.hoverTimeout=setTimeout(p,c)}),"onMouseMove"),f=r((function(){n.C.off(document,"mousemove",s),n.C.off(e.getWrapperElement(),"mouseout",f),clearTimeout(t.hoverTimeout),t.hoverTimeout=void 0}),"onMouseOut"),p=r((function(){n.C.off(document,"mousemove",s),n.C.off(e.getWrapperElement(),"mouseout",f),t.hoverTimeout=void 0,a(e,u)}),"onHover"),c=m(e);t.hoverTimeout=setTimeout(p,c),n.C.on(document,"mousemove",s),n.C.on(e.getWrapperElement(),"mouseout",f)}function a(e,o){const t=e.coordsChar({left:(o.left+o.right)/2,top:(o.top+o.bottom)/2}),n=e.state.info.options,i=n.render||e.getHelper(t,"info");if(i){const r=e.getTokenAt(t,!0);if(r){const u=i(r,n,e,t);u&&f(e,o,u)}}}function f(e,o,t){const i=document.createElement("div");i.className="CodeMirror-info",i.appendChild(t),document.body.appendChild(i);const u=i.getBoundingClientRect(),m=window.getComputedStyle(i),s=u.right-u.left+parseFloat(m.marginLeft)+parseFloat(m.marginRight),a=u.bottom-u.top+parseFloat(m.marginTop)+parseFloat(m.marginBottom);let f=o.bottom;a>window.innerHeight-o.bottom-15&&o.top>window.innerHeight-o.bottom&&(f=o.top-a),f<0&&(f=o.bottom);let p,c=Math.max(0,window.innerWidth-s-15);c>o.left&&(c=o.left),i.style.opacity="1",i.style.top=f+"px",i.style.left=c+"px";const l=r((function(){clearTimeout(p)}),"onMouseOverPopup"),d=r((function(){clearTimeout(p),p=setTimeout(v,200)}),"onMouseOut"),v=r((function(){n.C.off(i,"mouseover",l),n.C.off(i,"mouseout",d),n.C.off(e.getWrapperElement(),"mouseout",d),i.style.opacity?(i.style.opacity="0",setTimeout((()=>{i.parentNode&&i.parentNode.removeChild(i)}),600)):i.parentNode&&i.parentNode.removeChild(i)}),"hidePopup");n.C.on(i,"mouseover",l),n.C.on(i,"mouseout",d),n.C.on(e.getWrapperElement(),"mouseout",d)}n.C.defineOption("info",!1,((e,o,t)=>{if(t&&t!==n.C.Init){const o=e.state.info.onMouseOver;n.C.off(e.getWrapperElement(),"mouseover",o),clearTimeout(e.state.info.hoverTimeout),delete e.state.info}if(o){const t=e.state.info=u(o);t.onMouseOver=s.bind(null,e),n.C.on(e.getWrapperElement(),"mouseover",t.onMouseOver)}})),r(u,"createState"),r(m,"getHoverTime"),r(s,"onMouseOver"),r(a,"onMouseHover"),r(f,"showPopup")}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[688],{89663:(e,t,n)=>{n.r(t);var r=n(96539),l=n(71254),a=n(87756),i=(n(27378),n(31542),Object.defineProperty),s=(e,t)=>i(e,"name",{value:t,configurable:!0});function o(e,t){var n,r;const l=e.levels;return((l&&0!==l.length?l[l.length-1]-((null===(n=this.electricInput)||void 0===n?void 0:n.test(t))?1:0):e.indentLevel)||0)*((null===(r=this.config)||void 0===r?void 0:r.indentUnit)||0)}s(o,"indent");const u=s((e=>{const t=(0,a.o)({eatWhitespace:e=>e.eatWhile(l.i),lexRules:l.L,parseRules:l.P,editorConfig:{tabSize:e.tabSize}});return{config:e,startState:t.startState,token:t.token,indent:o,electricInput:/^\s*[})\]]/,fold:"brace",lineComment:"#",closeBrackets:{pairs:'()[]{}""',explode:"()[]{}"}}}),"graphqlModeFactory");r.C.defineMode("graphql",u)},87756:(e,t,n)=>{n.d(t,{o:()=>s});var r=n(71254),l=n(57554),a=Object.defineProperty,i=(e,t)=>a(e,"name",{value:t,configurable:!0});function s(e={eatWhitespace:e=>e.eatWhile(r.i),lexRules:r.L,parseRules:r.P,editorConfig:{}}){return{startState(){const t={level:0,step:0,name:null,kind:null,type:null,rule:null,needsSeparator:!1,prevState:null};return p(e.parseRules,t,l.h.DOCUMENT),t},token:(t,n)=>o(t,n,e)}}function o(e,t,n){var r;if(t.inBlockstring)return e.match(/.*"""/)?(t.inBlockstring=!1,"string"):(e.skipToEnd(),"string");const{lexRules:l,parseRules:a,eatWhitespace:i,editorConfig:s}=n;if(t.rule&&0===t.rule.length?d(t):t.needsAdvance&&(t.needsAdvance=!1,f(t,!0)),e.sol()){const n=(null==s?void 0:s.tabSize)||2;t.indentLevel=Math.floor(e.indentation()/n)}if(i(e))return"ws";const o=S(l,e);if(!o)return e.match(/\S+/)||e.match(/\s/),p(c,t,"Invalid"),"invalidchar";if("Comment"===o.kind)return p(c,t,"Comment"),"comment";const v=u({},t);if("Punctuation"===o.kind)if(/^[{([]/.test(o.value))void 0!==t.indentLevel&&(t.levels=(t.levels||[]).concat(t.indentLevel+1));else if(/^[})\]]/.test(o.value)){const e=t.levels=(t.levels||[]).slice(0,-1);t.indentLevel&&e.length>0&&e[e.length-1]<t.indentLevel&&(t.indentLevel=e[e.length-1])}for(;t.rule;){let n="function"==typeof t.rule?0===t.step?t.rule(o,e):null:t.rule[t.step];if(t.needsSeparator&&(n=null==n?void 0:n.separator),n){if(n.ofRule&&(n=n.ofRule),"string"==typeof n){p(a,t,n);continue}if(null===(r=n.match)||void 0===r?void 0:r.call(n,o))return n.update&&n.update(t,o),"Punctuation"===o.kind?f(t,!0):t.needsAdvance=!0,n.style}h(t)}return u(t,v),p(c,t,"Invalid"),"invalidchar"}function u(e,t){const n=Object.keys(t);for(let r=0;r<n.length;r++)e[n[r]]=t[n[r]];return e}i(s,"onlineParser"),i(o,"getToken"),i(u,"assign");const c={Invalid:[],Comment:[]};function p(e,t,n){if(!e[n])throw new TypeError("Unknown rule: "+n);t.prevState=Object.assign({},t),t.kind=n,t.name=null,t.type=null,t.rule=e[n],t.step=0,t.needsSeparator=!1}function d(e){e.prevState&&(e.kind=e.prevState.kind,e.name=e.prevState.name,e.type=e.prevState.type,e.rule=e.prevState.rule,e.step=e.prevState.step,e.needsSeparator=e.prevState.needsSeparator,e.prevState=e.prevState.prevState)}function f(e,t){var n;if(v(e)&&e.rule){const n=e.rule[e.step];if(n.separator){const t=n.separator;if(e.needsSeparator=!e.needsSeparator,!e.needsSeparator&&t.ofRule)return}if(t)return}for(e.needsSeparator=!1,e.step++;e.rule&&!(Array.isArray(e.rule)&&e.step<e.rule.length);)d(e),e.rule&&(v(e)?(null===(n=e.rule)||void 0===n?void 0:n[e.step].separator)&&(e.needsSeparator=!e.needsSeparator):(e.needsSeparator=!1,e.step++))}function v(e){const t=Array.isArray(e.rule)&&"string"!=typeof e.rule[e.step]&&e.rule[e.step];return t&&t.isList}function h(e){for(;e.rule&&(!Array.isArray(e.rule)||!e.rule[e.step].ofRule);)d(e);e.rule&&f(e,!1)}function S(e,t){const n=Object.keys(e);for(let r=0;r<n.length;r++){const l=t.match(e[n[r]]);if(l&&l instanceof Array)return{kind:n[r],value:l[0]}}}i(p,"pushRule"),i(d,"popRule"),i(f,"advanceRule"),i(v,"isList"),i(h,"unsuccessful"),i(S,"lex")}}]);

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[725],{43725:(e,r,n)=>{n.r(r),n.d(r,{b:()=>s});var t=n(96539),i=Object.defineProperty,o=(e,r)=>i(e,"name",{value:r,configurable:!0});function l(e,r){return r.forEach((function(r){r&&"string"!=typeof r&&!Array.isArray(r)&&Object.keys(r).forEach((function(n){if("default"!==n&&!(n in e)){var t=Object.getOwnPropertyDescriptor(r,n);Object.defineProperty(e,n,t.get?t:{enumerable:!0,get:function(){return r[n]}})}}))})),Object.freeze(e)}o(l,"_mergeNamespaces");var f={exports:{}};!function(e){function r(r){return function(n,t){var i=t.line,l=n.getLine(i);function f(r){for(var o,f=t.ch,a=0;;){var s=f<=0?-1:l.lastIndexOf(r[0],f-1);if(-1!=s){if(1==a&&s<t.ch)break;if(o=n.getTokenTypeAt(e.Pos(i,s+1)),!/^(comment|string)/.test(o))return{ch:s+1,tokenType:o,pair:r};f=s-1}else{if(1==a)break;a=1,f=l.length}}}function a(r){var t,o,l=1,f=n.lastLine(),a=r.ch;e:for(var s=i;s<=f;++s)for(var u=n.getLine(s),c=s==i?a:0;;){var g=u.indexOf(r.pair[0],c),p=u.indexOf(r.pair[1],c);if(g<0&&(g=u.length),p<0&&(p=u.length),(c=Math.min(g,p))==u.length)break;if(n.getTokenTypeAt(e.Pos(s,c+1))==r.tokenType)if(c==g)++l;else if(!--l){t=s,o=c;break e}++c}return null==t||i==t?null:{from:e.Pos(i,a),to:e.Pos(t,o)}}o(f,"findOpening"),o(a,"findRange");for(var s=[],u=0;u<r.length;u++){var c=f(r[u]);c&&s.push(c)}for(s.sort((function(e,r){return e.ch-r.ch})),u=0;u<s.length;u++){var g=a(s[u]);if(g)return g}return null}}o(r,"bracketFolding"),e.registerHelper("fold","brace",r([["{","}"],["[","]"]])),e.registerHelper("fold","brace-paren",r([["{","}"],["[","]"],["(",")"]])),e.registerHelper("fold","import",(function(r,n){function t(n){if(n<r.firstLine()||n>r.lastLine())return null;var t=r.getTokenAt(e.Pos(n,1));if(/\S/.test(t.string)||(t=r.getTokenAt(e.Pos(n,t.end+1))),"keyword"!=t.type||"import"!=t.string)return null;for(var i=n,o=Math.min(r.lastLine(),n+10);i<=o;++i){var l=r.getLine(i).indexOf(";");if(-1!=l)return{startCh:t.end,end:e.Pos(i,l)}}}o(t,"hasImport");var i,l=n.line,f=t(l);if(!f||t(l-1)||(i=t(l-2))&&i.end.line==l-1)return null;for(var a=f.end;;){var s=t(a.line+1);if(null==s)break;a=s.end}return{from:r.clipPos(e.Pos(l,f.startCh+1)),to:a}})),e.registerHelper("fold","include",(function(r,n){function t(n){if(n<r.firstLine()||n>r.lastLine())return null;var t=r.getTokenAt(e.Pos(n,1));return/\S/.test(t.string)||(t=r.getTokenAt(e.Pos(n,t.end+1))),"meta"==t.type&&"#include"==t.string.slice(0,8)?t.start+8:void 0}o(t,"hasInclude");var i=n.line,l=t(i);if(null==l||null!=t(i-1))return null;for(var f=i;null!=t(f+1);)++f;return{from:e.Pos(i,l+1),to:r.clipPos(e.Pos(f))}}))}(t.a.exports);var a=f.exports,s=Object.freeze(l({__proto__:null,[Symbol.toStringTag]:"Module",default:a},[f.exports]))}}]);

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[729],{68729:(e,n,r)=>{r.r(n);var t=r(96539),a=r(84553),i=(r(71254),r(27378),r(31542),Object.defineProperty),s=(e,n)=>i(e,"name",{value:n,configurable:!0});function c(e){o=e,u=e.length,l=d=f=-1,x(),O();const n=h();return g("EOF"),n}let o,u,l,d,f,p,b;function h(){const e=l,n=[];if(g("{"),!E("}")){do{n.push(m())}while(E(","));g("}")}return{kind:"Object",start:e,end:f,members:n}}function m(){const e=l,n="String"===b?y():null;g("String"),g(":");const r=v();return{kind:"Member",start:e,end:f,key:n,value:r}}function k(){const e=l,n=[];if(g("["),!E("]")){do{n.push(v())}while(E(","));g("]")}return{kind:"Array",start:e,end:f,values:n}}function v(){switch(b){case"[":return k();case"{":return h();case"String":case"Number":case"Boolean":case"Null":const e=y();return O(),e}g("Value")}function y(){return{kind:b,start:l,end:d,value:JSON.parse(o.slice(l,d))}}function g(e){if(b===e)return void O();let n;if("EOF"===b)n="[end of file]";else if(d-l>1)n="`"+o.slice(l,d)+"`";else{const e=o.slice(l).match(/^.+?\b/);n="`"+(e?e[0]:o[l])+"`"}throw N(`Expected ${e} but found ${n}.`)}s(c,"jsonParse"),s(h,"parseObj"),s(m,"parseMember"),s(k,"parseArr"),s(v,"parseVal"),s(y,"curToken"),s(g,"expect");class w extends Error{constructor(e,n){super(e),this.position=n}}function N(e){return new w(e,{start:l,end:d})}function E(e){if(b===e)return O(),!0}function x(){return d<u&&(d++,p=d===u?0:o.charCodeAt(d)),p}function O(){for(f=d;9===p||10===p||13===p||32===p;)x();if(0!==p){switch(l=d,p){case 34:return b="String",S();case 45:case 48:case 49:case 50:case 51:case 52:case 53:case 54:case 55:case 56:case 57:return b="Number",j();case 102:if("false"!==o.slice(l,l+5))break;return d+=4,x(),void(b="Boolean");case 110:if("null"!==o.slice(l,l+4))break;return d+=3,x(),void(b="Null");case 116:if("true"!==o.slice(l,l+4))break;return d+=3,x(),void(b="Boolean")}b=o[l],x()}else b="EOF"}function S(){for(x();34!==p&&p>31;)if(92===p)switch(p=x(),p){case 34:case 47:case 92:case 98:case 102:case 110:case 114:case 116:x();break;case 117:x(),$(),$(),$(),$();break;default:throw N("Bad character escape sequence.")}else{if(d===u)throw N("Unterminated string.");x()}if(34!==p)throw N("Unterminated string.");x()}function $(){if(p>=48&&p<=57||p>=65&&p<=70||p>=97&&p<=102)return x();throw N("Expected hexadecimal digit.")}function j(){45===p&&x(),48===p?x():F(),46===p&&(x(),F()),69!==p&&101!==p||(p=x(),43!==p&&45!==p||x(),F())}function F(){if(p<48||p>57)throw N("Expected decimal digit.");do{x()}while(p>=48&&p<=57)}function T(e,n,r){const t=[];return r.members.forEach((r=>{var a;if(r){const i=null===(a=r.key)||void 0===a?void 0:a.value,s=n[i];s?B(s,r.value).forEach((([n,r])=>{t.push(V(e,n,r))})):t.push(V(e,r.key,`Variable "$${i}" does not appear in any GraphQL query.`))}})),t}function B(e,n){if(!e||!n)return[];if(e instanceof a.bM)return"Null"===n.kind?[[n,`Type "${e}" is non-nullable and cannot be null.`]]:B(e.ofType,n);if("Null"===n.kind)return[];if(e instanceof a.p2){const r=e.ofType;return"Array"===n.kind?C(n.values||[],(e=>B(r,e))):B(r,n)}if(e instanceof a.sR){if("Object"!==n.kind)return[[n,`Type "${e}" must be an Object.`]];const r=Object.create(null),t=C(n.members,(n=>{var t;const a=null===(t=null==n?void 0:n.key)||void 0===t?void 0:t.value;r[a]=!0;const i=e.getFields()[a];return i?B(i?i.type:void 0,n.value):[[n.key,`Type "${e}" does not have a field "${a}".`]]}));return Object.keys(e.getFields()).forEach((i=>{r[i]||e.getFields()[i].type instanceof a.bM&&t.push([n,`Object of type "${e}" is missing required field "${i}".`])})),t}return"Boolean"===e.name&&"Boolean"!==n.kind||"String"===e.name&&"String"!==n.kind||"ID"===e.name&&"Number"!==n.kind&&"String"!==n.kind||"Float"===e.name&&"Number"!==n.kind||"Int"===e.name&&("Number"!==n.kind||(0|n.value)!==n.value)||(e instanceof a.mR||e instanceof a.n2)&&("String"!==n.kind&&"Number"!==n.kind&&"Boolean"!==n.kind&&"Null"!==n.kind||A(e.parseValue(n.value)))?[[n,`Expected value of type "${e}".`]]:[]}function V(e,n,r){return{message:r,severity:"error",type:"validation",from:e.posFromIndex(n.start),to:e.posFromIndex(n.end)}}function A(e){return null==e||e!=e}function C(e,n){return Array.prototype.concat.apply([],e.map(n))}s(w,"JSONSyntaxError"),s(N,"syntaxError"),s(E,"skip"),s(x,"ch"),s(O,"lex"),s(S,"readString"),s($,"readHex"),s(j,"readNumber"),s(F,"readDigits"),t.C.registerHelper("lint","graphql-variables",((e,n,r)=>{if(!e)return[];let t;try{t=c(e)}catch(e){if(e instanceof w)return[V(r,e.position,e.message)];throw e}const a=n.variableToType;return a?T(r,a,t):[]})),s(T,"validateVariables"),s(B,"validateValue"),s(V,"lintError"),s(A,"isNullish"),s(C,"mapCat")}}]);

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[732],{95772:(e,t,r)=>{r.r(t),r.d(t,{c:()=>c});var n=r(96539),a=Object.defineProperty,i=(e,t)=>a(e,"name",{value:t,configurable:!0});function s(e,t){return t.forEach((function(t){t&&"string"!=typeof t&&!Array.isArray(t)&&Object.keys(t).forEach((function(r){if("default"!==r&&!(r in e)){var n=Object.getOwnPropertyDescriptor(t,r);Object.defineProperty(e,r,n.get?n:{enumerable:!0,get:function(){return t[r]}})}}))})),Object.freeze(e)}i(s,"_mergeNamespaces");var o={exports:{}};!function(e){var t={pairs:"()[]{}''\"\"",closeBefore:")]}'\":;>",triples:"",explode:"[]{}"},r=e.Pos;function n(e,r){return"pairs"==r&&"string"==typeof e?e:"object"==typeof e&&null!=e[r]?e[r]:t[r]}e.defineOption("autoCloseBrackets",!1,(function(t,r,i){i&&i!=e.Init&&(t.removeKeyMap(a),t.state.closeBrackets=null),r&&(s(n(r,"pairs")),t.state.closeBrackets=r,t.addKeyMap(a))})),i(n,"getOption");var a={Backspace:c,Enter:f};function s(e){for(var t=0;t<e.length;t++){var r=e.charAt(t),n="'"+r+"'";a[n]||(a[n]=o(r))}}function o(e){return function(t){return p(t,e)}}function l(e){var t=e.state.closeBrackets;return!t||t.override?t:e.getModeAt(e.getCursor()).closeBrackets||t}function c(t){var a=l(t);if(!a||t.getOption("disableInput"))return e.Pass;for(var i=n(a,"pairs"),s=t.listSelections(),o=0;o<s.length;o++){if(!s[o].empty())return e.Pass;var c=d(t,s[o].head);if(!c||i.indexOf(c)%2!=0)return e.Pass}for(o=s.length-1;o>=0;o--){var f=s[o].head;t.replaceRange("",r(f.line,f.ch-1),r(f.line,f.ch+1),"+delete")}}function f(t){var r=l(t),a=r&&n(r,"explode");if(!a||t.getOption("disableInput"))return e.Pass;for(var i=t.listSelections(),s=0;s<i.length;s++){if(!i[s].empty())return e.Pass;var o=d(t,i[s].head);if(!o||a.indexOf(o)%2!=0)return e.Pass}t.operation((function(){var e=t.lineSeparator()||"\n";t.replaceSelection(e+e,null),u(t,-1),i=t.listSelections();for(var r=0;r<i.length;r++){var n=i[r].head.line;t.indentLine(n,null,!0),t.indentLine(n+1,null,!0)}}))}function u(e,t){for(var r=[],n=e.listSelections(),a=0,i=0;i<n.length;i++){var s=n[i];s.head==e.getCursor()&&(a=i);var o=s.head.ch||t>0?{line:s.head.line,ch:s.head.ch+t}:{line:s.head.line-1};r.push({anchor:o,head:o})}e.setSelections(r,a)}function h(t){var n=e.cmpPos(t.anchor,t.head)>0;return{anchor:new r(t.anchor.line,t.anchor.ch+(n?-1:1)),head:new r(t.head.line,t.head.ch+(n?1:-1))}}function p(t,a){var i=l(t);if(!i||t.getOption("disableInput"))return e.Pass;var s=n(i,"pairs"),o=s.indexOf(a);if(-1==o)return e.Pass;for(var c,f=n(i,"closeBefore"),p=n(i,"triples"),d=s.charAt(o+1)==a,v=t.listSelections(),b=o%2==0,k=0;k<v.length;k++){var S,y=v[k],O=y.head,P=t.getRange(O,r(O.line,O.ch+1));if(b&&!y.empty())S="surround";else if(!d&&b||P!=a)if(d&&O.ch>1&&p.indexOf(a)>=0&&t.getRange(r(O.line,O.ch-2),O)==a+a){if(O.ch>2&&/\bstring/.test(t.getTokenTypeAt(r(O.line,O.ch-2))))return e.Pass;S="addFour"}else if(d){var x=0==O.ch?" ":t.getRange(r(O.line,O.ch-1),O);if(e.isWordChar(P)||x==a||e.isWordChar(x))return e.Pass;S="both"}else{if(!b||!(0===P.length||/\s/.test(P)||f.indexOf(P)>-1))return e.Pass;S="both"}else S=d&&g(t,O)?"both":p.indexOf(a)>=0&&t.getRange(O,r(O.line,O.ch+3))==a+a+a?"skipThree":"skip";if(c){if(c!=S)return e.Pass}else c=S}var A=o%2?s.charAt(o-1):a,m=o%2?a:s.charAt(o+1);t.operation((function(){if("skip"==c)u(t,1);else if("skipThree"==c)u(t,3);else if("surround"==c){for(var e=t.getSelections(),r=0;r<e.length;r++)e[r]=A+e[r]+m;for(t.replaceSelections(e,"around"),e=t.listSelections().slice(),r=0;r<e.length;r++)e[r]=h(e[r]);t.setSelections(e)}else"both"==c?(t.replaceSelection(A+m,null),t.triggerElectric(A+m),u(t,-1)):"addFour"==c&&(t.replaceSelection(A+A+A+A,"before"),u(t,1))}))}function d(e,t){var n=e.getRange(r(t.line,t.ch-1),r(t.line,t.ch+1));return 2==n.length?n:null}function g(e,t){var n=e.getTokenAt(r(t.line,t.ch+1));return/\bstring/.test(n.type)&&n.start==t.ch&&(0==t.ch||!/\bstring/.test(e.getTokenTypeAt(t)))}i(s,"ensureBound"),s(t.pairs+"`"),i(o,"handler"),i(l,"getConfig"),i(c,"handleBackspace"),i(f,"handleEnter"),i(u,"moveSel"),i(h,"contractSelection"),i(p,"handleChar"),i(d,"charsAround"),i(g,"stringStartsAfter")}(n.a.exports);var l=o.exports,c=Object.freeze(s({__proto__:null,[Symbol.toStringTag]:"Module",default:l},[o.exports]))}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[783],{37783:(e,t,n)=>{n.r(t);var r=n(96539),l=n(71254),a=n(87756),u=(n(27378),n(31542),Object.defineProperty),i=(e,t)=>u(e,"name",{value:t,configurable:!0});function s(e,t){var n,r;const l=e.levels;return((l&&0!==l.length?l[l.length-1]-((null===(n=this.electricInput)||void 0===n?void 0:n.test(t))?1:0):e.indentLevel)||0)*((null===(r=this.config)||void 0===r?void 0:r.indentUnit)||0)}r.C.defineMode("graphql-variables",(e=>{const t=(0,a.o)({eatWhitespace:e=>e.eatSpace(),lexRules:o,parseRules:c,editorConfig:{tabSize:e.tabSize}});return{config:e,startState:t.startState,token:t.token,indent:s,electricInput:/^\s*[}\]]/,fold:"brace",closeBrackets:{pairs:'[]{}""',explode:"[]{}"}}})),i(s,"indent");const o={Punctuation:/^\[|]|\{|\}|:|,/,Number:/^-?(?:0|(?:[1-9][0-9]*))(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?/,String:/^"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?/,Keyword:/^true|false|null/},c={Document:[(0,l.p)("{"),(0,l.l)("Variable",(0,l.o)((0,l.p)(","))),(0,l.p)("}")],Variable:[p("variable"),(0,l.p)(":"),"Value"],Value(e){switch(e.kind){case"Number":return"NumberValue";case"String":return"StringValue";case"Punctuation":switch(e.value){case"[":return"ListValue";case"{":return"ObjectValue"}return null;case"Keyword":switch(e.value){case"true":case"false":return"BooleanValue";case"null":return"NullValue"}return null}},NumberValue:[(0,l.t)("Number","number")],StringValue:[(0,l.t)("String","string")],BooleanValue:[(0,l.t)("Keyword","builtin")],NullValue:[(0,l.t)("Keyword","keyword")],ListValue:[(0,l.p)("["),(0,l.l)("Value",(0,l.o)((0,l.p)(","))),(0,l.p)("]")],ObjectValue:[(0,l.p)("{"),(0,l.l)("ObjectField",(0,l.o)((0,l.p)(","))),(0,l.p)("}")],ObjectField:[p("attribute"),(0,l.p)(":"),"Value"]};function p(e){return{style:e,match:e=>"String"===e.kind,update(e,t){e.name=t.value.slice(1,-1)}}}i(p,"namedKey")},87756:(e,t,n)=>{n.d(t,{o:()=>i});var r=n(71254),l=n(57554),a=Object.defineProperty,u=(e,t)=>a(e,"name",{value:t,configurable:!0});function i(e={eatWhitespace:e=>e.eatWhile(r.i),lexRules:r.L,parseRules:r.P,editorConfig:{}}){return{startState(){const t={level:0,step:0,name:null,kind:null,type:null,rule:null,needsSeparator:!1,prevState:null};return p(e.parseRules,t,l.h.DOCUMENT),t},token:(t,n)=>s(t,n,e)}}function s(e,t,n){var r;if(t.inBlockstring)return e.match(/.*"""/)?(t.inBlockstring=!1,"string"):(e.skipToEnd(),"string");const{lexRules:l,parseRules:a,eatWhitespace:u,editorConfig:i}=n;if(t.rule&&0===t.rule.length?d(t):t.needsAdvance&&(t.needsAdvance=!1,f(t,!0)),e.sol()){const n=(null==i?void 0:i.tabSize)||2;t.indentLevel=Math.floor(e.indentation()/n)}if(u(e))return"ws";const s=h(l,e);if(!s)return e.match(/\S+/)||e.match(/\s/),p(c,t,"Invalid"),"invalidchar";if("Comment"===s.kind)return p(c,t,"Comment"),"comment";const v=o({},t);if("Punctuation"===s.kind)if(/^[{([]/.test(s.value))void 0!==t.indentLevel&&(t.levels=(t.levels||[]).concat(t.indentLevel+1));else if(/^[})\]]/.test(s.value)){const e=t.levels=(t.levels||[]).slice(0,-1);t.indentLevel&&e.length>0&&e[e.length-1]<t.indentLevel&&(t.indentLevel=e[e.length-1])}for(;t.rule;){let n="function"==typeof t.rule?0===t.step?t.rule(s,e):null:t.rule[t.step];if(t.needsSeparator&&(n=null==n?void 0:n.separator),n){if(n.ofRule&&(n=n.ofRule),"string"==typeof n){p(a,t,n);continue}if(null===(r=n.match)||void 0===r?void 0:r.call(n,s))return n.update&&n.update(t,s),"Punctuation"===s.kind?f(t,!0):t.needsAdvance=!0,n.style}S(t)}return o(t,v),p(c,t,"Invalid"),"invalidchar"}function o(e,t){const n=Object.keys(t);for(let r=0;r<n.length;r++)e[n[r]]=t[n[r]];return e}u(i,"onlineParser"),u(s,"getToken"),u(o,"assign");const c={Invalid:[],Comment:[]};function p(e,t,n){if(!e[n])throw new TypeError("Unknown rule: "+n);t.prevState=Object.assign({},t),t.kind=n,t.name=null,t.type=null,t.rule=e[n],t.step=0,t.needsSeparator=!1}function d(e){e.prevState&&(e.kind=e.prevState.kind,e.name=e.prevState.name,e.type=e.prevState.type,e.rule=e.prevState.rule,e.step=e.prevState.step,e.needsSeparator=e.prevState.needsSeparator,e.prevState=e.prevState.prevState)}function f(e,t){var n;if(v(e)&&e.rule){const n=e.rule[e.step];if(n.separator){const t=n.separator;if(e.needsSeparator=!e.needsSeparator,!e.needsSeparator&&t.ofRule)return}if(t)return}for(e.needsSeparator=!1,e.step++;e.rule&&!(Array.isArray(e.rule)&&e.step<e.rule.length);)d(e),e.rule&&(v(e)?(null===(n=e.rule)||void 0===n?void 0:n[e.step].separator)&&(e.needsSeparator=!e.needsSeparator):(e.needsSeparator=!1,e.step++))}function v(e){const t=Array.isArray(e.rule)&&"string"!=typeof e.rule[e.step]&&e.rule[e.step];return t&&t.isList}function S(e){for(;e.rule&&(!Array.isArray(e.rule)||!e.rule[e.step].ofRule);)d(e);e.rule&&f(e,!1)}function h(e,t){const n=Object.keys(e);for(let r=0;r<n.length;r++){const l=t.match(e[n[r]]);if(l&&l instanceof Array)return{kind:n[r],value:l[0]}}}u(p,"pushRule"),u(d,"popRule"),u(f,"advanceRule"),u(v,"isList"),u(S,"unsuccessful"),u(h,"lex")}}]);

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[820],{91820:(e,t,n)=>{n.r(t);var r=n(96539),l=n(71254),a=n(87756),u=(n(27378),n(31542),Object.defineProperty);function i(e,t){var n,r;const l=e.levels;return((l&&0!==l.length?l[l.length-1]-((null===(n=this.electricInput)||void 0===n?void 0:n.test(t))?1:0):e.indentLevel)||0)*((null===(r=this.config)||void 0===r?void 0:r.indentUnit)||0)}r.C.defineMode("graphql-results",(e=>{const t=(0,a.o)({eatWhitespace:e=>e.eatSpace(),lexRules:s,parseRules:o,editorConfig:{tabSize:e.tabSize}});return{config:e,startState:t.startState,token:t.token,indent:i,electricInput:/^\s*[}\]]/,fold:"brace",closeBrackets:{pairs:'[]{}""',explode:"[]{}"}}})),u(i,"name",{value:"indent",configurable:!0});const s={Punctuation:/^\[|]|\{|\}|:|,/,Number:/^-?(?:0|(?:[1-9][0-9]*))(?:\.[0-9]*)?(?:[eE][+-]?[0-9]+)?/,String:/^"(?:[^"\\]|\\(?:"|\/|\\|b|f|n|r|t|u[0-9a-fA-F]{4}))*"?/,Keyword:/^true|false|null/},o={Document:[(0,l.p)("{"),(0,l.l)("Entry",(0,l.p)(",")),(0,l.p)("}")],Entry:[(0,l.t)("String","def"),(0,l.p)(":"),"Value"],Value(e){switch(e.kind){case"Number":return"NumberValue";case"String":return"StringValue";case"Punctuation":switch(e.value){case"[":return"ListValue";case"{":return"ObjectValue"}return null;case"Keyword":switch(e.value){case"true":case"false":return"BooleanValue";case"null":return"NullValue"}return null}},NumberValue:[(0,l.t)("Number","number")],StringValue:[(0,l.t)("String","string")],BooleanValue:[(0,l.t)("Keyword","builtin")],NullValue:[(0,l.t)("Keyword","keyword")],ListValue:[(0,l.p)("["),(0,l.l)("Value",(0,l.p)(",")),(0,l.p)("]")],ObjectValue:[(0,l.p)("{"),(0,l.l)("ObjectField",(0,l.p)(",")),(0,l.p)("}")],ObjectField:[(0,l.t)("String","property"),(0,l.p)(":"),"Value"]}},87756:(e,t,n)=>{n.d(t,{o:()=>i});var r=n(71254),l=n(57554),a=Object.defineProperty,u=(e,t)=>a(e,"name",{value:t,configurable:!0});function i(e={eatWhitespace:e=>e.eatWhile(r.i),lexRules:r.L,parseRules:r.P,editorConfig:{}}){return{startState(){const t={level:0,step:0,name:null,kind:null,type:null,rule:null,needsSeparator:!1,prevState:null};return p(e.parseRules,t,l.h.DOCUMENT),t},token:(t,n)=>s(t,n,e)}}function s(e,t,n){var r;if(t.inBlockstring)return e.match(/.*"""/)?(t.inBlockstring=!1,"string"):(e.skipToEnd(),"string");const{lexRules:l,parseRules:a,eatWhitespace:u,editorConfig:i}=n;if(t.rule&&0===t.rule.length?d(t):t.needsAdvance&&(t.needsAdvance=!1,f(t,!0)),e.sol()){const n=(null==i?void 0:i.tabSize)||2;t.indentLevel=Math.floor(e.indentation()/n)}if(u(e))return"ws";const s=g(l,e);if(!s)return e.match(/\S+/)||e.match(/\s/),p(c,t,"Invalid"),"invalidchar";if("Comment"===s.kind)return p(c,t,"Comment"),"comment";const v=o({},t);if("Punctuation"===s.kind)if(/^[{([]/.test(s.value))void 0!==t.indentLevel&&(t.levels=(t.levels||[]).concat(t.indentLevel+1));else if(/^[})\]]/.test(s.value)){const e=t.levels=(t.levels||[]).slice(0,-1);t.indentLevel&&e.length>0&&e[e.length-1]<t.indentLevel&&(t.indentLevel=e[e.length-1])}for(;t.rule;){let n="function"==typeof t.rule?0===t.step?t.rule(s,e):null:t.rule[t.step];if(t.needsSeparator&&(n=null==n?void 0:n.separator),n){if(n.ofRule&&(n=n.ofRule),"string"==typeof n){p(a,t,n);continue}if(null===(r=n.match)||void 0===r?void 0:r.call(n,s))return n.update&&n.update(t,s),"Punctuation"===s.kind?f(t,!0):t.needsAdvance=!0,n.style}S(t)}return o(t,v),p(c,t,"Invalid"),"invalidchar"}function o(e,t){const n=Object.keys(t);for(let r=0;r<n.length;r++)e[n[r]]=t[n[r]];return e}u(i,"onlineParser"),u(s,"getToken"),u(o,"assign");const c={Invalid:[],Comment:[]};function p(e,t,n){if(!e[n])throw new TypeError("Unknown rule: "+n);t.prevState=Object.assign({},t),t.kind=n,t.name=null,t.type=null,t.rule=e[n],t.step=0,t.needsSeparator=!1}function d(e){e.prevState&&(e.kind=e.prevState.kind,e.name=e.prevState.name,e.type=e.prevState.type,e.rule=e.prevState.rule,e.step=e.prevState.step,e.needsSeparator=e.prevState.needsSeparator,e.prevState=e.prevState.prevState)}function f(e,t){var n;if(v(e)&&e.rule){const n=e.rule[e.step];if(n.separator){const t=n.separator;if(e.needsSeparator=!e.needsSeparator,!e.needsSeparator&&t.ofRule)return}if(t)return}for(e.needsSeparator=!1,e.step++;e.rule&&!(Array.isArray(e.rule)&&e.step<e.rule.length);)d(e),e.rule&&(v(e)?(null===(n=e.rule)||void 0===n?void 0:n[e.step].separator)&&(e.needsSeparator=!e.needsSeparator):(e.needsSeparator=!1,e.step++))}function v(e){const t=Array.isArray(e.rule)&&"string"!=typeof e.rule[e.step]&&e.rule[e.step];return t&&t.isList}function S(e){for(;e.rule&&(!Array.isArray(e.rule)||!e.rule[e.step].ofRule);)d(e);e.rule&&f(e,!1)}function g(e,t){const n=Object.keys(e);for(let r=0;r<n.length;r++){const l=t.match(e[n[r]]);if(l&&l instanceof Array)return{kind:n[r],value:l[0]}}}u(p,"pushRule"),u(d,"popRule"),u(f,"advanceRule"),u(v,"isList"),u(S,"unsuccessful"),u(g,"lex")}}]);

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[829],{92823:(e,t,n)=>{function i(e,t){const n=[];let i=e;for(;null==i?void 0:i.kind;)n.push(i),i=i.prevState;for(let e=n.length-1;e>=0;e--)t(n[e])}n.d(t,{f:()=>i}),(0,Object.defineProperty)(i,"name",{value:"forEachState",configurable:!0})},63829:(e,t,n)=>{n.r(t);var i=n(96539),r=n(84553),l=n(62697),o=n(92823),s=(n(71254),n(27378),n(31542),Object.defineProperty),a=(e,t)=>s(e,"name",{value:t,configurable:!0});function c(e,t,n){const i=f(n,p(t.string));if(!i)return;const r=null!==t.type&&/"|\w/.test(t.string[0])?t.start:t.end;return{list:i,from:{line:e.line,ch:r},to:{line:e.line,ch:t.end}}}function f(e,t){return t?u(u(e.map((e=>({proximity:d(p(e.text),t),entry:e}))),(e=>e.proximity<=2)),(e=>!e.entry.isDeprecated)).sort(((e,t)=>(e.entry.isDeprecated?1:0)-(t.entry.isDeprecated?1:0)||e.proximity-t.proximity||e.entry.text.length-t.entry.text.length)).map((e=>e.entry)):u(e,(e=>!e.isDeprecated))}function u(e,t){const n=e.filter(t);return 0===n.length?e:n}function p(e){return e.toLowerCase().replace(/\W/g,"")}function d(e,t){let n=y(t,e);return e.length>t.length&&(n-=e.length-t.length-1,n+=0===e.indexOf(t)?0:.5),n}function y(e,t){let n,i;const r=[],l=e.length,o=t.length;for(n=0;n<=l;n++)r[n]=[n];for(i=1;i<=o;i++)r[0][i]=i;for(n=1;n<=l;n++)for(i=1;i<=o;i++){const l=e[n-1]===t[i-1]?0:1;r[n][i]=Math.min(r[n-1][i]+1,r[n][i-1]+1,r[n-1][i-1]+l),n>1&&i>1&&e[n-1]===t[i-2]&&e[n-2]===t[i-1]&&(r[n][i]=Math.min(r[n][i],r[n-2][i-2]+l))}return r[l][o]}function m(e,t,n){const i="Invalid"===t.state.kind?t.state.prevState:t.state,o=i.kind,s=i.step;if("Document"===o&&0===s)return c(e,t,[{text:"{"}]);const a=n.variableToType;if(!a)return;const f=g(a,t.state);if("Document"===o||"Variable"===o&&0===s)return c(e,t,Object.keys(a).map((e=>({text:`"${e}": `,type:a[e]}))));if(("ObjectValue"===o||"ObjectField"===o&&0===s)&&f.fields)return c(e,t,Object.keys(f.fields).map((e=>f.fields[e])).map((e=>({text:`"${e.name}": `,type:e.type,description:e.description}))));if("StringValue"===o||"NumberValue"===o||"BooleanValue"===o||"NullValue"===o||"ListValue"===o&&1===s||"ObjectField"===o&&2===s||"Variable"===o&&2===s){const n=f.type?(0,r.xC)(f.type):void 0;if(n instanceof r.sR)return c(e,t,[{text:"{"}]);if(n instanceof r.mR)return c(e,t,n.getValues().map((e=>({text:`"${e.name}"`,type:n,description:e.description}))));if(n===l.EZ)return c(e,t,[{text:"true",type:l.EZ,description:"Not false."},{text:"false",type:l.EZ,description:"Not true."}])}}function g(e,t){const n={type:null,fields:null};return(0,o.f)(t,(t=>{if("Variable"===t.kind)n.type=e[t.name];else if("ListValue"===t.kind){const e=n.type?(0,r.tf)(n.type):void 0;n.type=e instanceof r.p2?e.ofType:null}else if("ObjectValue"===t.kind){const e=n.type?(0,r.xC)(n.type):void 0;n.fields=e instanceof r.sR?e.getFields():null}else if("ObjectField"===t.kind){const e=t.name&&n.fields?n.fields[t.name]:null;n.type=null==e?void 0:e.type}})),n}a(c,"hintList"),a(f,"filterAndSortList"),a(u,"filterNonEmpty"),a(p,"normalizeText"),a(d,"getProximity"),a(y,"lexicalDistance"),i.C.registerHelper("hint","graphql-variables",((e,t)=>{const n=e.getCursor(),r=e.getTokenAt(n),l=m(n,r,t);return(null==l?void 0:l.list)&&l.list.length>0&&(l.from=i.C.Pos(l.from.line,l.from.ch),l.to=i.C.Pos(l.to.line,l.to.ch),i.C.signal(e,"hasCompletion",e,l,r)),l})),a(m,"getVariablesHint"),a(g,"getTypeInfo")}}]);

View File

@@ -0,0 +1 @@
"use strict";(self.webpackChunk=self.webpackChunk||[]).push([[906],{61906:(t,e,r)=>{r.r(e),r.d(e,{a:()=>o,m:()=>l});var n=r(96539),a=Object.defineProperty,c=(t,e)=>a(t,"name",{value:e,configurable:!0});function i(t,e){return e.forEach((function(e){e&&"string"!=typeof e&&!Array.isArray(e)&&Object.keys(e).forEach((function(r){if("default"!==r&&!(r in t)){var n=Object.getOwnPropertyDescriptor(e,r);Object.defineProperty(t,r,n.get?n:{enumerable:!0,get:function(){return e[r]}})}}))})),Object.freeze(t)}c(i,"_mergeNamespaces");var o={exports:{}};!function(t){var e=/MSIE \d/.test(navigator.userAgent)&&(null==document.documentMode||document.documentMode<8),r=t.Pos,n={"(":")>",")":"(<","[":"]>","]":"[<","{":"}>","}":"{<","<":">>",">":"<<"};function a(t){return t&&t.bracketRegex||/[(){}[\]]/}function i(t,e,c){var i=t.getLineHandle(e.line),s=e.ch-1,l=c&&c.afterCursor;null==l&&(l=/(^| )cm-fat-cursor($| )/.test(t.getWrapperElement().className));var h=a(c),u=!l&&s>=0&&h.test(i.text.charAt(s))&&n[i.text.charAt(s)]||h.test(i.text.charAt(s+1))&&n[i.text.charAt(++s)];if(!u)return null;var f=">"==u.charAt(1)?1:-1;if(c&&c.strict&&f>0!=(s==e.ch))return null;var g=t.getTokenTypeAt(r(e.line,s+1)),m=o(t,r(e.line,s+(f>0?1:0)),f,g,c);return null==m?null:{from:r(e.line,s),to:m&&m.pos,match:m&&m.ch==u.charAt(0),forward:f>0}}function o(t,e,c,i,o){for(var s=o&&o.maxScanLineLength||1e4,l=o&&o.maxScanLines||1e3,h=[],u=a(o),f=c>0?Math.min(e.line+l,t.lastLine()+1):Math.max(t.firstLine()-1,e.line-l),g=e.line;g!=f;g+=c){var m=t.getLine(g);if(m){var d=c>0?0:m.length-1,k=c>0?m.length:-1;if(!(m.length>s))for(g==e.line&&(d=e.ch-(c<0?1:0));d!=k;d+=c){var p=m.charAt(d);if(u.test(p)&&(void 0===i||(t.getTokenTypeAt(r(g,d+1))||"")==(i||""))){var v=n[p];if(v&&">"==v.charAt(1)==c>0)h.push(p);else{if(!h.length)return{pos:r(g,d),ch:p};h.pop()}}}}}return g-c!=(c>0?t.lastLine():t.firstLine())&&null}function s(t,n,a){for(var o=t.state.matchBrackets.maxHighlightLineLength||1e3,s=a&&a.highlightNonMatching,l=[],h=t.listSelections(),u=0;u<h.length;u++){var f=h[u].empty()&&i(t,h[u].head,a);if(f&&(f.match||!1!==s)&&t.getLine(f.from.line).length<=o){var g=f.match?"CodeMirror-matchingbracket":"CodeMirror-nonmatchingbracket";l.push(t.markText(f.from,r(f.from.line,f.from.ch+1),{className:g})),f.to&&t.getLine(f.to.line).length<=o&&l.push(t.markText(f.to,r(f.to.line,f.to.ch+1),{className:g}))}}if(l.length){e&&t.state.focused&&t.focus();var m=c((function(){t.operation((function(){for(var t=0;t<l.length;t++)l[t].clear()}))}),"clear");if(!n)return m;setTimeout(m,800)}}function l(t){t.operation((function(){t.state.matchBrackets.currentlyHighlighted&&(t.state.matchBrackets.currentlyHighlighted(),t.state.matchBrackets.currentlyHighlighted=null),t.state.matchBrackets.currentlyHighlighted=s(t,!1,t.state.matchBrackets)}))}function h(t){t.state.matchBrackets&&t.state.matchBrackets.currentlyHighlighted&&(t.state.matchBrackets.currentlyHighlighted(),t.state.matchBrackets.currentlyHighlighted=null)}c(a,"bracketRegex"),c(i,"findMatchingBracket"),c(o,"scanForBracket"),c(s,"matchBrackets"),c(l,"doMatchBrackets"),c(h,"clearHighlighted"),t.defineOption("matchBrackets",!1,(function(e,r,n){n&&n!=t.Init&&(e.off("cursorActivity",l),e.off("focus",l),e.off("blur",h),h(e)),r&&(e.state.matchBrackets="object"==typeof r?r:{},e.on("cursorActivity",l),e.on("focus",l),e.on("blur",h))})),t.defineExtension("matchBrackets",(function(){s(this,!0)})),t.defineExtension("findMatchingBracket",(function(t,e,r){return(r||"boolean"==typeof e)&&(r?(r.strict=e,e=r):e=e?{strict:!0}:null),i(this,t,e)})),t.defineExtension("scanForBracket",(function(t,e,r,n){return o(this,t,e,r,n)}))}(n.a.exports);var s=o.exports,l=Object.freeze(i({__proto__:null,[Symbol.toStringTag]:"Module",default:s},[o.exports]))}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,61 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/**
* Prism: Lightweight, robust, elegant syntax highlighting
*
* @license MIT <https://opensource.org/licenses/MIT>
* @author Lea Verou <https://lea.verou.me>
* @namespace
* @public
*/
/** @license React v0.19.1
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.13.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.14.0
* react-dom-server.browser.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.14.0
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.14.0
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,97 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/* @license
Papa Parse
v5.4.1
https://github.com/mholt/PapaParse
License: MIT
*/
/*!
* escape-html
* Copyright(c) 2012-2013 TJ Holowaychuk
* Copyright(c) 2015 Andreas Lubbe
* Copyright(c) 2015 Tiancheng "Timothy" Gu
* MIT Licensed
*/
/*!
* is-primitive <https://github.com/jonschlinkert/is-primitive>
*
* Copyright (c) 2014-present, Jon Schlinkert.
* Released under the MIT License.
*/
/*!
* isobject <https://github.com/jonschlinkert/isobject>
*
* Copyright (c) 2014-2017, Jon Schlinkert.
* Released under the MIT License.
*/
/*!
* set-value <https://github.com/jonschlinkert/set-value>
*
* Copyright (c) Jon Schlinkert (https://github.com/jonschlinkert).
* Released under the MIT License.
*/
/*! regenerator-runtime -- Copyright (c) 2014-present, Facebook, Inc. -- license (MIT): https://github.com/facebook/regenerator/blob/main/LICENSE */
/**
* Prism: Lightweight, robust, elegant syntax highlighting
*
* @license MIT <https://opensource.org/licenses/MIT>
* @author Lea Verou <https://lea.verou.me>
* @namespace
* @public
*/
/** @license React v0.19.1
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.13.1
* react-is.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.14.0
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.14.0
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v17.0.2
* react-jsx-runtime.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 637 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,32 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/** @license React v0.19.1
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.14.0
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.14.0
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,32 @@
/*
object-assign
(c) Sindre Sorhus
@license MIT
*/
/** @license React v0.19.1
* scheduler.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.14.0
* react-dom.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
/** @license React v16.14.0
* react.production.min.js
*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 106 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -0,0 +1,16 @@
/* eslint-disable */
/*
This file is added to .prettierignore too!
It is very important that the steps in here are done in the right order.
*/
// Setup the platform before anything else is loading
// This is a problem since we are calling the platform when importing
import '@noodl/platform-electron';
// Setup the tracker to send to Mixpanel,
// Very important that this is before anything else.
import './src/utils/tracker';
import './src/utils/bugtracker';

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,5 @@
export enum FeedbackType {
Success = 'success',
Notice = 'notice',
Danger = 'danger'
}

View File

@@ -0,0 +1,9 @@
export enum KeyCode {
Up = 38,
Down = 40,
Left = 37,
Right = 39,
ESC = 27,
Enter = 13,
Space = 32
}

View File

@@ -0,0 +1,14 @@
import { Keybinding } from '@noodl-utils/keyboard/Keybinding';
import { KeyCode, KeyMod } from '@noodl-utils/keyboard/KeyCode';
export namespace Keybindings {
export const REFRESH_PREVIEW = new Keybinding(KeyMod.CtrlCmd, KeyCode.KEY_R);
export const OPEN_DEVTOOLS = new Keybinding(KeyMod.CtrlCmd, KeyCode.KEY_D);
export const OPEN_CLOUD_DEVTOOLS = new Keybinding(KeyMod.CtrlCmd, KeyMod.Shift, KeyCode.KEY_R);
export const TOGGLE_PREVIEW_MODE = new Keybinding(KeyMod.CtrlCmd, KeyCode.KEY_T);
export const PROPERTY_PANEL_OPEN_DOCS = new Keybinding(KeyCode.F1);
export const PROPERTY_PANEL_EDIT_LABEL = new Keybinding(KeyCode.Enter);
export const PROPERTY_PANEL_EDIT_LABEL2 = new Keybinding(KeyCode.F2);
export const PROPERTY_PANEL_DELETE = new Keybinding(KeyCode.Delete); // Actually node graph delete
}

View File

@@ -0,0 +1,5 @@
export enum LoadingState {
Loading = 'is-loading',
Completed = 'is-completed',
Error = 'is-error'
}

View File

@@ -0,0 +1,5 @@
export const LocalStorageKey = {
lastSeenChangelogDate: 'lastSeenChangelogDate',
hasNewEditorVersionAvailable: 'hasNewEditorVersionAvailable',
devModeSignInUsername: 'devModeSignInUsername'
};

View File

@@ -0,0 +1,13 @@
export const NodeGraphColors = {
yellow: '#ffa300',
darkyellow: '#916311',
orange: '#df691a',
red: '#dc322f',
magenta: '#d33682',
violet: '#6c71c4',
blue: '#268bd2',
cyan: '#2aa198',
green: '#859900',
multiSelect: '#aaaaaa',
base2: undefined
};

View File

@@ -0,0 +1,8 @@
export enum NodeType {
Visual = 'visual',
Logic = 'logic',
Data = 'data',
Connection = 'component',
Custom = 'javascript',
None = 'none'
}

View File

@@ -0,0 +1,14 @@
import { createContext } from 'react';
export interface IModule {
id: string;
title: string;
}
export interface IModuleLibraryContext {
modules: IModule[];
}
const ModuleLibraryContext = createContext<IModuleLibraryContext>({
modules: null
});

View File

@@ -0,0 +1,176 @@
import React, { createContext, useContext, useCallback, useState, useEffect } from 'react';
import { ComponentModel } from '@noodl-models/componentmodel';
import { SidebarModel } from '@noodl-models/sidebar';
import { isComponentModel_CloudRuntime } from '@noodl-utils/NodeGraph';
import { Slot } from '@noodl-core-ui/types/global';
import { CenterToFitMode, NodeGraphEditor } from '../../views/nodegrapheditor';
type NodeGraphID = 'frontend' | 'backend';
interface NodeGraphControlSwitchOptions {
pushHistory: boolean;
selectSheet?: boolean;
breadcrumbs?: boolean;
node?: TSFixme;
}
export interface NodeGraphControlContext {
active: NodeGraphID;
nodeGraph: NodeGraphEditor;
switchToComponent(component: ComponentModel, options: NodeGraphControlSwitchOptions): void;
}
const NodeGraphContext = createContext<NodeGraphControlContext>({
active: null,
nodeGraph: null,
switchToComponent: null
});
export interface NodeGraphContextProviderProps {
children: Slot;
}
export class NodeGraphContextTmp {
public static active: NodeGraphControlContext['active'];
public static nodeGraph: NodeGraphControlContext['nodeGraph'];
public static switchToComponent: NodeGraphControlContext['switchToComponent'];
}
export function NodeGraphContextProvider({ children }: NodeGraphContextProviderProps) {
const [active, setActive] = useState<NodeGraphID>(null);
const [nodeGraph, setNodeGraph] = useState<NodeGraphEditor>(null);
//create node graph, and support hot reloading it
useEffect(() => {
function createNodeGraph() {
const newNodeGraph = new NodeGraphEditor({});
newNodeGraph.render();
return newNodeGraph;
}
let currentInstance = createNodeGraph();
setNodeGraph(currentInstance);
if (import.meta.webpackHot) {
import.meta.webpackHot.accept('../../views/nodegrapheditor', () => {
const activeComponent = currentInstance.activeComponent;
currentInstance.dispose();
const newInstance = createNodeGraph();
newInstance.switchToComponent(activeComponent);
setNodeGraph(newInstance);
currentInstance = newInstance;
});
}
return () => {
currentInstance.dispose();
};
}, []);
const switchToComponent: NodeGraphControlContext['switchToComponent'] = useCallback(
(component, options) => {
if (!component) return;
nodeGraph.switchToComponent(component, options);
},
[nodeGraph]
);
//switch sidebar panel when components are selected in the node graph
useEffect(() => {
if (!nodeGraph) return;
function _update(model: ComponentModel) {
if (isComponentModel_CloudRuntime(model)) {
setActive('backend');
if (SidebarModel.instance.ActiveId === 'components') {
SidebarModel.instance.switch('cloud-functions');
}
} else {
setActive('frontend');
if (SidebarModel.instance.ActiveId === 'cloud-functions') {
SidebarModel.instance.switch('components');
}
}
}
const eventGroup = {};
nodeGraph.on(
'activeComponentChanged',
({ model }: { model: ComponentModel }) => {
_update(model);
},
eventGroup
);
_update(nodeGraph.activeComponent);
return () => {
nodeGraph.off(eventGroup);
};
}, [nodeGraph]);
// Screenshot helper
useEffect(() => {
function setupScreenshot() {
window.resizeTo(1920, 1080);
// Something something Panel size = default
// Allow the resize to do it's thing first
setTimeout(() => {
nodeGraph.centerToFit(CenterToFitMode.AllNodes);
}, 50);
}
// @ts-expect-error
window.setupScreenshot = setupScreenshot;
return function () {
// @ts-expect-error
window.setupScreenshot = undefined;
};
}, []);
//set global on a singleton for code that can't access the react context
useEffect(() => {
if (!nodeGraph) return;
NodeGraphContextTmp.switchToComponent = switchToComponent;
NodeGraphContextTmp.nodeGraph = nodeGraph;
return () => {
NodeGraphContextTmp.active = null;
NodeGraphContextTmp.nodeGraph = null;
NodeGraphContextTmp.switchToComponent = null;
};
}, [nodeGraph]);
NodeGraphContextTmp.active = active;
return (
<NodeGraphContext.Provider
value={{
active,
nodeGraph,
switchToComponent
}}
>
{children}
</NodeGraphContext.Provider>
);
}
export function useNodeGraphContext() {
const context = useContext(NodeGraphContext);
if (context === undefined) {
throw new Error('useNodeGraphContext must be a child of NodeGraphContextProvider');
}
return context;
}

View File

@@ -0,0 +1,83 @@
import { useModel } from '@noodl-hooks/useModel';
import React, { createContext, useContext, useState, useEffect } from 'react';
import { ProjectModel } from '@noodl-models/projectmodel';
import { StylesModel } from '@noodl-models/StylesModel';
import { Slot } from '@noodl-core-ui/types/global';
import { DesignTokenColor, extractProjectColors } from './extractProjectColors';
export interface ProjectDesignTokenContext {
staticColors: DesignTokenColor[];
dynamicColors: DesignTokenColor[];
textStyles: TSFixme[];
}
const ProjectDesignTokenContext = createContext<ProjectDesignTokenContext>({
staticColors: [],
dynamicColors: [],
textStyles: []
});
export interface ProjectDesignTokenContextProps {
children: Slot;
}
export function ProjectDesignTokenContextProvider({ children }: ProjectDesignTokenContextProps) {
useModel(ProjectModel.instance);
const [group] = useState({});
const [staticColors, setStaticColors] = useState<DesignTokenColor[]>([]);
const [dynamicColors, setDynamicColors] = useState<DesignTokenColor[]>([]);
const [textStyles, setTextStyles] = useState<TSFixme[]>([]);
useEffect(() => {
const stylesModel = new StylesModel();
function extract() {
const styles = stylesModel.getStyles('colors');
const colors = extractProjectColors(ProjectModel.instance, styles);
const textStyles = stylesModel.getStyles('text');
setStaticColors(colors.staticColors);
setDynamicColors(colors.dynamicColors);
setTextStyles(textStyles);
}
stylesModel.on('stylesChanged', (args) => {
if (['colors', 'text'].includes(args.type)) {
extract();
}
});
extract();
return () => {
stylesModel.dispose();
ProjectModel.instance.off(group);
};
}, []);
return (
<ProjectDesignTokenContext.Provider
value={{
staticColors,
dynamicColors,
textStyles
}}
>
{children}
</ProjectDesignTokenContext.Provider>
);
}
export function useProjectDesignTokenContext() {
const context = useContext(ProjectDesignTokenContext);
if (context === undefined) {
throw new Error('useProjectDesignTokenContext must be a child of ProjectDesignTokenContextProvider');
}
return context;
}

View File

@@ -0,0 +1,64 @@
import { ProjectModel } from '@noodl-models/projectmodel';
export type DesignTokenColor = {
name: string;
color: string;
refs: string[];
};
export function extractProjectColors(
project: ProjectModel,
colorStyles: {
name: string;
style: string;
}[]
): {
staticColors: DesignTokenColor[];
dynamicColors: DesignTokenColor[];
} {
const colors: { [key: string]: DesignTokenColor } = {};
const components = project.getComponents();
components.forEach((c) => {
c.graph.forEachNode((node) => {
const colorPorts = node.getPorts('input').filter((p) => p.type === 'color');
const values = colorPorts.map((port) => node.getParameter(port.name));
values
.filter((name) => name)
.forEach((name) => {
if (!colors[name]) {
colors[name] = {
name,
color: null,
refs: []
};
}
colors[name].refs.push(node.type.name);
});
});
});
const staticColors = Object.values(colors)
.filter((c) => colorStyles.find((s) => s.name === c.name))
.sort((a, b) => a.name.localeCompare(b.name))
.map((x) => ({
name: x.name,
refs: x.refs,
color: ProjectModel.instance.resolveColor(x.name)
}));
const dynamicColors = Object.values(colors)
// remove all color styles from the list, so we only get the #HEX colors
.filter((c) => !colorStyles.find((s) => s.name === c.name))
.sort((a, b) => a.name.localeCompare(b.name))
.map((x) => ({
name: x.name,
refs: x.refs,
color: ProjectModel.instance.resolveColor(x.name)
}));
return {
staticColors,
dynamicColors
};
}

View File

@@ -0,0 +1 @@
export * from './ProjectDesignTokenContext';

View File

@@ -0,0 +1,24 @@
import { useEffect, useState } from 'react';
import { CloudService, Environment } from '@noodl-models/CloudServices';
import { ProjectModel } from '@noodl-models/projectmodel';
export function useActiveEnvironment(project: ProjectModel) {
const [environment, setEnvironment] = useState<Environment>(null);
const [group] = useState({});
useEffect(() => {
function update() {
CloudService.instance.getActiveEnvironment(project).then((env) => setEnvironment(env));
}
update();
project.on('cloudServicesChanged', update, group);
return function () {
project.off(group);
};
}, []);
return environment;
}

View File

@@ -0,0 +1,126 @@
import { useState } from 'react';
import { guid } from '@noodl-utils/utils';
import { ToastType } from '../views/ToastLayer/components/ToastCard';
import { ToastLayer } from '../views/ToastLayer/ToastLayer';
export interface ActivityQueue {
activities: string[];
hasActivity: boolean;
runActivity: (message: string, callback: () => Promise<ActivityResult>) => Promise<void>;
runQuietActivity(callback: (id: string) => Promise<void>): Promise<void>;
}
export type ActivityResult = {
type: ToastType;
message: string;
};
export interface UseActivityQueueOptions {
errorMessage?: string;
onSuccess?: () => Promise<void>;
onError?: () => Promise<void>;
}
/**
*
* @returns
*/
export function useActivityQueue({
errorMessage = 'Something went wrong',
onSuccess,
onError
}: UseActivityQueueOptions): ActivityQueue {
const [activities, setActivities] = useState<string[]>([]);
function addActivity(activityId: string) {
setActivities((value) => {
if (!value.includes(activityId)) {
value.push(activityId);
}
return value;
});
}
function removeActivity(activityId: string) {
setActivities((value) => {
if (value.includes(activityId)) {
return value.filter((x) => x !== activityId);
}
return value;
});
}
async function runActivity(message: string, callback: () => Promise<ActivityResult>): Promise<void> {
const activityId = guid();
addActivity(activityId);
ToastLayer.showActivity(message, activityId);
try {
const response = await callback();
ToastLayer.hideActivity(activityId);
switch (response.type) {
default:
case ToastType.Neutral:
ToastLayer.showInteraction(response.message);
break;
case ToastType.Danger:
ToastLayer.showError(response.message);
break;
case ToastType.Success:
ToastLayer.showSuccess(response.message);
break;
}
if (onSuccess) {
await onSuccess();
}
} catch (error) {
ToastLayer.hideActivity(activityId);
ToastLayer.showError(errorMessage);
if (onError) {
await onError();
}
throw error;
} finally {
removeActivity(activityId);
}
}
async function runQuietActivity(callback: (id: string) => Promise<void>): Promise<void> {
const activityId = guid();
addActivity(activityId);
try {
await callback(activityId);
if (onSuccess) {
await onSuccess();
}
} catch (error) {
ToastLayer.hideActivity(activityId);
ToastLayer.showError(errorMessage);
if (onError) {
await onError();
}
throw error;
} finally {
removeActivity(activityId);
}
}
return {
activities,
hasActivity: activities.length > 0,
runActivity,
runQuietActivity
};
}

View File

@@ -0,0 +1,23 @@
import { useCallback, useRef } from 'react';
import useOnUnmount from './useOnUnmount';
export default function useCallAfterNextRender() {
const rafIdRef = useRef<number>(-1);
useOnUnmount(() => {
cancelAnimationFrame(rafIdRef.current);
});
const callAfterNextRender = useCallback((callback: () => void) => {
cancelAnimationFrame(rafIdRef.current);
rafIdRef.current = requestAnimationFrame(() => {
rafIdRef.current = requestAnimationFrame(() => {
callback();
});
});
}, []);
return callAfterNextRender;
}

View File

@@ -0,0 +1,29 @@
import { useMemo } from 'react';
export enum CustomPropertyAnimation {
EasingBase = '--easing-base',
EasingEqual = '--easing-equal',
SpeedQuick = '--speed-quick',
SpeedBase = '--speed-base',
SpeedSlow = '--speed-slow'
}
export function useCustomPropertyValue(propertyName: CustomPropertyAnimation): any {
const styles = useMemo(() => getComputedStyle(document.documentElement), []);
const style = useMemo(() => {
const temp = styles.getPropertyValue(propertyName);
switch (propertyName) {
case CustomPropertyAnimation.SpeedQuick:
case CustomPropertyAnimation.SpeedBase:
case CustomPropertyAnimation.SpeedSlow:
return parseInt(temp);
default:
return temp;
}
}, [styles]);
return style;
}

View File

@@ -0,0 +1,14 @@
import React, { useEffect, useState } from 'react';
export function useDebounceState<T>(value: T, delay: number) {
const [debouncedValue, setDebouncedValue] = useState(value);
useEffect(() => {
const handler = setTimeout(() => {
setDebouncedValue(value);
}, delay);
return () => {
clearTimeout(handler);
};
}, [value, delay]);
return debouncedValue;
}

View File

@@ -0,0 +1,31 @@
import { useEffect, useState } from 'react';
export default function useDocumentScrollTimestamp(isEnabled = true, debounceMs = 0) {
const [timestamp, setTimestamp] = useState(Date.now());
useEffect(() => {
let debounceTimeoutId: ReturnType<typeof setTimeout>;
function onResize() {
clearTimeout(debounceTimeoutId);
debounceTimeoutId = setTimeout(() => setTimestamp(Date.now()), debounceMs);
}
function cleanup() {
document.removeEventListener('scroll', onResize, true);
clearTimeout(debounceTimeoutId);
}
if (isEnabled) {
document.addEventListener('scroll', onResize, true);
} else {
cleanup();
}
return () => {
cleanup();
};
}, [isEnabled, debounceMs]);
return timestamp;
}

View File

@@ -0,0 +1,81 @@
import { useEffect, useState, useCallback } from 'react';
export interface DragHandlerOptions {
root: React.MutableRefObject<HTMLElement>;
minWidth: number;
minHeight: number;
onStartDrag?: () => void;
onDrag?: (contentWidth: number, contentHeight: number) => void;
onEndDrag?: () => void;
}
export function useDragHandler(options: DragHandlerOptions) {
const [dragging, setDragging] = useState(false);
const [dragState, setDragState] = useState({
dragStartWidth: 0,
dragStartHeight: 0,
dragStartX: 0,
dragStartY: 0
});
useEffect(() => {
function drag(event: MouseEvent) {
const deltaX = event.pageX - dragState.dragStartX;
const deltaY = event.pageY - dragState.dragStartY;
const newWidth = Math.max(options.minWidth, dragState.dragStartWidth + deltaX);
const newHeight = Math.max(options.minHeight, dragState.dragStartHeight + deltaY);
setDragState({
dragStartX: event.pageX,
dragStartY: event.pageY,
dragStartWidth: newWidth,
dragStartHeight: newHeight
});
options.onDrag && options.onDrag(newWidth, newHeight);
return false;
}
function endDrag(_event: MouseEvent) {
setDragging(false);
document.removeEventListener('mousemove', drag, true);
document.removeEventListener('mouseup', endDrag, true);
options.onEndDrag && options.onEndDrag();
return false;
}
if (dragging) {
document.addEventListener('mousemove', drag, true);
document.addEventListener('mouseup', endDrag, true);
}
return function () {
document.removeEventListener('mousemove', drag, true);
document.removeEventListener('mouseup', endDrag, true);
};
}, [dragging]);
const startDrag = useCallback((event: { pageX: number; pageY: number }) => {
setDragging(true);
setDragState({
dragStartX: event.pageX,
dragStartY: event.pageY,
dragStartWidth: options.root.current.offsetWidth,
dragStartHeight: options.root.current.offsetHeight
});
options.onStartDrag && options.onStartDrag();
return false;
}, []);
return {
startDrag
};
}

View File

@@ -0,0 +1,23 @@
import { useEffect, useState } from 'react';
export default function useFetch(url: string, options: Object = {}) {
const [response, setResponse] = useState(null);
const [error, setError] = useState(null);
useEffect(() => {
const fetchData = async () => {
try {
const res = await fetch(url, options);
const json = await res.json();
setResponse(json);
} catch (error) {
setError(error);
}
};
fetchData();
}, []);
return { response, error };
}

View File

@@ -0,0 +1,53 @@
import { useEffect } from 'react';
import { SidebarModel } from '@noodl-models/sidebar';
import { SidebarModelEvent } from '@noodl-models/sidebar/sidebarmodel';
export function useFocusRefOnPanelActive(inputRef: React.MutableRefObject<HTMLElement>, panelId: string) {
useEffect(() => {
if (!inputRef.current) {
return;
}
const eventRef = {};
SidebarModel.instance.on(
SidebarModelEvent.activeChanged,
(activeId, previousActiveId) => {
if (activeId === panelId && panelId !== previousActiveId) {
//not sure why this timeout is required, but it doesn't work without it
setTimeout(() => {
inputRef.current?.focus();
}, 10);
}
},
eventRef
);
return () => {
SidebarModel.instance.off(eventRef);
};
}, [inputRef.current, panelId]);
}
export function useOnPanelActive(func: () => void, panelId: string) {
useEffect(() => {
const eventRef = {};
SidebarModel.instance.on(
SidebarModelEvent.activeChanged,
(activeId, previousActiveId) => {
if (activeId === panelId && panelId !== previousActiveId) {
//not sure why this timeout is required, but it doesn't work without it
setTimeout(() => {
func();
}, 10);
}
},
eventRef
);
return () => {
SidebarModel.instance.off(eventRef);
};
}, [func, panelId]);
}

View File

@@ -0,0 +1,38 @@
import { useEffect, useRef } from 'react';
type IntervalCallback = () => Promise<void>;
export function useInterval(callback: IntervalCallback, delay: number) {
const savedCallback = useRef<IntervalCallback>();
// Remember the latest callback.
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
let timeoutId: NodeJS.Timeout;
let cancelTimeout = false;
async function tick() {
try {
await savedCallback.current();
} catch (e) {
console.log(e);
}
if (!cancelTimeout && delay !== null) {
timeoutId = setTimeout(tick, delay);
}
}
if (delay !== null) {
tick();
}
return () => {
cancelTimeout = true;
clearTimeout(timeoutId);
};
}, [delay]);
}

View File

@@ -0,0 +1,21 @@
import { useEffect, useState } from 'react';
export function useIsOnline() {
const [isOnline, setIsOnline] = useState(navigator.onLine);
useEffect(() => {
function onStatusChanged() {
setIsOnline(navigator.onLine);
}
window.addEventListener('online', onStatusChanged);
window.addEventListener('offline', onStatusChanged);
return () => {
window.removeEventListener('online', onStatusChanged);
window.removeEventListener('offline', onStatusChanged);
};
}, []);
return isOnline;
}

View File

@@ -0,0 +1,47 @@
import { useModernModel } from '@noodl-hooks/useModel';
import { useEffect } from 'react';
import { SidebarModel } from '@noodl-models/sidebar';
import { SidebarModelEvent } from '@noodl-models/sidebar/sidebarmodel';
import KeyboardHandler, { KeyboardCommand } from '@noodl-utils/keyboardhandler';
export function useKeyboardCommands(createCommandsFn: () => KeyboardCommand[], deps?: React.DependencyList) {
useEffect(() => {
const commands = createCommandsFn();
KeyboardHandler.instance.registerCommands(commands);
return () => {
KeyboardHandler.instance.deregisterCommands(commands);
};
}, deps || []);
}
/**
* The Side Panel is always active,
* so lets unregister the commands while it is not visible.
*
* @param createCommandsFn
* @param panelId
* @param deps
*/
export function useSidePanelKeyboardCommands(
createCommandsFn: () => KeyboardCommand[],
panelId: string,
deps?: React.DependencyList
) {
const sidebarModel = useModernModel(SidebarModel.instance, [SidebarModelEvent.activeChanged]);
const activeId = sidebarModel.ActiveId;
useEffect(() => {
if (activeId !== panelId) return;
const commands = createCommandsFn();
KeyboardHandler.instance.registerCommands(commands);
return () => {
KeyboardHandler.instance.deregisterCommands(commands);
};
}, [...(deps || []), panelId, activeId]);
}

View File

@@ -0,0 +1,13 @@
import { useEffect } from 'react';
export default function useLogEffect(data: unknown, key?: string) {
console.warn('USING useLogEffect, REMOVE BEFORE DEPLOY');
useEffect(() => {
if (Boolean(key)) {
console.debug(key, data);
} else {
console.debug(data);
}
}, [data]);
}

View File

@@ -0,0 +1,77 @@
import { useEffect, useState } from 'react';
import { Model as ModernModel, ModelEventEnum } from '@noodl-utils/model';
import Model from '../../../shared/model';
/**
* const hosting = useModel(HostingModel.instance) // rerenders on all value updates
* const hosting = useModel(HostingModel.instance, ['FrontendsFetched']) // rerender on FrontendsFetched event only
*
* useModelCallback(HostingModel.instance, (data) => console.log(data)) // runs on all value updates
* useModelCallback(HostingModel.instance, (data) => console.log(data), ['FrontendsFetched']) // runs on FrontendsFetched event only
*/
export function useModel<TModel extends Model>(model: TModel, subscribedEvents?: string[]) {
// set and update timestamp to force a component reload
const [, setTimestamp] = useState(`${Date.now()}`);
const [group] = useState({});
useEffect(() => {
function attachListener(event) {
model.on(
'Model.' + event,
() => {
setTimestamp(`Model.${event}: ${Date.now()}`);
},
group
);
}
if (!subscribedEvents) {
for (const event in model.events) {
attachListener(event);
}
} else if (Array.isArray(subscribedEvents)) {
subscribedEvents.forEach((event) => attachListener(event));
}
return () => {
model.off(group);
};
}, []);
return model;
}
export function useModernModel<TModel extends ModernModel<TEnum>, TEnum extends ModelEventEnum = any>(
model: TModel,
subscribedEvents?: TEnum[]
) {
// set and update timestamp to force a component reload
const [, setTimestamp] = useState(`${Date.now()}`);
const [group] = useState({});
useEffect(() => {
function attachListener(event: TSFixme) {
model.on(
event,
() => {
setTimestamp(`${event}: ${Date.now()}`);
},
group
);
}
if (!subscribedEvents) {
attachListener('*');
} else if (Array.isArray(subscribedEvents)) {
subscribedEvents.forEach((event) => attachListener(event));
}
return () => {
model.off(group);
};
}, []);
return model;
}

View File

@@ -0,0 +1,23 @@
import { useEffect, useState } from 'react';
import { NodeLibrary } from '@noodl-models/nodelibrary';
export function useNodeLibraryLoaded() {
const [group] = useState({});
const [loaded, setLoaded] = useState(false);
useEffect(() => {
function update() {
setLoaded(NodeLibrary.instance.isLoaded());
}
update();
NodeLibrary.instance.on('libraryUpdated', update, group);
return function () {
NodeLibrary.instance.off(group);
};
}, []);
return loaded;
}

View File

@@ -0,0 +1,5 @@
import { useEffect, EffectCallback } from 'react';
export default function useOnMount(onMount: EffectCallback) {
useEffect(onMount, []);
}

View File

@@ -0,0 +1,5 @@
import useOnMount from './useOnMount';
export default function useOnUnmount(onUnmount: () => void) {
useOnMount(() => onUnmount);
}

View File

@@ -0,0 +1,20 @@
import { useMemo } from 'react';
export default function useParsedHref(href?: string) {
if (!href) return null;
const parsedHref = useMemo(() => {
let newHref = href.trim().replace(/\s/g, '');
if (/^(:\/\/)/.test(newHref)) {
return `http${newHref}`;
}
if (!/^(f|ht)tps?:\/\//i.test(newHref)) {
return `http://${newHref}`;
}
return newHref;
}, [href]);
return parsedHref;
}

View File

@@ -0,0 +1,11 @@
import { useRef, useEffect } from 'react';
export default function usePrevious<T = unknown>(value: T): T | undefined {
const ref = useRef<T | undefined>(undefined);
useEffect(() => {
ref.current = value;
});
return ref.current;
}

View File

@@ -0,0 +1,17 @@
import useTimeout from '@noodl-hooks/useTimeout';
import { useState } from 'react';
export function useRunOnExpire(onExpire: () => void, ms: number) {
const [isTimeoutRunning, setIsTimeoutRunning] = useState(false);
useTimeout(onExpire, isTimeoutRunning ? ms : null);
function startExpiration() {
setIsTimeoutRunning(true);
}
function cancelExpiration() {
setIsTimeoutRunning(false);
}
return [startExpiration, cancelExpiration];
}

View File

@@ -0,0 +1,95 @@
import React, { useState, useEffect, useRef, useCallback } from 'react';
interface ThrottleOptions<T = any> {
onChange?: (value: T) => void;
leading?: boolean;
trailing?: boolean;
}
const defaultOptions: ThrottleOptions = {
onChange: () => {},
leading: false,
trailing: true
};
function useThrottle<T>(value: T, delay: number, options: ThrottleOptions<T> = {}): T {
const [throttledValue, setThrottledValue] = useState(value);
const lastExecuted = useRef(Date.now());
const handler = useRef<NodeJS.Timeout | null>(null);
const componentMounted = useRef<boolean | null>(null);
const leadingCall = useRef(false);
const optionsRef = useRef<ThrottleOptions<T> | null>(null);
options = Object.assign({}, defaultOptions, options);
// Updating the options on every render, room for improvement
useEffect(() => {
optionsRef.current = options;
});
const clearHandler = useCallback(() => {
if (handler.current) clearTimeout(handler.current);
handler.current = null;
leadingCall.current = false;
}, []);
useEffect(() => {
componentMounted.current = true;
return () => {
// on component unmount
componentMounted.current = false;
};
}, []);
useEffect(() => {
if (optionsRef.current?.onChange) optionsRef.current.onChange(throttledValue);
}, [throttledValue]);
useEffect(() => {
if (handler.current) clearTimeout(handler.current);
if (leadingCall.current) {
leadingCall.current = false;
}
if (!handler.current && options.leading && !leadingCall.current) {
setThrottledValue(value);
leadingCall.current = true;
lastExecuted.current = Date.now();
}
handler.current = setTimeout(() => {
let shouldCallFunction = true;
if (options.leading && leadingCall.current) {
shouldCallFunction = false;
}
clearHandler();
if (componentMounted.current && options.trailing && shouldCallFunction) {
if (Date.now() - lastExecuted.current >= delay) {
setThrottledValue(value);
lastExecuted.current = Date.now();
}
}
}, delay - (Date.now() - lastExecuted.current));
return () => {
if (handler.current) clearTimeout(handler.current);
};
}, [value, delay, clearHandler, options.leading, options.trailing]);
return throttledValue;
}
function useThrottleState<T>(
initialValue: T,
delay: number,
options: ThrottleOptions<T> = {}
): [T, React.Dispatch<React.SetStateAction<T>>, T] {
const [value, setValue] = useState(initialValue);
const throttledValue = useThrottle(value, delay, options);
return [value, setValue, throttledValue];
}
export { useThrottle, useThrottleState };

View File

@@ -0,0 +1,20 @@
import { useEffect, useRef } from 'react';
export default function useTimeout(callback: () => void, delay: number) {
const timeoutRef = useRef(null);
const savedCallback = useRef(callback);
useEffect(() => {
savedCallback.current = callback;
}, [callback]);
useEffect(() => {
const tick = () => savedCallback.current();
if (typeof delay === 'number') {
timeoutRef.current = window.setTimeout(tick, delay);
return () => window.clearTimeout(timeoutRef.current);
}
}, [delay]);
return timeoutRef;
}

View File

@@ -0,0 +1,30 @@
import { useState } from 'react';
export function useTogglableArray<T = string | number>(): [
items: T[],
toggleItem: (value: T) => void,
isItemInArray: (value: T) => boolean,
clearArray: () => void
] {
const [items, setItems] = useState<T[]>([]);
function toggleItem(item: T) {
setItems((prev) => {
if (prev.includes(item)) {
return [...prev].filter((arrValue) => arrValue !== item);
} else {
return [...prev, item];
}
});
}
function isItemInArray(item: T) {
return items.includes(item);
}
function clearArray() {
setItems([]);
}
return [items, toggleItem, isItemInArray, clearArray];
}

View File

@@ -0,0 +1,23 @@
import { useState } from 'react';
export function useTriggerRerender() {
const [_, setTimestamp] = useState(0);
function triggerRender() {
const timestamp = Date.now();
setTimestamp(timestamp);
}
return triggerRender;
}
export function useTriggerRerenderState(): [number, () => void] {
const [time, setTimestamp] = useState(0);
function triggerRender() {
const timestamp = Date.now();
setTimestamp(timestamp);
}
return [time, triggerRender];
}

View File

@@ -0,0 +1,30 @@
import { useState, useEffect } from 'react';
function getWindowSize() {
return {
width: window.innerWidth,
height: window.innerHeight
};
}
export default function useWindowSize(debounceMs = 250) {
const [size, setSize] = useState(getWindowSize());
useEffect(() => {
let debounceTimeoutId: ReturnType<typeof setTimeout>;
function onResize() {
clearTimeout(debounceTimeoutId);
debounceTimeoutId = setTimeout(() => setSize(getWindowSize()), debounceMs);
}
window.addEventListener('resize', onResize);
return () => {
window.removeEventListener('resize', onResize);
clearTimeout(debounceTimeoutId);
};
}, [debounceMs]);
return size;
}

View File

@@ -0,0 +1,307 @@
import { NodeGraphContextTmp } from '@noodl-contexts/NodeGraphContext/NodeGraphContext';
import { filesystem } from '@noodl/platform';
import { AiCopilotContext } from '@noodl-models/AiAssistant/AiCopilotContext';
import { aiNodeTemplates } from '@noodl-models/AiAssistant/AiTemplates';
import { ChatHistory, ChatHistoryEvent } from '@noodl-models/AiAssistant/ChatHistory';
import { AiNodeTemplate, AiNodeTemplateType } from '@noodl-models/AiAssistant/interfaces';
import { ComponentModel } from '@noodl-models/componentmodel';
import { NodeGraphModel, NodeGraphNode, NodeGraphNodeSet } from '@noodl-models/nodegraphmodel';
import { ProjectModel } from '@noodl-models/projectmodel';
import { Model } from '@noodl-utils/model';
import { guid } from '@noodl-utils/utils';
import { EventDispatcher } from '../../../../shared/utils/EventDispatcher';
import { PopupItemType } from '../../views/Clippy/ClippyCommandsMetadata';
import { ToastLayer } from '../../views/ToastLayer/ToastLayer';
const docsTemplates = [
{
label: 'Read from database',
desc: 'Create a node that queries the database, filters and returns the results.',
examples: [
'Get all users that belong to the "Vendor" group',
'Get all products, sort from lowest to highest price',
'Get all unread messages for the currently logged in user'
],
primer: 'query.md',
prefix: 'const query = Noodl.Records.query;\n',
template: 'function-query-database'
},
{
label: 'Fetch REST API',
desc: 'Create a node that connects to an external REST API via a HTTP request and performs an action.',
examples: ['Get the main image from a wikipedia page', 'List the songs in a playlist in spotify'],
primer: 'rest.md',
template: 'rest'
},
{
label: 'Form Validation',
desc: 'Specify inputs and how you want them validated, the outputs are any validations and errors.',
examples: ['Validate a phone number and email'],
primer: 'validation.md',
template: 'function-form-validation'
},
{
label: 'AI Function',
desc: 'Create a function node that performs a task when you trigger Run, it can have inputs and outputs.',
examples: [
'Create inputs for Array1 and Array2 and output all items with the same ID',
'Get a random number between the min and max inputs',
'Get the current location of the device'
],
primer: 'function.md',
template: 'function'
},
{
label: 'Write to database',
desc: '',
examples: [],
template: 'function-crud'
},
{
label: '',
desc: '',
examples: [],
template: 'chart'
}
];
export type AiTemplate = {
id: string;
type: AiNodeTemplateType;
nodeName: string;
templateId: string;
template: AiNodeTemplate;
name: string;
description: string;
examples: string[];
promptUrl: string;
};
export enum AiAssistantEvent {
ProcessingUpdated,
ActivityUpdated
}
export type AiAssistantEvents = {
[AiAssistantEvent.ProcessingUpdated]: (nodeId: string) => void;
[AiAssistantEvent.ActivityUpdated]: () => void;
};
export interface AiActivityItem {
id: string;
type: PopupItemType;
title: string;
prompt: string;
node?: any;
graph?: ComponentModel;
}
async function deprecated_getAiDirPath() {
const relative = '.noodl/ai';
const path = filesystem.resolve(ProjectModel.instance._retainedProjectDirectory, relative);
if (!filesystem.exists(path)) {
await filesystem.makeDirectory(path);
}
return path;
}
export class AiAssistantModel extends Model<AiAssistantEvent, AiAssistantEvents> {
public static instance = new AiAssistantModel();
public templates: AiTemplate[] = docsTemplates.map(
(x): AiTemplate => ({
id: x.label,
type: aiNodeTemplates[x.template]?.type,
nodeName: aiNodeTemplates[x.template]?.name,
templateId: x.template,
template: aiNodeTemplates[x.template],
name: x.label,
description: x.desc,
examples: x.examples || [],
promptUrl: null
})
);
private _contexts: Record<string, AiCopilotContext> = {};
public activities: AiActivityItem[] = [];
constructor() {
super();
const _self = this;
EventDispatcher.instance.on(
['Model.nodeRemoved'],
function ({ args }: { args: { model: NodeGraphNode }; model: NodeGraphModel }) {
const nodeId = args.model.id;
if (_self._contexts[nodeId]) {
_self._contexts[nodeId].abortController.abort('node deleted');
delete _self._contexts[nodeId];
}
},
this
);
}
public addActivity({ id, type, title, prompt, node, graph }: AiActivityItem) {
this.activities.push({ id, type, title, prompt, node, graph });
this.notifyListeners(AiAssistantEvent.ActivityUpdated);
}
public removeActivity(id: AiActivityItem['id']) {
const activityTitle = this.activities.find((item) => item.id === id).title;
this.activities = this.activities.filter((item) => item.id !== id);
this.notifyListeners(AiAssistantEvent.ActivityUpdated);
ToastLayer.showInteraction(`AI finished the ${activityTitle} activity`);
}
/**
* @returns A list of all Node ids that are currently getting processed.
*/
public getProcessingNodeIds(): string[] {
return Object.keys(this._contexts).filter((x) => this._contexts[x].chatHistory.activities.length > 0);
}
public async createContext(node: NodeGraphNode) {
const aiAssistant = node.metadata.AiAssistant;
if (!aiAssistant) {
throw 'This node is not an AI node.';
}
if (this._contexts[node.id]) {
return this._contexts[node.id];
}
const chatHistory = ChatHistory.fromJSON(node.metadata.prompt);
// Backwards compatibility, load the AI file and fetch the template.
if (node.metadata.AiAssistant && !node.metadata.prompt) {
try {
const path = await deprecated_getAiDirPath();
const filePath = filesystem.resolve(path, node.metadata.AiAssistant);
if (filesystem.exists(filePath)) {
const json = await filesystem.readJson(filePath);
const messages = json.history || [];
messages.forEach((message) => {
chatHistory.add(message);
});
chatHistory.metadata.templateId = json.metadata.templateId;
// NOTE: Keeping this since it is used in other places to define it as AI node
node.metadata.AiAssistant = 'moved';
node.metadata.prompt = chatHistory.toJSON();
node.notifyListeners('metadataChanged', { key: 'prompt', data: node.metadata.prompt });
await filesystem.removeFile(filePath);
}
} catch (error) {
console.error('Failed to load old AI file.', error);
}
}
// HACK: It is loading it twice...
if (this._contexts[node.id]) {
return this._contexts[node.id];
}
chatHistory.on(ChatHistoryEvent.ActivitiesChanged, () => {
this.notifyListeners(AiAssistantEvent.ProcessingUpdated, node.id);
});
const template = this.templates.find((x) => x.templateId === chatHistory.metadata.templateId);
if (!template) {
throw 'Template not found';
}
const context = new AiCopilotContext(template, chatHistory, node);
this._contexts[node.id] = context;
return context;
}
public async send(context: AiCopilotContext) {
await context.template.template.onMessage(
// Send it as an object so the methods are bound to this class.
context.toObject(),
context.chatHistory.messages.length > 0
? context.chatHistory.messages[context.chatHistory.messages.length - 1]
: null
);
// Save the chat history
context.node.metadata.prompt = context.chatHistory.toJSON();
}
public async createNode(templateId: string, parentModel: NodeGraphNode, pos: TSFixme) {
function createNodes(nodeset: NodeGraphNodeSet, pos?: TSFixme, parentModel?: NodeGraphNode, toastMessage?: string) {
const nodes: NodeGraphNode[] = [];
if (parentModel) {
for (const node of nodeset.nodes) {
parentModel.addChild(node);
nodes.push(node);
}
} else {
const nodeGraph = NodeGraphContextTmp.nodeGraph;
const insertedNodeset = nodeGraph.insertNodeSet({
nodeset: nodeset,
x: pos.x,
y: pos.y,
toastMessage
});
for (const node of insertedNodeset.nodes) {
nodes.push(node);
}
}
return nodes;
}
const template = this.templates.find((x) => x.templateId === templateId);
if (!template) {
throw 'Template not found';
}
const metadata: Record<string, unknown> = {
prompt: new ChatHistory([], { templateId }).toJSON(),
AiAssistant: 'old'
};
//hack: nodes that are of type 'green' will get a color override to the node color theme 'data'
let color: NodeColor;
switch (template.type) {
case 'green':
color = 'data';
break;
}
if (color) {
metadata.colorOverride = color;
}
if (template.template.nodeDisplayName) {
metadata.typeLabelOverride = template.template.nodeDisplayName;
}
const nodeset = new NodeGraphNodeSet({
nodes: [
NodeGraphNode.fromJSON({
id: guid(),
label: template.name,
type: template.nodeName,
x: 0,
y: 0,
metadata
})
],
connections: []
});
// NOTE: This will create a clone of the nodeset, so the ids will be changed
const insertedNodes = createNodes(nodeset, pos, parentModel, `Created AI Node`);
// HACK: Expect only one node back
return this.createContext(insertedNodes[0]);
}
//clears all the context, important when closing a project
resetContexts() {
this._contexts = {};
}
}

View File

@@ -0,0 +1,44 @@
import { AiTemplate } from '@noodl-models/AiAssistant/AiAssistantModel';
import { ChatHistory } from '@noodl-models/AiAssistant/ChatHistory';
import { Ai } from '@noodl-models/AiAssistant/context/ai-api';
import { AiQuery } from '@noodl-models/AiAssistant/context/ai-query';
import {
AiCopilotChatStreamArgs,
AiCopilotChatStreamXmlArgs,
IAiCopilotContext
} from '@noodl-models/AiAssistant/interfaces';
import { NodeGraphNode } from '@noodl-models/nodegraphmodel';
export class AiCopilotContext implements IAiCopilotContext {
public readonly abortController = new AbortController();
constructor(
public readonly template: AiTemplate,
public readonly chatHistory: ChatHistory,
public readonly node: NodeGraphNode
) {}
chatStream(args: AiCopilotChatStreamArgs): Promise<string> {
if (!args.abortController) {
args.abortController = this.abortController;
}
return Ai.chatStream(args);
}
chatStreamXml(args: AiCopilotChatStreamXmlArgs): Promise<string> {
if (!args.abortController) {
args.abortController = this.abortController;
}
return AiQuery.chatStreamXml(args);
}
toObject(): IAiCopilotContext {
return {
template: this.template,
chatHistory: this.chatHistory,
node: this.node,
chatStream: this.chatStream.bind(this),
chatStreamXml: this.chatStreamXml.bind(this)
};
}
}

View File

@@ -0,0 +1,13 @@
import { AiNodeTemplate } from '@noodl-models/AiAssistant/interfaces';
import * as ChartTemplate from './templates/chart';
import * as FunctionTemplate from './templates/function';
import * as FunctionCrud from './templates/function-crud';
import * as FunctionQueryDatabase from './templates/function-query-database';
export const aiNodeTemplates: Record<string, AiNodeTemplate> = {
['function-crud']: FunctionCrud.template,
['function-query-database']: FunctionQueryDatabase.template,
function: FunctionTemplate.template,
chart: ChartTemplate.template
};

View File

@@ -0,0 +1,161 @@
import { AiAssistantModel } from '@noodl-models/AiAssistant/AiAssistantModel';
import { AiUtils } from '@noodl-models/AiAssistant/context/ai-utils';
import { Model } from '@noodl-utils/model';
export enum ChatMessageType {
User = 'user',
Assistant = 'assistant'
}
export enum ChatHistoryState {
Idle,
Processing
}
export type ChatHistoryActivityId = 'processing' | 'code-generation';
export type ChatHistoryActivity = {
id: ChatHistoryActivityId | string;
name: string;
status?: string;
};
export type ChatMessage = {
snowflakeId: string;
type: ChatMessageType;
content: string;
metadata: Record<string, unknown>;
};
export type ChatSuggestion = {
id: string;
text: string;
};
export enum ChatHistoryEvent {
MessagesChanged,
ActivitiesChanged,
MetadataChanged
}
type ChatHistoryEvents = {
[ChatHistoryEvent.MessagesChanged]: () => void;
[ChatHistoryEvent.ActivitiesChanged]: (activities: readonly ChatHistoryActivity[]) => void;
[ChatHistoryEvent.MetadataChanged]: () => void;
};
export class ChatHistory extends Model<ChatHistoryEvent, ChatHistoryEvents> {
private _messages: ChatMessage[] = [];
private _activities: ChatHistoryActivity[] = [];
private _metadata: Record<string, unknown>;
get messages() {
return this._messages;
}
get metadata() {
return this._metadata;
}
get activities() {
return this._activities;
}
get suggestions(): readonly ChatSuggestion[] {
if (this._messages.length > 0) {
const metadata = this._messages[this._messages.length - 1].metadata;
return (metadata.suggestions as ChatSuggestion[]) || [];
}
// When there are no messages,
// show a list of example suggestions
const template = AiAssistantModel.instance.templates.find((x) => x.templateId === this.metadata.templateId);
if (template) {
return template.examples.map((x) => ({
id: x,
text: x
}));
}
return [];
}
constructor(items: ChatMessage[], metadata: Record<string, unknown> = {}) {
super();
this._messages = items || [];
this._metadata = metadata || {};
}
addActivity(activity: ChatHistoryActivity) {
this._activities.push(activity);
this.notifyListeners(ChatHistoryEvent.ActivitiesChanged, this._activities);
}
removeActivity(activityId: string) {
const length = this._activities.length;
this._activities = this._activities.filter((x) => x.id !== activityId);
if (this._activities.length !== length) {
this.notifyListeners(ChatHistoryEvent.ActivitiesChanged, this._activities);
}
}
clearActivities() {
if (this._activities.length === 0) return;
this._activities.length = 0;
this.notifyListeners(ChatHistoryEvent.ActivitiesChanged, this._activities);
}
add(message: PartialWithRequired<ChatMessage, 'content'>) {
if (!message) {
throw new Error();
}
message.snowflakeId = AiUtils.generateSnowflakeId();
if (!message.type) message.type = ChatMessageType.User;
if (!message.metadata) message.metadata = {};
this.messages.push(message as ChatMessage);
this.notifyListeners(ChatHistoryEvent.MessagesChanged);
return message.snowflakeId;
}
updateLast(data?: Partial<Pick<ChatMessage, 'content' | 'metadata'>>) {
if (data.content) {
this.messages[this.messages.length - 1].content = data.content;
}
if (data.metadata) {
this.messages[this.messages.length - 1].metadata = {
...this.messages[this.messages.length - 1].metadata,
...data.metadata
};
}
this.notifyListeners(ChatHistoryEvent.MessagesChanged);
}
clear(): void {
this._messages.length = 0;
// this.copilot.notifyListeners(CopilotEvent.MessagesChanged);
}
removeLast(): void {
this._messages.pop();
}
toJSON() {
return {
history: this._messages,
metadata: this._metadata
};
}
static fromJSON(json: any) {
return new ChatHistory(json?.history, json?.metadata);
}
}
export interface CreateNodeFileOptions {
nodeId: string;
templateId: string;
}

View File

@@ -0,0 +1,82 @@
export enum CopilotMessageType {
User,
System,
Assistant,
AssistantData,
Debug
}
export enum CopilotRole {
User = 'user',
Assistant = 'assistant',
System = 'system'
}
type CopilotMessageUser = {
type: CopilotMessageType.User;
role: CopilotRole.User;
index: number;
prompt: string;
};
export type CopilotMessageAssistant = {
type: CopilotMessageType.Assistant | CopilotMessageType.AssistantData;
role: CopilotRole.Assistant;
subject: string;
shortend: string;
conversationStage: string;
action: string;
response: string;
};
type CopilotMessageSystem = {
type: CopilotMessageType.Debug | CopilotMessageType.System;
role: CopilotRole.System;
response: string;
};
export type CopilotMessage = CopilotMessageUser | CopilotMessageAssistant | CopilotMessageSystem;
export namespace CopilotMessagePrompt {
export function system(content: string): CopilotMessage {
return {
type: CopilotMessageType.System,
role: CopilotRole.System,
response: content
};
}
export function debug(content: string): CopilotMessage {
return {
type: CopilotMessageType.Debug,
role: CopilotRole.System,
response: content
};
}
export function user(prompt: string, index: number): CopilotMessage {
return {
type: CopilotMessageType.User,
role: CopilotRole.User,
index: index || -1,
prompt: prompt.trim()
};
}
}
export namespace CopilotMessageUtils {
export function isVisibleToUser(message: CopilotMessage) {
return [CopilotMessageType.User, CopilotMessageType.Assistant].includes(message.type);
}
export function toText(message: CopilotMessage) {
switch (message.role) {
case CopilotRole.Assistant:
return message.response;
case CopilotRole.System:
return message.response;
case CopilotRole.User:
return message.prompt;
}
}
}

View File

@@ -0,0 +1,68 @@
import SchemaHandler from '@noodl-utils/schemahandler';
export async function extractDatabaseSchema() {
const schema = SchemaHandler.instance;
if (typeof schema.haveCloudServices === 'undefined') {
console.error('Missing database schema');
try {
await schema._fetch();
} catch (error) {
// lets ignore it then...
console.error(error);
}
}
const dbCollectionsSource =
schema.dbCollections
.map((collection) => {
let str = `${collection.name}\n`;
Object.keys(collection.schema.properties).forEach((name) => {
const property = collection.schema.properties[name];
switch (property.type) {
case 'Pointer': {
str += `- ${name}:Pointer ${property.targetClass}\n`;
break;
}
case 'Relation': {
str += `- ${name}:Relation ${property.targetClass}\n`;
break;
}
default: {
str += `- ${name}:${property.type}\n`;
break;
}
}
});
return str;
})
.join('\n') + '\n';
return dbCollectionsSource;
}
export async function extractDatabaseSchemaJSON(): Promise<{ name: string; schema: TSFixme }[]> {
const schema = SchemaHandler.instance;
if (typeof schema.haveCloudServices === 'undefined') {
console.error('Missing database schema');
try {
await schema._fetch();
} catch (error) {
// lets ignore it then...
console.error(error);
}
}
return Object.keys(schema.dbCollections).map((key) => schema.dbCollections[key]);
}
export function databaseSchemaCompact(schema: TSFixme): { name: string; compact: string }[] {
return schema.map((x) => ({
name: x.name,
compact: Object.keys(x.schema.properties).join(',')
}));
}

View File

@@ -0,0 +1,56 @@
import { ReActCommand, ReActCommandLexer } from '@noodl-models/AiAssistant/_backend/commandLexer';
import { ChatHistory, ChatMessageType } from '@noodl-models/AiAssistant/ChatHistory';
import { Ai } from '@noodl-models/AiAssistant/context/ai-api';
import { AiCopilotChatMessage } from '@noodl-models/AiAssistant/interfaces';
import { NodeGraphModel } from '@noodl-models/nodegraphmodel';
export class ReActContext {
snowflakeId: string;
chatHistory: ChatHistory;
nodeGraphModel?: NodeGraphModel;
}
export abstract class ReActBaseTool {
public abstract execute(command: ReActCommand, context: ReActContext): void;
}
export abstract class ReActAgent<TParams = unknown> {
protected abstract get commands(): Record<string, ReActBaseTool>;
protected abstract createSystemContext(context: ReActContext, params: TParams): string;
protected abstract createHistory(context: ReActContext, params: TParams): AiCopilotChatMessage[];
public async act(context: ReActContext, params: TParams) {
const parser = new ReActCommandLexer();
const systemContext = this.createSystemContext(context, params);
const history = this.createHistory(context, params);
context.chatHistory.add({
type: ChatMessageType.Assistant,
content: ''
});
await Ai.chatStream({
messages: [
{
role: 'system',
content: systemContext
},
...history
],
provider: {
model: 'gpt-4',
temperature: 0
},
onStream: (_, text) => {
const newCommands = parser.append(text);
console.log('[stream]', _);
newCommands.forEach((command) => {
if (this.commands[command.type]) {
this.commands[command.type].execute(command, context);
}
});
}
});
}
}

View File

@@ -0,0 +1,108 @@
export class ReActCommand {
constructor(public type: string, public args: string[]) {}
}
export class ReActCommandLexer {
private _position = 0;
private _commands: ReActCommand[] = [];
private _buffer = '';
public get commands(): readonly ReActCommand[] {
return this._commands;
}
private peek(input: string): string {
if (this._position < input.length) {
return input[this._position];
}
return '';
}
private next(input: string): string {
const ch = input[this._position];
this._position++;
return ch;
}
private readUntil(input: string, stopChars: string[]): string {
let value = '';
let escaped = false;
while (this._position < input.length) {
const ch = this.peek(input);
if (ch === '\n') {
value += ch;
this.next(input);
} else if (stopChars.includes(ch) && !escaped) {
break;
} else if (ch === '\\' && !escaped) {
escaped = true;
this.next(input);
} else {
escaped = false;
value += this.next(input);
}
}
return value.trim();
}
public append(ch: string): ReActCommand[] {
this._buffer += ch;
const commandCount = this.commands.length;
this.tokenize(this._buffer);
// TODO: Check if any of the command content changed
if (this.commands.length > commandCount) {
return this.commands.slice(commandCount - 1);
}
return [];
}
public tokenize(input: string): ReActCommand[] {
this._position = 0;
this._commands = [];
while (this._position < input.length) {
const uppercaseRegex = /[A-Z]/;
while (this._position < input.length && !uppercaseRegex.test(this.peek(input))) {
this.next(input);
}
const value = this.readUntil(input, ['[']);
const commandType = value.trim();
const args: string[] = [];
if (this.peek(input) === '[') {
this.next(input);
}
while (this.peek(input) !== ']') {
if (this._position >= input.length) {
break;
}
if (this.peek(input) === '"') {
this.next(input);
const arg = this.readUntil(input, ['"']);
args.push(arg);
this.next(input);
} else {
this.next(input);
}
}
if (this.peek(input) === ']') {
this.next(input);
if (commandType !== '' && /^[A-Z]/.test(commandType)) {
this._commands.push(new ReActCommand(commandType, args));
}
} else {
if (this._commands.length > 0) {
const lastCommand = this._commands[this._commands.length - 1];
lastCommand.type = commandType;
lastCommand.args = args;
}
}
}
return this._commands;
}
}

View File

@@ -0,0 +1,177 @@
export enum TokenTypes {
OPEN_TAG = 'OPEN_TAG',
CLOSE_TAG = 'CLOSE_TAG',
SELF_CLOSING_TAG = 'SELF_CLOSING_TAG',
TEXT = 'TEXT'
}
export class Token {
constructor(public type: TokenTypes, public value: string, public attributes: Record<string, string> = {}) {}
}
export class Lexer {
private _position = 0;
private _tokens: Token[] = [];
private _buffer = '';
public get tokens(): readonly Token[] {
return this._tokens;
}
private peek(input: string): string {
if (this._position < input.length) {
return input[this._position];
}
return '';
}
private next(input: string): string {
const ch = input[this._position];
this._position++;
return ch;
}
private readUntil(input: string, stopChar: string): string {
let value = '';
while (this._position < input.length) {
const ch = this.peek(input);
if (ch === stopChar) {
break;
}
value += this.next(input);
}
return value;
}
private tokenizeTag(input: string): { tagName: string; attributes: Record<string, string> } {
const parts = input.trim().split(/(?=\s\w+=)/);
const tagName = parts.shift()?.trim() || '';
const attributes: Record<string, string> = {};
for (const part of parts) {
const [key, value] = part.trim().split('=');
if (value) {
attributes[key] = value.replace(/^"(.*)"$/, '$1');
}
}
return { tagName, attributes };
}
public tokenize(input: string): Token[] {
const _tokens: Token[] = [];
this._position = 0;
while (this._position < input.length) {
const ch = this.peek(input);
if (ch === '<') {
this.next(input);
const value = this.readUntil(input, '>');
// If there is no closing '>' for an OPEN_TAG, return an empty array and store it in the _buffer
if (this._position >= input.length) {
this._buffer = '<' + value;
return [];
}
this.next(input);
if (value.startsWith('/')) {
_tokens.push(new Token(TokenTypes.CLOSE_TAG, value.slice(1)));
} else if (value.endsWith('/')) {
const { tagName, attributes } = this.tokenizeTag(value.slice(0, -1));
_tokens.push(new Token(TokenTypes.SELF_CLOSING_TAG, tagName, attributes));
} else {
const { tagName, attributes } = this.tokenizeTag(value);
_tokens.push(new Token(TokenTypes.OPEN_TAG, tagName, attributes));
}
} else {
// handle tag values
let value = '';
while (this._position < input.length) {
const nextChar = this.peek(input);
if (nextChar === '<') {
break;
}
value += this.next(input);
}
if (value) {
_tokens.push(new Token(TokenTypes.TEXT, value));
}
}
}
return _tokens;
}
public append(input: string): Token[] {
// If there is a _buffer, prepend it to the input and clear the _buffer
if (this._buffer) {
input = this._buffer + input;
this._buffer = '';
}
// Tokenize the new input
const new_tokens = this.tokenize(input);
const updated_tokens = [];
// If the last token is TEXT and the first new token is not an OPEN_TAG, merge them
if (this._tokens.length > 0 && new_tokens.length > 0) {
const lastToken = this._tokens[this._tokens.length - 1];
const firstNewToken = new_tokens[0];
if (
lastToken.type === TokenTypes.TEXT &&
![TokenTypes.OPEN_TAG, TokenTypes.CLOSE_TAG, TokenTypes.SELF_CLOSING_TAG].includes(firstNewToken.type)
) {
lastToken.value += firstNewToken.value;
new_tokens.shift();
updated_tokens.push(lastToken);
}
}
this._tokens = this._tokens.concat(new_tokens);
return [...new_tokens, ...updated_tokens];
}
public getTokenIndex() {
return this._tokens.length - 1;
}
public getTextBetween(start: number, end: number) {
return _tokensToText(this._tokens.slice(start, end));
}
public getLastToken(): Token | undefined {
if (this._tokens.length > 0) {
return this._tokens[this._tokens.length - 1];
}
return null;
}
public getFullText(): string {
return _tokensToText(this._tokens);
}
}
export function _tokensToText(_tokens: Token[]): string {
return _tokens.reduce((text, token) => {
if (token.type === TokenTypes.TEXT) {
return text + token.value;
} else if (token.type === TokenTypes.OPEN_TAG) {
const attributes = Object.keys(token.attributes).map((x) => `${x}="${token.attributes[x]}"`);
return attributes.length > 0
? text + '<' + token.value + ' ' + attributes.join(' ') + '>'
: text + '<' + token.value + '>';
} else if (token.type === TokenTypes.CLOSE_TAG) {
return text + '</' + token.value + '>';
} else if (token.type === TokenTypes.SELF_CLOSING_TAG) {
const attributes = Object.keys(token.attributes).map((x) => `${x}="${token.attributes[x]}"`);
return attributes.length > 0
? text + '<' + token.value + ' ' + attributes.join(' ') + ' />'
: text + '<' + token.value + '/>';
}
return text;
}, '');
}

View File

@@ -0,0 +1,46 @@
import { CopilotMessage, CopilotMessageType, CopilotRole } from '@noodl-models/AiAssistant/ChatMessage';
export interface ChatGPTMessage {
role: 'system' | 'assistant' | 'user';
name?: string;
content: string;
}
export function isVisibleToOpenAI(message: CopilotMessage) {
return [
CopilotMessageType.Assistant,
CopilotMessageType.AssistantData,
CopilotMessageType.System,
CopilotMessageType.User
].includes(message.type);
}
export function toOpenAI(message: CopilotMessage): ChatGPTMessage {
// if (message.name) {
// return {
// role: this.role,
// name: this.name,
// content: this.content
// };
// }
switch (message.role) {
case CopilotRole.Assistant:
return {
role: message.role,
content: message.response
};
case CopilotRole.System:
return {
role: message.role,
content: message.response
};
case CopilotRole.User:
return {
role: message.role,
content: `Message ${message.index}: ${message.prompt}`
};
}
}

View File

@@ -0,0 +1,69 @@
import { Lexer, Token, TokenTypes } from './lexer';
export type CallbackFunction = (tagName: string, text: string) => void;
export type TagCallbackFunction = (tagName: string, fullText: string) => void;
export type TagOpenCallbackFunction = (tagName: string, attributes: Record<string, string>) => void;
export class Parser extends Lexer {
private openTagStack: Token[] = [];
private lastTextToken: Token | null = null;
private callback: CallbackFunction;
private openTagCallback: TagOpenCallbackFunction;
private closeTagCallback: TagCallbackFunction;
constructor(
callback: CallbackFunction,
openTagCallback: TagOpenCallbackFunction,
closeTagCallback: TagCallbackFunction
) {
super();
this.callback = callback;
this.openTagCallback = openTagCallback;
this.closeTagCallback = closeTagCallback;
}
public append(input: string): Token[] {
const newTokens = super.append(input);
for (const token of newTokens) {
if (token.type === TokenTypes.OPEN_TAG) {
this.openTagStack.push(token);
this.openTagCallback(token.value, token.attributes);
} else if (token.type === TokenTypes.CLOSE_TAG) {
const openTagIndex = this.openTagStack.findIndex((t) => t.value === token.value);
if (openTagIndex !== -1) {
this.openTagStack.splice(openTagIndex, 1);
const lastToken = this.getLastToken();
if (lastToken && lastToken.type === TokenTypes.TEXT && this.openTagStack.length === 0) {
this.callback(token.value, lastToken.value);
}
this.closeTagCallback(token.value, this.lastTextToken?.value || '');
}
} else if (token.type === TokenTypes.SELF_CLOSING_TAG) {
this.openTagCallback(token.value, token.attributes);
this.closeTagCallback(token.value, '');
} else if (token.type === TokenTypes.TEXT) {
this.lastTextToken = token;
if (this.openTagStack.length > 0) {
const currentOpenTag = this.openTagStack[this.openTagStack.length - 1];
if (currentOpenTag.type === TokenTypes.OPEN_TAG) {
this.callback(currentOpenTag.value, token.value);
}
}
}
}
return newTokens;
}
public getCurrentOpenTag(): Token | null {
if (this.openTagStack.length > 0) {
return this.openTagStack[this.openTagStack.length - 1];
}
return null;
}
public getLastTextToken(): Token | null {
return this.lastTextToken;
}
}

View File

@@ -0,0 +1,55 @@
export type AiAssistantModel = {
name: string;
displayName: string;
promptTokenCost: number;
completionTokenCost: number;
};
export interface AiAssistantConfig {
version: string;
models: AiAssistantModel[];
}
export async function verifyOpenAiApiKey(apiKey: string): Promise<Record<string, { id: string }> | null> {
const response = await fetch(`https://api.openai.com/v1/models`, {
method: 'GET',
headers: {
Authorization: 'Bearer ' + apiKey
}
});
if (response.status !== 200) {
return null;
}
const json = await response.json();
const models = json.data.reduce((acc, item) => {
acc[item.id] = item;
return acc;
}, {});
return models;
}
export namespace AiAssistantApi {
export async function getConfig(): Promise<AiAssistantConfig> {
return {
version: '0.0.0',
models: [
{
name: 'gpt-4',
displayName: 'gpt-4 (8k context)',
promptTokenCost: 0.03,
completionTokenCost: 0.06
},
{
name: 'gpt-3.5-turbo',
displayName: 'gpt-3.5-turbo',
promptTokenCost: 0.002,
completionTokenCost: 0.03
}
]
};
}
}

View File

@@ -0,0 +1,108 @@
import { EventStreamContentType, fetchEventSource } from '@microsoft/fetch-event-source';
import { OpenAiStore } from '@noodl-store/AiAssistantStore';
import { AiCopilotChatProviders, AiCopilotChatStreamArgs } from '@noodl-models/AiAssistant/interfaces';
function toChatProvider(provider: AiCopilotChatProviders | undefined) {
return {
model: provider?.model || 'gpt-3.5-turbo',
temperature: provider?.temperature,
max_tokens: provider?.max_tokens
};
}
async function directChatOpenAi({ messages, provider, abortController, onEnd, onStream }: AiCopilotChatStreamArgs) {
const OPENAI_API_KEY = OpenAiStore.getApiKey();
const controller = abortController || new AbortController();
let endpoint = `https://api.openai.com/v1/chat/completions`;
if (OpenAiStore.getVersion() === 'enterprise') {
endpoint = OpenAiStore.getEndpoint();
}
let fullText = '';
let completionTokenCount = 0;
let tries = 2;
await fetchEventSource(endpoint, {
method: 'POST',
openWhenHidden: true,
headers: {
Authorization: 'Bearer ' + OPENAI_API_KEY,
'Content-Type': 'application/json'
},
signal: controller.signal,
body: JSON.stringify({
...toChatProvider(provider),
messages,
stream: true
}),
async onopen(response) {
if (response.ok && response.headers.get('content-type') === EventStreamContentType) {
return; // everything's good
} else if (response.status >= 400 && response.status < 500 && response.status !== 429) {
// client-side errors are usually non-retriable:
throw 'FatalError';
} else {
throw 'RetriableError';
}
},
onmessage(ev) {
if (ev.data === '[DONE]') {
controller.abort();
return;
}
try {
const json = JSON.parse(ev.data);
const delta = json.choices[0].delta.content;
if (delta) {
completionTokenCount++;
fullText += delta;
console.debug('[stream]', fullText);
onStream && onStream(fullText, delta);
}
} catch (error) {
console.error(error);
}
},
onclose() {
onEnd && onEnd();
},
onerror(err) {
const errText = err.toString();
if (['FatalError'].includes(errText)) {
throw err; // rethrow to stop the operation
} else if (['RetriableError'].includes(errText)) {
if (tries <= 0) {
throw `Apologies, OpenAI is currently facing heavy traffic, causing delays in processing requests. Please be patient and try again later.`;
}
tries--;
} else {
// do nothing to automatically retry. You can also
// return a specific retry interval here.
}
}
});
return {
fullText,
completionTokenCount
};
}
export namespace Ai {
export async function chatStream(args: AiCopilotChatStreamArgs): Promise<string> {
let fullText = '';
const version = OpenAiStore.getVersion();
if (['full-beta', 'enterprise'].includes(version)) {
const result = await directChatOpenAi(args);
fullText = result.fullText;
} else {
throw 'Invalid AI version.';
}
return fullText;
}
}

View File

@@ -0,0 +1,69 @@
import { ReActCommand, ReActCommandLexer } from '@noodl-models/AiAssistant/_backend/commandLexer';
import { Parser } from '@noodl-models/AiAssistant/_backend/parser';
import { Ai } from '@noodl-models/AiAssistant/context/ai-api';
import { AiCopilotChatArgs, AiCopilotChatStreamXmlArgs } from '@noodl-models/AiAssistant/interfaces';
export namespace AiQuery {
export async function chatReAct({
messages,
provider,
abortController
}: AiCopilotChatArgs): Promise<{ commands: readonly ReActCommand[]; fullText: string }> {
const parser = new ReActCommandLexer();
let fullText = '';
await Ai.chatStream({
provider,
messages,
abortController,
onStream: (_, text) => {
if (text) {
fullText += text;
parser.append(text);
}
}
});
return {
commands: parser.commands,
fullText
};
}
export async function chatStreamXml({
messages,
provider,
abortController,
onEnd,
onStream,
onTagOpen,
onTagEnd
}: AiCopilotChatStreamXmlArgs): Promise<string> {
const parser = new Parser(
(tagName, text) => {
console.debug(tagName, text);
onStream && onStream(tagName, text);
},
(tagName, attributes) => {
onTagOpen && onTagOpen(tagName, attributes);
},
(tagName, fullText) => {
onTagEnd && onTagEnd(tagName, fullText);
}
);
await Ai.chatStream({
provider,
messages,
abortController,
onEnd,
onStream: (_, text) => {
if (text) {
parser.append(text);
}
}
});
return parser.getFullText();
}
}

View File

@@ -0,0 +1,66 @@
import { PromiseUtils, RandomUtils } from '@noodl/platform';
// NOTE: Would be nice to have a text buffer class where we can write text blocks,
// perhaps with streaming and then fake stream out the text as it becomes ready.
// This will create a really nice UX flow while the LLM is processing.
// Maybe call it something like StreamingTextBuffer?
export namespace AiUtils {
export function generateSnowflakeId() {
const timestamp = Date.now().toString(16).padStart(12, '0');
const randomString = Math.random().toString(36).substring(2, 8);
return `${timestamp}-${randomString}`;
}
/**
* Alias for fakeTokenStream, just with a smaller delay.
*
* @param inputString
* @param callback
* @param options
* @returns
*/
export function fakeTokenStreamFast(
inputString: string,
callback: (delta: string, fullText: string) => void,
options?: {
delay?: [number, number];
signal?: AbortSignal;
}
) {
return fakeTokenStream(inputString, callback, { delay: [10, 25], ...(options || {}) });
}
export async function fakeTokenStream(
inputString: string,
callback: (delta: string, fullText: string) => void,
options?: {
delay?: [number, number];
signal?: AbortSignal;
}
) {
// Split the input string into smaller chunks (tokens) of 2 to 3 characters
const tokens = [];
let tokenLength: number;
for (let i = 0; i < inputString.length; i += tokenLength) {
tokenLength = Math.floor(Math.random() * 2 + 2);
tokens.push(inputString.slice(i, i + tokenLength));
}
const delayMin = options?.delay?.length === 2 ? Number(options.delay[0]) : 50;
const delayMax = options?.delay?.length === 2 ? Number(options.delay[1]) : 100;
let fullText = '';
// Iterate through the tokens and call the callback function with each token
for (let i = 0; i < tokens.length; i++) {
if (options?.signal?.aborted) {
return;
}
fullText += tokens[i];
callback(tokens[i], fullText);
await PromiseUtils.sleep(RandomUtils.range(delayMin, delayMax));
}
}
}

View File

@@ -0,0 +1 @@
export * from './AiAssistantModel';

View File

@@ -0,0 +1,124 @@
import { AiTemplate } from '@noodl-models/AiAssistant/AiAssistantModel';
import { ChatHistory, ChatMessage } from '@noodl-models/AiAssistant/ChatHistory';
import { CopilotMessage, CopilotMessageAssistant } from '@noodl-models/AiAssistant/ChatMessage';
import { ChatGPTMessage } from '@noodl-models/AiAssistant/_backend/mapper';
import { NodeGraphNode } from '@noodl-models/nodegraphmodel';
import { IModel } from '@noodl-utils/model';
export type AiNodeTemplateType = 'pink' | 'purple' | 'green' | 'grey' | 'blue';
export type AiCopilotTextProviders = {
model: 'text-davinci-003',
temperature?: number;
max_tokens?: number;
}
export type ModelName = 'gpt-3.5-turbo' | 'gpt-4';
export type AiCopilotChatProviders = {
model: 'gpt-3.5-turbo',
temperature?: number;
max_tokens?: number;
} | {
model: 'gpt-4',
temperature?: number;
max_tokens?: number;
}
export type AiCopilotTextArgs = {
content: string;
provider?: AiCopilotTextProviders;
}
export type AiCopilotChatMessage = {
role: 'system' | 'user' | 'assistant' | string;
content: string;
}
export type AiCopilotChatArgs = {
messages: AiCopilotChatMessage[];
provider?: AiCopilotChatProviders;
abortController?: AbortController;
}
export type AiCopilotChatStreamArgs = Prettify<AiCopilotChatArgs & {
onStream?: (fullText: string, text: string) => void;
onEnd?: () => void;
}>;
export type AiCopilotChatStreamXmlArgs = Prettify<AiCopilotChatArgs & {
onStream?: (tagName: string, text: string) => void;
onTagOpen?: (tagName: string, attributes: Record<string, string>) => void;
onTagEnd?: (tagName: string, fullText: string) => void;
onEnd?: () => void;
}>;
export interface IAiCopilotContext {
template: AiTemplate;
chatHistory: ChatHistory;
node: NodeGraphNode;
chatStream(args: AiCopilotChatStreamArgs): Promise<string>;
chatStreamXml(args: AiCopilotChatStreamXmlArgs): Promise<string>;
}
export type AiNodeTemplate = {
type: AiNodeTemplateType;
name: string;
nodeDisplayName?: string;
onMessage: (context: IAiCopilotContext, message: ChatMessage) => Promise<void>;
}
// Memory fragments?
export interface ICopilotMemory {
get messages(): ReadonlyArray<CopilotMessage>;
add(message: CopilotMessage): void;
clear(): void;
forget(): void;
fetch(tokenLimit: number): ChatGPTMessage[];
}
export interface ICopilotHistory {
/** Send more information to AI. */
respond(text: string): void;
assistant(text: string): void;
user(text: string): void;
/** Notify the user. */
notify(text: string): void;
}
export enum CopilotState {
Idle,
Processing
}
export interface ICopilotAgentExecutor {
state: CopilotState;
currentResponse: CopilotMessageAssistant | null;
stop(): void;
execute(): void;
}
export enum CopilotEvent {
MessagesChanged,
StateChanged
}
export type CopilotEvents = {
[CopilotEvent.MessagesChanged]: () => void;
[CopilotEvent.StateChanged]: () => void;
};
export interface ICopilot extends IModel<CopilotEvent, CopilotEvents>, ICopilotHistory {
get memory(): ICopilotMemory;
get executor(): ICopilotAgentExecutor;
}

Some files were not shown because too many files have changed in this diff Show More