Skip to content

6.6.0: Modernize toolchain — Electron 42 (hardened), Vite, Vitest, Capacitor#1287

Draft
jthrilly wants to merge 1 commit into
masterfrom
release/6.6.0
Draft

6.6.0: Modernize toolchain — Electron 42 (hardened), Vite, Vitest, Capacitor#1287
jthrilly wants to merge 1 commit into
masterfrom
release/6.6.0

Conversation

@jthrilly

@jthrilly jthrilly commented Jun 8, 2026

Copy link
Copy Markdown
Member

Modernizes the build, runtime, and test toolchain for v6.6.0. No product behavior changes beyond removing the obsolete Server integration. Work is split into dependency-ordered phases, each landing on a buildable/testable tree.

What changed

  • Node 24 LTS toolchain (.node-version/.nvmrc/engines).
  • Vendored the three git submodules (networkQuery, network-exporters, protocol-validation) as in-tree source; .gitmodules removed.
  • Removed the obsolete Server integration (pairing, mDNS/zeroconf discovery, secure-comms certificates) from desktop and mobile. request-promise-native → native fetch.
  • Electron 9 → 42 with security best practices: contextIsolation: true, sandbox: true, nodeIntegration: false, no @electron/remote. A typed contextBridge preload (window.NCAPI) exposes a minimal API; all privileged operations (filesystem, dialogs, app info, the zip extraction, and the network-exporters export pipeline) run in the main process behind IPC. The asset scheme uses the modern protocol.handle. IPC is hardened against path-traversal / zip-slip, with a shell-scheme allowlist.
  • Webpack → Vite 7 (+ electron-vite for main/preload/renderer). One renderer build feeds Electron and Capacitor.
  • Jest → Vitest 4 (Enzyme retained via enzyme-adapter-react-16). The dead Spectron integration-tests/ suite is removed; Jest is fully gone.
  • Cordova → Capacitor 8 for iOS/Android, wrapping the same Vite web build. Native ios//android/ projects scaffolded and committed; the platform abstraction now uses Capacitor plugins (@capacitor/filesystem, device, app, browser, keyboard, status-bar, network) and @capawesome/capacitor-file-picker for protocol import.
  • Cleanup: removed dead webpack/CRA config, www/, public/, the obsolete Dockerfile; modernized README and CI (Node 24, npm ci, vitest + electron-vite). Version bumped to 6.6.0 (package.json + native projects).

Verification

  • npm run lint clean · 540 Vitest tests pass · vite build + electron-vite build (main/preload/renderer) succeed · the hardened Electron app builds and launches (boots, rehydrates state, routes; protocol import verified) · npx cap sync succeeds with both native projects present.

Notes / out of scope

  • Native mobile device builds (Gradle/Xcode) are left to CI — not run here. The mobile code is ported and builds, but is not device-verified.
  • electron-builder packaging (dist:*) is a release/CI step; only electron-vite build + launch were verified locally.
  • Electron no longer downloads its binary on npm install (it downloads on first npm run dev); a download:electron script and README note are included.
  • Design spec and implementation plan are committed under docs/superpowers/.

🤖 Generated with Claude Code

Copilot AI review requested due to automatic review settings June 8, 2026 11:46

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot wasn't able to review this pull request because it exceeds the maximum number of files (300). Try reducing the number of changed files and requesting a review from Copilot again.

@coderabbitai

coderabbitai Bot commented Jun 8, 2026

Copy link
Copy Markdown

Important

Review skipped

Too many files!

This PR contains 215 files, which is 65 over the limit of 150.

To get a review, narrow the scope:
• coderabbit review --type committed # exclude uncommitted changes
• coderabbit review --dir # limit to a subdirectory
• coderabbit review --base # compare against a closer base

Upgrade to a paid plan to raise the limit.

⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 64d9a5cf-2092-4367-bf92-77478b32c2db

📥 Commits

Reviewing files that changed from the base of the PR and between 8053b58 and 23657d9.

