3 Commits

Author SHA1 Message Date
Eric Tuvesson
9433cde97f fix: Allow empty description 2024-03-26 22:04:41 +01:00
Eric Tuvesson
fcf3a740e7 fix: save appId and url 2024-03-25 09:44:17 +01:00
Eric Tuvesson
985d609f03 feat: Cloud Services, allow changing all fields 2024-03-25 09:21:59 +01:00
156 changed files with 1049 additions and 2120 deletions

View File

@@ -1,15 +1,15 @@
name: Build fluxscape-editor name: Build noodl-editor
on: on:
# Allows you to run this workflow manually from the Actions tab # Allows you to run this workflow manually from the Actions tab
workflow_dispatch: workflow_dispatch:
# Allows you to run this workflow from another workflow # Allows you to run this workflow from another workflow
workflow_call: workflow_call:
# release: # release:
# types: [created] # types: [created]
jobs: jobs:
build_noodl_editor: build_noodl_editor:
runs-on: ${{ matrix.os }} runs-on: ${{ matrix.os }}
@@ -21,22 +21,22 @@ jobs:
- node: 16 - node: 16
os: windows-latest os: windows-latest
platform: win32-x64 platform: win32-x64
# - node: 16
# os: macos-latest
# platform: darwin-arm64
# - node: 16
# os: macos-latest
# platform: darwin-x64
- node: 16 - node: 16
os: ubuntu-latest os: macos-latest
platform: linux-x64 platform: darwin-arm64
- node: 16
os: macos-latest
platform: darwin-x64
# - node: 16
# os: ubuntu-latest
# platform: linux-x64
steps: steps:
- if: ${{ matrix.platform == 'darwin-arm64' }} - if: ${{ matrix.platform == 'darwin-arm64' }}
name: Setup name: Setup
uses: actions/setup-python@v5 uses: actions/setup-python@v5
with: with:
python-version: '3.11' python-version: '3.11'
- name: Checkout - name: Checkout
uses: actions/checkout@v4 uses: actions/checkout@v4
@@ -65,13 +65,12 @@ jobs:
env: env:
WORKSPACE_PATH: . WORKSPACE_PATH: .
TARGET_PLATFORM: ${{ matrix.platform }} TARGET_PLATFORM: ${{ matrix.platform }}
DISABLE_SIGNING: true # disable for now
- run: npm run build:editor:pack - run: npm run build:editor:pack
- name: Upload artifact - name: Upload artifact
uses: actions/upload-artifact@v3 uses: actions/upload-artifact@v3
with: with:
name: fluxscape-editor-${{ matrix.platform }}-${{ github.head_ref }}-${{ github.sha }} name: noodl-editor-${{ matrix.platform }}-${{ github.head_ref }}-${{ github.sha }}
path: publish path: publish
retention-days: '12' retention-days: "12"

View File

@@ -1,4 +1,4 @@
name: Test fluxscape-editor name: Test noodl-editor
on: on:
# Allows you to run this workflow manually from the Actions tab # Allows you to run this workflow manually from the Actions tab

View File

@@ -1,21 +1,21 @@
# Fluxscape # Noodl
Fluxscape is a low-code platform where designers and developers build custom applications and experiences. Designed as a visual programming environment, it aims to expedite your development process. It promotes the swift and efficient creation of applications, requiring minimal coding knowledge. [Noodl](https://noodl.net) is a low-code platform where designers and developers build custom applications and experiences. Designed as a visual programming environment, it aims to expedite your development process. It promotes the swift and efficient creation of applications, requiring minimal coding knowledge.
## Documentation ## Documentation
Documentation for how to use Fluxscape can be found here: Documentation for how to use Noodl can be found here:
[Fluxscape Documentation](https://docs.fluxscape.io) [https://noodlapp.github.io/noodl-docs/](https://noodlapp.github.io/noodl-docs/)
## Community ## Community
Main support channel is Discord: [Fluxscape Discord](https://discord.gg/fXNW9EXa6A) Main support channel is Discord: [https://www.noodl.net/community](https://www.noodl.net/community)
## Download releases ## Download releases
Pre-built binaries can be [downloaded from Github](https://github.com/fluxscape/fluxscape/releases) Pre-built binaries can be [downloaded from Github](https://github.com/noodlapp/noodl/releases)
## Note for users who are migrating from the deprecated closed source version ## Note for users who are migrating from the deprecated closed source version
- [Migrating the project files and workspaces to a Git provider](https://docs.fluxscape.io/docs/guides/collaboration/migrating-from-noodl-hosted-git/) - [Migrating the project files and workspaces to a Git provider](https://noodlapp.github.io/noodl-docs/docs/guides/collaboration/migrating-from-noodl-hosted-git)
- [Migrate backend and database](https://docs.fluxscape.io/docs/guides/deploy/using-an-external-backend/#migrating-from-a-noodl-cloud-service) - [Migrate backend and database](https://noodlapp.github.io/noodl-docs/docs/guides/deploy/using-an-external-backend#migrating-from-a-noodl-cloud-service)
- [Self-host frontend](https://docs.fluxscape.io/docs/guides/deploy/hosting-frontend/) - [Self-host frontend](https://noodlapp.github.io/noodl-docs/docs/guides/deploy/hosting-frontend)
## Building from source ## Building from source
@@ -23,24 +23,24 @@ Pre-built binaries can be [downloaded from Github](https://github.com/fluxscape/
# Install all dependencies # Install all dependencies
$ npm install $ npm install
# Start the Fluxscape Editor and build a production version of the cloud and react runtime (useful when running Fluxscape from source but want to deploy to production) # Start the Noodl Editor and build a production version of the cloud and react runtime (useful when running Noodl from source but want to deploy to production)
$ npm start $ npm start
# Start the Fluxscape Editor and watch the filesystem for changes to the runtimes. Development versions of the runtimes, not meant for production (mostly due to source maps and file size) # Start the Noodl Editor and watch the filesystem for changes to the runtimes. Development versions of the runtimes, not meant for production (mostly due to source maps and file size)
# This is ideal for a quick workflow when doing changes on the runtimes. # This is ideal for a quick workflow when doing changes on the runtimes.
$ npm run dev $ npm run dev
# Start Fluxscape Editor test runner # Start Noodl Editor test runner
$ npm run test:editor $ npm run test:editor
``` ```
## Licenses ## Licenses
This repository contains two different licenses for different parts of the Fluxscape platform. This repository contains two different licenses for different parts of the Noodl platform.
- Components related to the editor, used to edit Fluxscape projects, are under GPLv3 - Components related to the editor, used to edit Noodl projects, are under GPLv3
- Components related to the end applications, used by the applications Fluxscape deploys, are under MIT - Components related to the end applications, used by the applications Noodl deploys, are under MIT
All of the source code of applications created with Fluxscape are under MIT. This means you can do project specific changes to the runtime without having to redistribute your changes. All of the source code of applications created with Noodl are under MIT. This means you can do project specific changes to the runtime without having to redistribute your changes.
Packaged licensed under MIT: Packaged licensed under MIT:
- `noodl-runtime` - `noodl-runtime`

347
package-lock.json generated
View File

@@ -2849,9 +2849,9 @@
} }
}, },
"node_modules/@electron/remote": { "node_modules/@electron/remote": {
"version": "2.1.2", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/@electron/remote/-/remote-2.1.2.tgz", "resolved": "https://registry.npmjs.org/@electron/remote/-/remote-2.1.1.tgz",
"integrity": "sha512-EPwNx+nhdrTBxyCqXt/pftoQg/ybtWDW3DUWHafejvnB1ZGGfMpv6e15D8KeempocjXe78T7WreyGGb3mlZxdA==", "integrity": "sha512-Lfxul2yBxL+FBVaKszNAkuUqSIDbUQ1I7BC394iRXyqA2XGz7im2bAxroNIM51jhySSPKUaOLHaFLxfV6pC9VQ==",
"peerDependencies": { "peerDependencies": {
"electron": ">= 13.0.0" "electron": ">= 13.0.0"
} }
@@ -25220,13 +25220,13 @@
} }
}, },
"node_modules/electron": { "node_modules/electron": {
"version": "31.3.1", "version": "28.1.4",
"resolved": "https://registry.npmjs.org/electron/-/electron-31.3.1.tgz", "resolved": "https://registry.npmjs.org/electron/-/electron-28.1.4.tgz",
"integrity": "sha512-9fiuWlRhBfygtcT+auRd/WdBK/f8LZZcrpx0RjpXhH2DPTP/PfnkC4JB1PW55qCbGbh4wAgkYbf4ExIag8oGCA==", "integrity": "sha512-WE6go611KOhtH6efRPMnVC7FE7DCKnQ3ZyHFeI1DbaCy8OU4UjZ8/CZGcuZmZgRdxSBEHoHdgaJkWRHZzF0FOg==",
"hasInstallScript": true, "hasInstallScript": true,
"dependencies": { "dependencies": {
"@electron/get": "^2.0.0", "@electron/get": "^2.0.0",
"@types/node": "^20.9.0", "@types/node": "^18.11.18",
"extract-zip": "^2.0.1" "extract-zip": "^2.0.1"
}, },
"bin": { "bin": {
@@ -25452,14 +25452,6 @@
"tiny-typed-emitter": "^2.1.0" "tiny-typed-emitter": "^2.1.0"
} }
}, },
"node_modules/electron/node_modules/@types/node": {
"version": "20.14.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz",
"integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==",
"dependencies": {
"undici-types": "~5.26.4"
}
},
"node_modules/elliptic": { "node_modules/elliptic": {
"version": "6.5.4", "version": "6.5.4",
"dev": true, "dev": true,
@@ -27211,10 +27203,6 @@
"react": "^15.0.2 || ^16.0.0 || ^17.0.0" "react": "^15.0.2 || ^16.0.0 || ^17.0.0"
} }
}, },
"node_modules/fluxscape-editor": {
"resolved": "packages/noodl-editor",
"link": true
},
"node_modules/focus-lock": { "node_modules/focus-lock": {
"version": "0.8.1", "version": "0.8.1",
"dev": true, "dev": true,
@@ -35455,6 +35443,10 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/noodl-editor": {
"resolved": "packages/noodl-editor",
"link": true
},
"node_modules/nopt": { "node_modules/nopt": {
"version": "1.0.10", "version": "1.0.10",
"license": "MIT", "license": "MIT",
@@ -43199,11 +43191,6 @@
"version": "1.13.6", "version": "1.13.6",
"license": "MIT" "license": "MIT"
}, },
"node_modules/undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
},
"node_modules/unfetch": { "node_modules/unfetch": {
"version": "4.2.0", "version": "4.2.0",
"dev": true, "dev": true,
@@ -48980,10 +48967,9 @@
"dev": true "dev": true
}, },
"packages/noodl-editor": { "packages/noodl-editor": {
"name": "fluxscape-editor", "version": "1.0.1",
"version": "1.1.0",
"dependencies": { "dependencies": {
"@electron/remote": "^2.1.2", "@electron/remote": "^2.1.1",
"@jaames/iro": "^5.5.2", "@jaames/iro": "^5.5.2",
"@microsoft/fetch-event-source": "^2.0.1", "@microsoft/fetch-event-source": "^2.0.1",
"@noodl/git": "file:../noodl-git", "@noodl/git": "file:../noodl-git",
@@ -49039,7 +49025,7 @@
"babel-loader": "^8.2.4", "babel-loader": "^8.2.4",
"concurrently": "^7.4.0", "concurrently": "^7.4.0",
"css-loader": "^6.7.1", "css-loader": "^6.7.1",
"electron": "31.3.1", "electron": "28.1.4",
"electron-builder": "^24.9.1", "electron-builder": "^24.9.1",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"html-loader": "^3.1.0", "html-loader": "^3.1.0",
@@ -53389,9 +53375,9 @@
} }
}, },
"@electron/remote": { "@electron/remote": {
"version": "2.1.2", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/@electron/remote/-/remote-2.1.2.tgz", "resolved": "https://registry.npmjs.org/@electron/remote/-/remote-2.1.1.tgz",
"integrity": "sha512-EPwNx+nhdrTBxyCqXt/pftoQg/ybtWDW3DUWHafejvnB1ZGGfMpv6e15D8KeempocjXe78T7WreyGGb3mlZxdA==", "integrity": "sha512-Lfxul2yBxL+FBVaKszNAkuUqSIDbUQ1I7BC394iRXyqA2XGz7im2bAxroNIM51jhySSPKUaOLHaFLxfV6pC9VQ==",
"requires": {} "requires": {}
}, },
"@electron/universal": { "@electron/universal": {
@@ -74071,23 +74057,13 @@
} }
}, },
"electron": { "electron": {
"version": "31.3.1", "version": "28.1.4",
"resolved": "https://registry.npmjs.org/electron/-/electron-31.3.1.tgz", "resolved": "https://registry.npmjs.org/electron/-/electron-28.1.4.tgz",
"integrity": "sha512-9fiuWlRhBfygtcT+auRd/WdBK/f8LZZcrpx0RjpXhH2DPTP/PfnkC4JB1PW55qCbGbh4wAgkYbf4ExIag8oGCA==", "integrity": "sha512-WE6go611KOhtH6efRPMnVC7FE7DCKnQ3ZyHFeI1DbaCy8OU4UjZ8/CZGcuZmZgRdxSBEHoHdgaJkWRHZzF0FOg==",
"requires": { "requires": {
"@electron/get": "^2.0.0", "@electron/get": "^2.0.0",
"@types/node": "^20.9.0", "@types/node": "^18.11.18",
"extract-zip": "^2.0.1" "extract-zip": "^2.0.1"
},
"dependencies": {
"@types/node": {
"version": "20.14.10",
"resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz",
"integrity": "sha512-MdiXf+nDuMvY0gJKxyfZ7/6UFsETO7mGKF54MVD/ekJS6HdFtpZFBgrh6Pseu64XTb2MLyFPlbW6hj8HYRQNOQ==",
"requires": {
"undici-types": "~5.26.4"
}
}
} }
}, },
"electron-builder": { "electron-builder": {
@@ -75432,144 +75408,6 @@
"fbjs": "^3.0.1" "fbjs": "^3.0.1"
} }
}, },
"fluxscape-editor": {
"version": "file:packages/noodl-editor",
"requires": {
"@babel/core": "^7.19.1",
"@babel/preset-react": "^7.18.6",
"@electron/remote": "^2.1.2",
"@jaames/iro": "^5.5.2",
"@microsoft/fetch-event-source": "^2.0.1",
"@noodl/git": "file:../noodl-git",
"@noodl/noodl-parse-dashboard": "file:../noodl-parse-dashboard",
"@noodl/platform": "file:../noodl-platform",
"@noodl/platform-electron": "file:../noodl-platform-electron",
"@svgr/webpack": "^6.4.0",
"@types/checksum": "^0.1.33",
"@types/jasmine": "^4.3.0",
"@types/jquery": "^3.5.14",
"@types/react": "^17.0.50",
"@types/react-dom": "^18.0.0",
"@types/remarkable": "^2.0.3",
"@types/rimraf": "^3.0.2",
"@types/split2": "^3.2.1",
"@types/string.prototype.matchall": "^4.0.1",
"@types/underscore": "^1.11.4",
"@types/webpack-env": "^1.18.0",
"about-window": "^1.15.2",
"algoliasearch": "^4.14.2",
"archiver": "^5.3.0",
"async": "^3.2.4",
"babel-loader": "^8.2.4",
"classnames": "^2.3.2",
"concurrently": "^7.4.0",
"css-loader": "^6.7.1",
"diff3": "0.0.4",
"dmg-license": "^1.0.11",
"electron": "31.3.1",
"electron-builder": "^24.9.1",
"electron-store": "^8.1.0",
"electron-updater": "^6.1.7",
"express": "^4.17.3",
"file-loader": "^6.2.0",
"highlight.js": "^11.5.1",
"html-loader": "^3.1.0",
"isbinaryfile": "^5.0.0",
"md5": "^2.3.0",
"md5-file": "^5.0.0",
"mixpanel-browser": "^2.45.0",
"mkdirp": "0.5.1",
"mkdirp-sync": "0.0.2",
"monaco-editor": "^0.34.0",
"monaco-editor-webpack-plugin": "^7.0.1",
"ncp": "^2.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.0",
"react-hot-toast": "^2.4.0",
"react-instantsearch-hooks-web": "^6.38.0",
"react-json-view": "^1.21.3",
"react-rnd": "^10.3.7",
"remarkable": "^2.0.1",
"rimraf": "^3.0.2",
"s3": "git+https://github.com/noodlapp/node-s3-client.git",
"sass": "^1.55.0",
"sass-loader": "^12.6.0",
"string.prototype.matchall": "^4.0.7",
"stringify": "^5.2.0",
"style-loader": "^3.3.1",
"ts-loader": "^9.4.1",
"ts-node": "^10.7.0",
"typescript": "^4.8.3",
"underscore": "^1.13.6",
"url-loader": "^4.1.1",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1",
"webpack-merge": "^5.8.0",
"websocket-stream": "^5.5.2",
"ws": "^8.9.0"
},
"dependencies": {
"@webpack-cli/configtest": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
"integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
"dev": true,
"requires": {}
},
"@webpack-cli/info": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz",
"integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==",
"dev": true,
"requires": {
"envinfo": "^7.7.3"
}
},
"@webpack-cli/serve": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
"integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
"dev": true,
"requires": {}
},
"commander": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"dev": true
},
"rechoir": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
"integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==",
"dev": true,
"requires": {
"resolve": "^1.9.0"
}
},
"webpack-cli": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
"integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
"dev": true,
"requires": {
"@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/configtest": "^1.2.0",
"@webpack-cli/info": "^1.5.0",
"@webpack-cli/serve": "^1.7.0",
"colorette": "^2.0.14",
"commander": "^7.0.0",
"cross-spawn": "^7.0.3",
"fastest-levenshtein": "^1.0.12",
"import-local": "^3.0.2",
"interpret": "^2.2.0",
"rechoir": "^0.7.0",
"webpack-merge": "^5.7.3"
}
}
}
},
"focus-lock": { "focus-lock": {
"version": "0.8.1", "version": "0.8.1",
"dev": true, "dev": true,
@@ -81145,6 +80983,144 @@
"version": "2.0.10", "version": "2.0.10",
"dev": true "dev": true
}, },
"noodl-editor": {
"version": "file:packages/noodl-editor",
"requires": {
"@babel/core": "^7.19.1",
"@babel/preset-react": "^7.18.6",
"@electron/remote": "^2.1.1",
"@jaames/iro": "^5.5.2",
"@microsoft/fetch-event-source": "^2.0.1",
"@noodl/git": "file:../noodl-git",
"@noodl/noodl-parse-dashboard": "file:../noodl-parse-dashboard",
"@noodl/platform": "file:../noodl-platform",
"@noodl/platform-electron": "file:../noodl-platform-electron",
"@svgr/webpack": "^6.4.0",
"@types/checksum": "^0.1.33",
"@types/jasmine": "^4.3.0",
"@types/jquery": "^3.5.14",
"@types/react": "^17.0.50",
"@types/react-dom": "^18.0.0",
"@types/remarkable": "^2.0.3",
"@types/rimraf": "^3.0.2",
"@types/split2": "^3.2.1",
"@types/string.prototype.matchall": "^4.0.1",
"@types/underscore": "^1.11.4",
"@types/webpack-env": "^1.18.0",
"about-window": "^1.15.2",
"algoliasearch": "^4.14.2",
"archiver": "^5.3.0",
"async": "^3.2.4",
"babel-loader": "^8.2.4",
"classnames": "^2.3.2",
"concurrently": "^7.4.0",
"css-loader": "^6.7.1",
"diff3": "0.0.4",
"dmg-license": "^1.0.11",
"electron": "28.1.4",
"electron-builder": "^24.9.1",
"electron-store": "^8.1.0",
"electron-updater": "^6.1.7",
"express": "^4.17.3",
"file-loader": "^6.2.0",
"highlight.js": "^11.5.1",
"html-loader": "^3.1.0",
"isbinaryfile": "^5.0.0",
"md5": "^2.3.0",
"md5-file": "^5.0.0",
"mixpanel-browser": "^2.45.0",
"mkdirp": "0.5.1",
"mkdirp-sync": "0.0.2",
"monaco-editor": "^0.34.0",
"monaco-editor-webpack-plugin": "^7.0.1",
"ncp": "^2.0.0",
"react": "^17.0.2",
"react-dom": "^17.0.0",
"react-hot-toast": "^2.4.0",
"react-instantsearch-hooks-web": "^6.38.0",
"react-json-view": "^1.21.3",
"react-rnd": "^10.3.7",
"remarkable": "^2.0.1",
"rimraf": "^3.0.2",
"s3": "git+https://github.com/noodlapp/node-s3-client.git",
"sass": "^1.55.0",
"sass-loader": "^12.6.0",
"string.prototype.matchall": "^4.0.7",
"stringify": "^5.2.0",
"style-loader": "^3.3.1",
"ts-loader": "^9.4.1",
"ts-node": "^10.7.0",
"typescript": "^4.8.3",
"underscore": "^1.13.6",
"url-loader": "^4.1.1",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0",
"webpack-dev-server": "^4.11.1",
"webpack-merge": "^5.8.0",
"websocket-stream": "^5.5.2",
"ws": "^8.9.0"
},
"dependencies": {
"@webpack-cli/configtest": {
"version": "1.2.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/configtest/-/configtest-1.2.0.tgz",
"integrity": "sha512-4FB8Tj6xyVkyqjj1OaTqCjXYULB9FMkqQ8yGrZjRDrYh0nOE+7Lhs45WioWQQMV+ceFlE368Ukhe6xdvJM9Egg==",
"dev": true,
"requires": {}
},
"@webpack-cli/info": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/info/-/info-1.5.0.tgz",
"integrity": "sha512-e8tSXZpw2hPl2uMJY6fsMswaok5FdlGNRTktvFk2sD8RjH0hE2+XistawJx1vmKteh4NmGmNUrp+Tb2w+udPcQ==",
"dev": true,
"requires": {
"envinfo": "^7.7.3"
}
},
"@webpack-cli/serve": {
"version": "1.7.0",
"resolved": "https://registry.npmjs.org/@webpack-cli/serve/-/serve-1.7.0.tgz",
"integrity": "sha512-oxnCNGj88fL+xzV+dacXs44HcDwf1ovs3AuEzvP7mqXw7fQntqIhQ1BRmynh4qEKQSSSRSWVyXRjmTbZIX9V2Q==",
"dev": true,
"requires": {}
},
"commander": {
"version": "7.2.0",
"resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz",
"integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==",
"dev": true
},
"rechoir": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.7.1.tgz",
"integrity": "sha512-/njmZ8s1wVeR6pjTZ+0nCnv8SpZNRMT2D1RLOJQESlYFDBvwpTA4KWJpZ+sBJ4+vhjILRcK7JIFdGCdxEAAitg==",
"dev": true,
"requires": {
"resolve": "^1.9.0"
}
},
"webpack-cli": {
"version": "4.10.0",
"resolved": "https://registry.npmjs.org/webpack-cli/-/webpack-cli-4.10.0.tgz",
"integrity": "sha512-NLhDfH/h4O6UOy+0LSso42xvYypClINuMNBVVzX4vX98TmTaTUxwRbXdhucbFMd2qLaCTcLq/PdYrvi8onw90w==",
"dev": true,
"requires": {
"@discoveryjs/json-ext": "^0.5.0",
"@webpack-cli/configtest": "^1.2.0",
"@webpack-cli/info": "^1.5.0",
"@webpack-cli/serve": "^1.7.0",
"colorette": "^2.0.14",
"commander": "^7.0.0",
"cross-spawn": "^7.0.3",
"fastest-levenshtein": "^1.0.12",
"import-local": "^3.0.2",
"interpret": "^2.2.0",
"rechoir": "^0.7.0",
"webpack-merge": "^5.7.3"
}
}
}
},
"nopt": { "nopt": {
"version": "1.0.10", "version": "1.0.10",
"requires": { "requires": {
@@ -86427,11 +86403,6 @@
"underscore": { "underscore": {
"version": "1.13.6" "version": "1.13.6"
}, },
"undici-types": {
"version": "5.26.5",
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA=="
},
"unfetch": { "unfetch": {
"version": "4.2.0", "version": "4.2.0",
"dev": true "dev": true

View File

@@ -2,8 +2,8 @@
"private": true, "private": true,
"name": "@noodl/repo", "name": "@noodl/repo",
"description": "Low-code for when experience matter", "description": "Low-code for when experience matter",
"author": "Fluxscape <contact@fluxcsape.io>", "author": "Noodl <info@noodl.net>",
"homepage": "https://fluxscape.io", "homepage": "https://noodl.net",
"version": "1.0.0", "version": "1.0.0",
"workspaces": [ "workspaces": [
"packages/*" "packages/*"
@@ -12,7 +12,7 @@
"graph": "npx nx graph", "graph": "npx nx graph",
"ci:prepare:editor": "ts-node ./scripts/ci-editor-prepare.ts", "ci:prepare:editor": "ts-node ./scripts/ci-editor-prepare.ts",
"ci:build:viewer": "lerna exec --scope @noodl/noodl-viewer-react -- npm run build", "ci:build:viewer": "lerna exec --scope @noodl/noodl-viewer-react -- npm run build",
"ci:build:editor": "lerna exec --scope fluxscape-editor -- npm run ci:build", "ci:build:editor": "lerna exec --scope noodl-editor -- npm run ci:build",
"build:editor": "ts-node ./scripts/build-editor.ts", "build:editor": "ts-node ./scripts/build-editor.ts",
"build:editor:_viewer": "ts-node ./scripts/noodl-editor/build-viewer.ts", "build:editor:_viewer": "ts-node ./scripts/noodl-editor/build-viewer.ts",
"build:editor:_editor": "ts-node ./scripts/noodl-editor/build-editor.ts", "build:editor:_editor": "ts-node ./scripts/noodl-editor/build-editor.ts",
@@ -20,7 +20,7 @@
"build:cloud-runtime": "lerna run build --scope @noodl/cloud-runtime --stream && lerna run build:pack --scope @noodl/cloud-runtime --stream", "build:cloud-runtime": "lerna run build --scope @noodl/cloud-runtime --stream && lerna run build:pack --scope @noodl/cloud-runtime --stream",
"start:storybook": "lerna exec --scope @noodl/noodl-core-ui -- npm run start", "start:storybook": "lerna exec --scope @noodl/noodl-core-ui -- npm run start",
"start:viewer": "lerna run start --scope @noodl/noodl-viewer-react --stream", "start:viewer": "lerna run start --scope @noodl/noodl-viewer-react --stream",
"start:editor": "lerna run start --scope fluxscape-editor --stream", "start:editor": "lerna run start --scope noodl-editor --stream",
"dev": "ts-node ./scripts/start.ts", "dev": "ts-node ./scripts/start.ts",
"start": "ts-node ./scripts/start.ts -- --build-viewer", "start": "ts-node ./scripts/start.ts -- --build-viewer",
"test:editor": "ts-node ./scripts/test-editor.ts", "test:editor": "ts-node ./scripts/test-editor.ts",
@@ -47,4 +47,4 @@
"npm": ">=6.0.0", "npm": ">=6.0.0",
"node": ">=16.0.0 <=18" "node": ">=16.0.0 <=18"
} }
} }

View File

@@ -1,4 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.609 9.22205H14.4786C15.5078 9.22205 16.3421 10.0512 16.3421 11.074C16.3421 12.0968 15.5078 12.9259 14.4786 12.9259L11.609 12.9259C10.9813 12.9259 10.4725 13.4316 10.4725 14.0555C10.4725 14.6793 10.9813 15.185 11.6091 15.185C13.5014 15.185 15.0357 16.7086 15.0377 18.5888V18.5961C15.0357 20.4763 13.5014 21.9999 11.609 21.9999H10.5656C10.2568 21.9999 10.0065 21.7512 10.0065 21.4443C10.0065 21.1374 10.2568 20.8887 10.5656 20.8887H11.609C12.2367 20.8887 12.7456 20.383 12.7456 19.7591C12.7456 19.1353 12.2368 18.6296 11.6091 18.6296C8.99654 18.6296 6.8784 16.526 6.87604 13.9302V13.9215C6.8784 11.3257 8.99654 9.22205 11.609 9.22205Z" fill="white"/> <path d="M21 8.46785C21 6.8533 20.0098 5.47016 18.6036 4.89221L18.4702 4.83923L18.8936 4.10593C19.0158 3.89432 18.8631 3.63006 18.6187 3.63006H14.8823C14.6382 3.63006 14.4855 3.89465 14.6074 4.10593L16.4756 7.34158C16.5978 7.55318 16.9032 7.55318 17.0251 7.34158L17.4956 6.52658L17.9396 6.72041C18.6089 7.02197 19.0747 7.69166 19.0747 8.46965C19.0747 8.76585 19.0073 9.04613 18.8868 9.29674L14.5003 18.6933C14.461 18.7753 14.4033 18.8507 14.3269 18.9132C14.0931 19.1046 13.7492 19.1043 13.5155 18.9126C13.4817 18.885 13.4519 18.8549 13.4252 18.8226L9.79186 14.368L8.7771 16.1566L11.9959 20.1111C12.4667 20.6461 13.1565 20.9834 13.9253 20.9834C14.983 20.9834 15.8915 20.3446 16.2856 19.4313L20.6354 10.1097C20.8692 9.61133 21 9.05499 21 8.46785Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.6087 2H18.537C19.8973 2 21 3.1027 21 4.46295C21 5.8232 19.8973 6.9259 18.5371 6.9259L11.6087 6.9259L11.6087 2ZM11.6087 8.25933L11.6087 6.9259L11.6087 2.00004L11.6085 2.00004C6.87488 2.00004 3.03361 5.79695 3 10.4934V10.6177C3.02455 14.0492 5.08185 17.0005 8.03472 18.3413C6.73836 17.3036 5.90846 15.7136 5.90692 13.9309V13.9209C5.90963 10.7936 8.46136 8.25933 11.6087 8.25933ZM11.6087 13.8888C11.6086 13.8888 11.6086 13.8888 11.6085 13.8888V14.2223C11.6086 14.2223 11.6086 14.2223 11.6087 14.2223L11.6087 13.8888ZM11.6089 6.92591H12.6504C12.0819 6.92893 11.6206 7.38207 11.6089 7.94502V6.92591Z" fill="white"/> <path d="M5.54434 16.485C5.5396 16.485 5.53486 16.4847 5.53012 16.4847C4.46423 16.4847 3.60013 17.3488 3.60013 18.4148C3.60013 19.4807 4.46423 20.3448 5.53012 20.3448C6.59607 20.3448 7.46017 19.4807 7.46017 18.4148C7.46017 18.0652 7.36723 17.7374 7.20477 17.4548L11.4253 9.67665C11.4315 9.6657 11.438 9.65475 11.4439 9.64381L11.4472 9.6385C11.7934 9.00136 11.9902 8.27128 11.9902 7.4951C11.9902 5.01255 9.97759 3 7.4951 3C5.01255 3 3 5.01255 3 7.4951C3 8.61075 3.40629 9.63139 4.07921 10.4173L6.37285 13.2269L7.39377 11.4513L5.53046 9.17183C5.15966 8.72644 4.91995 8.12039 4.91995 7.49538C4.91995 6.07641 6.0702 4.92616 7.48917 4.92616C8.90814 4.92616 10.0584 6.07641 10.0584 7.49538C10.0584 7.95466 9.93797 8.38583 9.72665 8.759L9.72546 8.76108L5.54434 16.485Z" fill="white"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

View File

@@ -1,8 +1,6 @@
import { UnsafeStyleProps } from '@noodl-core-ui/types/global';
import classNames from 'classnames'; import classNames from 'classnames';
import React from 'react'; import React from 'react';
import { UnsafeStyleProps } from '@noodl-core-ui/types/global';
import css from './Logo.module.scss'; import css from './Logo.module.scss';
export enum LogoVariant { export enum LogoVariant {
@@ -45,7 +43,12 @@ export function Logo({
return ( return (
<div <div
className={classNames([css['Root'], css[`is-variant-${variant}`], css[`is-size-${size}`], UNSAFE_className])} className={classNames([
css['Root'],
css[`is-variant-${variant}`],
css[`is-size-${size}`],
UNSAFE_className
])}
onClick={onClick} onClick={onClick}
style={UNSAFE_style} style={UNSAFE_style}
> >
@@ -57,92 +60,18 @@ export function Logo({
const DefaultIcon = React.memo(function () { const DefaultIcon = React.memo(function () {
return ( return (
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<g filter="url(#filter0_i_574_6111)"> <path
<path d="M30 60C46.5685 60 60 46.5686 60 30C60 13.4315 46.5685 0 30 0C13.4315 0 0 13.4315 0 30C0 46.5686 13.4315 60 30 60Z"
fillRule="evenodd" fill="#F5BC41"
clipRule="evenodd" />
d="M3.76172 24.8943L3.76172 25.7516C3.99042 39.1618 14.9298 49.9629 28.3932 49.9685H28.4072L28.4072 14.8675L48.1979 14.8675C52.1163 14.8675 55.2928 11.691 55.2928 7.77258C55.2928 3.85417 52.1163 0.677665 48.1979 0.677666L28.4072 0.677669V0.67749L28.4036 0.67749C14.9354 0.677491 3.99048 11.4808 3.76172 24.8943ZM31.3869 14.8676H28.4105V17.7311C28.481 16.1441 29.7849 14.8778 31.3869 14.8676ZM26.5352 35.4054C26.5352 36.4366 27.3711 37.2725 28.4022 37.2725V33.5383C27.3711 33.5383 26.5352 34.3743 26.5352 35.4054Z" <path
fill="url(#paint0_linear_574_6111)" d="M48.9051 22.4621C48.9051 19.0553 46.8158 16.1367 43.8486 14.9172L43.567 14.8055L44.4605 13.2582C44.7184 12.8117 44.3962 12.2541 43.8804 12.2541H35.9965C35.4813 12.2541 35.1592 12.8123 35.4164 13.2582L39.3584 20.0856C39.6163 20.532 40.2607 20.532 40.5179 20.0856L41.5107 18.3659L42.4474 18.7749C43.8598 19.4112 44.8426 20.8242 44.8426 22.4658C44.8426 23.0909 44.7003 23.6822 44.4461 24.2111L35.1904 44.0383H35.191C35.1079 44.2112 34.9856 44.3705 34.8245 44.5022C34.3312 44.9062 33.6056 44.9056 33.1123 44.501C33.0411 44.4429 32.9781 44.3792 32.9219 44.3112L25.2553 34.9118L23.1141 38.6857L29.9059 47.0299C30.8994 48.1588 32.3549 48.8707 33.9771 48.8707C36.2088 48.8707 38.1258 47.5225 38.9575 45.5956L48.1358 25.9264C48.6291 24.8749 48.9051 23.7009 48.9051 22.4621Z"
/> fill="#1F1F1F"
</g> />
<g filter="url(#filter1_i_574_6111)"> <path
<path d="M16.2933 39.3787C16.2833 39.3787 16.2733 39.3781 16.2633 39.3781C14.0142 39.3781 12.1909 41.2014 12.1909 43.4506C12.1909 45.6997 14.0142 47.523 16.2633 47.523C18.5125 47.523 20.3358 45.6997 20.3358 43.4506C20.3358 42.7131 20.1397 42.0213 19.7969 41.425L28.7024 25.0127L28.7037 25.0133C28.7168 24.9902 28.7293 24.9665 28.7417 24.9434L28.7486 24.9322C29.4792 23.5878 29.8944 22.0473 29.8944 20.4095C29.8944 15.1712 25.6477 10.9246 20.4095 10.9246C15.1712 10.9246 10.9246 15.1712 10.9246 20.4095C10.9246 22.7636 11.7819 24.9172 13.2018 26.5756L18.0415 32.5039L20.1957 28.7573L16.264 23.9475C15.4816 23.0077 14.9758 21.7289 14.9758 20.4101C14.9758 17.416 17.4029 14.9889 20.397 14.9889C23.3911 14.9889 25.8182 17.416 25.8182 20.4101C25.8182 21.3792 25.5641 22.289 25.1182 23.0764L25.1157 23.0808L16.2933 39.3787Z"
fillRule="evenodd" fill="#1F1F1F"
clipRule="evenodd" />
d="M13.4805 35.166L13.4805 34.8968C13.5528 26.7095 20.2122 20.0947 28.4165 20.0947L28.4171 20.0947L28.4171 37.2721H28.4176C34.571 37.2721 39.5657 42.2334 39.6196 48.3741V48.5751C39.5657 54.7136 34.5746 59.6736 28.4242 59.6771H28.4177V59.6772H25.4304C23.7805 59.6772 22.443 58.3397 22.443 56.6898C22.443 55.04 23.7805 53.7025 25.4304 53.7025H28.4051V53.7026C29.4363 53.7026 30.2722 52.8667 30.2722 51.8355C30.2722 50.8084 29.4428 49.975 28.4171 49.9685V49.9681H28.4102C20.2088 49.9647 13.5527 43.3512 13.4805 35.166ZM28.4177 20.0948L36.6329 20.0948C40.345 20.0948 43.3544 23.1042 43.3544 26.8163C43.3544 30.5285 40.3451 33.5378 36.6329 33.5378L28.4177 33.5378L28.4177 20.0948ZM28.4049 37.2724C27.3737 37.2724 26.5378 36.4365 26.5378 35.4053C26.5378 34.3741 27.3737 33.5382 28.4049 33.5382V37.2724Z"
fill="url(#paint1_radial_574_6111)"
/>
</g>
<defs>
<filter
id="filter0_i_574_6111"
x="3.76172"
y="0.67749"
width="51.5312"
height="53.291"
filterUnits="userSpaceOnUse"
colorInterpolationFilters="sRGB"
>
<feFlood floodOpacity="0" result="BackgroundImageFix" />
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
<feColorMatrix
in="SourceAlpha"
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
result="hardAlpha"
/>
<feOffset dy="4" />
<feGaussianBlur stdDeviation="8" />
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.15 0" />
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_574_6111" />
</filter>
<filter
id="filter1_i_574_6111"
x="13.4805"
y="20.0947"
width="29.875"
height="43.5825"
filterUnits="userSpaceOnUse"
colorInterpolationFilters="sRGB"
>
<feFlood floodOpacity="0" result="BackgroundImageFix" />
<feBlend mode="normal" in="SourceGraphic" in2="BackgroundImageFix" result="shape" />
<feColorMatrix
in="SourceAlpha"
type="matrix"
values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0"
result="hardAlpha"
/>
<feOffset dy="4" />
<feGaussianBlur stdDeviation="12" />
<feComposite in2="hardAlpha" operator="arithmetic" k2="-1" k3="1" />
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.2 0" />
<feBlend mode="normal" in2="shape" result="effect1_innerShadow_574_6111" />
</filter>
<linearGradient
id="paint0_linear_574_6111"
x1="28.407"
y1="25.323"
x2="3.76172"
y2="25.323"
gradientUnits="userSpaceOnUse"
>
<stop stopColor="#FF1818" />
<stop offset="0.835" stopColor="#FFC700" />
</linearGradient>
<radialGradient
id="paint1_radial_574_6111"
cx="0"
cy="0"
r="1"
gradientUnits="userSpaceOnUse"
gradientTransform="translate(43.5954 26.9914) rotate(125.992) scale(39.6798 39.1304)"
>
<stop stopColor="#FF0000" />
<stop offset="1" stopColor="#6732FF" />
</radialGradient>
</defs>
</svg> </svg>
); );
}); });
@@ -151,36 +80,17 @@ const InvertedIcon = React.memo(function () {
return ( return (
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<path <path
d="M0 13.3981C0 5.99852 5.99852 0 13.3981 0H46.6019C54.0015 0 60 5.99852 60 13.3981V46.6019C60 54.0015 54.0015 60 46.6019 60H13.3981C5.99852 60 0 54.0015 0 46.6019V13.3981Z" d="M30 60C46.5685 60 60 46.5685 60 30C60 13.4315 46.5685 0 30 0C13.4315 0 0 13.4315 0 30C0 46.5685 13.4315 60 30 60Z"
fill="url(#paint0_linear_569_5866)" fill="#1F1F1F"
/> />
<path <path
fill-rule="evenodd" d="M48.9051 22.462C48.9051 19.0552 46.8158 16.1367 43.8486 14.9172L43.567 14.8054L44.4605 13.2581C44.7184 12.8116 44.3962 12.254 43.8804 12.254H35.9965C35.4814 12.254 35.1592 12.8123 35.4164 13.2581L39.3584 20.0855C39.6163 20.532 40.2607 20.532 40.5179 20.0855L41.5107 18.3658L42.4474 18.7748C43.8598 19.4111 44.8427 20.8242 44.8427 22.4658C44.8427 23.0908 44.7003 23.6822 44.4461 24.211L35.1904 44.0382H35.191C35.108 44.2112 34.9856 44.3704 34.8245 44.5022C34.3312 44.9062 33.6056 44.9055 33.1123 44.5009C33.0411 44.4428 32.9781 44.3792 32.9219 44.3111L25.2553 34.9117L23.1141 38.6857L29.9059 47.0298C30.8994 48.1588 32.3549 48.8706 33.9771 48.8706C36.2088 48.8706 38.1258 47.5225 38.9575 45.5955L48.1358 25.9263C48.6291 24.8748 48.9051 23.7009 48.9051 22.462Z"
clip-rule="evenodd" fill="#F5BC41"
d="M29.5856 25.4583L36.212 25.4583C38.5885 25.4583 40.515 27.3848 40.515 29.7613C40.515 32.1378 38.5885 34.0643 36.212 34.0643L29.5856 34.0643C28.1361 34.0643 26.9611 35.2394 26.9611 36.6889C26.9611 38.1383 28.1362 39.3134 29.5856 39.3134C33.9555 39.3134 37.4985 42.8535 37.5031 47.2222V47.2393C37.4985 51.608 33.9555 55.1482 29.5856 55.1482H27.1761C26.463 55.1482 25.885 54.5701 25.885 53.8571C25.885 53.1441 26.463 52.566 27.1761 52.566H29.5856C31.0351 52.566 32.2102 51.3911 32.2102 49.9416C32.2102 48.4921 31.0351 47.317 29.5856 47.317C23.5529 47.317 18.6617 42.4292 18.6562 36.3978V36.3775C18.6617 30.3461 23.5529 25.4583 29.5856 25.4583Z"
fill="black"
/> />
<path <path
fill-rule="evenodd" d="M16.2933 39.3787C16.2833 39.3787 16.2733 39.3781 16.2633 39.3781C14.0142 39.3781 12.1909 41.2014 12.1909 43.4506C12.1909 45.6997 14.0142 47.523 16.2633 47.523C18.5125 47.523 20.3358 45.6997 20.3358 43.4506C20.3358 42.7131 20.1397 42.0213 19.7969 41.425L28.7024 25.0127L28.7037 25.0133C28.7168 24.9902 28.7293 24.9665 28.7417 24.9434L28.7486 24.9322C29.4792 23.5878 29.8944 22.0473 29.8944 20.4095C29.8944 15.1712 25.6477 10.9246 20.4095 10.9246C15.1712 10.9246 10.9246 15.1712 10.9246 20.4095C10.9246 22.7636 11.7819 24.9172 13.2018 26.5756L18.0415 32.5039L20.1957 28.7573L16.264 23.9475C15.4816 23.0077 14.9758 21.7289 14.9758 20.4101C14.9758 17.416 17.4029 14.9889 20.397 14.9889C23.3911 14.9889 25.8182 17.416 25.8182 20.4101C25.8182 21.3792 25.5641 22.289 25.1182 23.0764L25.1157 23.0808L16.2933 39.3787Z"
clip-rule="evenodd" fill="#F5BC41"
d="M29.5868 8.67749L45.5503 8.67749C48.7109 8.67749 51.2731 11.2397 51.2731 14.4002C51.2731 17.5608 48.7109 20.123 45.5503 20.123L31.9874 20.123C30.6594 20.1323 29.5857 21.2117 29.5857 22.5419V22.5419H29.5856V23.2213C22.3185 23.222 16.4268 29.1103 16.4206 36.3762V36.3993C16.4241 40.5418 18.3408 44.2365 21.3346 46.6476C14.4743 43.5135 9.70703 36.5918 9.70703 28.5567C9.70703 17.5779 18.6069 8.67784 29.5856 8.6776L29.5856 20.123H29.5868L29.5868 8.67749ZM29.5856 39.3135V47.3171C23.5535 47.3164 18.6631 42.4289 18.6576 36.3978V36.3776C18.6631 30.3466 23.5535 25.4591 29.5856 25.4583V34.0644C28.1368 34.0652 26.9625 35.2399 26.9625 36.6889C26.9625 38.138 28.1368 39.3127 29.5856 39.3135ZM29.5856 37.0764V36.3015C29.5852 36.3015 29.5847 36.3015 29.5842 36.3015V37.0764C29.5847 37.0764 29.5852 37.0764 29.5856 37.0764Z"
fill="black"
/> />
<defs>
<linearGradient
id="paint0_linear_569_5866"
x1="9.6215e-06"
y1="-4.68362e-06"
x2="60"
y2="60"
gradientUnits="userSpaceOnUse"
>
<stop stop-color="#EFBB07" />
<stop offset="0.0001" stop-color="#682BD8" />
<stop offset="0.505" stop-color="#FF0000" />
<stop offset="0.88" stop-color="#EFBB07" />
</linearGradient>
</defs>
</svg> </svg>
); );
}); });
@@ -189,15 +99,11 @@ const GrayscaleIcon = React.memo(function () {
return ( return (
<svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="60" height="60" viewBox="0 0 60 60" fill="none" xmlns="http://www.w3.org/2000/svg">
<path <path
fill-rule="evenodd" d="M48.9051 22.462C48.9051 19.0552 46.8158 16.1367 43.8486 14.9172L43.567 14.8054L44.4605 13.2581C44.7184 12.8116 44.3962 12.254 43.8804 12.254H35.9965C35.4814 12.254 35.1592 12.8123 35.4164 13.2581L39.3584 20.0855C39.6163 20.532 40.2607 20.532 40.5179 20.0855L41.5107 18.3658L42.4474 18.7748C43.8598 19.4111 44.8427 20.8242 44.8427 22.4658C44.8427 23.0908 44.7003 23.6822 44.4461 24.211L35.1904 44.0382H35.191C35.108 44.2112 34.9856 44.3704 34.8245 44.5022C34.3312 44.9062 33.6056 44.9055 33.1123 44.5009C33.0411 44.4428 32.9781 44.3792 32.9219 44.3111L25.2553 34.9117L23.1141 38.6857L29.9059 47.0298C30.8994 48.1588 32.3549 48.8706 33.9771 48.8706C36.2088 48.8706 38.1258 47.5225 38.9575 45.5955L48.1358 25.9263C48.6291 24.8748 48.9051 23.7009 48.9051 22.462Z"
clip-rule="evenodd"
d="M29.5856 25.4583L36.212 25.4583C38.5885 25.4583 40.515 27.3848 40.515 29.7613C40.515 32.1378 38.5885 34.0643 36.212 34.0643L29.5856 34.0643C28.1361 34.0643 26.9611 35.2394 26.9611 36.6889C26.9611 38.1383 28.1362 39.3134 29.5856 39.3134C33.9555 39.3134 37.4985 42.8535 37.5031 47.2222V47.2393C37.4985 51.608 33.9555 55.1482 29.5856 55.1482H27.1761C26.463 55.1482 25.885 54.5701 25.885 53.8571C25.885 53.1441 26.463 52.566 27.1761 52.566H29.5856C31.0351 52.566 32.2102 51.3911 32.2102 49.9416C32.2102 48.4921 31.0351 47.317 29.5856 47.317C23.5529 47.317 18.6617 42.4292 18.6562 36.3978V36.3775C18.6617 30.3461 23.5529 25.4583 29.5856 25.4583Z"
fill="white" fill="white"
/> />
<path <path
fill-rule="evenodd" d="M16.2933 39.3787C16.2833 39.3787 16.2733 39.3781 16.2633 39.3781C14.0142 39.3781 12.1909 41.2014 12.1909 43.4506C12.1909 45.6997 14.0142 47.523 16.2633 47.523C18.5125 47.523 20.3358 45.6997 20.3358 43.4506C20.3358 42.7131 20.1397 42.0213 19.7969 41.425L28.7024 25.0127L28.7037 25.0133C28.7168 24.9902 28.7293 24.9665 28.7417 24.9434L28.7486 24.9322C29.4792 23.5878 29.8944 22.0473 29.8944 20.4095C29.8944 15.1712 25.6477 10.9246 20.4095 10.9246C15.1712 10.9246 10.9246 15.1712 10.9246 20.4095C10.9246 22.7636 11.7819 24.9172 13.2018 26.5756L18.0415 32.5039L20.1957 28.7573L16.264 23.9475C15.4816 23.0077 14.9758 21.7289 14.9758 20.4101C14.9758 17.416 17.4029 14.9889 20.397 14.9889C23.3911 14.9889 25.8182 17.416 25.8182 20.4101C25.8182 21.3792 25.5641 22.289 25.1182 23.0764L25.1157 23.0808L16.2933 39.3787Z"
clip-rule="evenodd"
d="M29.5868 8.67749L45.5503 8.67749C48.7109 8.67749 51.2731 11.2397 51.2731 14.4002C51.2731 17.5608 48.7109 20.123 45.5503 20.123L31.9874 20.123C30.6594 20.1323 29.5857 21.2117 29.5857 22.5419V22.5419H29.5856V23.2213C22.3185 23.222 16.4268 29.1103 16.4206 36.3762V36.3993C16.4241 40.5418 18.3408 44.2365 21.3346 46.6476C14.4743 43.5135 9.70703 36.5918 9.70703 28.5567C9.70703 17.5779 18.6069 8.67784 29.5856 8.6776L29.5856 20.123H29.5868L29.5868 8.67749ZM29.5856 39.3135V47.3171C23.5535 47.3164 18.6631 42.4289 18.6576 36.3978V36.3776C18.6631 30.3466 23.5535 25.4591 29.5856 25.4583V34.0644C28.1368 34.0652 26.9625 35.2399 26.9625 36.6889C26.9625 38.138 28.1368 39.3127 29.5856 39.3135ZM29.5856 37.0764V36.3015C29.5852 36.3015 29.5847 36.3015 29.5842 36.3015V37.0764C29.5847 37.0764 29.5852 37.0764 29.5856 37.0764Z"
fill="white" fill="white"
/> />
</svg> </svg>

View File

@@ -1,128 +1,123 @@
.Root { .Root {
border: none; border: none;
padding: 0; padding: 0;
background: transparent; background: transparent;
box-sizing: border-box; box-sizing: border-box;
position: fixed; position: fixed;
top: 0; top: 0;
left: 0; left: 0;
right: 0; right: 0;
bottom: 0; bottom: 0;
&.is-hidden { &.has-backdrop {
visibility: hidden; background-color: var(--theme-color-bg-1-transparent);
pointer-events: none; }
}
&.is-locking-scroll {
&.has-backdrop { background-color: transparent;
background-color: var(--theme-color-bg-1-transparent); }
}
&:not(.has-backdrop):not(.is-locking-scroll) {
&.is-locking-scroll { pointer-events: none;
background-color: transparent; }
} }
&:not(.has-backdrop):not(.is-locking-scroll) { .VisibleDialog {
pointer-events: none; filter: drop-shadow(0 4px 15px var(--theme-color-bg-1-transparent-2));
} box-shadow: 0 0 10px -5px var(--theme-color-bg-1-transparent-2);
} position: absolute;
width: var(--width);
.VisibleDialog { pointer-events: all;
filter: drop-shadow(0 4px 15px var(--theme-color-bg-1-transparent-2));
box-shadow: 0 0 10px -5px var(--theme-color-bg-1-transparent-2); .Root.is-centered & {
position: absolute; top: 50%;
width: var(--width); left: 50%;
pointer-events: all; animation: enter-centered var(--speed-quick) var(--easing-base) both;
}
.Root.is-centered & {
top: 50%; .Root:not(.is-centered) &.is-visible {
left: 50%; &.is-variant-default {
animation: enter-centered var(--speed-quick) var(--easing-base) both; animation: enter var(--speed-quick) var(--easing-base) both;
} }
.Root:not(.is-centered) &.is-visible { &.is-variant-select {
&.is-variant-default { transform: translate(var(--offsetX), var(--offsetY));
animation: enter var(--speed-quick) var(--easing-base) both; }
} }
&.is-variant-select { &::after {
transform: translate(var(--offsetX), var(--offsetY)); content: '';
} position: absolute;
} top: 0;
left: 0;
&::after { right: 0;
content: ''; bottom: 0;
position: absolute; background-color: var(--background);
top: 0; border-radius: 2px;
left: 0; overflow: hidden;
right: 0; }
bottom: 0; }
background-color: var(--background);
border-radius: 2px; .Arrow {
overflow: hidden; position: absolute;
} width: 0;
} height: 0;
top: var(--arrow-top);
.Arrow { left: var(--arrow-left);
position: absolute; pointer-events: none;
width: 0;
height: 0; &::after {
top: var(--arrow-top); content: '';
left: var(--arrow-left); display: block;
pointer-events: none; width: 11px;
height: 11px;
&::after { transform: translate(-50%, -50%) rotate(45deg);
content: ''; background: var(--background);
display: block; }
width: 11px;
height: 11px; &.is-contrast::after {
transform: translate(-50%, -50%) rotate(45deg); background: var(--backgroundContrast);
background: var(--background); }
} }
&.is-contrast::after { .Title {
background: var(--backgroundContrast); background-color: var(--backgroundContrast);
} padding: 12px;
} }
.Title { .MeasuringContainer {
background-color: var(--backgroundContrast); pointer-events: none;
padding: 12px; height: 0;
} overflow: visible;
opacity: 0;
.MeasuringContainer { }
pointer-events: none;
height: 0; .ChildContainer {
overflow: visible; position: relative;
opacity: 0; z-index: 1;
} }
.ChildContainer { @keyframes enter {
position: relative; from {
z-index: 1; opacity: 0;
} transform: translate(
calc(var(--animationStartOffsetX) + var(--offsetX)),
@keyframes enter { calc(var(--animationStartOffsetY) + var(--offsetY))
from { );
opacity: 0; }
transform: translate( to {
calc(var(--animationStartOffsetX) + var(--offsetX)), opacity: 1;
calc(var(--animationStartOffsetY) + var(--offsetY)) transform: translate(var(--offsetX), var(--offsetY));
); }
} }
to {
opacity: 1; @keyframes enter-centered {
transform: translate(var(--offsetX), var(--offsetY)); from {
} opacity: 0;
} transform: translate(-50%, calc(-50% + 16px));
}
@keyframes enter-centered { to {
from { opacity: 1;
opacity: 0; transform: translate(-50%, -50%);
transform: translate(-50%, calc(-50% + 16px)); }
} }
to {
opacity: 1;
transform: translate(-50%, -50%);
}
}

View File

@@ -42,7 +42,6 @@ export interface BaseDialogProps extends UnsafeStyleProps {
isVisible?: boolean; isVisible?: boolean;
hasBackdrop?: boolean; hasBackdrop?: boolean;
hasArrow?: boolean; hasArrow?: boolean;
alwaysMounted?: boolean;
children?: Slot; children?: Slot;
@@ -70,7 +69,6 @@ export function CoreBaseDialog({
isVisible, isVisible,
hasBackdrop, hasBackdrop,
hasArrow, hasArrow,
alwaysMounted,
children, children,
@@ -263,7 +261,7 @@ export function CoreBaseDialog({
} }
}, [background]); }, [background]);
if (!isVisible && !alwaysMounted) return null; if (!isVisible) return null;
return ( return (
<div <div
@@ -272,7 +270,6 @@ export function CoreBaseDialog({
hasBackdrop && css['has-backdrop'], hasBackdrop && css['has-backdrop'],
isLockingScroll && css['is-locking-scroll'], isLockingScroll && css['is-locking-scroll'],
typeof triggerRef === 'undefined' && css['is-centered'], typeof triggerRef === 'undefined' && css['is-centered'],
!isVisible && css['is-hidden'],
css[variant] css[variant]
)} )}
onClick={onClose} onClick={onClose}

View File

@@ -72,7 +72,7 @@ export function MenuDialog({
hasArrow hasArrow
> >
<div className={classNames(css['Root'], css[width])} style={{ maxHeight: UNSAFE_maxHeight }}> <div className={classNames(css['Root'], css[width])} style={{ maxHeight: UNSAFE_maxHeight }}>
{items.filter(Boolean).map((item, i) => { {items.map((item, i) => {
if (item === 'divider') return <div className={css['Divider']} key={i} />; if (item === 'divider') return <div className={css['Divider']} key={i} />;
if (item?.isHidden) return null; if (item?.isHidden) return null;

View File

@@ -11,7 +11,7 @@ import css from './Tooltip.module.scss';
export interface TooltipProps extends UnsafeStyleProps { export interface TooltipProps extends UnsafeStyleProps {
content: SingleSlot; content: SingleSlot;
fineType?: string | string[]; fineType?: string;
children: Slot; children: Slot;
showAfterMs?: number; showAfterMs?: number;
@@ -79,17 +79,9 @@ export function Tooltip({
{fineType && ( {fineType && (
<div className={css['FineType']}> <div className={css['FineType']}>
{Array.isArray(fineType) ? ( <Label size={LabelSize.Small} variant={TextType.Secondary}>
fineType.map((x) => ( {fineType}
<Label size={LabelSize.Small} variant={TextType.Secondary}> </Label>
{x}
</Label>
))
) : (
<Label size={LabelSize.Small} variant={TextType.Secondary}>
{fineType}
</Label>
)}
</div> </div>
)} )}
</BaseDialog> </BaseDialog>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 331 KiB

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 838 B

After

Width:  |  Height:  |  Size: 671 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 925 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -1,5 +1,6 @@
const fs = require('fs'); const fs = require('fs');
const path = require('path'); const path = require('path');
var electron_notarize = require('electron-notarize');
module.exports = async function (params) { module.exports = async function (params) {
if (process.platform !== 'darwin') { if (process.platform !== 'darwin') {
@@ -11,7 +12,7 @@ module.exports = async function (params) {
return; return;
} }
const appId = 'fluxscape.net.fluxscape'; const appId = 'noodl.net.noodl';
const appPath = path.join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`); const appPath = path.join(params.appOutDir, `${params.packager.appInfo.productFilename}.app`);
if (!fs.existsSync(appPath)) { if (!fs.existsSync(appPath)) {
@@ -21,7 +22,6 @@ module.exports = async function (params) {
console.log(`Notarizing ${appId} found at ${appPath}`); console.log(`Notarizing ${appId} found at ${appPath}`);
try { try {
const electron_notarize = require('electron-notarize');
await electron_notarize.notarize({ await electron_notarize.notarize({
appBundleId: appId, appBundleId: appId,
appPath: appPath, appPath: appPath,

View File

@@ -1,10 +1,10 @@
{ {
"name": "fluxscape-editor", "name": "noodl-editor",
"productName": "Fluxscape", "productName": "Noodl Editor",
"description": "Node-Based App Builder for Scalability & Rapid Development, a fork of Noodl", "description": "Low-code for when experience matter",
"author": "Fluxscape <contact@fluxscape.io>", "author": "Noodl <info@noodl.net>",
"homepage": "https://fluxscape.io", "homepage": "https://noodl.net",
"version": "1.1.0", "version": "1.0.1",
"main": "src/main/main.js", "main": "src/main/main.js",
"scripts": { "scripts": {
"build": "npx ts-node -P ./tsconfig.build.json ./scripts/build.ts", "build": "npx ts-node -P ./tsconfig.build.json ./scripts/build.ts",
@@ -15,30 +15,17 @@
"test:ci": "webpack-cli --config=webpackconfigs/webpack.test-ci.js && electron test.js" "test:ci": "webpack-cli --config=webpackconfigs/webpack.test-ci.js && electron test.js"
}, },
"build": { "build": {
"appId": "fluxscape.net.fluxscape", "appId": "noodl.net.noodl-editor",
"afterSign": "./build/macos-notarize.js",
"mac": {
"hardenedRuntime": true,
"entitlements": "build/entitlements.mac.plist",
"extendInfo": {
"LSMultipleInstancesProhibited": true,
"NSMicrophoneUsageDescription": "Allow Fluxscape apps that you create and run to access the microphone?",
"NSCameraUsageDescription": "Allow Fluxscape apps that you create and run to access the camera?"
}
},
"win": { "win": {
"target": "nsis" "target": "nsis"
}, },
"nsis": { "nsis": {
"guid": "fluxscape.net.fluxscape" "guid": "noodl.net.noodl-editor"
},
"linux": {
"target": "deb"
}, },
"protocols": { "protocols": {
"name": "fluxscape", "name": "noodl",
"schemes": [ "schemes": [
"fluxscape" "noodl"
] ]
}, },
"npmRebuild": false, "npmRebuild": false,
@@ -58,7 +45,7 @@
] ]
}, },
"dependencies": { "dependencies": {
"@electron/remote": "^2.1.2", "@electron/remote": "^2.1.1",
"@jaames/iro": "^5.5.2", "@jaames/iro": "^5.5.2",
"@microsoft/fetch-event-source": "^2.0.1", "@microsoft/fetch-event-source": "^2.0.1",
"@noodl/git": "file:../noodl-git", "@noodl/git": "file:../noodl-git",
@@ -114,7 +101,7 @@
"babel-loader": "^8.2.4", "babel-loader": "^8.2.4",
"concurrently": "^7.4.0", "concurrently": "^7.4.0",
"css-loader": "^6.7.1", "css-loader": "^6.7.1",
"electron": "31.3.1", "electron": "28.1.4",
"electron-builder": "^24.9.1", "electron-builder": "^24.9.1",
"file-loader": "^6.2.0", "file-loader": "^6.2.0",
"html-loader": "^3.1.0", "html-loader": "^3.1.0",

View File

@@ -7,7 +7,6 @@ import { BuildTarget, getDistPlatform } from './platform/build-platforms';
// Inputs // Inputs
const DISABLE_SIGNING = valueToBoolean(process.env.DISABLE_SIGNING); const DISABLE_SIGNING = valueToBoolean(process.env.DISABLE_SIGNING);
const TARGET_PLATFORM = process.env.TARGET_PLATFORM; const TARGET_PLATFORM = process.env.TARGET_PLATFORM;
const CSC_NAME = process.env.CSC_NAME;
if (!TARGET_PLATFORM) throw new Error('TARGET_PLATFORM is falsy'); if (!TARGET_PLATFORM) throw new Error('TARGET_PLATFORM is falsy');
@@ -49,7 +48,7 @@ import { BuildTarget, getDistPlatform } from './platform/build-platforms';
DISABLE_SIGNING DISABLE_SIGNING
? {} ? {}
: { : {
CSC_NAME // CSC_NAME: 'Add signing name here'
}, },
process.env process.env
) )

View File

@@ -1,4 +1,4 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg"> <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.609 9.22205H14.4786C15.5078 9.22205 16.3421 10.0512 16.3421 11.074C16.3421 12.0968 15.5078 12.9259 14.4786 12.9259L11.609 12.9259C10.9813 12.9259 10.4725 13.4316 10.4725 14.0555C10.4725 14.6793 10.9813 15.185 11.6091 15.185C13.5014 15.185 15.0357 16.7086 15.0377 18.5888V18.5961C15.0357 20.4763 13.5014 21.9999 11.609 21.9999H10.5656C10.2568 21.9999 10.0065 21.7512 10.0065 21.4443C10.0065 21.1374 10.2568 20.8887 10.5656 20.8887H11.609C12.2367 20.8887 12.7456 20.383 12.7456 19.7591C12.7456 19.1353 12.2368 18.6296 11.6091 18.6296C8.99654 18.6296 6.8784 16.526 6.87604 13.9302V13.9215C6.8784 11.3257 8.99654 9.22205 11.609 9.22205Z" fill="white"/> <path d="M21 8.46785C21 6.8533 20.0098 5.47016 18.6036 4.89221L18.4702 4.83923L18.8936 4.10593C19.0158 3.89432 18.8631 3.63006 18.6187 3.63006H14.8823C14.6382 3.63006 14.4855 3.89465 14.6074 4.10593L16.4756 7.34158C16.5978 7.55318 16.9032 7.55318 17.0251 7.34158L17.4956 6.52658L17.9396 6.72041C18.6089 7.02197 19.0747 7.69166 19.0747 8.46965C19.0747 8.76585 19.0073 9.04613 18.8868 9.29674L14.5003 18.6933C14.461 18.7753 14.4033 18.8507 14.3269 18.9132C14.0931 19.1046 13.7492 19.1043 13.5155 18.9126C13.4817 18.885 13.4519 18.8549 13.4252 18.8226L9.79186 14.368L8.7771 16.1566L11.9959 20.1111C12.4667 20.6461 13.1565 20.9834 13.9253 20.9834C14.983 20.9834 15.8915 20.3446 16.2856 19.4313L20.6354 10.1097C20.8692 9.61133 21 9.05499 21 8.46785Z" fill="white"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M11.6087 2H18.537C19.8973 2 21 3.1027 21 4.46295C21 5.8232 19.8973 6.9259 18.5371 6.9259L11.6087 6.9259L11.6087 2ZM11.6087 8.25933L11.6087 6.9259L11.6087 2.00004L11.6085 2.00004C6.87488 2.00004 3.03361 5.79695 3 10.4934V10.6177C3.02455 14.0492 5.08185 17.0005 8.03472 18.3413C6.73836 17.3036 5.90846 15.7136 5.90692 13.9309V13.9209C5.90963 10.7936 8.46136 8.25933 11.6087 8.25933ZM11.6087 13.8888C11.6086 13.8888 11.6086 13.8888 11.6085 13.8888V14.2223C11.6086 14.2223 11.6086 14.2223 11.6087 14.2223L11.6087 13.8888ZM11.6089 6.92591H12.6504C12.0819 6.92893 11.6206 7.38207 11.6089 7.94502V6.92591Z" fill="white"/> <path d="M5.54434 16.485C5.5396 16.485 5.53486 16.4847 5.53012 16.4847C4.46423 16.4847 3.60013 17.3488 3.60013 18.4148C3.60013 19.4807 4.46423 20.3448 5.53012 20.3448C6.59607 20.3448 7.46017 19.4807 7.46017 18.4148C7.46017 18.0652 7.36723 17.7374 7.20477 17.4548L11.4253 9.67665C11.4315 9.6657 11.438 9.65475 11.4439 9.64381L11.4472 9.6385C11.7934 9.00136 11.9902 8.27128 11.9902 7.4951C11.9902 5.01255 9.97759 3 7.4951 3C5.01255 3 3 5.01255 3 7.4951C3 8.61075 3.40629 9.63139 4.07921 10.4173L6.37285 13.2269L7.39377 11.4513L5.53046 9.17183C5.15966 8.72644 4.91995 8.12039 4.91995 7.49538C4.91995 6.07641 6.0702 4.92616 7.48917 4.92616C8.90814 4.92616 10.0584 6.07641 10.0584 7.49538C10.0584 7.95466 9.93797 8.38583 9.72665 8.759L9.72546 8.76108L5.54434 16.485Z" fill="white"/>
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 125 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 94 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 884 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 68 KiB

After

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M19.35 10.04C18.67 6.59 15.64 4 12 4 9.11 4 6.6 5.64 5.35 8.04 2.34 8.36 0 10.91 0 14c0 3.31 2.69 6 6 6h13c2.76 0 5-2.24 5-5 0-2.64-2.05-4.78-4.65-4.96zM19 18H6c-2.21 0-4-1.79-4-4 0-2.05 1.53-3.76 3.56-3.97l1.07-.11.5-.95C8.08 7.14 9.94 6 12 6c2.62 0 4.88 1.86 5.39 4.43l.3 1.5 1.53.11c1.56.1 2.78 1.41 2.78 2.96 0 1.65-1.35 3-3 3zm-9-3.82l-2.09-2.09L6.5 13.5 10 17l6.01-6.01-1.41-1.41z"/></svg>

After

Width:  |  Height:  |  Size: 526 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 540 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg>

After

Width:  |  Height:  |  Size: 175 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><g fill="none"><path d="M0 0h24v24H0V0z"/><path opacity=".87" d="M0 0h24v24H0V0z"/></g><path d="M21 3.01H3c-1.1 0-2 .9-2 2V9h2V4.99h18v14.03H3V15H1v4.01c0 1.1.9 1.98 2 1.98h18c1.1 0 2-.88 2-1.98v-14c0-1.11-.9-2-2-2zM11 16l4-4-4-4v3H1v2h10v3zM23 3.01H1V9h2V4.99h18v14.03H3V15H1v5.99h22V3.01zM11 16l4-4-4-4v3H1v2h10v3z"/></svg>

After

Width:  |  Height:  |  Size: 408 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M4 6H2v16h16v-2H4V6zm18-4H6v16h16V2zm-3 9H9V9h10v2zm-4 4H9v-2h6v2zm4-8H9V5h10v2z"/></svg>

After

Width:  |  Height:  |  Size: 220 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><g fill="none"><path d="M0 0h24v24H0V0z"/><path opacity=".87" d="M0 0h24v24H0V0z"/></g><path d="M3 13h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7zm-4 6h2v-2H3v2zm0 4h2v-2H3v2zm0-8h2V7H3v2zm4 4h14v-2H7v2zm0 4h14v-2H7v2zM7 7v2h14V7H7z"/></svg>

After

Width:  |  Height:  |  Size: 360 B

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24"><path fill="none" d="M0 0h24v24H0V0z"/><path d="M19.44 12.99l-.01.02c.04-.33.08-.67.08-1.01 0-.34-.03-.66-.07-.99l.01.02 2.44-1.92-2.43-4.22-2.87 1.16.01.01c-.52-.4-1.09-.74-1.71-1h.01L14.44 2H9.57l-.44 3.07h.01c-.62.26-1.19.6-1.71 1l.01-.01-2.88-1.17-2.44 4.22 2.44 1.92.01-.02c-.04.33-.07.65-.07.99 0 .34.03.68.08 1.01l-.01-.02-2.1 1.65-.33.26 2.43 4.2 2.88-1.15-.02-.04c.53.41 1.1.75 1.73 1.01h-.03L9.58 22h4.85s.03-.18.06-.42l.38-2.65h-.01c.62-.26 1.2-.6 1.73-1.01l-.02.04 2.88 1.15 2.43-4.2s-.14-.12-.33-.26l-2.11-1.66zM12 15.5c-1.93 0-3.5-1.57-3.5-3.5s1.57-3.5 3.5-3.5 3.5 1.57 3.5 3.5-1.57 3.5-3.5 3.5z"/></svg>

After

Width:  |  Height:  |  Size: 701 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 522 KiB

View File

@@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
<title>Fluxscape</title> <title>Noodl</title>
<link href="../assets/lib/fontawesome/css/font-awesome.min.css" rel="stylesheet" /> <link href="../assets/lib/fontawesome/css/font-awesome.min.css" rel="stylesheet" />
<link href="../assets/css/style.css" rel="stylesheet" /> <link href="../assets/css/style.css" rel="stylesheet" />

View File

@@ -2,11 +2,6 @@ import { Keybinding } from '@noodl-utils/keyboard/Keybinding';
import { KeyCode, KeyMod } from '@noodl-utils/keyboard/KeyCode'; import { KeyCode, KeyMod } from '@noodl-utils/keyboard/KeyCode';
export namespace Keybindings { export namespace Keybindings {
export const SEARCH = new Keybinding(KeyMod.CtrlCmd, KeyCode.KEY_F);
export const CLOUD_SERVICE_OPEN_DASHBOARD = new Keybinding(KeyMod.CtrlCmd, KeyMod.Shift, KeyCode.KEY_P);
export const CLOUD_SERVICE_OPEN_DASHBOARD_BROWSER = new Keybinding(KeyMod.CtrlCmd, KeyCode.KEY_P);
export const REFRESH_PREVIEW = new Keybinding(KeyMod.CtrlCmd, KeyCode.KEY_R); 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_DEVTOOLS = new Keybinding(KeyMod.CtrlCmd, KeyCode.KEY_D);
export const OPEN_CLOUD_DEVTOOLS = new Keybinding(KeyMod.CtrlCmd, KeyMod.Shift, KeyCode.KEY_R); export const OPEN_CLOUD_DEVTOOLS = new Keybinding(KeyMod.CtrlCmd, KeyMod.Shift, KeyCode.KEY_R);

View File

@@ -1,142 +0,0 @@
import React, { createContext, useContext, useState, useEffect } from 'react';
import { type ComponentModel } from '@noodl-models/componentmodel';
import { type NodeGraphNode } from '@noodl-models/nodegraphmodel';
import { type NodeLibraryNodeType } from '@noodl-models/nodelibrary';
import { type Slot } from '@noodl-core-ui/types/global';
import { ProjectModel } from '@noodl-models/projectmodel';
import { EventDispatcher } from '../../../../shared/utils/EventDispatcher';
export type NodeReference = {
type: NodeLibraryNodeType | undefined;
displayName: string;
referenaces: {
displayName: string;
node?: NodeGraphNode;
component: ComponentModel;
}[];
};
export interface NodeReferencesContext {
nodeReferences: NodeReference[];
}
const NodeReferencesContext = createContext<NodeReferencesContext>({
nodeReferences: [],
});
// Since all the editor code is not written in React we need a way to be able to
// access this information outside of React too.
let HACK_nodeReferences: NodeReference[] = [];
export function HACK_findNodeReference(componentName: string): NodeReference | undefined {
return HACK_nodeReferences.find(x => x.type?.fullName === componentName);
}
export interface NodeReferencesContextProps {
children: Slot;
}
export function NodeReferencesContextProvider({ children }: NodeReferencesContextProps) {
const [group] = useState({});
const [nodeReferences, setNodeReferences] = useState<NodeReference[]>([]);
useEffect(() => {
function updateIndex() {
const types: { [key: string]: NodeReference['type'] } = {};
const references = new Map<string, NodeReference['referenaces']>();
function handleComponent(component: ComponentModel) {
component.forEachNode((node: NodeGraphNode) => {
const name = node.type.name;
// Add the reference
references.set(name, [
...(references.get(name) || []),
{
displayName: component.displayName || component.name,
node,
component
}
]);
// Repeater
if (name === 'For Each' && node.parameters.template) {
const templateComponent = ProjectModel.instance.getComponentWithName(node.parameters.template);
if (templateComponent) {
references.set(templateComponent.fullName, [
...(references.get(templateComponent.fullName) || []),
{
displayName: component.displayName || component.name,
node,
component
}
]);
handleComponent(templateComponent);
}
}
// Add some metadata for this node if we dont have it yet.
if (!types[name]) {
types[name] = node.type;
}
});
}
// Loop all the nodes in the project
ProjectModel.instance.forEachComponent(handleComponent);
// Combine the result to look a little better.
const results: NodeReference[] = Array.from(references.keys())
.map((key) => ({
type: types[key],
displayName: types[key]?.displayName || key,
referenaces: references.get(key)
}))
.sort((a, b) => b.referenaces.length - a.referenaces.length);
HACK_nodeReferences = results;
setNodeReferences(results);
}
updateIndex();
EventDispatcher.instance.on(
[
'Model.nodeAdded',
'Model.nodeRemoved',
'Model.componentAdded',
'Model.componentRemoved',
'Model.componentRenamed'
],
updateIndex,
group
);
return function () {
EventDispatcher.instance.off(group);
};
}, []);
return (
<NodeReferencesContext.Provider
value={{
nodeReferences,
}}
>
{children}
</NodeReferencesContext.Provider>
);
}
export function useNodeReferencesContext() {
const context = useContext(NodeReferencesContext);
if (context === undefined) {
throw new Error('useNodeReferencesContext must be a child of NodeReferencesContextProvider');
}
return context;
}

View File

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

View File

@@ -1,35 +0,0 @@
import React, { createContext, useContext, useEffect } from 'react';
import { Slot } from '@noodl-core-ui/types/global';
import { commandEventHandler } from './iframe';
export interface PluginContext {}
const PluginContext = createContext<PluginContext>({});
export interface PluginContextProps {
children: Slot;
}
export function PluginContextProvider({ children }: PluginContextProps) {
// Listen for all the iframe commands
useEffect(() => {
window.addEventListener('message', commandEventHandler, false);
return function () {
window.removeEventListener('message', commandEventHandler, false);
};
}, []);
return <PluginContext.Provider value={{}}>{children}</PluginContext.Provider>;
}
export function usePluginContext() {
const context = useContext(PluginContext);
if (context === undefined) {
throw new Error('usePluginContext must be a child of PluginContextProvider');
}
return context;
}

View File

@@ -1,24 +0,0 @@
import { ToastLayer } from '../../../views/ToastLayer';
export type Command = {
kind: 'notify';
messageType: 'info' | 'success' | 'error';
message: string;
};
export async function execute(command: Command, _event: MessageEvent) {
switch (command.messageType || 'info') {
case 'info': {
ToastLayer.showInteraction(String(command.message));
break;
}
case 'success': {
ToastLayer.showSuccess(String(command.message));
break;
}
case 'error': {
ToastLayer.showError(String(command.message));
break;
}
}
}

View File

@@ -1,169 +0,0 @@
import s3 from 's3';
import { filesystem, platform } from '@noodl/platform';
import { Environment, EnvironmentDataFormat } from '@noodl-models/CloudServices';
import { ProjectModel } from '@noodl-models/projectmodel';
import { createEditorCompilation } from '@noodl-utils/compilation/compilation.editor';
import { guid } from '@noodl-utils/utils';
import { ToastLayer } from '../../../views/ToastLayer';
export type Command = {
kind: 'upload-aws-s3';
taskId: string;
cloudService: EnvironmentDataFormat;
s3: {
accessKeyId: string;
secretAccessKey: string;
sessionToken: string;
region: string;
bucket: string;
prefix: string;
}
messages: {
progress: string;
success: string;
failure: string;
}
// Initial version to a more extendable system that can be used with these
// kind of events.
events: {
complete: {
kind: "fetch",
resource: string,
options: RequestInit
}[]
}
};
export async function execute(command: Command, event: MessageEvent) {
const project = ProjectModel.instance;
const taskId = command.taskId || guid();
// Setup the build steps
const compilation = createEditorCompilation(project).addProjectBuildScripts();
// Create a temp folder
const tempDir = platform.getTempPath() + '/upload-' + taskId;
// Deploy to temp folder
await compilation.deployToFolder(tempDir, {
environment: command.cloudService ? new Environment(command.cloudService) : undefined
});
// Upload to S3
try {
await uploadDirectory(
{
localDir: tempDir,
accessKeyId: command.s3.accessKeyId,
secretAccessKey: command.s3.secretAccessKey,
sessionToken: command.s3.sessionToken,
region: command.s3.region,
bucket: command.s3.bucket,
prefix: command.s3.prefix
},
({ progress, total }) => {
ToastLayer.showProgress(command.messages.progress, (progress / total) * 100, taskId);
}
);
ToastLayer.showSuccess(command.messages.success);
} catch (error) {
console.error(error);
ToastLayer.showError(command.messages.failure);
} finally {
ToastLayer.hideProgress(taskId);
}
// Clean up the temp folder
filesystem.removeDirRecursive(tempDir);
// NOTE: Would be nice to clean up the events in here, so "complete" is like
// "finally". And then also have "success" and "failure".
// Notify that the process is done
event.source.postMessage({
kind: "upload-aws-s3",
id: taskId,
status: "complete",
}, { targetOrigin: event.origin })
// Execute complete event
if (Array.isArray(command?.events?.complete)) {
for (const event of command.events.complete) {
if (event.kind === "fetch") {
await fetch(event.resource, event.options);
} else {
console.error("invalid event type", event);
}
}
}
}
function uploadDirectory(
options: {
localDir: string;
accessKeyId: string;
secretAccessKey: string;
sessionToken: string;
region: string;
bucket: string;
prefix: string;
},
progress: (args: { progress: number; total: number }) => void
) {
return new Promise<void>((resolve, reject) => {
// https://github.com/noodlapp/node-s3-client?tab=readme-ov-file#create-a-client
const client = s3.createClient({
maxAsyncS3: 20, // this is the default
s3RetryCount: 3, // this is the default
s3RetryDelay: 1000, // this is the default
multipartUploadThreshold: 20971520, // this is the default (20 MB)
multipartUploadSize: 15728640, // this is the default (15 MB)
s3Options: {
accessKeyId: options.accessKeyId,
secretAccessKey: options.secretAccessKey,
sessionToken: options.sessionToken,
region: options.region
}
});
function getFileCacheControl(fullPath: string) {
switch (fullPath.split('.').at(-1)) {
case 'html':
return 'no-cache';
default: {
const TIME_1 = 31536000; // 365 days
const TIME_2 = 10800; // 3 hours for files with hash
const maxAge = /-[a-f0-9]{16}\./.test(fullPath) ? TIME_1 : TIME_2;
return `public, max-age=${maxAge}`;
}
}
}
const uploader = client.uploadDir({
localDir: options.localDir,
deleteRemoved: true,
s3Params: {
Bucket: options.bucket,
Prefix: options.prefix
},
getS3Params(fullPath, _s3Object, callback) {
callback(null, {
CacheControl: getFileCacheControl(fullPath)
});
}
});
uploader.on('error', function (error) {
reject(error);
});
uploader.on('progress', function () {
progress({ progress: uploader.progressAmount, total: uploader.progressTotal });
});
uploader.on('end', function () {
resolve();
});
});
}

View File

@@ -1,19 +0,0 @@
import * as Notify from './commands/notify';
import * as UploadAwsS3 from './commands/upload-aws-s3';
type IFrameCommand = Notify.Command | UploadAwsS3.Command;
const commands: Record<IFrameCommand['kind'], (command: IFrameCommand, event: MessageEvent) => Promise<void>> = {
notify: Notify.execute,
'upload-aws-s3': UploadAwsS3.execute
};
export function commandEventHandler(event: MessageEvent) {
try {
const command = event.data;
const handler = commands[command.kind];
handler && handler(command, event);
} catch (error) {
console.error(error);
}
}

View File

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

View File

@@ -38,7 +38,7 @@ async function directChatOpenAi({ messages, provider, abortController, onEnd, on
stream: true stream: true
}), }),
async onopen(response) { async onopen(response) {
if (response.ok && response.headers.get('content-type').includes(EventStreamContentType)) { if (response.ok && response.headers.get('content-type') === EventStreamContentType) {
return; // everything's good return; // everything's good
} else if (response.status >= 400 && response.status < 500 && response.status !== 429) { } else if (response.status >= 400 && response.status < 500 && response.status !== 429) {
// client-side errors are usually non-retriable: // client-side errors are usually non-retriable:

View File

@@ -3,7 +3,7 @@ import { JSONStorage } from '@noodl/platform';
import { CreateEnvironment, CreateEnvironmentRequest, UpdateEnvironmentRequest } from '@noodl-models/CloudServices'; import { CreateEnvironment, CreateEnvironmentRequest, UpdateEnvironmentRequest } from '@noodl-models/CloudServices';
/** The data format is separated from our internal model. */ /** The data format is separated from our internal model. */
export type EnvironmentDataFormat = { type EnvironmentDataFormat = {
enabled: boolean; enabled: boolean;
id: string; id: string;
name: string; name: string;

View File

@@ -57,13 +57,10 @@ export class CloudFunctionAdapter extends NodeTypeAdapter {
// Collect all cloud function components // Collect all cloud function components
const functionRequestNodes = ProjectModel.instance.getNodesWithType('noodl.cloud.request'); const functionRequestNodes = ProjectModel.instance.getNodesWithType('noodl.cloud.request');
const functions = functionRequestNodes const functions = functionRequestNodes.map((r) => {
.map((r) => { const component = r.owner.owner;
const component = r.owner.owner; return component.fullName;
return component.fullName; });
})
// Remove all the Cloud Trigger functions
.filter((x) => !x.startsWith('/#__cloud__/__noodl_cloud_triggers__'));
ports.push({ ports.push({
plug: 'input', plug: 'input',

View File

@@ -1,4 +1,4 @@
import { AppRouter } from "./AppRouter"; import { AppRouter } from "noodl-editor/src/editor/src/pages/AppRouter";
export class AppRoute { export class AppRoute {
constructor(public readonly router: AppRouter) {} constructor(public readonly router: AppRouter) {}

View File

@@ -1,6 +1,4 @@
import { NodeGraphContextProvider } from '@noodl-contexts/NodeGraphContext/NodeGraphContext'; import { NodeGraphContextProvider } from '@noodl-contexts/NodeGraphContext/NodeGraphContext';
import { NodeReferencesContextProvider } from '@noodl-contexts/NodeReferencesContext';
import { PluginContextProvider } from '@noodl-contexts/PluginContext';
import { ProjectDesignTokenContextProvider } from '@noodl-contexts/ProjectDesignTokenContext'; import { ProjectDesignTokenContextProvider } from '@noodl-contexts/ProjectDesignTokenContext';
import { useKeyboardCommands } from '@noodl-hooks/useKeyboardCommands'; import { useKeyboardCommands } from '@noodl-hooks/useKeyboardCommands';
import { useModel } from '@noodl-hooks/useModel'; import { useModel } from '@noodl-hooks/useModel';
@@ -224,30 +222,26 @@ export function EditorPage({ route }: EditorPageProps) {
return ( return (
<NodeGraphContextProvider> <NodeGraphContextProvider>
<NodeReferencesContextProvider> <ProjectDesignTokenContextProvider>
<ProjectDesignTokenContextProvider> <BaseWindow>
<PluginContextProvider> {isLoading ? (
<BaseWindow> <ActivityIndicator />
{isLoading ? ( ) : (
<ActivityIndicator /> <>
) : ( <FrameDivider
<> first={<SidePanel />}
<FrameDivider second={<ErrorBoundary>{Boolean(Document) && <Document />}</ErrorBoundary>}
first={<SidePanel />} sizeMin={200}
second={<ErrorBoundary>{Boolean(Document) && <Document />}</ErrorBoundary>} size={frameDividerSize}
sizeMin={200} horizontal
size={frameDividerSize} onSizeChanged={setFrameDividerSize}
horizontal />
onSizeChanged={setFrameDividerSize}
/>
{Boolean(lesson) && <Frame instance={lesson} isContentSize isFitWidth />} {Boolean(lesson) && <Frame instance={lesson} isContentSize isFitWidth />}
</> </>
)} )}
</BaseWindow> </BaseWindow>
</PluginContextProvider> </ProjectDesignTokenContextProvider>
</ProjectDesignTokenContextProvider>
</NodeReferencesContextProvider>
</NodeGraphContextProvider> </NodeGraphContextProvider>
); );
} }

View File

@@ -109,7 +109,7 @@ function TopBar({ showSpinner, setShowSpinner }: TopBarProps) {
}} }}
/> />
<TextButton label="Docs" onClick={() => platform.openExternal(getDocsEndpoint())} /> <TextButton label="Docs" onClick={() => platform.openExternal(getDocsEndpoint())} />
<TextButton label="Community" onClick={() => platform.openExternal('https://www.fluxscape.io/community')} /> <TextButton label="Community" onClick={() => platform.openExternal('https://www.noodl.net/community')} />
</HStack> </HStack>
</div> </div>
); );

View File

@@ -1,6 +1,7 @@
import { AppRegistry } from '@noodl-models/app_registry'; import { AppRegistry } from '@noodl-models/app_registry';
import { SidebarModel } from '@noodl-models/sidebar'; import { SidebarModel } from '@noodl-models/sidebar';
import { Keybindings } from '@noodl-constants/Keybindings'; import { Keybinding } from '@noodl-utils/keyboard/Keybinding';
import { KeyCode, KeyMod } from '@noodl-utils/keyboard/KeyCode';
import { IconName } from '@noodl-core-ui/components/common/Icon'; import { IconName } from '@noodl-core-ui/components/common/Icon';
@@ -68,7 +69,7 @@ export function installSidePanel({ isLesson }: SetupEditorOptions) {
SidebarModel.instance.register({ SidebarModel.instance.register({
id: 'search', id: 'search',
name: 'Search', name: 'Search',
fineType: Keybindings.SEARCH.label, fineType: new Keybinding(KeyMod.CtrlCmd, KeyCode.KEY_F).label,
order: 2, order: 2,
icon: IconName.Search, icon: IconName.Search,
panel: SearchPanel panel: SearchPanel

View File

@@ -16,7 +16,6 @@ import { projectFromDirectory, unzipIntoDirectory } from '../models/projectmodel
import FileSystem from './filesystem'; import FileSystem from './filesystem';
import { tracker } from './tracker'; import { tracker } from './tracker';
import { guid } from './utils'; import { guid } from './utils';
import { getTopLevelWorkingDirectory } from '@noodl/git/src/core/open';
export interface ProjectItem { export interface ProjectItem {
id: string; id: string;
@@ -268,15 +267,12 @@ export class LocalProjectsModel extends Model {
}); });
} }
/** isGitProject(project: ProjectModel): boolean {
* Check if this project is in a git repository. // TODO: check if there's is git in any parent folder too
*
* @param project // Check if the git folder exists.
* @returns const gitPath = filesystem.join(project._retainedProjectDirectory, '.git');
*/ return filesystem.exists(gitPath);
async isGitProject(project: ProjectModel): Promise<boolean> {
const gitPath = await getTopLevelWorkingDirectory(project._retainedProjectDirectory);
return gitPath !== null;
} }
setCurrentGlobalGitAuth(projectId: string) { setCurrentGlobalGitAuth(projectId: string) {

View File

@@ -67,14 +67,6 @@ async function _writeFileToFolder({
runtimeType runtimeType
}: WriteFileToFolderArgs) { }: WriteFileToFolderArgs) {
const fullPath = filesystem.join(getExternalFolderPath(), runtimeType, url); const fullPath = filesystem.join(getExternalFolderPath(), runtimeType, url);
if (!filesystem.exists(fullPath)) {
// TODO: Save this warning somewhere, usually, this is not an issue though.
// This occurred because building in dev mode does not create the source map
// files which it expects to copy over.
return;
}
let content = await filesystem.readFile(fullPath); let content = await filesystem.readFile(fullPath);
let filename = url; let filename = url;

View File

@@ -41,7 +41,7 @@ export class HtmlProcessor {
baseUrl = baseUrl + '/'; baseUrl = baseUrl + '/';
} }
const title = parameters.title || settings.htmlTitle || 'Fluxscape Viewer'; const title = parameters.title || settings.htmlTitle || 'Noodl Viewer';
let headCode = settings.headCode || ''; let headCode = settings.headCode || '';
if (parameters.headCode) { if (parameters.headCode) {

View File

@@ -74,13 +74,7 @@ export const deployCloudFunctionBuildScript: BuildScript = {
'X-Parse-Application-Id': environment.appId, 'X-Parse-Application-Id': environment.appId,
'X-Parse-Master-Key': environment.masterKey 'X-Parse-Master-Key': environment.masterKey
}, },
body: JSON.stringify({ body: JSON.stringify({ deploy: json, runtime: manifest.version })
// Project ID, let the server know about which project is pushing changes.
projectId: context.project.id,
projectName: context.project.name,
deploy: json,
runtime: manifest.version
})
}); });
// NOTE: Expecting that we always get a JSON response // NOTE: Expecting that we always get a JSON response

View File

@@ -6,7 +6,7 @@ import { ITemplateProvider, ProgressCallback, TemplateItem, TemplateListFilter }
*/ */
export class NoodlDocsTemplateProvider implements ITemplateProvider { export class NoodlDocsTemplateProvider implements ITemplateProvider {
get name(): string { get name(): string {
return this.getDocsEndpoint() || 'https://docs.fluxscape.io'; return 'https://docs.noodl.net';
} }
constructor(private readonly getDocsEndpoint: () => string) {} constructor(private readonly getDocsEndpoint: () => string) {}

View File

@@ -2,5 +2,5 @@ const remote = require('@electron/remote');
export default function getDocsEndpoint() { export default function getDocsEndpoint() {
const localDocs = remote.getGlobal('useLocalDocs'); const localDocs = remote.getGlobal('useLocalDocs');
return localDocs ? 'http://localhost:3000' : 'https://docs.fluxscape.io'; return localDocs ? 'http://localhost:3000' : 'https://noodlapp.github.io/noodl-docs/';
} }

View File

@@ -11,14 +11,6 @@ export interface ArrayDiff<T> {
changed: T[]; changed: T[];
unchanged: T[]; unchanged: T[];
} }
export function createEmptyArrayDiff<T>(): ArrayDiff<T> {
return {
deleted: [],
created: [],
changed: [],
unchanged: [],
}
}
export interface ProjectDiffItem { export interface ProjectDiffItem {
graph: TSFixme; graph: TSFixme;

View File

@@ -13,7 +13,6 @@ export default class SchemaHandler {
public dbCollections: TSFixme[]; public dbCollections: TSFixme[];
public systemCollections: TSFixme[]; public systemCollections: TSFixme[];
public configSchema: TSFixme; public configSchema: TSFixme;
public parseServerVersion: string;
constructor() { constructor() {
EventDispatcher.instance.on( EventDispatcher.instance.on(
@@ -120,20 +119,6 @@ export default class SchemaHandler {
console.log(e); console.log(e);
} }
}); });
// Get Parse Server Version & Supported features
fetch(environment.url + '/serverInfo', {
method: 'POST',
body: JSON.stringify({
"_method": "GET",
"_ApplicationId": environment.appId,
"_MasterKey": environment.masterKey,
})
})
.then((response) => response.json())
.then((json) => {
this.parseServerVersion = json.parseServerVersion;
});
}); });
}); });
} }
@@ -144,20 +129,10 @@ export default class SchemaHandler {
ProjectModel.instance.setMetaData('dbCollections', this.dbCollections); ProjectModel.instance.setMetaData('dbCollections', this.dbCollections);
ProjectModel.instance.setMetaData('systemCollections', this.systemCollections); ProjectModel.instance.setMetaData('systemCollections', this.systemCollections);
ProjectModel.instance.setMetaData('dbConfigSchema', this.configSchema); ProjectModel.instance.setMetaData('dbConfigSchema', this.configSchema);
const versionNumbers = this.parseServerVersion?.split(".")
if (versionNumbers && versionNumbers.length > 0) {
// Let's only save the major version number,
// since this will be used to determine which verison of the API to use.
ProjectModel.instance.setMetaData('dbVersionMajor', versionNumbers[0]);
} else {
ProjectModel.instance.setMetaData('dbVersionMajor', undefined);
}
} else { } else {
ProjectModel.instance.setMetaData('dbCollections', undefined); ProjectModel.instance.setMetaData('dbCollections', undefined);
ProjectModel.instance.setMetaData('systemCollections', undefined); ProjectModel.instance.setMetaData('systemCollections', undefined);
ProjectModel.instance.setMetaData('dbConfigSchema', undefined); ProjectModel.instance.setMetaData('dbConfigSchema', undefined);
ProjectModel.instance.setMetaData('dbVersionMajor', undefined);
} }
} }
} }

View File

@@ -1,7 +1,5 @@
import React, { RefObject } from 'react'; import React, { RefObject } from 'react';
import { ProjectModel } from '@noodl-models/projectmodel';
import { ActivityIndicator } from '@noodl-core-ui/components/common/ActivityIndicator'; import { ActivityIndicator } from '@noodl-core-ui/components/common/ActivityIndicator';
import { BaseDialog } from '@noodl-core-ui/components/layout/BaseDialog'; import { BaseDialog } from '@noodl-core-ui/components/layout/BaseDialog';
import { Tabs } from '@noodl-core-ui/components/layout/Tabs'; import { Tabs } from '@noodl-core-ui/components/layout/Tabs';
@@ -27,12 +25,7 @@ function DeployPopupChild() {
> >
<PopupSection title="Deploy options" /> <PopupSection title="Deploy options" />
<Tabs <Tabs tabs={[{ label: 'Self Hosting', content: <DeployToFolderTab />, testId: 'self-hosting-tab-button' }]} />
tabs={[
{ label: 'Fluxscape', content: <FluxscapeDeployTab />, testId: 'fluxscape-tab-button' },
{ label: 'Self Hosting', content: <DeployToFolderTab />, testId: 'self-hosting-tab-button' }
]}
/>
{hasActivity && <ActivityIndicator isOverlay />} {hasActivity && <ActivityIndicator isOverlay />}
</div> </div>
@@ -55,28 +48,9 @@ export function DeployPopup(props: DeployPopupProps) {
onClose={props.onClose} onClose={props.onClose}
hasArrow hasArrow
isLockingScroll isLockingScroll
alwaysMounted
> >
<DeployPopupChild /> <DeployPopupChild />
</BaseDialog> </BaseDialog>
</DeployContextProvider> </DeployContextProvider>
); );
} }
function FluxscapeDeployTab() {
const params = {};
const projectId = ProjectModel.instance.id;
if (projectId) {
params['projectId'] = projectId;
}
const urlParams = new URLSearchParams(params);
return (
<iframe
src={`https://portal.fluxscape.io/?${urlParams.toString()}`}
style={{ width: '100%', height: '50vh', borderStyle: 'none' }}
/>
);
}

View File

@@ -96,12 +96,6 @@ export class CanvasView extends View {
}); });
} }
}); });
// Patch to open the next window in the same webview.
// Since we don't support multiple webviews.
window.open = function (url) {
window.location.href = url;
}
`; `;
webview.executeJavaScript(code); webview.executeJavaScript(code);

View File

@@ -1,16 +1,13 @@
import classNames from 'classnames'; import classNames from 'classnames';
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { Keybindings } from '@noodl-constants/Keybindings';
import { Environment } from '@noodl-models/CloudServices'; import { Environment } from '@noodl-models/CloudServices';
import ParseDashboardServer from '@noodl-utils/parsedashboardserver'; import ParseDashboardServer from '@noodl-utils/parsedashboardserver';
import { Icon, IconName, IconSize } from '@noodl-core-ui/components/common/Icon'; import { Icon, IconName, IconSize } from '@noodl-core-ui/components/common/Icon';
import { IconButton, IconButtonState, IconButtonVariant } from '@noodl-core-ui/components/inputs/IconButton'; import { IconButton, IconButtonState, IconButtonVariant } from '@noodl-core-ui/components/inputs/IconButton';
import { PrimaryButton, PrimaryButtonSize, PrimaryButtonVariant } from '@noodl-core-ui/components/inputs/PrimaryButton'; import { PrimaryButton, PrimaryButtonSize, PrimaryButtonVariant } from '@noodl-core-ui/components/inputs/PrimaryButton';
import { DialogRenderDirection } from '@noodl-core-ui/components/layout/BaseDialog';
import { Collapsible } from '@noodl-core-ui/components/layout/Collapsible'; import { Collapsible } from '@noodl-core-ui/components/layout/Collapsible';
import { Tooltip } from '@noodl-core-ui/components/popups/Tooltip';
import { Label, LabelSpacingSize } from '@noodl-core-ui/components/typography/Label'; import { Label, LabelSpacingSize } from '@noodl-core-ui/components/typography/Label';
import { Text, TextType } from '@noodl-core-ui/components/typography/Text'; import { Text, TextType } from '@noodl-core-ui/components/typography/Text';
@@ -121,21 +118,12 @@ export function CloudServiceCard({
</div> </div>
{isEditorEnvironment && ( {isEditorEnvironment && (
<Tooltip <PrimaryButton
content="Open the Parse Dashboard" label="Open dashboard"
fineType={[ size={PrimaryButtonSize.Small}
`In Window: ${Keybindings.CLOUD_SERVICE_OPEN_DASHBOARD.label}`, onClick={onDashboardClicked}
`In Browser: ${Keybindings.CLOUD_SERVICE_OPEN_DASHBOARD_BROWSER.label}` isGrowing
]} />
renderDirection={DialogRenderDirection.Below}
>
<PrimaryButton
label="Open dashboard"
size={PrimaryButtonSize.Small}
onClick={onDashboardClicked}
isGrowing
/>
</Tooltip>
)} )}
</div> </div>
</div> </div>

View File

@@ -1,12 +1,14 @@
import { NodeGraphContextTmp } from '@noodl-contexts/NodeGraphContext/NodeGraphContext'; import { NodeGraphContextTmp } from '@noodl-contexts/NodeGraphContext/NodeGraphContext';
import { type NodeReference, useNodeReferencesContext } from '@noodl-contexts/NodeReferencesContext';
import { useFocusRefOnPanelActive } from '@noodl-hooks/useFocusRefOnPanelActive'; import { useFocusRefOnPanelActive } from '@noodl-hooks/useFocusRefOnPanelActive';
import { useNodeLibraryLoaded } from '@noodl-hooks/useNodeLibraryLoaded'; import { useNodeLibraryLoaded } from '@noodl-hooks/useNodeLibraryLoaded';
import React, { useMemo, useRef, useState } from 'react'; import React, { useEffect, useMemo, useRef, useState } from 'react';
import { INodeColorScheme } from '@noodl-types/nodeTypes'; import { INodeColorScheme } from '@noodl-types/nodeTypes';
import { NodeLibrary } from '@noodl-models/nodelibrary'; import { ComponentModel } from '@noodl-models/componentmodel';
import { NodeGraphNode } from '@noodl-models/nodegraphmodel';
import { NodeLibrary, NodeLibraryNodeType } from '@noodl-models/nodelibrary';
import { BasicNodeType } from '@noodl-models/nodelibrary/BasicNodeType'; import { BasicNodeType } from '@noodl-models/nodelibrary/BasicNodeType';
import { ProjectModel } from '@noodl-models/projectmodel';
import { EditorNode } from '@noodl-core-ui/components/common/EditorNode'; import { EditorNode } from '@noodl-core-ui/components/common/EditorNode';
import { IconName, IconSize } from '@noodl-core-ui/components/common/Icon'; import { IconName, IconSize } from '@noodl-core-ui/components/common/Icon';
@@ -24,17 +26,113 @@ import { Section, SectionVariant } from '@noodl-core-ui/components/sidebar/Secti
import { Label } from '@noodl-core-ui/components/typography/Label'; import { Label } from '@noodl-core-ui/components/typography/Label';
import { NodeReferencesPanel_ID } from '.'; import { NodeReferencesPanel_ID } from '.';
import { EventDispatcher } from '../../../../../shared/utils/EventDispatcher';
type ResultItem = {
type: NodeLibraryNodeType;
displayName: string;
referenaces: {
displayName: string;
node?: NodeGraphNode;
component: ComponentModel;
}[];
};
function useNodeReferences() {
const [group] = useState({});
const [result, setResult] = useState<ResultItem[]>([]);
useEffect(() => {
function updateIndex() {
const types: { [key: string]: ResultItem['type'] } = {};
const references = new Map<string, ResultItem['referenaces']>();
function handleComponent(component: ComponentModel) {
component.forEachNode((node: NodeGraphNode) => {
const name = node.type.name;
// Add the reference
references.set(name, [
...(references.get(name) || []),
{
displayName: component.displayName || component.name,
node,
component
}
]);
// Repeater
if (name === 'For Each' && node.parameters.template) {
const templateComponent = ProjectModel.instance.getComponentWithName(node.parameters.template);
if (templateComponent) {
references.set(templateComponent.fullName, [
...(references.get(templateComponent.fullName) || []),
{
displayName: component.displayName || component.name,
node,
component
}
]);
handleComponent(templateComponent);
}
}
// Add some metadata for this node if we dont have it yet.
if (!types[name]) {
types[name] = node.type;
}
});
}
// Loop all the nodes in the project
ProjectModel.instance.forEachComponent(handleComponent);
// Combine the result to look a little better.
const results: ResultItem[] = Array.from(references.keys())
.map((key) => ({
type: types[key],
displayName: types[key]?.displayName || key,
referenaces: references.get(key)
}))
.sort((a, b) => b.referenaces.length - a.referenaces.length);
setResult(results);
}
updateIndex();
EventDispatcher.instance.on(
[
'Model.nodeAdded',
'Model.nodeRemoved',
'Model.componentAdded',
'Model.componentRemoved',
'Model.componentRenamed'
],
updateIndex,
group
);
return function () {
EventDispatcher.instance.off(group);
};
}, []);
return [result];
}
export function NodeReferencesPanel() { export function NodeReferencesPanel() {
const [searchTerm, setSearchTerm] = useState(''); const [searchTerm, setSearchTerm] = useState('');
const [includeCoreNodes, setIncludeCoreNodes] = useState(false); const [includeCoreNodes, setIncludeCoreNodes] = useState(false);
const inputRef = useRef(null); const inputRef = useRef(null);
const { nodeReferences } = useNodeReferencesContext(); const [result] = useNodeReferences();
const nodeLibraryLoaded = useNodeLibraryLoaded(); const nodeLibraryLoaded = useNodeLibraryLoaded();
useFocusRefOnPanelActive(inputRef, NodeReferencesPanel_ID); useFocusRefOnPanelActive(inputRef, NodeReferencesPanel_ID);
function searchFilter(x: NodeReference) { function searchFilter(x: ResultItem) {
if (x.displayName.toLowerCase().includes(searchTerm)) { if (x.displayName.toLowerCase().includes(searchTerm)) {
return true; return true;
} }
@@ -46,7 +144,7 @@ export function NodeReferencesPanel() {
return false; return false;
} }
let filteredResult = nodeReferences.filter(searchFilter); let filteredResult = result.filter(searchFilter);
if (!includeCoreNodes) { if (!includeCoreNodes) {
filteredResult = filteredResult.filter((x) => x.displayName.startsWith('/')); filteredResult = filteredResult.filter((x) => x.displayName.startsWith('/'));
} }
@@ -87,7 +185,7 @@ export function NodeReferencesPanel() {
} }
interface ItemProps { interface ItemProps {
entry: NodeReference; entry: ResultItem;
} }
function Item({ entry }: ItemProps) { function Item({ entry }: ItemProps) {
@@ -147,8 +245,8 @@ function Item({ entry }: ItemProps) {
} }
interface ItemReferenceProps { interface ItemReferenceProps {
entry: NodeReference; entry: ResultItem;
referenace: NodeReference['referenaces'][0]; referenace: ResultItem['referenaces'][0];
colors: INodeColorScheme; colors: INodeColorScheme;
} }

View File

@@ -33,7 +33,6 @@ import { History } from './components/History';
import { LocalChanges } from './components/LocalChanges'; import { LocalChanges } from './components/LocalChanges';
import { MergeConflicts } from './components/MergeConflicts'; import { MergeConflicts } from './components/MergeConflicts';
import { useVersionControlContext, VersionControlProvider } from './context'; import { useVersionControlContext, VersionControlProvider } from './context';
import { convertGitRemoteUrlToRepoUrl } from './github';
enum ViewState { enum ViewState {
Default, Default,
@@ -41,6 +40,25 @@ enum ViewState {
BranchMerge BranchMerge
} }
function convertGitRemoteUrlToRepoUrl(gitRemoteUrl) {
// Remove the .git extension if present
gitRemoteUrl = gitRemoteUrl.replace(/\.git$/, '');
// Extract the repository name and owner from the URL
const regex = /^(?:https?:\/\/)?github\.com\/([^/]+)\/([^/]+)$/;
const match = gitRemoteUrl.match(regex);
if (match) {
const owner = match[1];
const repo = match[2];
// Construct the GitHub repository URL
const repoUrl = `https://github.com/${owner}/${repo}`;
return repoUrl;
} else {
throw new Error('Invalid GitHub Git remote URL');
}
}
function BaseVersionControlPanel() { function BaseVersionControlPanel() {
const { git, activeTabId, setActiveTabId, localChangesCount, branchStatus, fetch, updateLocalDiff } = const { git, activeTabId, setActiveTabId, localChangesCount, branchStatus, fetch, updateLocalDiff } =
useVersionControlContext(); useVersionControlContext();
@@ -199,7 +217,6 @@ function BaseVersionControlPanel() {
export function VersionControlPanel() { export function VersionControlPanel() {
const [git, setGit] = useState<Git>(null); const [git, setGit] = useState<Git>(null);
const [state, setState] = useState<'loading' | 'loaded' | 'not-git'>('loading');
async function createGit() { async function createGit() {
const gitClient = new Git(mergeProject); const gitClient = new Git(mergeProject);
@@ -207,18 +224,12 @@ export function VersionControlPanel() {
setGit(gitClient); setGit(gitClient);
} }
const isGitProject = git === null ? LocalProjectsModel.instance.isGitProject(ProjectModel.instance) : true;
useEffect(() => { useEffect(() => {
LocalProjectsModel.instance if (isGitProject) {
.isGitProject(ProjectModel.instance) createGit();
.then(async (isGitProject) => { }
if (isGitProject) { }, [isGitProject]);
await createGit();
setState('loaded');
} else {
setState('not-git');
}
});
}, []);
async function setupGit() { async function setupGit() {
const gitClient = new Git(mergeProject); const gitClient = new Git(mergeProject);
@@ -227,7 +238,7 @@ export function VersionControlPanel() {
setGit(gitClient); setGit(gitClient);
} }
if (git === null && state === 'not-git') { if (git === null && !isGitProject) {
return ( return (
<BasePanel isFill title="Version Control"> <BasePanel isFill title="Version Control">
<Box hasXSpacing hasYSpacing> <Box hasXSpacing hasYSpacing>

View File

@@ -6,13 +6,11 @@ import { Commit } from '@noodl/git/src/core/models/snapshot';
import { FileChange } from '@noodl/git/src/core/models/status'; import { FileChange } from '@noodl/git/src/core/models/status';
import { revRange } from '@noodl/git/src/core/rev-list'; import { revRange } from '@noodl/git/src/core/rev-list';
import { ProjectModel } from '@noodl-models/projectmodel';
import { applyPatches } from '@noodl-models/ProjectPatches/applypatches'; import { applyPatches } from '@noodl-models/ProjectPatches/applypatches';
import { mergeProject } from '@noodl-utils/projectmerger'; import { mergeProject } from '@noodl-utils/projectmerger';
import { ProjectDiff, diffProject } from '@noodl-utils/projectmerger.diff'; import { ProjectDiff, diffProject } from '@noodl-utils/projectmerger.diff';
import { useVersionControlContext } from '../context'; import { useVersionControlContext } from '../context';
import { getProjectFilePath } from '../context/DiffUtils';
import { DiffList } from './DiffList'; import { DiffList } from './DiffList';
//Kind: //Kind:
@@ -126,10 +124,7 @@ async function getMergeDiff(repositoryPath: string, commit: Commit, refToDiffTo:
} }
async function getProjectFile(commit: Commit) { async function getProjectFile(commit: Commit) {
const projectFilePath = getProjectFilePath(commit.repositoryDir, ProjectModel.instance._retainedProjectDirectory); const projectContent = JSON.parse(await commit.getFileAsString('project.json'));
const projectContentRaw = await commit.getFileAsString(projectFilePath);
const projectContent = JSON.parse(projectContentRaw);
applyPatches(projectContent); applyPatches(projectContent);
return projectContent; return projectContent;
} }

View File

@@ -61,7 +61,7 @@ export function DiffList({ diff, fileChanges, componentDiffTitle, actions, commi
const [imageDiff, setImageDiff] = useState<IImageDiff>(null); const [imageDiff, setImageDiff] = useState<IImageDiff>(null);
const components = diff?.components ? getChangedComponents(diff.components) : []; const components = diff?.components ? getChangedComponents(diff.components) : [];
const files = (fileChanges || [])?.filter((f) => !f.path.endsWith('project.json')) || []; const files = (fileChanges || [])?.filter((f) => f.path !== 'project.json') || [];
const settings = diff?.settings ? getChangedObjectProperties(diff.settings) : []; const settings = diff?.settings ? getChangedObjectProperties(diff.settings) : [];
const colorStyles = diff?.styles.colors ? getChangedObjectProperties(diff.styles.colors) : []; const colorStyles = diff?.styles.colors ? getChangedObjectProperties(diff.styles.colors) : [];
const textStyles = diff?.styles.text ? getChangedObjectProperties(diff.styles.text) : []; const textStyles = diff?.styles.text ? getChangedObjectProperties(diff.styles.text) : [];

View File

@@ -13,15 +13,13 @@ import { EventDispatcher } from '../../../../../../shared/utils/EventDispatcher'
import { ToastLayer } from '../../../ToastLayer/ToastLayer'; import { ToastLayer } from '../../../ToastLayer/ToastLayer';
import { useVersionControlContext } from '../context'; import { useVersionControlContext } from '../context';
import { CommitChangesDiff } from './CommitChangesDiff'; import { CommitChangesDiff } from './CommitChangesDiff';
import { convertGitRemoteUrlToCommitUrl } from '../github';
import { platform } from '@noodl/platform';
export interface HistoryCommitDiffProps { export interface HistoryCommitDiffProps {
commit: Commit; commit: Commit;
} }
export function HistoryCommitDiff({ commit }: HistoryCommitDiffProps) { export function HistoryCommitDiff({ commit }: HistoryCommitDiffProps) {
const { git, repositoryPath, localChangesCount, fetch } = useVersionControlContext(); const { repositoryPath, localChangesCount, fetch } = useVersionControlContext();
const [HaveLocalChangesDialog, showHaveLocalChangesDialog] = useConfirmationDialog({ const [HaveLocalChangesDialog, showHaveLocalChangesDialog] = useConfirmationDialog({
isCancelButtonHidden: true, isCancelButtonHidden: true,
@@ -73,13 +71,6 @@ export function HistoryCommitDiff({ commit }: HistoryCommitDiffProps) {
copyValueToClipboard({ copyValueToClipboard({
value: commit.sha value: commit.sha
}) })
},
git.Provider === 'github' && {
label: 'View on GitHub',
onClick: () => {
const commitLink = convertGitRemoteUrlToCommitUrl(git.OriginUrl, commit.sha);
platform.openExternal(commitLink);
}
} }
]} ]}
/> />

View File

@@ -1,24 +1,21 @@
import path from 'path';
import { getCommit } from '@noodl/git/src/core/logs';
import { FileStatusKind } from '@noodl/git/src/core/models/status';
import { FeedbackType } from '@noodl-constants/FeedbackType';
import { applyPatches } from '@noodl-models/ProjectPatches/applypatches';
import { import {
ProjectDiff, ProjectDiff,
ProjectDiffItem, ProjectDiffItem,
ProjectBasicDiffItem, ProjectBasicDiffItem,
ArrayDiff, ArrayDiff,
diffProject, diffProject
createEmptyArrayDiff
} from '@noodl-utils/projectmerger.diff'; } from '@noodl-utils/projectmerger.diff';
import { IconName } from '@noodl-core-ui/components/common/Icon';
import { ListItemProps } from '@noodl-core-ui/components/layout/ListItem';
import { ProjectModel } from '../../../../models/projectmodel'; import { ProjectModel } from '../../../../models/projectmodel';
export interface ProjectLocalDiff extends ProjectDiff { import { applyPatches } from '@noodl-models/ProjectPatches/applypatches';
import { FileStatusKind } from '@noodl/git/src/core/models/status';
import { IconName } from '@noodl-core-ui/components/common/Icon';
import { ListItemProps } from '@noodl-core-ui/components/layout/ListItem';
import { FeedbackType } from '@noodl-constants/FeedbackType';
import { getCommit } from '@noodl/git/src/core/logs';
export interface ProjectLocalDiff extends ProjectDiff{
baseProject: TSFixme; //Project model as an object from raw json baseProject: TSFixme; //Project model as an object from raw json
commitShaDiffedTo: string; commitShaDiffedTo: string;
} }
@@ -87,49 +84,17 @@ export function getFileStatusIconProps(status: FileStatusKind): Partial<ListItem
} }
} }
export function getProjectFilePath(repositoryPath: string, projectPath: string) { export async function doLocalDiff(repositoryPath: string, headCommitId: string): Promise<ProjectLocalDiff> {
const relativePath = path.relative(repositoryPath, projectPath); const baseCommit = await getCommit(repositoryPath, headCommitId);
const projectFilePath = path.join(relativePath, 'project.json').replaceAll('\\', '/'); const baseProjectJson = await baseCommit.getFileAsString('project.json');
return projectFilePath; const baseProject = JSON.parse(baseProjectJson);
} applyPatches(baseProject);
export async function doLocalDiff( const diff = diffProject(baseProject, ProjectModel.instance.toJSON());
repositoryPath: string,
projectPath: string, return {
headCommitId: string ...diff,
): Promise<ProjectLocalDiff> { baseProject,
const projectFilePath = getProjectFilePath(repositoryPath, projectPath); commitShaDiffedTo: headCommitId
};
try {
const baseCommit = await getCommit(projectPath, headCommitId);
const baseProjectJson = await baseCommit.getFileAsString(projectFilePath);
const baseProject = JSON.parse(baseProjectJson);
applyPatches(baseProject);
const diff = diffProject(baseProject, ProjectModel.instance.toJSON());
return {
...diff,
baseProject,
commitShaDiffedTo: headCommitId
};
} catch (error) {
if (error.toString().includes('exists on disk, but not in')) {
console.warn('project.json does not exist in this commit.');
}
// Return empty state
return {
baseProject: {},
commitShaDiffedTo: headCommitId,
components: createEmptyArrayDiff(),
variants: createEmptyArrayDiff(),
settings: createEmptyArrayDiff(),
styles: {
colors: createEmptyArrayDiff(),
text: createEmptyArrayDiff()
},
cloudservices: createEmptyArrayDiff()
};
}
} }

View File

@@ -8,7 +8,6 @@ import { Slot } from '@noodl-core-ui/types/global';
import { doLocalDiff, ProjectLocalDiff } from './DiffUtils'; import { doLocalDiff, ProjectLocalDiff } from './DiffUtils';
import { useVersionControlFetch } from './fetch.context'; import { useVersionControlFetch } from './fetch.context';
import { BranchStatus, IVersionControlContext } from './types'; import { BranchStatus, IVersionControlContext } from './types';
import { ProjectModel } from '@noodl-models/projectmodel';
const VersionControlContext = createContext<IVersionControlContext>({ const VersionControlContext = createContext<IVersionControlContext>({
git: null, git: null,
@@ -58,8 +57,7 @@ export function VersionControlProvider({ git, children }: { git: Git; children:
(async () => { (async () => {
const currentCommitSha = await git.getHeadCommitId(); const currentCommitSha = await git.getHeadCommitId();
if (currentCommitSha) { if (currentCommitSha) {
const projectPath = ProjectModel.instance._retainedProjectDirectory; const diff = await doLocalDiff(git.repositoryPath, currentCommitSha);
const diff = await doLocalDiff(git.repositoryPath, projectPath, currentCommitSha);
setLocalDiff(diff); setLocalDiff(diff);
} }
})(); })();

View File

@@ -1,23 +0,0 @@
export function convertGitRemoteUrlToRepoUrl(gitRemoteUrl: string): string {
// Remove the .git extension if present
gitRemoteUrl = gitRemoteUrl.replace(/\.git$/, '');
// Extract the repository name and owner from the URL
const regex = /^(?:https?:\/\/)?github\.com\/([^/]+)\/([^/]+)$/;
const match = gitRemoteUrl.match(regex);
if (match) {
const owner = match[1];
const repo = match[2];
// Construct the GitHub repository URL
const repoUrl = `https://github.com/${owner}/${repo}`;
return repoUrl;
} else {
throw new Error('Invalid GitHub Git remote URL');
}
}
export function convertGitRemoteUrlToCommitUrl(gitRemoteUrl: string, commitSha: string): string {
const githubLink = convertGitRemoteUrlToRepoUrl(gitRemoteUrl);
return `${githubLink}/commit/${commitSha}`;
}

View File

@@ -17,11 +17,9 @@ import { EventDispatcher } from '../../../../../shared/utils/EventDispatcher';
import View from '../../../../../shared/view'; import View from '../../../../../shared/view';
import { NodeGraphEditor } from '../../nodegrapheditor'; import { NodeGraphEditor } from '../../nodegrapheditor';
import * as NewPopupLayer from '../../PopupLayer/index'; import * as NewPopupLayer from '../../PopupLayer/index';
import { type PopupMenuItem } from '../../PopupLayer/index';
import { ToastLayer } from '../../ToastLayer/ToastLayer'; import { ToastLayer } from '../../ToastLayer/ToastLayer';
import { ComponentsPanelFolder } from './ComponentsPanelFolder'; import { ComponentsPanelFolder } from './ComponentsPanelFolder';
import { ComponentTemplates } from './ComponentTemplates'; import { ComponentTemplates } from './ComponentTemplates';
import { HACK_findNodeReference } from '@noodl-contexts/NodeReferencesContext';
const PopupLayer = require('@noodl-views/popuplayer'); const PopupLayer = require('@noodl-views/popuplayer');
const ComponentsPanelTemplate = require('../../../templates/componentspanel.html'); const ComponentsPanelTemplate = require('../../../templates/componentspanel.html');
@@ -963,7 +961,7 @@ export class ComponentsPanelView extends View {
forRuntimeType: this.getRuntimeType() forRuntimeType: this.getRuntimeType()
}); });
let items: PopupMenuItem[] = templates.map((t) => ({ let items: TSFixme[] = templates.map((t) => ({
icon: IconName.Plus, icon: IconName.Plus,
label: t.label, label: t.label,
onClick: () => { onClick: () => {
@@ -989,10 +987,6 @@ export class ComponentsPanelView extends View {
}); });
} }
// Find references
const nodeReference = HACK_findNodeReference(scope.comp.name);
const nodeReferencesText = `Used in ${nodeReference?.referenaces?.length || 0} places`;
items = items.concat([ items = items.concat([
{ {
icon: IconName.Pencil, icon: IconName.Pencil,
@@ -1017,9 +1011,6 @@ export class ComponentsPanelView extends View {
_this.onDeleteClicked(scope, el); _this.onDeleteClicked(scope, el);
evt.stopPropagation(); evt.stopPropagation();
} }
},
{
label: nodeReferencesText
} }
]); ]);
@@ -1119,16 +1110,6 @@ export class ComponentsPanelView extends View {
} }
]); ]);
if (scope.canBecomeRoot) {
// Find references
const nodeReference = HACK_findNodeReference(scope.folder.component.name);
const nodeReferencesText = `Used in ${nodeReference?.referenaces?.length || 0} places`;
items = items.concat([{
label: nodeReferencesText
}]);
}
const menu = new NewPopupLayer.PopupMenu({ const menu = new NewPopupLayer.PopupMenu({
items: items items: items
}); });

View File

@@ -5,8 +5,6 @@ import { useSidePanelKeyboardCommands } from '@noodl-hooks/useKeyboardCommands';
import classNames from 'classnames'; import classNames from 'classnames';
import React, { useEffect, useRef, useState } from 'react'; import React, { useEffect, useRef, useState } from 'react';
import { ComponentModel } from '@noodl-models/componentmodel';
import { NodeGraphNode } from '@noodl-models/nodegraphmodel';
import { KeyCode, KeyMod } from '@noodl-utils/keyboard/KeyCode'; import { KeyCode, KeyMod } from '@noodl-utils/keyboard/KeyCode';
import { performSearch } from '@noodl-utils/universal-search'; import { performSearch } from '@noodl-utils/universal-search';
@@ -56,7 +54,7 @@ export function SearchPanel() {
} }
}, [debouncedSearchTerm]); }, [debouncedSearchTerm]);
function onSearchItemClicked(searchResult: SearchResultItem) { function onSearchItemClicked(searchResult) {
if (searchResult.type === 'Component') { if (searchResult.type === 'Component') {
NodeGraphContextTmp.switchToComponent(searchResult.componentTarget, { NodeGraphContextTmp.switchToComponent(searchResult.componentTarget, {
breadcrumbs: false, breadcrumbs: false,
@@ -87,7 +85,29 @@ export function SearchPanel() {
<div className={css.SearchResults}> <div className={css.SearchResults}>
{searchResults.map((component) => ( {searchResults.map((component) => (
<SearchItem key={component.componentId} component={component} onSearchItemClicked={onSearchItemClicked} /> <Section
title={`${component.componentName} (${component.results.length} result${
component.results.length > 1 ? 's' : ''
})`}
key={component.componentId}
variant={SectionVariant.Panel}
>
{component.results.map((result, index) => (
<div
className={classNames(
css.SearchResultItem
// lastActiveComponentId === result.componentTarget.id && css['is-active']
)}
key={index}
onClick={() => onSearchItemClicked(result)}
>
<Label variant={TextType.Proud}>
{result.userLabel ? result.type + ' - ' + result.userLabel : result.type}
</Label>
<Text>{result.label}</Text>
</div>
))}
</Section>
))} ))}
{searchResults.length === 0 && debouncedSearchTerm.length > 0 && ( {searchResults.length === 0 && debouncedSearchTerm.length > 0 && (
<Container hasXSpacing hasYSpacing> <Container hasXSpacing hasYSpacing>
@@ -98,51 +118,3 @@ export function SearchPanel() {
</BasePanel> </BasePanel>
); );
} }
type SearchResultItem = {
componentTarget: ComponentModel;
label: string;
nodeTarget: NodeGraphNode;
type: string;
userLabel: string;
};
type SearchItemProps = {
component: {
componentName: string;
componentId: string;
results: SearchResultItem[];
};
onSearchItemClicked: (item: SearchResultItem) => void;
};
function SearchItem({ component, onSearchItemClicked }: SearchItemProps) {
const resultCountText = `${component.results.length} result${component.results.length > 1 ? 's' : ''}`;
let titleText = `${component.componentName} (${resultCountText})`;
// We expect there to always be at least one result, to get the full component name.
const isInCloudFunctions = component.results[0].componentTarget.name.startsWith('/#__cloud__/');
if (isInCloudFunctions) {
titleText += ' (Cloud Function)';
}
return (
<Section title={titleText} variant={SectionVariant.Panel}>
{component.results.map((result, index) => (
<div
className={classNames(
css.SearchResultItem
// lastActiveComponentId === result.componentTarget.id && css['is-active']
)}
key={index}
onClick={() => onSearchItemClicked(result)}
>
<Label variant={TextType.Proud}>
{result.userLabel ? result.type + ' - ' + result.userLabel : result.type}
</Label>
<Text>{result.label}</Text>
</div>
))}
</Section>
);
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -2,7 +2,7 @@
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<title>Fluxscape Viewer</title> <title>Noodl Viewer</title>
<link href="../../assets/lib/fontawesome/css/font-awesome.min.css" rel="stylesheet"> <link href="../../assets/lib/fontawesome/css/font-awesome.min.css" rel="stylesheet">
<link href="assets/style.css" rel="stylesheet"> <link href="assets/style.css" rel="stylesheet">
<script type="text/javascript" src="../../assets/lib/jquery-min.js"></script> <script type="text/javascript" src="../../assets/lib/jquery-min.js"></script>

View File

@@ -365,7 +365,7 @@ function launchApp() {
click: () => { click: () => {
require('about-window').default({ require('about-window').default({
icon_path: appPath + '/src/assets/images/icon.png', icon_path: appPath + '/src/assets/images/icon.png',
copyright: 'Copyright (c) 2024 Fluxscape LLC', copyright: 'Copyright (c) 2023 Future Platforms AB',
description: buildNumber ? 'Build ' + buildNumber : undefined description: buildNumber ? 'Build ' + buildNumber : undefined
}); });
} }

View File

@@ -67,7 +67,7 @@ function startServer(app, projectGetSettings, projectGetInfo, projectGetComponen
ProjectModules.instance.injectIntoHtml(info.projectDirectory, data, '/', function (injected) { ProjectModules.instance.injectIntoHtml(info.projectDirectory, data, '/', function (injected) {
projectGetSettings((settings) => { projectGetSettings((settings) => {
settings = settings || {}; settings = settings || {};
injected = injected.replace('{{#title#}}', settings.htmlTitle || 'Fluxscape Viewer'); injected = injected.replace('{{#title#}}', settings.htmlTitle || 'Noodl Viewer');
injected = injected.replace('{{#customHeadCode#}}', settings.headCode || ''); injected = injected.replace('{{#customHeadCode#}}', settings.headCode || '');
response.writeHead(200, { response.writeHead(200, {

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 113 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

@@ -3,8 +3,8 @@
"version": "2.7.0", "version": "2.7.0",
"main": "src/index.ts", "main": "src/index.ts",
"description": "", "description": "",
"author": "Fluxscape <contact@fluxscape.io>", "author": "Noodl <info@noodl.net>",
"homepage": "https://fluxscape.io", "homepage": "https://noodl.net",
"dependencies": { "dependencies": {
"desktop-trampoline": "https://github.com/desktop/desktop-trampoline/archive/refs/tags/v0.9.8.tar.gz", "desktop-trampoline": "https://github.com/desktop/desktop-trampoline/archive/refs/tags/v0.9.8.tar.gz",
"dugite": "^1.106.0", "dugite": "^1.106.0",

View File

@@ -22,11 +22,7 @@ export async function open(basePath: string): Promise<string> {
// console.log("VCS error when opening project: " + e); // console.log("VCS error when opening project: " + e);
// } // }
return basePath;
// Find the relative git repository path
const repositoryPath = await getTopLevelWorkingDirectory(basePath);
return repositoryPath;
} }
/** /**

View File

@@ -3,8 +3,8 @@
"version": "2.7.0", "version": "2.7.0",
"main": "src/index.ts", "main": "src/index.ts",
"description": "Cross platform implementation of platform specific features.", "description": "Cross platform implementation of platform specific features.",
"author": "Fluxscape <contact@fluxscape.io>", "author": "Noodl <info@noodl.net>",
"homepage": "https://fluxscape.io", "homepage": "https://noodl.net",
"dependencies": { "dependencies": {
"@noodl/platform": "file:../noodl-platform", "@noodl/platform": "file:../noodl-platform",
"@noodl/platform-node": "file:../noodl-platform-node" "@noodl/platform-node": "file:../noodl-platform-node"

View File

@@ -3,8 +3,8 @@
"version": "2.7.0", "version": "2.7.0",
"main": "src/index.ts", "main": "src/index.ts",
"description": "Cross platform implementation of platform specific features.", "description": "Cross platform implementation of platform specific features.",
"author": "Fluxscape <contact@fluxscape.io>", "author": "Noodl <info@noodl.net>",
"homepage": "https://fluxscape.io", "homepage": "https://noodl.net",
"scripts": { "scripts": {
"test": "jest", "test": "jest",
"test:coverage": "jest --coverage" "test:coverage": "jest --coverage"

View File

@@ -3,6 +3,6 @@
"version": "2.7.0", "version": "2.7.0",
"main": "src/index.ts", "main": "src/index.ts",
"description": "Cross platform implementation of platform specific features.", "description": "Cross platform implementation of platform specific features.",
"author": "Fluxscape <contact@fluxscape.io>", "author": "Noodl <info@noodl.net>",
"homepage": "https://fluxscape.io" "homepage": "https://noodl.net"
} }

View File

@@ -32,15 +32,12 @@ class CloudStore {
_initCloudServices() { _initCloudServices() {
_collections = undefined; // clear collection cache, so it's refetched _collections = undefined; // clear collection cache, so it's refetched
const cloudServices = NoodlRuntime.instance.getMetaData('cloudservices'); const cloudServices = NoodlRuntime.instance.getMetaData('cloudservices');
if (cloudServices) { if (cloudServices) {
this.appId = cloudServices.appId; this.appId = cloudServices.appId;
this.endpoint = cloudServices.endpoint; this.endpoint = cloudServices.endpoint;
} }
const dbVersionMajor = NoodlRuntime.instance.getMetaData('dbVersionMajor');
this.dbVersionMajor = dbVersionMajor;
} }
on() { on() {
@@ -73,9 +70,8 @@ class CloudStore {
xhr.open(options.method || 'GET', this.endpoint + path, true); xhr.open(options.method || 'GET', this.endpoint + path, true);
xhr.setRequestHeader('X-Parse-Application-Id', this.appId); xhr.setRequestHeader('X-Parse-Application-Id', this.appId);
if (typeof _noodl_cloudservices !== 'undefined') { if (typeof _noodl_cloudservices !== 'undefined')
xhr.setRequestHeader('X-Parse-Master-Key', _noodl_cloudservices.masterKey); xhr.setRequestHeader('X-Parse-Master-Key', _noodl_cloudservices.masterKey);
}
// Check for current users // Check for current users
var _cu = localStorage['Parse/' + this.appId + '/currentUser']; var _cu = localStorage['Parse/' + this.appId + '/currentUser'];
@@ -172,10 +168,13 @@ class CloudStore {
return; return;
} }
if (options.where) args.push('match=' + encodeURIComponent(JSON.stringify(options.where)));
if (options.limit) args.push('limit=' + options.limit); if (options.limit) args.push('limit=' + options.limit);
if (options.skip) args.push('skip=' + options.skip); if (options.skip) args.push('skip=' + options.skip);
const grouping = {}; const grouping = {
objectId: null
};
Object.keys(options.group).forEach((k) => { Object.keys(options.group).forEach((k) => {
const _g = {}; const _g = {};
@@ -189,20 +188,7 @@ class CloudStore {
grouping[k] = _g; grouping[k] = _g;
}); });
// I don't know which version the API was changed, lets just say above 4 for now. args.push('group=' + JSON.stringify(grouping));
if (this.dbVersionMajor && this.dbVersionMajor > 4) {
grouping._id = null;
if (options.where) args.push('$match=' + encodeURIComponent(JSON.stringify(options.where)));
args.push('$group=' + JSON.stringify(grouping));
} else {
grouping.objectId = null;
if (options.where) args.push('match=' + encodeURIComponent(JSON.stringify(options.where)));
args.push('group=' + JSON.stringify(grouping));
}
this._makeRequest('/aggregate/' + options.collection + (args.length > 0 ? '?' + args.join('&') : ''), { this._makeRequest('/aggregate/' + options.collection + (args.length > 0 ? '?' + args.join('&') : ''), {
success: function (response) { success: function (response) {
@@ -258,22 +244,11 @@ class CloudStore {
}); });
} }
/**
*
* @param {{
* objectId: string;
* collection: string;
* include?: string[] | string;
* success: (data: unknown) => void;
* error: (error: unknown) => void;
* }} options
*/
fetch(options) { fetch(options) {
const args = []; const args = [];
if (options.include) { if (options.include)
args.push('include=' + (Array.isArray(options.include) ? options.include.join(',') : options.include)); args.push('include=' + (Array.isArray(options.include) ? options.include.join(',') : options.include));
}
this._makeRequest( this._makeRequest(
'/classes/' + options.collection + '/' + options.objectId + (args.length > 0 ? '?' + args.join('&') : ''), '/classes/' + options.collection + '/' + options.objectId + (args.length > 0 ? '?' + args.join('&') : ''),
@@ -445,8 +420,6 @@ class CloudStore {
* file: { * file: {
* name: string; * name: string;
* } * }
* success: (data: unknown) => void;
* error: (error: unknown) => void;
* }} options * }} options
*/ */
deleteFile(options) { deleteFile(options) {
@@ -577,26 +550,21 @@ function _deserializeJSON(data, type, modelScope) {
} }
function _fromJSON(item, collectionName, modelScope) { function _fromJSON(item, collectionName, modelScope) {
const modelStore = modelScope || Model; const m = (modelScope || Model).get(item.objectId);
m._class = collectionName;
const model = modelStore.get(item.objectId); if (collectionName !== undefined && CloudStore._collections[collectionName] !== undefined)
model._class = collectionName; var schema = CloudStore._collections[collectionName].schema;
let schema = undefined; for (var key in item) {
if (collectionName !== undefined && CloudStore._collections[collectionName] !== undefined) { if (key === 'objectId' || key === 'ACL') continue;
schema = CloudStore._collections[collectionName].schema;
var _type = schema && schema.properties && schema.properties[key] ? schema.properties[key].type : undefined;
m.set(key, _deserializeJSON(item[key], _type, modelScope));
} }
for (const key in item) { return m;
if (key === 'objectId' || key === 'ACL') {
continue;
}
const _type = schema && schema.properties && schema.properties[key] ? schema.properties[key].type : undefined;
model.set(key, _deserializeJSON(item[key], _type, modelScope));
}
return model;
} }
CloudStore._fromJSON = _fromJSON; CloudStore._fromJSON = _fromJSON;

View File

@@ -36,15 +36,16 @@ function convertVisualFilter(query, options) {
const _res = {}; const _res = {};
var cond; var cond;
var value = query.input !== undefined ? inputs[query.input] : query.value; var value = query.input !== undefined ? inputs[query.input] : query.value;
if (query.operator === 'exist') { if (query.operator === 'exist') {
_res[query.property] = { $exists: true }; _res[query.property] = { $exists: true };
return _res; return _res;
} else if (query.operator === 'not exist') {
_res[query.property] = { $exists: false };
return _res;
} }
else if (query.operator === 'not exist') {
_res[query.property] = { $exists: false };
return _res;
}
if (value === undefined) return; if (value === undefined) return;
if (CloudStore._collections[options.collectionName]) if (CloudStore._collections[options.collectionName])
@@ -79,6 +80,7 @@ function convertVisualFilter(query, options) {
cond = { $regex: value, $options: 'i' }; cond = { $regex: value, $options: 'i' };
} }
_res[query.property] = cond; _res[query.property] = cond;
return _res; return _res;
@@ -161,22 +163,10 @@ function _value(v) {
return v; return v;
} }
/**
*
* @param {Record<string, unknown>} filter
* @param {{
* collectionName?: string;
* modelScope?: unknown;
* error: (error: string) => void;
* }} options
* @returns
*/
function convertFilterOp(filter, options) { function convertFilterOp(filter, options) {
const keys = Object.keys(filter); const keys = Object.keys(filter);
if (keys.length === 0) return {}; if (keys.length === 0) return {};
if (keys.length !== 1) { if (keys.length !== 1) return options.error('Filter must only have one key found ' + keys.join(','));
return options.error('Filter must only have one key found ' + keys.join(','));
}
const res = {}; const res = {};
const key = keys[0]; const key = keys[0];
@@ -189,27 +179,18 @@ function convertFilterOp(filter, options) {
} else if (filter['idContainedIn'] !== undefined) { } else if (filter['idContainedIn'] !== undefined) {
res['objectId'] = { $in: filter['idContainedIn'] }; res['objectId'] = { $in: filter['idContainedIn'] };
} else if (filter['relatedTo'] !== undefined) { } else if (filter['relatedTo'] !== undefined) {
const modelId = filter['relatedTo']['id']; var modelId = filter['relatedTo']['id'];
if (modelId === undefined) { if (modelId === undefined) return options.error('Must provide id in relatedTo filter');
return options.error('Must provide id in relatedTo filter');
}
const relationKey = filter['relatedTo']['key']; var relationKey = filter['relatedTo']['key'];
if (relationKey === undefined) { if (relationKey === undefined) return options.error('Must provide key in relatedTo filter');
return options.error('Must provide key in relatedTo filter');
}
const className = filter['relatedTo']['className'] || (options.modelScope || Model).get(modelId)?._class;
if (typeof className === 'undefined') {
// Either the pointer is loaded as an object or we allow passing in the className.
return options.error('Must preload the Pointer or include className');
}
var m = (options.modelScope || Model).get(modelId);
res['$relatedTo'] = { res['$relatedTo'] = {
object: { object: {
__type: 'Pointer', __type: 'Pointer',
objectId: modelId, objectId: modelId,
className className: m._class
}, },
key: relationKey key: relationKey
}; };
@@ -227,14 +208,13 @@ function convertFilterOp(filter, options) {
else if (opAndValue['containedIn'] !== undefined) res[key] = { $in: opAndValue['containedIn'] }; else if (opAndValue['containedIn'] !== undefined) res[key] = { $in: opAndValue['containedIn'] };
else if (opAndValue['notContainedIn'] !== undefined) res[key] = { $nin: opAndValue['notContainedIn'] }; else if (opAndValue['notContainedIn'] !== undefined) res[key] = { $nin: opAndValue['notContainedIn'] };
else if (opAndValue['pointsTo'] !== undefined) { else if (opAndValue['pointsTo'] !== undefined) {
let schema = null; var m = (options.modelScope || Model).get(opAndValue['pointsTo']);
if (CloudStore._collections[options.collectionName]) { if (CloudStore._collections[options.collectionName])
schema = CloudStore._collections[options.collectionName].schema; var schema = CloudStore._collections[options.collectionName].schema;
}
const targetClass = var targetClass =
schema && schema.properties && schema.properties[key] ? schema.properties[key].targetClass : undefined; schema && schema.properties && schema.properties[key] ? schema.properties[key].targetClass : undefined;
const type = schema && schema.properties && schema.properties[key] ? schema.properties[key].type : undefined; var type = schema && schema.properties && schema.properties[key] ? schema.properties[key].type : undefined;
if (type === 'Relation') { if (type === 'Relation') {
res[key] = { res[key] = {
@@ -243,13 +223,13 @@ function convertFilterOp(filter, options) {
className: targetClass className: targetClass
}; };
} else { } else {
if (Array.isArray(opAndValue['pointsTo'])) { if (Array.isArray(opAndValue['pointsTo']))
res[key] = { res[key] = {
$in: opAndValue['pointsTo'].map((v) => { $in: opAndValue['pointsTo'].map((v) => {
return { __type: 'Pointer', objectId: v, className: targetClass }; return { __type: 'Pointer', objectId: v, className: targetClass };
}) })
}; };
} else { else
res[key] = { res[key] = {
$eq: { $eq: {
__type: 'Pointer', __type: 'Pointer',
@@ -257,7 +237,6 @@ function convertFilterOp(filter, options) {
className: targetClass className: targetClass
} }
}; };
}
} }
} else if (opAndValue['matchesRegex'] !== undefined) { } else if (opAndValue['matchesRegex'] !== undefined) {
res[key] = { res[key] = {
@@ -278,42 +257,43 @@ function convertFilterOp(filter, options) {
} }
} }
}; };
// Geo points // Geo points
} else if (opAndValue['nearSphere'] !== undefined) { } else if (opAndValue['nearSphere'] !== undefined) {
var _v = opAndValue['nearSphere']; var _v = opAndValue['nearSphere'];
res[key] = { res[key] = {
$nearSphere: { $nearSphere: {
__type: 'GeoPoint', __type: "GeoPoint",
latitude: _v.latitude, latitude: _v.latitude,
longitude: _v.longitude longitude: _v.longitude,
}, },
$maxDistanceInMiles: _v.$maxDistanceInMiles, $maxDistanceInMiles:_v.$maxDistanceInMiles,
$maxDistanceInKilometers: _v.maxDistanceInKilometers, $maxDistanceInKilometers:_v.maxDistanceInKilometers,
$maxDistanceInRadians: _v.maxDistanceInRadians $maxDistanceInRadians:_v.maxDistanceInRadians
}; };
} else if (opAndValue['withinBox'] !== undefined) { } else if (opAndValue['withinBox'] !== undefined) {
var _v = opAndValue['withinBox']; var _v = opAndValue['withinBox'];
res[key] = { res[key] = {
$within: { $within:{
$box: _v.map((gp) => ({ $box: _v.map(gp => ({
__type: 'GeoPoint', __type:"GeoPoint",
latitude: gp.latitude, latitude:gp.latitude,
longitude: gp.longitude longitude:gp.longitude
})) }))
} }
}; };
} else if (opAndValue['withinPolygon'] !== undefined) { } else if (opAndValue['withinPolygon'] !== undefined) {
var _v = opAndValue['withinPolygon']; var _v = opAndValue['withinPolygon'];
res[key] = { res[key] = {
$geoWithin: { $geoWithin:{
$polygon: _v.map((gp) => ({ $polygon: _v.map(gp => ({
__type: 'GeoPoint', __type:"GeoPoint",
latitude: gp.latitude, latitude:gp.latitude,
longitude: gp.longitude longitude:gp.longitude
})) }))
} }
}; };
} }
} else { } else {
options.error('Unrecognized filter keys ' + keys.join(',')); options.error('Unrecognized filter keys ' + keys.join(','));
} }

View File

@@ -12,7 +12,6 @@ function createRecordsAPI(modelScope) {
return { return {
async query(className, query, options) { async query(className, query, options) {
if (typeof className === 'undefined') throw new Error("'className' is undefined");
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
cloudstore().query({ cloudstore().query({
collection: className, collection: className,
@@ -27,9 +26,9 @@ function createRecordsAPI(modelScope) {
include: options ? options.include : undefined, include: options ? options.include : undefined,
select: options ? options.select : undefined, select: options ? options.select : undefined,
count: options ? options.count : undefined, count: options ? options.count : undefined,
success: (results, count) => { success: (results,count) => {
const _results = results.map((r) => cloudstore()._fromJSON(r, className)); const _results = results.map((r) => cloudstore()._fromJSON(r, className));
if (count !== undefined) resolve({ results: _results, count }); if(count !== undefined) resolve({results:_results,count});
else resolve(_results); else resolve(_results);
}, },
error: (err) => { error: (err) => {
@@ -40,7 +39,6 @@ function createRecordsAPI(modelScope) {
}, },
async count(className, query) { async count(className, query) {
if (typeof className === 'undefined') throw new Error("'className' is undefined");
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
cloudstore().count({ cloudstore().count({
collection: className, collection: className,
@@ -62,7 +60,6 @@ function createRecordsAPI(modelScope) {
}, },
async distinct(className, property, query) { async distinct(className, property, query) {
if (typeof className === 'undefined') throw new Error("'className' is undefined");
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
cloudstore().distinct({ cloudstore().distinct({
collection: className, collection: className,
@@ -85,7 +82,6 @@ function createRecordsAPI(modelScope) {
}, },
async aggregate(className, group, query) { async aggregate(className, group, query) {
if (typeof className === 'undefined') throw new Error("'className' is undefined");
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
cloudstore().aggregate({ cloudstore().aggregate({
collection: className, collection: className,
@@ -107,31 +103,19 @@ function createRecordsAPI(modelScope) {
}); });
}, },
/**
*
* @param {string | { getId(): string; }} objectOrId
* @param {{
* className: string;
* include?: string[] | string;
* }} options
* @returns {Promise<unknown>}
*/
async fetch(objectOrId, options) { async fetch(objectOrId, options) {
if (typeof objectOrId === 'undefined') return Promise.reject(new Error("'objectOrId' is undefined."));
if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId(); if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId();
const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class; const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class;
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (!className) { if (!className) return reject('No class name specified');
return reject('No class name specified');
}
cloudstore().fetch({ cloudstore().fetch({
collection: className, collection: className,
objectId: objectOrId, objectId: objectOrId,
include: options ? options.include : undefined, include: options ? options.include : undefined,
success: function (response) { success: function (response) {
const record = cloudstore()._fromJSON(response, className); var record = cloudstore()._fromJSON(response, className);
resolve(record); resolve(record);
}, },
error: function (err) { error: function (err) {
@@ -142,7 +126,6 @@ function createRecordsAPI(modelScope) {
}, },
async increment(objectOrId, properties, options) { async increment(objectOrId, properties, options) {
if (typeof objectOrId === 'undefined') return Promise.reject(new Error("'objectOrId' is undefined."));
if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId(); if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId();
const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class; const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class;
@@ -166,7 +149,6 @@ function createRecordsAPI(modelScope) {
}, },
async save(objectOrId, properties, options) { async save(objectOrId, properties, options) {
if (typeof objectOrId === 'undefined') return Promise.reject(new Error("'objectOrId' is undefined."));
if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId(); if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId();
const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class; const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class;
@@ -197,7 +179,6 @@ function createRecordsAPI(modelScope) {
}, },
async create(className, properties, options) { async create(className, properties, options) {
if (typeof className === 'undefined') throw new Error("'className' is undefined");
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
cloudstore().create({ cloudstore().create({
collection: className, collection: className,
@@ -216,7 +197,6 @@ function createRecordsAPI(modelScope) {
}, },
async delete(objectOrId, options) { async delete(objectOrId, options) {
if (typeof objectOrId === 'undefined') return Promise.reject(new Error("'objectOrId' is undefined."));
if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId(); if (typeof objectOrId !== 'string') objectOrId = objectOrId.getId();
const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class; const className = (options ? options.className : undefined) || (modelScope || Model).get(objectOrId)._class;
@@ -285,7 +265,7 @@ function createRecordsAPI(modelScope) {
resolve(); resolve();
}, },
error: (err) => { error: (err) => {
reject(Error(err || 'Failed to add relation.')); reject(Error(rr || 'Failed to add relation.'));
} }
}); });
}); });

View File

@@ -28,7 +28,6 @@ var DbCollectionNode = {
_this.scheduleAfterInputsHaveUpdated(function () { _this.scheduleAfterInputsHaveUpdated(function () {
_this.flagOutputDirty('count'); _this.flagOutputDirty('count');
_this.flagOutputDirty('firstItemId'); _this.flagOutputDirty('firstItemId');
_this.flagOutputDirty('isEmpty');
collectionChangedScheduled = false; collectionChangedScheduled = false;
}); });
}; };
@@ -67,7 +66,6 @@ var DbCollectionNode = {
_this.flagOutputDirty('count'); _this.flagOutputDirty('count');
_this.flagOutputDirty('firstItemId'); _this.flagOutputDirty('firstItemId');
_this.flagOutputDirty('isEmpty');
} }
if (args.type === 'create') { if (args.type === 'create') {
@@ -93,7 +91,6 @@ var DbCollectionNode = {
_this.flagOutputDirty('count'); _this.flagOutputDirty('count');
_this.flagOutputDirty('firstItemId'); _this.flagOutputDirty('firstItemId');
_this.flagOutputDirty('isEmpty');
} else if (matchesQuery && !_this._internal.collection.contains(m)) { } else if (matchesQuery && !_this._internal.collection.contains(m)) {
// It's not part of the result collection but now matches they query, add it and resort // It's not part of the result collection but now matches they query, add it and resort
_addModelAtCorrectIndex(m); _addModelAtCorrectIndex(m);
@@ -109,7 +106,6 @@ var DbCollectionNode = {
_this.flagOutputDirty('count'); _this.flagOutputDirty('count');
_this.flagOutputDirty('firstItemId'); _this.flagOutputDirty('firstItemId');
_this.flagOutputDirty('isEmpty');
} }
} }
}; };
@@ -157,17 +153,6 @@ var DbCollectionNode = {
} }
} }
}, },
isEmpty: {
type: 'boolean',
displayName: 'Is Empty',
group: 'General',
getter: function () {
if (this._internal.collection) {
return this._internal.collection.size() === 0;
}
return true;
}
},
count: { count: {
type: 'number', type: 'number',
displayName: 'Count', displayName: 'Count',
@@ -204,7 +189,6 @@ var DbCollectionNode = {
setCollection: function (collection) { setCollection: function (collection) {
this.bindCollection(collection); this.bindCollection(collection);
this.flagOutputDirty('firstItemId'); this.flagOutputDirty('firstItemId');
this.flagOutputDirty('isEmpty');
this.flagOutputDirty('items'); this.flagOutputDirty('items');
this.flagOutputDirty('count'); this.flagOutputDirty('count');
}, },
@@ -273,7 +257,7 @@ var DbCollectionNode = {
limit: limit, limit: limit,
skip: skip, skip: skip,
count: count, count: count,
success: (results, count) => { success: (results,count) => {
if (results !== undefined) { if (results !== undefined) {
_c.set( _c.set(
results.map((i) => { results.map((i) => {
@@ -283,9 +267,10 @@ var DbCollectionNode = {
}) })
); );
} }
if (count !== undefined) { if(count !== undefined) {
this._internal.storageSettings.storageTotalCount = count; this._internal.storageSettings.storageTotalCount = count;
if (this.hasOutput('storageTotalCount')) this.flagOutputDirty('storageTotalCount'); if(this.hasOutput('storageTotalCount'))
this.flagOutputDirty('storageTotalCount');
} }
this.setCollection(_c); this.setCollection(_c);
this.sendSignalOnOutput('fetched'); this.sendSignalOnOutput('fetched');
@@ -398,7 +383,7 @@ var DbCollectionNode = {
if (!storageSettings['storageEnableLimit']) return; if (!storageSettings['storageEnableLimit']) return;
else return storageSettings['storageSkip'] || 0; else return storageSettings['storageSkip'] || 0;
}, },
getStorageFetchTotalCount: function () { getStorageFetchTotalCount: function() {
const storageSettings = this._internal.storageSettings; const storageSettings = this._internal.storageSettings;
return !!storageSettings['storageEnableCount']; return !!storageSettings['storageEnableCount'];

View File

@@ -2,10 +2,10 @@
const { Node, EdgeTriggeredInput } = require('../../../../noodl-runtime'); const { Node, EdgeTriggeredInput } = require('../../../../noodl-runtime');
const Model = require('../../../model'); var Model = require('../../../model');
const CloudStore = require('../../../api/cloudstore'); const CloudStore = require('../../../api/cloudstore');
const ModelNodeDefinition = { var ModelNodeDefinition = {
name: 'DbModel2', name: 'DbModel2',
docs: 'https://docs.noodl.net/nodes/data/cloud-data/record', docs: 'https://docs.noodl.net/nodes/data/cloud-data/record',
displayNodeName: 'Record', displayNodeName: 'Record',
@@ -21,11 +21,11 @@ const ModelNodeDefinition = {
} }
], ],
initialize: function () { initialize: function () {
const internal = this._internal; var internal = this._internal;
internal.inputValues = {}; internal.inputValues = {};
internal.relationModelIds = {}; internal.relationModelIds = {};
const _this = this; var _this = this;
this._internal.onModelChangedCallback = function (args) { this._internal.onModelChangedCallback = function (args) {
if (_this.isInputConnected('fetch')) return; if (_this.isInputConnected('fetch')) return;
@@ -109,18 +109,13 @@ const ModelNodeDefinition = {
displayName: 'Id', displayName: 'Id',
group: 'General', group: 'General',
set: function (value) { set: function (value) {
if (value instanceof Model) { if (value instanceof Model) value = value.getId();
// Can be passed as model as well // Can be passed as model as well
value = value.getId(); else if (typeof value === 'object') value = Model.create(value).getId(); // If this is an js object, dereference it
} else if (typeof value === 'object') {
// If this is an js object, dereference it
value = Model.create(value).getId();
}
this._internal.modelId = value; // Wait to fetch data this._internal.modelId = value; // Wait to fetch data
if (this.isInputConnected('fetch') === false) { if (this.isInputConnected('fetch') === false) this.setModelID(value);
this.setModelID(value); else {
} else {
this.flagOutputDirty('id'); this.flagOutputDirty('id');
} }
} }
@@ -143,10 +138,9 @@ const ModelNodeDefinition = {
this.setModel(model); this.setModel(model);
}, },
setModel: function (model) { setModel: function (model) {
if (this._internal.model) { if (this._internal.model)
// Remove old listener if existing // Remove old listener if existing
this._internal.model.off('change', this._internal.onModelChangedCallback); this._internal.model.off('change', this._internal.onModelChangedCallback);
}
this._internal.model = model; this._internal.model = model;
this.flagOutputDirty('id'); this.flagOutputDirty('id');
@@ -154,9 +148,7 @@ const ModelNodeDefinition = {
// We have a new model, mark all outputs as dirty // We have a new model, mark all outputs as dirty
for (var key in model.data) { for (var key in model.data) {
if (this.hasOutput('prop-' + key)) { if (this.hasOutput('prop-' + key)) this.flagOutputDirty('prop-' + key);
this.flagOutputDirty('prop-' + key);
}
} }
this.sendSignalOnOutput('fetched'); this.sendSignalOnOutput('fetched');
}, },
@@ -192,7 +184,7 @@ const ModelNodeDefinition = {
} }
}, },
scheduleFetch: function () { scheduleFetch: function () {
const _this = this; var _this = this;
const internal = this._internal; const internal = this._internal;
this.scheduleOnce('Fetch', function () { this.scheduleOnce('Fetch', function () {
@@ -207,13 +199,12 @@ const ModelNodeDefinition = {
collection: internal.collectionId, collection: internal.collectionId,
objectId: internal.modelId, // Get the objectId part of the model id objectId: internal.modelId, // Get the objectId part of the model id
success: function (response) { success: function (response) {
const model = cloudstore._fromJSON(response, internal.collectionId); var model = cloudstore._fromJSON(response, internal.collectionId);
if (internal.model !== model) { if (internal.model !== model) {
// Check if we need to change model // Check if we need to change model
if (internal.model) { if (internal.model)
// Remove old listener if existing // Remove old listener if existing
internal.model.off('change', internal.onModelChangedCallback); internal.model.off('change', internal.onModelChangedCallback);
}
internal.model = model; internal.model = model;
model.on('change', internal.onModelChangedCallback); model.on('change', internal.onModelChangedCallback);
@@ -222,10 +213,8 @@ const ModelNodeDefinition = {
delete response.objectId; delete response.objectId;
for (const key in response) { for (var key in response) {
if (_this.hasOutput('prop-' + key)) { if (_this.hasOutput('prop-' + key)) _this.flagOutputDirty('prop-' + key);
_this.flagOutputDirty('prop-' + key);
}
} }
_this.sendSignalOnOutput('fetched'); _this.sendSignalOnOutput('fetched');
@@ -237,6 +226,7 @@ const ModelNodeDefinition = {
}); });
}, },
scheduleStore: function () { scheduleStore: function () {
var _this = this;
var internal = this._internal; var internal = this._internal;
if (!internal.model) return; if (!internal.model) return;
@@ -257,6 +247,8 @@ const ModelNodeDefinition = {
}); });
}, },
registerInputIfNeeded: function (name) { registerInputIfNeeded: function (name) {
var _this = this;
if (this.hasInput(name)) { if (this.hasInput(name)) {
return; return;
} }
@@ -336,7 +328,8 @@ function updatePorts(nodeId, parameters, editorConnection, graphModel) {
var p = props[key]; var p = props[key];
if (ports.find((_p) => _p.name === key)) continue; if (ports.find((_p) => _p.name === key)) continue;
if (p.type !== 'Relation') { if (p.type === 'Relation') {
} else {
// Other schema type ports // Other schema type ports
const _typeMap = { const _typeMap = {
String: 'string', String: 'string',
@@ -380,16 +373,16 @@ module.exports = {
function _managePortsForNode(node) { function _managePortsForNode(node) {
updatePorts(node.id, node.parameters, context.editorConnection, graphModel); updatePorts(node.id, node.parameters, context.editorConnection, graphModel);
node.on('parameterUpdated', function () { node.on('parameterUpdated', function (event) {
updatePorts(node.id, node.parameters, context.editorConnection, graphModel); updatePorts(node.id, node.parameters, context.editorConnection, graphModel);
}); });
graphModel.on('metadataChanged.dbCollections', function () { graphModel.on('metadataChanged.dbCollections', function (data) {
CloudStore.invalidateCollections(); CloudStore.invalidateCollections();
updatePorts(node.id, node.parameters, context.editorConnection, graphModel); updatePorts(node.id, node.parameters, context.editorConnection, graphModel);
}); });
graphModel.on('metadataChanged.systemCollections', function () { graphModel.on('metadataChanged.systemCollections', function (data) {
CloudStore.invalidateCollections(); CloudStore.invalidateCollections();
updatePorts(node.id, node.parameters, context.editorConnection, graphModel); updatePorts(node.id, node.parameters, context.editorConnection, graphModel);
}); });

View File

@@ -75,12 +75,12 @@ var SetDbModelPropertiedNodeDefinition = {
_this.setError('Missing Record Id'); _this.setError('Missing Record Id');
return; return;
} }
var model = internal.model;
const model = internal.model;
for (const key in internal.inputValues) { for (var i in internal.inputValues) {
model.set(key, internal.inputValues[key], { resolve: true }); model.set(i, internal.inputValues[i], { resolve: true });
} }
CloudStore.forScope(_this.nodeScope.modelScope).save({ CloudStore.forScope(_this.nodeScope.modelScope).save({
collection: internal.collectionId, collection: internal.collectionId,
objectId: model.getId(), // Get the objectId part of the model id objectId: model.getId(), // Get the objectId part of the model id

View File

@@ -31,6 +31,8 @@ const DateToStringNode = {
this._internal.currentInput = _value; this._internal.currentInput = _value;
this._format(); this._format();
this.flagOutputDirty('currentValue');
this.sendSignalOnOutput('inputChanged');
} }
} }
}, },
@@ -47,45 +49,28 @@ const DateToStringNode = {
type: 'signal', type: 'signal',
displayName: 'Date Changed', displayName: 'Date Changed',
group: 'Signals' group: 'Signals'
},
onError: {
type: 'signal',
displayName: 'Invalid Date',
group: 'Signals'
} }
}, },
methods: { methods: {
_format() { _format() {
try { const t = this._internal.currentInput;
const t = this._internal.currentInput; const format = this._internal.formatString;
const format = this._internal.formatString; const date = ('0' + t.getDate()).slice(-2);
const date = ('0' + t.getDate()).slice(-2); const month = ('0' + (t.getMonth() + 1)).slice(-2);
const month = ('0' + (t.getMonth() + 1)).slice(-2); const monthShort = new Intl.DateTimeFormat('en-US', { month: 'short' }).format(t);
const monthShort = new Intl.DateTimeFormat('en-US', { month: 'short' }).format(t); const year = t.getFullYear();
const year = t.getFullYear(); const hours = ('0' + t.getHours()).slice(-2);
const yearShort = year.toString().substring(2); const minutes = ('0' + t.getMinutes()).slice(-2);
const hours = ('0' + t.getHours()).slice(-2); const seconds = ('0' + t.getSeconds()).slice(-2);
const minutes = ('0' + t.getMinutes()).slice(-2);
const seconds = ('0' + t.getSeconds()).slice(-2);
this._internal.dateString = format this._internal.dateString = format
.replace(/\{date\}/g, date) .replace(/\{date\}/g, date)
.replace(/\{month\}/g, month) .replace(/\{month\}/g, month)
.replace(/\{monthShort\}/g, monthShort) .replace(/\{monthShort\}/g, monthShort)
.replace(/\{year\}/g, year) .replace(/\{year\}/g, year)
.replace(/\{yearShort\}/g, yearShort) .replace(/\{hours\}/g, hours)
.replace(/\{hours\}/g, hours) .replace(/\{minutes\}/g, minutes)
.replace(/\{minutes\}/g, minutes) .replace(/\{seconds\}/g, seconds);
.replace(/\{seconds\}/g, seconds);
} catch (error) {
// Set the output to be blank, makes it easier to handle.
this._internal.dateString = '';
this.flagOutputDirty('onError');
}
// Flag that the value have changed
this.flagOutputDirty('currentValue');
this.sendSignalOnOutput('inputChanged');
} }
} }
}; };

View File

@@ -1,5 +1,4 @@
const JavascriptNodeParser = require('../../javascriptnodeparser'); const JavascriptNodeParser = require('../../javascriptnodeparser');
const { logJavaScriptNodeError } = require('../../utils');
const SimpleJavascriptNode = { const SimpleJavascriptNode = {
name: 'JavaScriptFunction', name: 'JavaScriptFunction',
@@ -140,8 +139,11 @@ const SimpleJavascriptNode = {
JavascriptNodeParser.getComponentScopeForNode(this) JavascriptNodeParser.getComponentScopeForNode(this)
]); ]);
} catch (e) { } catch (e) {
logJavaScriptNodeError(e); console.log(
'Error in JS node run code.',
Object.getPrototypeOf(e).constructor.name + ': ' + e.message,
e.stack
);
if (this.context.editorConnection && this.context.isWarningTypeEnabled('javascriptExecution')) { if (this.context.editorConnection && this.context.isWarningTypeEnabled('javascriptExecution')) {
this.context.editorConnection.sendWarning( this.context.editorConnection.sendWarning(
this.nodeScope.componentOwner.name, this.nodeScope.componentOwner.name,

View File

@@ -2,8 +2,6 @@ const StringFormatDefinition = {
name: 'String Format', name: 'String Format',
docs: 'https://docs.noodl.net/nodes/string-manipulation/string-format', docs: 'https://docs.noodl.net/nodes/string-manipulation/string-format',
category: 'String Manipulation', category: 'String Manipulation',
usePortAsLabel: 'format',
portLabelTruncationMode: 'length',
initialize() { initialize() {
const internal = this._internal; const internal = this._internal;
internal.format = ''; internal.format = '';

View File

@@ -12,24 +12,6 @@ function getAbsoluteUrl(_url) {
return (Noodl.baseUrl || '/') + url; return (Noodl.baseUrl || '/') + url;
} }
/**
* Log an error thrown by the JavaScript nodes.
*
* @param {any} error
*/
function logJavaScriptNodeError(error) {
if (typeof error === 'string') {
console.log('Error in JS node run code.', error);
} else {
console.log(
'Error in JS node run code.',
Object.getPrototypeOf(error).constructor.name + ': ' + error.message,
error.stack
);
}
}
module.exports = { module.exports = {
getAbsoluteUrl, getAbsoluteUrl
logJavaScriptNodeError
}; };

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