⛔ Files ignored due to path filters (85)
  • android/app/src/main/res/drawable-land-hdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-ldpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-mdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-night-hdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-night-ldpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-night-mdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-night-xhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-night-xxhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-night-xxxhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-xhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-xxhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-land-xxxhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-night/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-hdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-ldpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-mdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-night-hdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-night-ldpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-night-mdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-night-xhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-night-xxhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-night-xxxhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-xhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-xxhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable-port-xxxhdpi/splash.png is excluded by !**/*.png
  • android/app/src/main/res/drawable/splash.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-hdpi/ic_launcher.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-hdpi/ic_launcher_background.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-hdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-ldpi/ic_launcher.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-ldpi/ic_launcher_background.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-ldpi/ic_launcher_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-ldpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-mdpi/ic_launcher.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-mdpi/ic_launcher_background.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-mdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xhdpi/ic_launcher.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xhdpi/ic_launcher_background.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxhdpi/ic_launcher_background.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_background.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png is excluded by !**/*.png
  • android/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png is excluded by !**/*.png
  • android/gradle/wrapper/gradle-wrapper.jar is excluded by !**/*.jar
  • assets/capacitor/icon-only.png is excluded by !**/*.png
  • assets/capacitor/logo.png is excluded by !**/*.png
  • ios/App/App/Assets.xcassets/AppIcon.appiconset/AppIcon-512@2x.png is excluded by !**/*.png
  • ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany-dark.png is excluded by !**/*.png
  • ios/App/App/Assets.xcassets/Splash.imageset/Default@1x~universal~anyany.png is excluded by !**/*.png
  • ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany-dark.png is excluded by !**/*.png
  • ios/App/App/Assets.xcassets/Splash.imageset/Default@2x~universal~anyany.png is excluded by !**/*.png
  • ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany-dark.png is excluded by !**/*.png
  • ios/App/App/Assets.xcassets/Splash.imageset/Default@3x~universal~anyany.png is excluded by !**/*.png
  • ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-1.png is excluded by !**/*.png
  • ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732-2.png is excluded by !**/*.png
  • ios/App/App/Assets.xcassets/Splash.imageset/splash-2732x2732.png is excluded by !**/*.png
  • package-lock.json is excluded by !**/package-lock.json
  • public/icons/android/NC-Round-hdpi.png is excluded by !**/*.png
  • public/icons/android/NC-Round-ldpi.png is excluded by !**/*.png
  • public/icons/android/NC-Round-mdpi.png is excluded by !**/*.png
  • public/icons/android/NC-Round-xhdpi.png is excluded by !**/*.png
  • public/icons/android/NC-Round-xxhdpi.png is excluded by !**/*.png
  • public/icons/android/NC-Round-xxxhdpi.png is excluded by !**/*.png
  • public/icons/ios/Default@2x~universal~anyany.png is excluded by !**/*.png
  • public/icons/ios/NC-Square-100.png is excluded by !**/*.png
  • public/icons/ios/NC-Square-1024.png is excluded by !**/*.png
  • public/icons/ios/NC-Square-144.png is excluded by !**/*.png
  • public/icons/ios/NC-Square-152.png is excluded by !**/*.png
  • public/icons/ios/NC-Square-167.png is excluded by !**/*.png
  • public/icons/ios/NC-Square-40.png is excluded by !**/*.png
  • public/icons/ios/NC-Square-50.png is excluded by !**/*.png
  • public/icons/ios/NC-Square-72.png is excluded by !**/*.png
  • public/icons/ios/NC-Square-76.png is excluded by !**/*.png
  • public/icons/ios/NC-Square-80.png is excluded by !**/*.png
  • src/components/Canvas/__tests__/__snapshots__/EdgeLayout.test.js.snap is excluded by !**/*.snap
  • src/components/Canvas/__tests__/__snapshots__/EdgeLayout.test.jsx.snap is excluded by !**/*.snap
  • src/components/Canvas/__tests__/__snapshots__/NodeLayout.test.js.snap is excluded by !**/*.snap
  • src/components/Canvas/__tests__/__snapshots__/NodeLayout.test.jsx.snap is excluded by !**/*.snap
📒 Files selected for processing (215)
  • .browserslistrc
  • .env
  • .eslintignore
  • .eslintrc.json
  • .github/workflows/codeql-analysis.yml
  • .github/workflows/dist.yml
  • .github/workflows/main.yml
  • .gitignore
  • .gitmodules
  • .node-version
  • .npmrc
  • .oxlintrc.json
  • .stylelintrc.json
  • .vscode/settings.json
  • CHANGELOG.md
  • README.md
  • __mocks__/electron.js
  • __mocks__/redux-logger.js
  • android/.gitignore
  • android/app/.gitignore
  • android/app/build.gradle
  • android/app/capacitor.build.gradle
  • android/app/proguard-rules.pro
  • android/app/src/main/AndroidManifest.xml
  • android/app/src/main/java/org/codaco/NetworkCanvasInterviewer6/MainActivity.java
  • android/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
  • android/app/src/main/res/drawable/ic_launcher_background.xml
  • android/app/src/main/res/layout/activity_main.xml
  • android/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
  • android/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
  • android/app/src/main/res/values/colors.xml
  • android/app/src/main/res/values/ic_launcher_background.xml
  • android/app/src/main/res/values/strings.xml
  • android/app/src/main/res/values/styles.xml
  • android/app/src/main/res/xml/file_paths.xml
  • android/build.gradle
  • android/capacitor.settings.gradle
  • android/gradle.properties
  • android/gradle/wrapper/gradle-wrapper.properties
  • android/gradlew
  • android/gradlew.bat
  • android/settings.gradle
  • android/variables.gradle
  • babel.config.js
  • build-resources/scripts/afterSignHook.js
  • capacitor.config.ts
  • config.xml
  • config/env.js
  • config/jest/automock.js
  • config/jest/cssTransform.js
  • config/jest/enzyme.js
  • config/jest/fileTransform.js
  • config/jest/matchMedia.js
  • config/jest/polyfills.js
  • config/nc-dev-utils.js
  • config/paths.js
  • config/polyfills.js
  • config/vitest/setup.js
  • config/webpack.config.dev.js
  • config/webpack.config.prod.js
  • config/webpackDevServer.config.js
  • electron-builder.config.cjs
  • electron.vite.config.js
  • integration-tests/.data/.gitkeep
  • integration-tests/README.md
  • integration-tests/__tests__/alter-edge-form.test.js
  • integration-tests/__tests__/dyad-census.test.js
  • integration-tests/__tests__/ego-form.test.js
  • integration-tests/__tests__/helpers.js
  • integration-tests/__tests__/name-generator.test.js
  • integration-tests/__tests__/playbook-development-protocol.js
  • integration-tests/__tests__/playbook.js
  • integration-tests/__tests__/sociogram.test.js
  • integration-tests/__tests__/stages-menu.test.js
  • integration-tests/__tests__/start-screen.test.js
  • integration-tests/__tests__/timeline.test.js
  • integration-tests/config.js
  • integration-tests/getData.js
  • integration-tests/jest.config.js
  • integration-tests/scripts/get-development-protocol.js
  • integration-tests/scripts/image-reporter.js
  • integration-tests/setup.js
  • ios/.gitignore
  • ios/App/App.xcodeproj/project.pbxproj
  • ios/App/App.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolved
  • ios/App/App/AppDelegate.swift
  • ios/App/App/Assets.xcassets/AppIcon.appiconset/Contents.json
  • ios/App/App/Assets.xcassets/Contents.json
  • ios/App/App/Assets.xcassets/Splash.imageset/Contents.json
  • ios/App/App/Base.lproj/LaunchScreen.storyboard
  • ios/App/App/Base.lproj/Main.storyboard
  • ios/App/App/Info.plist
  • ios/App/App/MainViewController.swift
  • ios/App/CapApp-SPM/.gitignore
  • ios/App/CapApp-SPM/Package.swift
  • ios/App/CapApp-SPM/README.md
  • ios/App/CapApp-SPM/Sources/CapApp-SPM/CapApp-SPM.swift
  • ios/debug.xcconfig
  • package.json
  • postcss.config.js
  • public/.eslintrc
  • public/components/appManager.js
  • public/components/appURL.js
  • public/components/assetProtocol.js
  • public/components/dialogs.js
  • public/components/loadDevTools.js
  • public/dev-app-update.yml
  • public/electron-starter.js
  • public/package.json
  • scripts/build.js
  • scripts/cap-dev.mjs
  • scripts/check-dev-server.js
  • scripts/cordova/before-prepare.js
  • scripts/cordova/helpers/dev-server.js
  • scripts/generate-app-icons.js
  • scripts/start.js
  • scripts/sync-platform-versions.mjs
  • scripts/test.js
  • src/__mocks__/electron-log.js
  • src/__mocks__/fs.js
  • src/behaviours/AssetMetaProvider.js
  • src/behaviours/DragAndDrop/DragManager.js
  • src/behaviours/DragAndDrop/DragPreview.js
  • src/behaviours/DragAndDrop/DragSource.js
  • src/behaviours/DragAndDrop/DragSource.jsx
  • src/behaviours/DragAndDrop/DropObstacle.js
  • src/behaviours/DragAndDrop/DropObstacle.jsx
  • src/behaviours/DragAndDrop/DropTarget.jsx
  • src/behaviours/DragAndDrop/Monitor.jsx
  • src/behaviours/DragAndDrop/MonitorDragSource.js
  • src/behaviours/DragAndDrop/MonitorDropTarget.js
  • src/behaviours/DragAndDrop/__mocks__/DragManager.js
  • src/behaviours/DragAndDrop/__mocks__/DragPreview.js
  • src/behaviours/DragAndDrop/__mocks__/reducer.js
  • src/behaviours/DragAndDrop/__tests__/DragSource.test.jsx
  • src/behaviours/DragAndDrop/__tests__/DropObstacle.test.jsx
  • src/behaviours/DragAndDrop/__tests__/DropTarget.test.jsx
  • src/behaviours/DragAndDrop/__tests__/reducer.test.js
  • src/behaviours/DragAndDrop/index.js
  • src/behaviours/DragAndDrop/reducer.js
  • src/behaviours/DragAndDrop/store.js
  • src/behaviours/DragAndDrop/useDropMonitor.js
  • src/behaviours/__tests__/withPrompt.test.jsx
  • src/behaviours/autoInitialisedForm.jsx
  • src/behaviours/index.js
  • src/behaviours/injectAssetUrl.js
  • src/behaviours/scrollable.jsx
  • src/behaviours/withBounds.jsx
  • src/behaviours/withOptionsFromSelector.js
  • src/behaviours/withPrompt.jsx
  • src/components/AddCountButton.jsx
  • src/components/Audio.jsx
  • src/components/BackgroundDimmer.jsx
  • src/components/BackgroundImage.jsx
  • src/components/Canvas/Canvas.jsx
  • src/components/Canvas/ConvexHull.jsx
  • src/components/Canvas/ConvexHulls.jsx
  • src/components/Canvas/EdgeLayout.jsx
  • src/components/Canvas/NodeLayout.js
  • src/components/Canvas/NodeLayout.jsx
  • src/components/Canvas/__tests__/Canvas.test.jsx
  • src/components/Canvas/__tests__/ConvexHull.test.jsx
  • src/components/Canvas/__tests__/EdgeLayout.test.jsx
  • src/components/Canvas/__tests__/NodeLayout.test.jsx
  • src/components/Card.js
  • src/components/Card.jsx
  • src/components/CardList.jsx
  • src/components/Cards/ProtocolCard.jsx
  • src/components/Cards/ServerCard.js
  • src/components/Cards/SessionCard.jsx
  • src/components/Cards/index.js
  • src/components/CategoricalItem.jsx
  • src/components/CloseButton.jsx
  • src/components/CollapsablePrompts.jsx
  • src/components/DialogManager.js
  • src/components/DropZone.jsx
  • src/components/Edge.jsx
  • src/components/ExternalLink.js
  • src/components/ExternalLink.jsx
  • src/components/FilterableListWrapper.jsx
  • src/components/Image.js
  • src/components/Image.jsx
  • src/components/List.jsx
  • src/components/Loading.jsx
  • src/components/MultiNodeBucket.jsx
  • src/components/NewFilterableListWrapper.jsx
  • src/components/NodeBin.jsx
  • src/components/NodeList.jsx
  • src/components/Panel.jsx
  • src/components/Panels.jsx
  • src/components/Picker.jsx
  • src/components/Prompts.jsx
  • src/components/RealtimeCanvas/Canvas.jsx
  • src/components/RealtimeCanvas/EdgeLayout.jsx
  • src/components/RealtimeCanvas/LayoutNode.jsx
  • src/components/RealtimeCanvas/NodeLayout.jsx
  • src/components/RealtimeCanvas/ScreenManager.js
  • src/components/RealtimeCanvas/SimulationPanel.jsx
  • src/components/RealtimeCanvas/index.js
  • src/components/RealtimeCanvas/useDrag.js
  • src/components/RealtimeCanvas/utils.js
  • src/components/Search/Search.jsx
  • src/components/Search/SearchButton.jsx
  • src/components/Search/__tests__/Search.test.jsx
  • src/components/SessionPanel/SessionInformation.jsx
  • src/components/SessionPanel/SessionNavigation.jsx
  • src/components/SessionPanel/SessionPanel.jsx
  • src/components/SessionPanel/SubMenu.jsx
  • src/components/SessionPanel/__tests__/SessionNavigation.test.jsx
  • src/components/SettingsMenu/Sections/DeveloperTools.jsx
  • src/components/SettingsMenu/Sections/ExportOptions.jsx
  • src/components/SettingsMenu/Sections/Pairing.jsx
  • src/components/SettingsMenu/Sections/VisualPreferences.jsx
  • src/components/SettingsMenu/SettingsMenu.jsx
  • src/components/SettingsMenu/SettingsMenuButton.jsx

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch release/6.6.0

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@jthrilly

jthrilly commented Jun 8, 2026

Copy link
Copy Markdown
Member Author

Note for reviewers — both automated reviewers (Copilot, CodeRabbit) skipped this PR purely on file count. That count is dominated by two parts of the migration that are large but not hand-authored here:

  • Vendored submodules (~120 files): networkQuery, network-exporters, and protocol-validation are now in-tree (.gitmodules removed). Moved as-is — diff vs. their upstream is unchanged except where the platform abstraction touches them.
  • Capacitor native projects (~71 files): the generated ios/ and android/ scaffolds, committed per the plan.

The hand-written changes worth focusing on:

  • src/main/** + src/preload/index.js — hardened Electron main process + contextBridge IPC (window.NCAPI); all fs/dialog/export/extraction moved to main.
  • src/utils/Environment.js, filesystem.js, exportProcess.js, protocol/* — renderer → NCAPI / Capacitor platform-abstraction rewrites.
  • vite.config.js, vite.shared.js, electron.vite.config.js, vitest.setup.js — build/test config.
  • package.json — dependency surgery.

Design rationale + phased plan: docs/superpowers/specs/ and docs/superpowers/plans/. CI (lint, 545 Vitest tests, Vite + Electron build, Linux dist) is green.

@jthrilly jthrilly marked this pull request as draft June 18, 2026 12:12
@jthrilly

Copy link
Copy Markdown
Member Author

Branch release/6.6.0 force-updated to a single hard-sync commit mirrored from the monorepo (complexdatacollective/network-canvas-monorepo@a924c6cb, apps/interviewer). The prior 29-commit modernization history is superseded — its content is preserved in the monorepo. Converted to draft pending the 6.6.0 release.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants