mirror of
https://github.com/enso-org/enso.git
synced 2024-11-22 03:32:23 +03:00
Merge branch 'develop' into wip/sb/async-execution
This commit is contained in:
commit
b7e5b812ca
196
.github/workflows/gui-checks.yml
vendored
Normal file
196
.github/workflows/gui-checks.yml
vendored
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
name: GUI Checks
|
||||||
|
on: workflow_call
|
||||||
|
|
||||||
|
# Cancel in-progress workflows if a new one is started
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}-gui-checks
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read # Read-only access to repository contents
|
||||||
|
issues: write # Write access to issues
|
||||||
|
pull-requests: write # Write access to pull requests
|
||||||
|
statuses: write # Write access to commit statuses
|
||||||
|
checks: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
lint:
|
||||||
|
name: 👮 Lint GUI
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
ref: ${{ github.event.pull_request.head.ref }}
|
||||||
|
|
||||||
|
- name: 📦 Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
name: ⎔ Setup Node
|
||||||
|
with:
|
||||||
|
node-version-file: .node-version
|
||||||
|
cache: "pnpm"
|
||||||
|
|
||||||
|
- uses: actions/cache/restore@v4
|
||||||
|
name: Download cache
|
||||||
|
id: cache
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
**/.eslintcache
|
||||||
|
node_modules/.cache/prettier
|
||||||
|
key: ${{ runner.os }}-gui-${{ github.run_id }}
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-gui
|
||||||
|
|
||||||
|
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
|
||||||
|
name: Installing wasm-pack
|
||||||
|
uses: jetli/wasm-pack-action@v0.4.0
|
||||||
|
with:
|
||||||
|
version: v0.12.1
|
||||||
|
|
||||||
|
- name: 📦 Install dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: 📝 Prettier
|
||||||
|
id: prettier
|
||||||
|
continue-on-error: true
|
||||||
|
run: pnpm run ci:prettier
|
||||||
|
|
||||||
|
# Next Tasks are depend on Typecheck, because we build libraries at this stage
|
||||||
|
- name: 🧠 Typecheck
|
||||||
|
id: typecheck
|
||||||
|
continue-on-error: true
|
||||||
|
run: pnpm run ci:typecheck
|
||||||
|
|
||||||
|
- name: 🧹 Lint
|
||||||
|
id: lint
|
||||||
|
continue-on-error: true
|
||||||
|
run: pnpm run ci:lint
|
||||||
|
|
||||||
|
- name: 🧪 Unit Tests
|
||||||
|
id: unit-tests
|
||||||
|
continue-on-error: true
|
||||||
|
run: pnpm run ci:test
|
||||||
|
|
||||||
|
- name: 💾 Save cache
|
||||||
|
uses: actions/cache/save@v4
|
||||||
|
if: always() && steps.cache.outputs.cache-hit != 'true'
|
||||||
|
id: save-cache
|
||||||
|
with:
|
||||||
|
key: ${{ steps.cache.outputs.cache-primary-key }}
|
||||||
|
path: |
|
||||||
|
**/.eslintcache
|
||||||
|
node_modules/.cache/prettier
|
||||||
|
|
||||||
|
- name: 📝 Annotate Code Linting Results
|
||||||
|
uses: ataylorme/eslint-annotate-action@v3
|
||||||
|
with:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
report-json: "./**/eslint_report.json"
|
||||||
|
markdown-report-on-step-summary: true
|
||||||
|
check-name: 🧹 GUI Lint Results
|
||||||
|
|
||||||
|
- name: ❌ Fail if any check failed
|
||||||
|
if: always() && (steps.prettier.outcome == 'failure' || steps.lint.outcome == 'failure' || steps.typecheck.outcome == 'failure' || steps.unit-tests.outcome == 'failure')
|
||||||
|
run: |
|
||||||
|
echo "Prettier outcome: ${{ steps.prettier.outcome }}"
|
||||||
|
echo "Lint outcome: ${{ steps.lint.outcome }}"
|
||||||
|
echo "Typecheck outcome: ${{ steps.typecheck.outcome }}"
|
||||||
|
echo "Unit tests outcome: ${{ steps.unit-tests.outcome }}"
|
||||||
|
exit 1
|
||||||
|
|
||||||
|
playwright:
|
||||||
|
name: 🎭 Playwright Tests
|
||||||
|
env:
|
||||||
|
NODE_OPTIONS: --disable-warning=ExperimentalWarning
|
||||||
|
runs-on:
|
||||||
|
- self-hosted
|
||||||
|
- Linux
|
||||||
|
timeout-minutes: 60
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
max-parallel: 24
|
||||||
|
matrix:
|
||||||
|
shardIndex: [1, 2, 3, 4, 5, 6]
|
||||||
|
shardTotal: [6]
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: 📦 Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
name: ⎔ Setup Node
|
||||||
|
with:
|
||||||
|
node-version-file: .node-version
|
||||||
|
cache: "pnpm"
|
||||||
|
|
||||||
|
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
|
||||||
|
name: Installing wasm-pack
|
||||||
|
uses: jetli/wasm-pack-action@v0.4.0
|
||||||
|
with:
|
||||||
|
version: v0.12.1
|
||||||
|
|
||||||
|
- name: 📦 Install dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: 📺 Install Playwright Browsers
|
||||||
|
working-directory: app/gui
|
||||||
|
run: pnpm run playwright:install
|
||||||
|
|
||||||
|
- name: 🎭 Playwright Tests
|
||||||
|
working-directory: app/gui
|
||||||
|
run: pnpm run e2e --shard=${{ matrix.shardIndex }}/${{ matrix.shardTotal }}
|
||||||
|
|
||||||
|
- name: ⬆️ Upload blob report to GitHub Actions Artifacts
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: blob-report-${{ matrix.shardIndex }}
|
||||||
|
path: app/gui/blob-report
|
||||||
|
retention-days: 7
|
||||||
|
|
||||||
|
merge-reports:
|
||||||
|
name: 🔗 Merge Playwright Reports
|
||||||
|
if: ${{ !cancelled() }}
|
||||||
|
needs: [playwright]
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: 📦 Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: .node-version
|
||||||
|
cache: "pnpm"
|
||||||
|
|
||||||
|
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
|
||||||
|
name: Installing wasm-pack
|
||||||
|
uses: jetli/wasm-pack-action@v0.4.0
|
||||||
|
with:
|
||||||
|
version: v0.12.1
|
||||||
|
|
||||||
|
- name: 📦 Install dependencies
|
||||||
|
run: pnpm install --frozen-lockfile --ignore-scripts
|
||||||
|
|
||||||
|
- name: 📥 Download blob reports from GitHub Actions Artifacts
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
path: app/gui/blob-report/
|
||||||
|
pattern: blob-report-*
|
||||||
|
merge-multiple: true
|
||||||
|
|
||||||
|
- name: 🔗 Merge into HTML Report
|
||||||
|
working-directory: app/gui
|
||||||
|
run: pnpm playwright merge-reports --reporter html ./blob-report
|
||||||
|
|
||||||
|
- name: ⬆️ Upload HTML report
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: playwright-report--attempt-${{ github.run_attempt }}
|
||||||
|
path: app/gui/playwright-report/
|
||||||
|
retention-days: 14
|
83
.github/workflows/gui-pull-request.yml
vendored
Normal file
83
.github/workflows/gui-pull-request.yml
vendored
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
# This file is not auto-generated. Feel free to edit it.
|
||||||
|
|
||||||
|
name: ✨ GUI Pull Request
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- develop
|
||||||
|
pull_request:
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read # Read-only access to repository contents
|
||||||
|
issues: write # Write access to issues
|
||||||
|
pull-requests: write # Write access to pull requests
|
||||||
|
statuses: write # Write access to commit statuses
|
||||||
|
checks: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
changed-files:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
name: 🔍 Detect changed files in GUI
|
||||||
|
outputs:
|
||||||
|
all_changed_files: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||||
|
any_changed: ${{ steps.changed-files.outputs.any_changed }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 2
|
||||||
|
- name: Get changed files
|
||||||
|
id: changed-files
|
||||||
|
uses: tj-actions/changed-files@v44
|
||||||
|
with:
|
||||||
|
files: |
|
||||||
|
app/**
|
||||||
|
package.json
|
||||||
|
pnpm-lock.yaml
|
||||||
|
pnpm-workspace.yaml
|
||||||
|
eslint.config.js
|
||||||
|
.prettierrc.js
|
||||||
|
.prettierignore
|
||||||
|
vitest.workspace.ts
|
||||||
|
files_ignore: |
|
||||||
|
app/ide-desktop/**
|
||||||
|
app/gui/scripts/**
|
||||||
|
app/gui/.gitignore
|
||||||
|
.git-*
|
||||||
|
|
||||||
|
- name: List all changed files
|
||||||
|
env:
|
||||||
|
ALL_CHANGED_FILES: ${{ steps.changed-files.outputs.all_changed_files }}
|
||||||
|
run: |
|
||||||
|
for file in ${ALL_CHANGED_FILES}; do
|
||||||
|
echo "$file was changed"
|
||||||
|
done
|
||||||
|
|
||||||
|
checks:
|
||||||
|
name: 🧰 Checks
|
||||||
|
uses: ./.github/workflows/gui-checks.yml
|
||||||
|
needs: [changed-files]
|
||||||
|
if: ${{ needs.changed-files.outputs.any_changed == 'true' }}
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
storybook:
|
||||||
|
name: 📚 Deploy Storybook
|
||||||
|
uses: ./.github/workflows/storybook.yml
|
||||||
|
needs: [changed-files]
|
||||||
|
if: ${{ needs.changed-files.outputs.any_changed == 'true' }}
|
||||||
|
secrets: inherit
|
||||||
|
|
||||||
|
# This job is used to report success if the needed jobs were successful.
|
||||||
|
# This is a workaround to make optional jobs required if they run
|
||||||
|
report-success:
|
||||||
|
name: ✅ Success or skipped due to no changes
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: [checks, storybook]
|
||||||
|
if: needs.checks.result == 'skipped' && needs.storybook.result == 'skipped' || needs.checks.result == 'success' && needs.storybook.result == 'success'
|
||||||
|
steps:
|
||||||
|
- name: Report success
|
||||||
|
run: echo "Success!"
|
43
.github/workflows/gui-tests.yml
vendored
43
.github/workflows/gui-tests.yml
vendored
@ -27,49 +27,6 @@ jobs:
|
|||||||
access_token: ${{ github.token }}
|
access_token: ${{ github.token }}
|
||||||
permissions:
|
permissions:
|
||||||
actions: write
|
actions: write
|
||||||
enso-build-ci-gen-job-gui-check-linux-amd64:
|
|
||||||
name: GUI tests (linux, amd64)
|
|
||||||
runs-on:
|
|
||||||
- self-hosted
|
|
||||||
- Linux
|
|
||||||
steps:
|
|
||||||
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
|
|
||||||
name: Installing wasm-pack
|
|
||||||
uses: jetli/wasm-pack-action@v0.4.0
|
|
||||||
with:
|
|
||||||
version: v0.12.1
|
|
||||||
- name: Expose Artifact API and context information.
|
|
||||||
uses: actions/github-script@v7
|
|
||||||
with:
|
|
||||||
script: "\n core.exportVariable(\"ACTIONS_RUNTIME_TOKEN\", process.env[\"ACTIONS_RUNTIME_TOKEN\"])\n core.exportVariable(\"ACTIONS_RUNTIME_URL\", process.env[\"ACTIONS_RUNTIME_URL\"])\n core.exportVariable(\"GITHUB_RETENTION_DAYS\", process.env[\"GITHUB_RETENTION_DAYS\"])\n console.log(context)\n "
|
|
||||||
- name: Checking out the repository
|
|
||||||
uses: actions/checkout@v4
|
|
||||||
with:
|
|
||||||
clean: false
|
|
||||||
submodules: recursive
|
|
||||||
- name: Build Script Setup
|
|
||||||
run: ./run --help || (git clean -ffdx && ./run --help)
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- if: "(contains(github.event.pull_request.labels.*.name, 'CI: Clean build required') || inputs.clean_build_required)"
|
|
||||||
name: Clean before
|
|
||||||
run: ./run git-clean
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- run: ./run gui check
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
- if: failure() && runner.os == 'Windows'
|
|
||||||
name: List files if failed (Windows)
|
|
||||||
run: Get-ChildItem -Force -Recurse
|
|
||||||
- if: failure() && runner.os != 'Windows'
|
|
||||||
name: List files if failed (non-Windows)
|
|
||||||
run: ls -lAR
|
|
||||||
- if: "(always()) && (contains(github.event.pull_request.labels.*.name, 'CI: Clean build required') || inputs.clean_build_required)"
|
|
||||||
name: Clean after
|
|
||||||
run: ./run git-clean
|
|
||||||
env:
|
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
||||||
enso-build-ci-gen-job-lint-linux-amd64:
|
enso-build-ci-gen-job-lint-linux-amd64:
|
||||||
name: Lint (linux, amd64)
|
name: Lint (linux, amd64)
|
||||||
runs-on:
|
runs-on:
|
||||||
|
104
.github/workflows/storybook.yml
vendored
Normal file
104
.github/workflows/storybook.yml
vendored
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
# This file is not auto-generated. Feel free to edit it.
|
||||||
|
|
||||||
|
name: Storybook Chromatic Deployment
|
||||||
|
|
||||||
|
on: workflow_call
|
||||||
|
|
||||||
|
# Cancel in-progress workflows if a new one is started
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.ref }}-chromatic
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read # Read-only access to repository contents
|
||||||
|
issues: write # Write access to issues
|
||||||
|
pull-requests: write # Write access to pull requests
|
||||||
|
statuses: write # Write access to commit statuses
|
||||||
|
|
||||||
|
env:
|
||||||
|
ENSO_BUILD_SKIP_VERSION_CHECK: "true"
|
||||||
|
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
deploy-chromatic-react:
|
||||||
|
name: 🚀 Deploy React to Chromatic
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
dashboardUrl: ${{ steps.publish_chromatic.outputs.url }}
|
||||||
|
dashboardStorybookUrl: ${{ steps.publish_chromatic.outputs.storybookUrl }}
|
||||||
|
env:
|
||||||
|
CHROMATIC_RETRIES: 3
|
||||||
|
CHROMATIC_PROJECT_TOKEN: ${{ secrets.DASHBOARD_CHROMATIC_PROJECT_TOKEN }}
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
name: Checkout
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
ref: ${{ github.event.pull_request.head.ref }}
|
||||||
|
fetch-tags: false
|
||||||
|
|
||||||
|
- name: 📦 Setup pnpm
|
||||||
|
uses: pnpm/action-setup@v4
|
||||||
|
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
name: ⎔ Setup Node
|
||||||
|
with:
|
||||||
|
node-version-file: .node-version
|
||||||
|
cache: "pnpm"
|
||||||
|
|
||||||
|
- if: startsWith(runner.name, 'GitHub Actions') || startsWith(runner.name, 'Hosted Agent')
|
||||||
|
name: Installing wasm-pack
|
||||||
|
uses: jetli/wasm-pack-action@v0.4.0
|
||||||
|
with:
|
||||||
|
version: v0.12.1
|
||||||
|
|
||||||
|
- name: 📦 Install dependencies
|
||||||
|
run: pnpm install --frozen-lockfile
|
||||||
|
|
||||||
|
- name: 📥 Download storybook cache
|
||||||
|
uses: actions/cache@v4
|
||||||
|
with:
|
||||||
|
key: ${{ runner.os }}-gui-${{ github.run_id }}
|
||||||
|
path: app/gui/node_modules/.cache/
|
||||||
|
restore-keys: |
|
||||||
|
${{ runner.os }}-gui
|
||||||
|
|
||||||
|
- name: 🚀 Deploy to Chromatic
|
||||||
|
id: publish_chromatic
|
||||||
|
uses: chromaui/action@v11
|
||||||
|
with:
|
||||||
|
workingDir: app/gui
|
||||||
|
autoAcceptChanges: develop
|
||||||
|
exitZeroOnChanges: true
|
||||||
|
exitOnceUploaded: true
|
||||||
|
configFile: "chromatic.config.json"
|
||||||
|
|
||||||
|
comment-on-pr:
|
||||||
|
name: 💬 Comment on PR
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
needs: deploy-chromatic-react
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version-file: .node-version
|
||||||
|
- name: 💬 Comment on PR
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
script: |
|
||||||
|
const { setMessage } = await import('${{ github.workspace }}/app/gui/scripts/ci/set-message.js')
|
||||||
|
|
||||||
|
await setMessage({
|
||||||
|
header: "## 🧪 Storybook is successfully deployed!",
|
||||||
|
body: `
|
||||||
|
### 📊 Dashboard:
|
||||||
|
- 👀 Review changes: ${{ needs.deploy-chromatic-react.outputs.dashboardUrl }}
|
||||||
|
- 👨🎨 Preview storybook: ${{ needs.deploy-chromatic-react.outputs.dashboardStorybookUrl }}
|
||||||
|
`,
|
||||||
|
github,
|
||||||
|
repo: context.repo,
|
||||||
|
prNumber: context.payload.pull_request.number
|
||||||
|
})
|
2
.gitignore
vendored
2
.gitignore
vendored
@ -37,6 +37,8 @@ generated/
|
|||||||
############
|
############
|
||||||
|
|
||||||
node_modules/
|
node_modules/
|
||||||
|
eslint_report.json
|
||||||
|
.eslintcache
|
||||||
|
|
||||||
############
|
############
|
||||||
## System ##
|
## System ##
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"test": "vitest run",
|
"test": "vitest run",
|
||||||
"lint": "eslint . --max-warnings=0"
|
"lint": "eslint . --cache --max-warnings=0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@tanstack/query-core": "5.54.1",
|
"@tanstack/query-core": "5.54.1",
|
||||||
|
@ -46,24 +46,9 @@ export async function readEnvironmentFromFile() {
|
|||||||
}
|
}
|
||||||
process.env.ENSO_CLOUD_DASHBOARD_VERSION ??= buildInfo.version ?? '0.0.0-dev'
|
process.env.ENSO_CLOUD_DASHBOARD_VERSION ??= buildInfo.version ?? '0.0.0-dev'
|
||||||
process.env.ENSO_CLOUD_DASHBOARD_COMMIT_HASH ??= buildInfo.commit
|
process.env.ENSO_CLOUD_DASHBOARD_COMMIT_HASH ??= buildInfo.commit
|
||||||
} catch (error) {
|
} catch {
|
||||||
process.env.ENSO_CLOUD_DASHBOARD_VERSION ??= buildInfo.version
|
process.env.ENSO_CLOUD_DASHBOARD_VERSION ??= buildInfo.version
|
||||||
process.env.ENSO_CLOUD_DASHBOARD_COMMIT_HASH ??= buildInfo.commit
|
process.env.ENSO_CLOUD_DASHBOARD_COMMIT_HASH ??= buildInfo.commit
|
||||||
const expectedKeys = Object.keys(DUMMY_DEFINES)
|
|
||||||
.map(key => key.replace(/^process[.]env[.]/, ''))
|
|
||||||
.filter(key => key !== 'NODE_ENV')
|
|
||||||
/** @type {string[]} */
|
|
||||||
const missingKeys = []
|
|
||||||
for (const key of expectedKeys) {
|
|
||||||
if (!(key in process.env)) {
|
|
||||||
missingKeys.push(key)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (missingKeys.length !== 0) {
|
|
||||||
console.warn('Could not load `.env` file; disabling cloud backend.')
|
|
||||||
console.warn(`Missing keys: ${missingKeys.map(key => `'${key}'`).join(', ')}`)
|
|
||||||
console.error(error)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
4
app/gui/.gitignore
vendored
4
app/gui/.gitignore
vendored
@ -25,7 +25,11 @@ mockDist
|
|||||||
|
|
||||||
test-results/
|
test-results/
|
||||||
playwright-report/
|
playwright-report/
|
||||||
|
blob-report/
|
||||||
playwright/
|
playwright/
|
||||||
|
|
||||||
src/project-view/util/iconList.json
|
src/project-view/util/iconList.json
|
||||||
src/project-view/util/iconName.ts
|
src/project-view/util/iconName.ts
|
||||||
|
|
||||||
|
*storybook.log
|
||||||
|
storybook-static
|
||||||
|
9
app/gui/.storybook/env.d.ts
vendored
Normal file
9
app/gui/.storybook/env.d.ts
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
declare global {
|
||||||
|
interface Window {
|
||||||
|
ENV: {
|
||||||
|
FRAMEWORK: 'vue' | 'react'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export {}
|
63
app/gui/.storybook/main.ts
Normal file
63
app/gui/.storybook/main.ts
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
/**
|
||||||
|
* @file
|
||||||
|
*
|
||||||
|
* Main file for Storybook configuration.
|
||||||
|
*/
|
||||||
|
import type { StorybookConfig as ReactStorybookConfig } from '@storybook/react-vite'
|
||||||
|
import type { StorybookConfig as VueStorybookConfig } from '@storybook/vue3-vite'
|
||||||
|
import z from 'zod'
|
||||||
|
|
||||||
|
const framework = z.enum(['vue', 'react']).parse(process.env.FRAMEWORK)
|
||||||
|
|
||||||
|
const sharedConfig: Partial<ReactStorybookConfig> = {
|
||||||
|
addons: [
|
||||||
|
'@storybook/addon-onboarding',
|
||||||
|
'@storybook/addon-essentials',
|
||||||
|
'@chromatic-com/storybook',
|
||||||
|
'@storybook/addon-interactions',
|
||||||
|
],
|
||||||
|
features: {},
|
||||||
|
core: { disableTelemetry: true },
|
||||||
|
env: { FRAMEWORK: framework },
|
||||||
|
|
||||||
|
previewHead: (head) => {
|
||||||
|
return `
|
||||||
|
<script>
|
||||||
|
window.global = window;
|
||||||
|
window.ENV = {
|
||||||
|
FRAMEWORK: '${framework}',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
${head}
|
||||||
|
`
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const vueConfig: VueStorybookConfig = {
|
||||||
|
...sharedConfig,
|
||||||
|
stories: [
|
||||||
|
'../src/project-view/**/*.mdx',
|
||||||
|
'../src/project-view/**/*.stories.@(js|jsx|mjs|ts|tsx)',
|
||||||
|
],
|
||||||
|
framework: {
|
||||||
|
name: '@storybook/vue3-vite',
|
||||||
|
options: {},
|
||||||
|
},
|
||||||
|
refs: {
|
||||||
|
Dashboard: {
|
||||||
|
title: 'Dashboard',
|
||||||
|
url: 'http://localhost:6007',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const reactConfig: ReactStorybookConfig = {
|
||||||
|
...sharedConfig,
|
||||||
|
stories: ['../src/dashboard/**/*.mdx', '../src/dashboard/**/*.stories.tsx'],
|
||||||
|
framework: {
|
||||||
|
name: '@storybook/react-vite',
|
||||||
|
options: { strictMode: true },
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
export default framework === 'vue' ? vueConfig : reactConfig
|
69
app/gui/.storybook/preview.tsx
Normal file
69
app/gui/.storybook/preview.tsx
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
/**
|
||||||
|
* @file Storybook preview
|
||||||
|
*/
|
||||||
|
import type { Preview as ReactPreview } from '@storybook/react'
|
||||||
|
import type { Preview as VuePreview } from '@storybook/vue3'
|
||||||
|
import React, { useLayoutEffect, useState } from 'react'
|
||||||
|
import invariant from 'tiny-invariant'
|
||||||
|
import UIProviders from '../src/dashboard/components/UIProviders'
|
||||||
|
|
||||||
|
import z from 'zod'
|
||||||
|
import '../src/dashboard/tailwind.css'
|
||||||
|
|
||||||
|
const framework = z.enum(['vue', 'react']).parse(window.ENV.FRAMEWORK)
|
||||||
|
|
||||||
|
const vuePreview: VuePreview = {
|
||||||
|
parameters: {
|
||||||
|
controls: {
|
||||||
|
matchers: {
|
||||||
|
color: /(background|color)$/i,
|
||||||
|
date: /Date$/i,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
const reactPreview: ReactPreview = {
|
||||||
|
parameters: {
|
||||||
|
controls: {
|
||||||
|
matchers: {
|
||||||
|
color: /(background|color)$/i,
|
||||||
|
date: /Date$/i,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
|
||||||
|
// Decorators for all stories
|
||||||
|
// Decorators are applied in the reverse order they are defined
|
||||||
|
decorators: [
|
||||||
|
(Story, context) => {
|
||||||
|
const [portalRoot, setPortalRoot] = useState<Element | null>(null)
|
||||||
|
|
||||||
|
useLayoutEffect(() => {
|
||||||
|
const portalRoot = document.querySelector('#enso-portal-root')
|
||||||
|
invariant(portalRoot, 'PortalRoot element not found')
|
||||||
|
|
||||||
|
setPortalRoot(portalRoot)
|
||||||
|
}, [])
|
||||||
|
|
||||||
|
if (!portalRoot) return <></>
|
||||||
|
|
||||||
|
return (
|
||||||
|
<UIProviders locale="en-US" portalRoot={portalRoot}>
|
||||||
|
{Story(context)}
|
||||||
|
</UIProviders>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
|
||||||
|
(Story, context) => (
|
||||||
|
<>
|
||||||
|
<div className="enso-dashboard">{Story(context)}</div>
|
||||||
|
<div id="enso-portal-root" className="enso-portal-root" />
|
||||||
|
</>
|
||||||
|
),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
|
||||||
|
const preview = framework === 'vue' ? vuePreview : reactPreview
|
||||||
|
|
||||||
|
export default preview
|
8
app/gui/chromatic.config.json
Normal file
8
app/gui/chromatic.config.json
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://www.chromatic.com/config-file.schema.json",
|
||||||
|
"projectId": "Enso Dashboard",
|
||||||
|
"autoAcceptChanges": "main",
|
||||||
|
"exitOnceUploaded": true,
|
||||||
|
"skip": "dependabot/**",
|
||||||
|
"buildScriptName": "build-storybook:react"
|
||||||
|
}
|
@ -22,18 +22,22 @@
|
|||||||
"build-cloud": "cross-env CLOUD_BUILD=true corepack pnpm run build",
|
"build-cloud": "cross-env CLOUD_BUILD=true corepack pnpm run build",
|
||||||
"preview": "vite preview",
|
"preview": "vite preview",
|
||||||
"//": "max-warnings set to 41 to match the amount of warnings introduced by the new react compiler. Eventual goal is to remove all the warnings.",
|
"//": "max-warnings set to 41 to match the amount of warnings introduced by the new react compiler. Eventual goal is to remove all the warnings.",
|
||||||
"lint": "eslint . --max-warnings=39",
|
"lint": "eslint . --cache --max-warnings=39",
|
||||||
"format": "prettier --version && prettier --write src/ && eslint . --fix",
|
"format": "prettier --version && prettier --write src/ && eslint . --fix",
|
||||||
"dev:vite": "vite",
|
"dev:vite": "vite",
|
||||||
"test": "corepack pnpm run /^^^^test:.*/",
|
"test": "corepack pnpm run /^^^^test:.*/",
|
||||||
"test:unit": "vitest run",
|
"test:unit": "vitest run",
|
||||||
"test-dev:unit": "vitest",
|
"test-dev:unit": "vitest",
|
||||||
"test:e2e": "cross-env NODE_ENV=production playwright test",
|
|
||||||
"test-dev:e2e": "cross-env NODE_ENV=production playwright test --ui",
|
"test-dev:e2e": "cross-env NODE_ENV=production playwright test --ui",
|
||||||
"test-dev-dashboard:e2e": "cross-env NODE_ENV=production playwright test ./e2e/dashboard/ --ui",
|
"test-dev-dashboard:e2e": "cross-env NODE_ENV=production playwright test ./e2e/dashboard/ --ui",
|
||||||
"preinstall": "corepack pnpm run generate-metadata",
|
"preinstall": "corepack pnpm run generate-metadata",
|
||||||
"postinstall": "playwright install",
|
"generate-metadata": "node scripts/generateIconMetadata.js",
|
||||||
"generate-metadata": "node scripts/generateIconMetadata.js"
|
"build-storybook:react": "cross-env FRAMEWORK=react storybook build",
|
||||||
|
"build-storybook:vue": "cross-env FRAMEWORK=vue storybook build",
|
||||||
|
"chromatic:react": "cross-env FRAMEWORK=react chromatic deploy",
|
||||||
|
"chromatic:vue": "cross-env FRAMEWORK=vue chromatic deploy",
|
||||||
|
"e2e": "cross-env NODE_ENV=production playwright test",
|
||||||
|
"playwright:install": "playwright install chromium"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@aws-amplify/auth": "5.6.5",
|
"@aws-amplify/auth": "5.6.5",
|
||||||
@ -59,7 +63,7 @@
|
|||||||
"react": "^18.3.1",
|
"react": "^18.3.1",
|
||||||
"react-aria": "^3.34.3",
|
"react-aria": "^3.34.3",
|
||||||
"react-aria-components": "^1.3.3",
|
"react-aria-components": "^1.3.3",
|
||||||
"react-compiler-runtime": "19.0.0-beta-6fc168f-20241025",
|
"react-compiler-runtime": "19.0.0-beta-a7bf2bd-20241110",
|
||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"react-error-boundary": "4.0.13",
|
"react-error-boundary": "4.0.13",
|
||||||
"react-hook-form": "^7.51.4",
|
"react-hook-form": "^7.51.4",
|
||||||
@ -80,7 +84,7 @@
|
|||||||
"@ag-grid-enterprise/core": "^31.1.1",
|
"@ag-grid-enterprise/core": "^31.1.1",
|
||||||
"@ag-grid-enterprise/range-selection": "^31.1.1",
|
"@ag-grid-enterprise/range-selection": "^31.1.1",
|
||||||
"@babel/parser": "^7.24.7",
|
"@babel/parser": "^7.24.7",
|
||||||
"babel-plugin-react-compiler": "19.0.0-beta-6fc168f-20241025",
|
"babel-plugin-react-compiler": "19.0.0-beta-a7bf2bd-20241110",
|
||||||
"@codemirror/commands": "^6.6.0",
|
"@codemirror/commands": "^6.6.0",
|
||||||
"@codemirror/language": "^6.10.2",
|
"@codemirror/language": "^6.10.2",
|
||||||
"@codemirror/lang-markdown": "^v6.3.0",
|
"@codemirror/lang-markdown": "^v6.3.0",
|
||||||
@ -125,10 +129,20 @@
|
|||||||
"marked": "14.1.3"
|
"marked": "14.1.3"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@chromatic-com/storybook": "^3.2.2",
|
||||||
"@fast-check/vitest": "^0.0.8",
|
"@fast-check/vitest": "^0.0.8",
|
||||||
"@modyfi/vite-plugin-yaml": "^1.0.4",
|
"@modyfi/vite-plugin-yaml": "^1.0.4",
|
||||||
"@playwright/test": "^1.40.0",
|
"@playwright/test": "^1.40.0",
|
||||||
"@react-types/shared": "^3.22.1",
|
"@react-types/shared": "^3.22.1",
|
||||||
|
"@storybook/addon-essentials": "^8.4.2",
|
||||||
|
"@storybook/addon-interactions": "^8.4.2",
|
||||||
|
"@storybook/addon-onboarding": "^8.4.2",
|
||||||
|
"@storybook/blocks": "^8.4.2",
|
||||||
|
"@storybook/react": "^8.4.2",
|
||||||
|
"@storybook/react-vite": "^8.4.2",
|
||||||
|
"@storybook/test": "^8.4.2",
|
||||||
|
"@storybook/vue3": "^8.4.2",
|
||||||
|
"@storybook/vue3-vite": "^8.4.2",
|
||||||
"@tanstack/react-query-devtools": "5.45.1",
|
"@tanstack/react-query-devtools": "5.45.1",
|
||||||
"@types/node": "^22.9.0",
|
"@types/node": "^22.9.0",
|
||||||
"@types/react": "^18.0.27",
|
"@types/react": "^18.0.27",
|
||||||
@ -181,6 +195,8 @@
|
|||||||
"react-dom": "^18.3.1",
|
"react-dom": "^18.3.1",
|
||||||
"shuffle-seed": "^1.1.6",
|
"shuffle-seed": "^1.1.6",
|
||||||
"sql-formatter": "^13.0.0",
|
"sql-formatter": "^13.0.0",
|
||||||
|
"storybook": "^8.4.2",
|
||||||
|
"chromatic": "11.18.1",
|
||||||
"tar": "^6.2.1",
|
"tar": "^6.2.1",
|
||||||
"tsx": "^4.7.1",
|
"tsx": "^4.7.1",
|
||||||
"vite-plugin-vue-devtools": "7.6.3",
|
"vite-plugin-vue-devtools": "7.6.3",
|
||||||
|
@ -19,7 +19,8 @@ const TIMEOUT_MS =
|
|||||||
: 15_000
|
: 15_000
|
||||||
|
|
||||||
// We tend to use less CPU on CI to reduce the number of failures due to timeouts.
|
// We tend to use less CPU on CI to reduce the number of failures due to timeouts.
|
||||||
const WORKERS = isCI ? '25%' : '35%'
|
// Instead of using workers on CI, we use shards to run tests in parallel.
|
||||||
|
const WORKERS = isCI ? 2 : '35%'
|
||||||
|
|
||||||
async function findFreePortInRange(min: number, max: number) {
|
async function findFreePortInRange(min: number, max: number) {
|
||||||
for (let i = 0; i < 50; i++) {
|
for (let i = 0; i < 50; i++) {
|
||||||
@ -62,12 +63,13 @@ process.env.PLAYWRIGHT_PORT_PV = `${ports.projectView}`
|
|||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
fullyParallel: true,
|
fullyParallel: true,
|
||||||
...(WORKERS ? { workers: WORKERS } : {}),
|
...(WORKERS ? { workers: WORKERS } : {}),
|
||||||
forbidOnly: !!process.env.CI,
|
forbidOnly: isCI,
|
||||||
repeatEach: process.env.CI ? 3 : 1,
|
reporter: isCI ? ([['list'], ['blob']] as const) : ([['list']] as const),
|
||||||
reporter: 'html',
|
retries: isCI ? 3 : 0,
|
||||||
use: {
|
use: {
|
||||||
headless: !DEBUG,
|
headless: !DEBUG,
|
||||||
actionTimeout: 5000,
|
actionTimeout: 5000,
|
||||||
|
|
||||||
trace: 'retain-on-failure',
|
trace: 'retain-on-failure',
|
||||||
...(DEBUG ?
|
...(DEBUG ?
|
||||||
{}
|
{}
|
||||||
|
64
app/gui/scripts/ci/dedent.js
Normal file
64
app/gui/scripts/ci/dedent.js
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
/**
|
||||||
|
* @param {string | TemplateStringsArray} strings
|
||||||
|
* @param {...unknown[]} values
|
||||||
|
* @returns {string}
|
||||||
|
*/
|
||||||
|
export function dedent(strings, ...values) {
|
||||||
|
const raw = typeof strings === 'string' ? [strings] : strings.raw
|
||||||
|
const escapeSpecialCharacters = Array.isArray(strings)
|
||||||
|
|
||||||
|
// first, perform interpolation
|
||||||
|
let result = ''
|
||||||
|
for (let i = 0; i < raw.length; i++) {
|
||||||
|
let next = raw[i]
|
||||||
|
|
||||||
|
if (next === undefined) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (escapeSpecialCharacters) {
|
||||||
|
// handle escaped newlines, backticks, and interpolation characters
|
||||||
|
next = next
|
||||||
|
.replace(/\\\n[ \t]*/g, '')
|
||||||
|
.replace(/\\`/g, '`')
|
||||||
|
.replace(/\\\$/g, '$')
|
||||||
|
.replace(/\\\{/g, '{')
|
||||||
|
}
|
||||||
|
|
||||||
|
result += next
|
||||||
|
|
||||||
|
if (i < values.length) {
|
||||||
|
result += values[i]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// now strip indentation
|
||||||
|
const lines = result.split('\n')
|
||||||
|
let mindent = null
|
||||||
|
for (const l of lines) {
|
||||||
|
const m = l.match(/^(\s+)\S+/)
|
||||||
|
if (m && m[1]) {
|
||||||
|
const indent = m[1].length
|
||||||
|
if (!mindent) {
|
||||||
|
// this is the first indented line
|
||||||
|
mindent = indent
|
||||||
|
} else {
|
||||||
|
mindent = Math.min(mindent, indent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mindent !== null) {
|
||||||
|
const m = mindent
|
||||||
|
result = lines.map((l) => (l[0] === ' ' || l[0] === '\t' ? l.slice(m) : l)).join('\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
// dedent eats leading and trailing whitespace too
|
||||||
|
result = result.trim()
|
||||||
|
if (escapeSpecialCharacters) {
|
||||||
|
// handle escaped newlines at the end to ensure they don't get stripped too
|
||||||
|
result = result.replace(/\\n/g, '\n')
|
||||||
|
}
|
||||||
|
|
||||||
|
return result
|
||||||
|
}
|
35
app/gui/scripts/ci/set-message.js
Normal file
35
app/gui/scripts/ci/set-message.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
|
// @ts-nocheck
|
||||||
|
import { dedent } from './dedent.js'
|
||||||
|
|
||||||
|
export async function setMessage({ header, body, prNumber, repo, github }) {
|
||||||
|
const commentList = await github.paginate(
|
||||||
|
'GET /repos/:owner/:repo/issues/:issue_number/comments',
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
{ ...repo, issue_number: prNumber },
|
||||||
|
)
|
||||||
|
|
||||||
|
const commentBody = dedent`
|
||||||
|
${header}
|
||||||
|
|
||||||
|
${body}
|
||||||
|
`
|
||||||
|
|
||||||
|
const comment = commentList.find((comment) => comment.body.startsWith(header))
|
||||||
|
|
||||||
|
if (!comment) {
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
...repo,
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
issue_number: prNumber,
|
||||||
|
body: commentBody,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
await github.rest.issues.updateComment({
|
||||||
|
...repo,
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
comment_id: comment.id,
|
||||||
|
body: commentBody,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
import Enso from '#/assets/enso_logo.svg'
|
||||||
|
import type * as aria from '#/components/aria'
|
||||||
|
import { Text } from '#/components/AriaComponents'
|
||||||
|
import type { Meta, StoryObj } from '@storybook/react'
|
||||||
|
import { expect, userEvent, within } from '@storybook/test'
|
||||||
|
import type { BaseButtonProps } from './Button'
|
||||||
|
import { Button } from './Button'
|
||||||
|
|
||||||
|
type Story = StoryObj<BaseButtonProps<aria.ButtonRenderProps>>
|
||||||
|
|
||||||
|
export default {
|
||||||
|
title: 'Components/AriaComponents/Button',
|
||||||
|
component: Button,
|
||||||
|
render: (props) => <Button {...props} />,
|
||||||
|
} as Meta<BaseButtonProps<aria.ButtonRenderProps>>
|
||||||
|
|
||||||
|
export const Variants: Story = {
|
||||||
|
render: () => (
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<Text.Heading>Variants</Text.Heading>
|
||||||
|
<div className="grid grid-cols-4 place-content-start place-items-start gap-3">
|
||||||
|
<Button>Default</Button>
|
||||||
|
<Button variant="primary">Primary</Button>
|
||||||
|
<Button variant="accent">Accent</Button>
|
||||||
|
<Button variant="delete">Delete</Button>
|
||||||
|
<Button variant="ghost-fading">Ghost Fading</Button>
|
||||||
|
<Button variant="ghost">Ghost</Button>
|
||||||
|
<Button variant="link">Link</Button>
|
||||||
|
<Button variant="submit">Submit</Button>
|
||||||
|
<Button variant="outline">Outline</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Text.Heading>Sizes</Text.Heading>
|
||||||
|
<div className="grid grid-cols-4 place-content-center place-items-start gap-3">
|
||||||
|
<Button size="hero">Hero</Button>
|
||||||
|
<Button size="large">Large</Button>
|
||||||
|
<Button size="medium">Medium</Button>
|
||||||
|
<Button size="small">Small</Button>
|
||||||
|
<Button size="xsmall">XSmall</Button>
|
||||||
|
<Button size="xxsmall">XXSmall</Button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Text.Heading>Icons</Text.Heading>
|
||||||
|
<div className="grid grid-cols-4 place-content-center place-items-start gap-3">
|
||||||
|
<Button icon={Enso}>Icon start</Button>
|
||||||
|
<Button icon={Enso} iconPosition="end">
|
||||||
|
Icon end
|
||||||
|
</Button>
|
||||||
|
<Button icon={Enso} aria-label="Only icon" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<Text.Heading>States</Text.Heading>
|
||||||
|
<div className="grid grid-cols-4 place-content-center place-items-start gap-3">
|
||||||
|
<Button isDisabled>Disabled</Button>
|
||||||
|
<Button loading>Loading</Button>
|
||||||
|
<Button loaderPosition="icon" loading>
|
||||||
|
Loading
|
||||||
|
</Button>
|
||||||
|
<Button isActive>Active</Button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
export const Tooltips: Story = {
|
||||||
|
render: () => (
|
||||||
|
<div className="flex flex-col gap-4">
|
||||||
|
<Text.Heading>Tooltip</Text.Heading>
|
||||||
|
<div className="grid grid-cols-4 place-content-center place-items-start gap-3">
|
||||||
|
<Button tooltip="This is a tooltip">Tooltip</Button>
|
||||||
|
<Button
|
||||||
|
aria-label="Tooltip uses aria-label for icon buttons"
|
||||||
|
icon={Enso}
|
||||||
|
testId="icon-button"
|
||||||
|
/>
|
||||||
|
<Button icon={Enso} tooltip={false} testId="icon-button-no-tooltip" />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
),
|
||||||
|
}
|
||||||
|
|
||||||
|
export const LoadingOnPress: Story = {
|
||||||
|
render: () => {
|
||||||
|
return (
|
||||||
|
<Button
|
||||||
|
onPress={() => {
|
||||||
|
return new Promise((resolve) => setTimeout(resolve, 1000))
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Click me to trigger loading
|
||||||
|
</Button>
|
||||||
|
)
|
||||||
|
},
|
||||||
|
play: async ({ canvasElement }) => {
|
||||||
|
const { getByRole, findByTestId } = within(canvasElement)
|
||||||
|
|
||||||
|
const button = getByRole('button', { name: 'Click me to trigger loading' })
|
||||||
|
await userEvent.click(button)
|
||||||
|
await expect(button).toHaveAttribute('disabled')
|
||||||
|
// then the spinner appears after some delay
|
||||||
|
await expect(await findByTestId('spinner')).toBeInTheDocument()
|
||||||
|
},
|
||||||
|
}
|
@ -4,14 +4,14 @@ import * as React from 'react'
|
|||||||
import * as focusHooks from '#/hooks/focusHooks'
|
import * as focusHooks from '#/hooks/focusHooks'
|
||||||
|
|
||||||
import * as aria from '#/components/aria'
|
import * as aria from '#/components/aria'
|
||||||
import * as ariaComponents from '#/components/AriaComponents'
|
|
||||||
import { StatelessSpinner } from '#/components/StatelessSpinner'
|
import { StatelessSpinner } from '#/components/StatelessSpinner'
|
||||||
import SvgMask from '#/components/SvgMask'
|
import SvgMask from '#/components/SvgMask'
|
||||||
|
|
||||||
import { forwardRef } from '#/utilities/react'
|
import { forwardRef } from '#/utilities/react'
|
||||||
import type { ExtractFunction, VariantProps } from '#/utilities/tailwindVariants'
|
import type { ExtractFunction, VariantProps } from '#/utilities/tailwindVariants'
|
||||||
import { tv } from '#/utilities/tailwindVariants'
|
import { tv } from '#/utilities/tailwindVariants'
|
||||||
import { TEXT_STYLE } from '../Text'
|
import { TEXT_STYLE, useVisualTooltip } from '../Text'
|
||||||
|
import { Tooltip, TooltipTrigger } from '../Tooltip'
|
||||||
|
|
||||||
// ==============
|
// ==============
|
||||||
// === Button ===
|
// === Button ===
|
||||||
@ -82,7 +82,7 @@ export const BUTTON_STYLES = tv({
|
|||||||
],
|
],
|
||||||
variants: {
|
variants: {
|
||||||
isDisabled: {
|
isDisabled: {
|
||||||
true: 'disabled:opacity-50 disabled:cursor-not-allowed aria-disabled:opacity-50 aria-disabled:cursor-not-allowed',
|
true: 'opacity-50 cursor-not-allowed',
|
||||||
},
|
},
|
||||||
isFocused: {
|
isFocused: {
|
||||||
true: 'focus:outline-none focus-visible:outline-2 focus-visible:outline-black focus-visible:outline-offset-[-2px]',
|
true: 'focus:outline-none focus-visible:outline-2 focus-visible:outline-black focus-visible:outline-offset-[-2px]',
|
||||||
@ -256,6 +256,7 @@ export const BUTTON_STYLES = tv({
|
|||||||
variant: 'primary',
|
variant: 'primary',
|
||||||
iconPosition: 'start',
|
iconPosition: 'start',
|
||||||
showIconOnHover: false,
|
showIconOnHover: false,
|
||||||
|
isDisabled: false,
|
||||||
},
|
},
|
||||||
compoundVariants: [
|
compoundVariants: [
|
||||||
{ isFocused: true, iconOnly: true, class: 'focus-visible:outline-offset-[3px]' },
|
{ isFocused: true, iconOnly: true, class: 'focus-visible:outline-offset-[3px]' },
|
||||||
@ -393,14 +394,14 @@ export const Button = forwardRef(function Button(
|
|||||||
render: aria.ButtonRenderProps | aria.LinkRenderProps,
|
render: aria.ButtonRenderProps | aria.LinkRenderProps,
|
||||||
): React.ReactNode => {
|
): React.ReactNode => {
|
||||||
const iconComponent = (() => {
|
const iconComponent = (() => {
|
||||||
if (icon == null) {
|
if (isLoading && loaderPosition === 'icon') {
|
||||||
return null
|
|
||||||
} else if (isLoading && loaderPosition === 'icon') {
|
|
||||||
return (
|
return (
|
||||||
<span className={styles.icon()}>
|
<span className={styles.icon()}>
|
||||||
<StatelessSpinner state="loading-medium" size={16} />
|
<StatelessSpinner state="loading-medium" size={16} />
|
||||||
</span>
|
</span>
|
||||||
)
|
)
|
||||||
|
} else if (icon == null) {
|
||||||
|
return null
|
||||||
} else {
|
} else {
|
||||||
/* @ts-expect-error any here is safe because we transparently pass it to the children, and ts infer the type outside correctly */
|
/* @ts-expect-error any here is safe because we transparently pass it to the children, and ts infer the type outside correctly */
|
||||||
const actualIcon = typeof icon === 'function' ? icon(render) : icon
|
const actualIcon = typeof icon === 'function' ? icon(render) : icon
|
||||||
@ -429,7 +430,7 @@ export const Button = forwardRef(function Button(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const { tooltip: visualTooltip, targetProps } = ariaComponents.useVisualTooltip({
|
const { tooltip: visualTooltip, targetProps } = useVisualTooltip({
|
||||||
targetRef: contentRef,
|
targetRef: contentRef,
|
||||||
children: tooltipElement,
|
children: tooltipElement,
|
||||||
isDisabled: !shouldUseVisualTooltip,
|
isDisabled: !shouldUseVisualTooltip,
|
||||||
@ -483,14 +484,12 @@ export const Button = forwardRef(function Button(
|
|||||||
{button}
|
{button}
|
||||||
{visualTooltip}
|
{visualTooltip}
|
||||||
</>
|
</>
|
||||||
: <ariaComponents.TooltipTrigger delay={0} closeDelay={0}>
|
: <TooltipTrigger delay={0} closeDelay={0}>
|
||||||
{button}
|
{button}
|
||||||
|
|
||||||
<ariaComponents.Tooltip
|
<Tooltip {...(tooltipPlacement != null ? { placement: tooltipPlacement } : {})}>
|
||||||
{...(tooltipPlacement != null ? { placement: tooltipPlacement } : {})}
|
|
||||||
>
|
|
||||||
{tooltipElement}
|
{tooltipElement}
|
||||||
</ariaComponents.Tooltip>
|
</Tooltip>
|
||||||
</ariaComponents.TooltipTrigger>
|
</TooltipTrigger>
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
@ -4,10 +4,10 @@ import * as React from 'react'
|
|||||||
import Success from '#/assets/check_mark.svg'
|
import Success from '#/assets/check_mark.svg'
|
||||||
import Error from '#/assets/cross.svg'
|
import Error from '#/assets/cross.svg'
|
||||||
|
|
||||||
import * as ariaComponents from '#/components/AriaComponents'
|
|
||||||
import * as loader from '#/components/Loader'
|
|
||||||
import SvgMask from '#/components/SvgMask'
|
|
||||||
import { tv, type VariantProps } from '#/utilities/tailwindVariants'
|
import { tv, type VariantProps } from '#/utilities/tailwindVariants'
|
||||||
|
import { Text } from './AriaComponents/Text'
|
||||||
|
import * as loader from './Loader'
|
||||||
|
import SvgMask from './SvgMask'
|
||||||
|
|
||||||
// =================
|
// =================
|
||||||
// === Constants ===
|
// === Constants ===
|
||||||
@ -15,9 +15,9 @@ import { tv, type VariantProps } from '#/utilities/tailwindVariants'
|
|||||||
|
|
||||||
const INFO_ICON = (
|
const INFO_ICON = (
|
||||||
// eslint-disable-next-line no-restricted-syntax
|
// eslint-disable-next-line no-restricted-syntax
|
||||||
<ariaComponents.Text variant="custom" className="pb-0.5 text-xl leading-[0]" aria-hidden>
|
<Text variant="custom" className="pb-0.5 text-xl leading-[0]" aria-hidden>
|
||||||
!
|
!
|
||||||
</ariaComponents.Text>
|
</Text>
|
||||||
)
|
)
|
||||||
|
|
||||||
const STATUS_ICON_MAP: Readonly<Record<Status, StatusIcon>> = {
|
const STATUS_ICON_MAP: Readonly<Record<Status, StatusIcon>> = {
|
||||||
@ -142,15 +142,15 @@ export function Result(props: ResultProps) {
|
|||||||
: null}
|
: null}
|
||||||
|
|
||||||
{typeof title === 'string' ?
|
{typeof title === 'string' ?
|
||||||
<ariaComponents.Text.Heading level={2} className={classes.title()} variant="subtitle">
|
<Text.Heading level={2} className={classes.title()} variant="subtitle">
|
||||||
{title}
|
{title}
|
||||||
</ariaComponents.Text.Heading>
|
</Text.Heading>
|
||||||
: title}
|
: title}
|
||||||
|
|
||||||
{typeof subtitle === 'string' ?
|
{typeof subtitle === 'string' ?
|
||||||
<ariaComponents.Text elementType="p" className={classes.subtitle()} balance variant="body">
|
<Text elementType="p" className={classes.subtitle()} balance variant="body">
|
||||||
{subtitle}
|
{subtitle}
|
||||||
</ariaComponents.Text>
|
</Text>
|
||||||
: subtitle}
|
: subtitle}
|
||||||
|
|
||||||
{children != null && <div className={classes.content()}>{children}</div>}
|
{children != null && <div className={classes.content()}>{children}</div>}
|
||||||
|
@ -40,6 +40,7 @@ export function Spinner(props: SpinnerProps) {
|
|||||||
fill="none"
|
fill="none"
|
||||||
xmlns="http://www.w3.org/2000/svg"
|
xmlns="http://www.w3.org/2000/svg"
|
||||||
aria-hidden="true"
|
aria-hidden="true"
|
||||||
|
data-testid="spinner"
|
||||||
>
|
>
|
||||||
<rect
|
<rect
|
||||||
x={1.5}
|
x={1.5}
|
||||||
|
32
app/gui/src/dashboard/styles.css
Normal file
32
app/gui/src/dashboard/styles.css
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
:where(body) {
|
||||||
|
overflow: hidden;
|
||||||
|
height: 100vh;
|
||||||
|
background-blend-mode: lighten;
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(body:not(.vibrancy)) {
|
||||||
|
&::before {
|
||||||
|
content: '';
|
||||||
|
inset: 0 -16vw -16vh 0;
|
||||||
|
z-index: -1;
|
||||||
|
|
||||||
|
background-color: #b09778ff;
|
||||||
|
|
||||||
|
@apply pointer-events-none fixed bg-cover;
|
||||||
|
}
|
||||||
|
|
||||||
|
& > * {
|
||||||
|
@apply bg-white/80;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
:where(.enso-dashboard) {
|
||||||
|
@apply absolute inset-0 flex flex-col overflow-hidden;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Disable all animations. */
|
||||||
|
html.disable-animations * {
|
||||||
|
transition: none !important;
|
||||||
|
animation: none !important;
|
||||||
|
animation-play-state: paused !important;
|
||||||
|
}
|
@ -398,43 +398,10 @@
|
|||||||
--sidebar-section-heading-margin-b: 0.375rem;
|
--sidebar-section-heading-margin-b: 0.375rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Disable all animations. */
|
|
||||||
html.disable-animations * {
|
|
||||||
transition: none !important;
|
|
||||||
animation: none !important;
|
|
||||||
animation-play-state: paused !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
:where(body) {
|
|
||||||
overflow: hidden;
|
|
||||||
height: 100vh;
|
|
||||||
background-blend-mode: lighten;
|
|
||||||
}
|
|
||||||
|
|
||||||
:where(body:not(.vibrancy)) {
|
|
||||||
&::before {
|
|
||||||
content: '';
|
|
||||||
inset: 0 -16vw -16vh 0;
|
|
||||||
z-index: -1;
|
|
||||||
|
|
||||||
background-color: #b09778ff;
|
|
||||||
|
|
||||||
@apply pointer-events-none fixed bg-cover;
|
|
||||||
}
|
|
||||||
|
|
||||||
& > * {
|
|
||||||
@apply bg-white/80;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.Toastify--animate {
|
.Toastify--animate {
|
||||||
animation-duration: 200ms;
|
animation-duration: 200ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
:where(.enso-dashboard) {
|
|
||||||
@apply absolute inset-0 flex flex-col overflow-hidden;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* These styles MUST still be copied
|
/* These styles MUST still be copied
|
||||||
* as `.enso-dashboard body` and `.enso-dashboard html` make no sense. */
|
* as `.enso-dashboard body` and `.enso-dashboard html` make no sense. */
|
||||||
:where(.enso-dashboard, .enso-chat, .enso-portal-root) {
|
:where(.enso-dashboard, .enso-chat, .enso-portal-root) {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import * as dashboard from '#/index'
|
import * as dashboard from '#/index'
|
||||||
|
import '#/styles.css'
|
||||||
import '#/tailwind.css'
|
import '#/tailwind.css'
|
||||||
import { AsyncApp } from '@/asyncApp'
|
import { AsyncApp } from '@/asyncApp'
|
||||||
import { baseConfig, configValue, mergeConfig } from '@/util/config'
|
import { baseConfig, configValue, mergeConfig } from '@/util/config'
|
||||||
|
@ -49,7 +49,7 @@ const activity = shallowRef<VNode>()
|
|||||||
|
|
||||||
// How much wider a dropdown can be than a port it is attached to, when a long text is present.
|
// How much wider a dropdown can be than a port it is attached to, when a long text is present.
|
||||||
// Any text beyond that limit will receive an ellipsis and sliding animation on hover.
|
// Any text beyond that limit will receive an ellipsis and sliding animation on hover.
|
||||||
const MAX_DROPDOWN_OVERSIZE_PX = 150
|
const MAX_DROPDOWN_OVERSIZE_PX = 390
|
||||||
|
|
||||||
const floatReference = computed(
|
const floatReference = computed(
|
||||||
() => enclosingTopLevelArgument(widgetRoot.value, tree) ?? widgetRoot.value,
|
() => enclosingTopLevelArgument(widgetRoot.value, tree) ?? widgetRoot.value,
|
||||||
|
@ -148,7 +148,7 @@ export interface DropdownEntry {
|
|||||||
|
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: color-mix(in oklab, var(--dropdown-bg) 50%, white 50%);
|
background-color: color-mix(in oklab, var(--dropdown-bg) 50%, white 50%);
|
||||||
span {
|
.itemContent {
|
||||||
--text-scroll-max: calc(var(--dropdown-max-width) - 28px);
|
--text-scroll-max: calc(var(--dropdown-max-width) - 28px);
|
||||||
will-change: transform;
|
will-change: transform;
|
||||||
animation: 6s 1s infinite text-scroll;
|
animation: 6s 1s infinite text-scroll;
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
{
|
{
|
||||||
"extends": "./tsconfig.json",
|
"extends": "./tsconfig.json",
|
||||||
"include": [
|
"include": [
|
||||||
|
".storybook/**/*",
|
||||||
"env.d.ts",
|
"env.d.ts",
|
||||||
"lib0-ext.d.ts",
|
"lib0-ext.d.ts",
|
||||||
"src/**/*.vue",
|
"src/**/*.vue",
|
||||||
|
10
app/gui/tsconfig.storybook.json
Normal file
10
app/gui/tsconfig.storybook.json
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.app.json",
|
||||||
|
"include": [
|
||||||
|
".storybook/**/*",
|
||||||
|
".storybook/env.d.ts",
|
||||||
|
"./src/**/*.stories.tsx",
|
||||||
|
"./src/**/*.stories.vue",
|
||||||
|
"./src/**/*.stories.ts"
|
||||||
|
]
|
||||||
|
}
|
@ -30,12 +30,15 @@ const entrypoint =
|
|||||||
// and because Vite's HTML env replacements only work with import.meta.env variables, not defines.
|
// and because Vite's HTML env replacements only work with import.meta.env variables, not defines.
|
||||||
process.env.ENSO_IDE_VERSION = process.env.ENSO_CLOUD_DASHBOARD_VERSION
|
process.env.ENSO_IDE_VERSION = process.env.ENSO_CLOUD_DASHBOARD_VERSION
|
||||||
|
|
||||||
|
const isCI = process.env.CI === 'true'
|
||||||
|
|
||||||
// https://vitejs.dev/config/
|
// https://vitejs.dev/config/
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
root: fileURLToPath(new URL('.', import.meta.url)),
|
root: fileURLToPath(new URL('.', import.meta.url)),
|
||||||
cacheDir: fileURLToPath(new URL('../../node_modules/.cache/vite', import.meta.url)),
|
cacheDir: fileURLToPath(new URL('../../node_modules/.cache/vite', import.meta.url)),
|
||||||
publicDir: fileURLToPath(new URL('./public', import.meta.url)),
|
publicDir: fileURLToPath(new URL('./public', import.meta.url)),
|
||||||
envDir: fileURLToPath(new URL('.', import.meta.url)),
|
envDir: fileURLToPath(new URL('.', import.meta.url)),
|
||||||
|
logLevel: isCI ? 'error' : 'info',
|
||||||
plugins: [
|
plugins: [
|
||||||
wasm(),
|
wasm(),
|
||||||
...(process.env.NODE_ENV === 'development' ? [await VueDevTools()] : []),
|
...(process.env.NODE_ENV === 'development' ? [await VueDevTools()] : []),
|
||||||
|
@ -63,7 +63,7 @@
|
|||||||
"typecheck": "tsc --build",
|
"typecheck": "tsc --build",
|
||||||
"build": "tsx bundle.ts",
|
"build": "tsx bundle.ts",
|
||||||
"dist": "tsx dist.ts",
|
"dist": "tsx dist.ts",
|
||||||
"lint": "eslint . --max-warnings=0",
|
"lint": "eslint . --cache --max-warnings=0",
|
||||||
"watch:windows": "cross-env ENSO_BUILD_IDE=%LOCALAPPDATA%\\Temp\\enso\\dist\\ide ENSO_BUILD_PROJECT_MANAGER=%CD%\\..\\..\\..\\dist\\backend ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH=bin\\project-manager.exe ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION=0 ENSO_POLYGLOT_YDOC_SERVER=wss://localhost:8080 tsx watch.ts",
|
"watch:windows": "cross-env ENSO_BUILD_IDE=%LOCALAPPDATA%\\Temp\\enso\\dist\\ide ENSO_BUILD_PROJECT_MANAGER=%CD%\\..\\..\\..\\dist\\backend ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH=bin\\project-manager.exe ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION=0 ENSO_POLYGLOT_YDOC_SERVER=wss://localhost:8080 tsx watch.ts",
|
||||||
"watch:linux": "ENSO_BUILD_IDE=\"${ENSO_BUILD_IDE:-/tmp/enso/dist/ide}\" ENSO_BUILD_PROJECT_MANAGER=\"${ENSO_BUILD_PROJECT_MANAGER:-\"$(pwd)/../../../dist/backend\"}\" ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH=\"${ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH:-bin/project-manager}\" ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION=\"${ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION:-0}\" ENSO_POLYGLOT_YDOC_SERVER=\"${ENSO_POLYGLOT_YDOC_SERVER:-wss://localhost:8080}\" tsx watch.ts \"$@\"",
|
"watch:linux": "ENSO_BUILD_IDE=\"${ENSO_BUILD_IDE:-/tmp/enso/dist/ide}\" ENSO_BUILD_PROJECT_MANAGER=\"${ENSO_BUILD_PROJECT_MANAGER:-\"$(pwd)/../../../dist/backend\"}\" ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH=\"${ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH:-bin/project-manager}\" ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION=\"${ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION:-0}\" ENSO_POLYGLOT_YDOC_SERVER=\"${ENSO_POLYGLOT_YDOC_SERVER:-wss://localhost:8080}\" tsx watch.ts \"$@\"",
|
||||||
"watch:macos": "ENSO_BUILD_IDE=\"${ENSO_BUILD_IDE:-/tmp/enso/dist/ide}\" ENSO_BUILD_PROJECT_MANAGER=\"${ENSO_BUILD_PROJECT_MANAGER:-\"$(pwd)/../../../dist/backend\"}\" ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH=\"${ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH:-bin/project-manager}\" ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION=\"${ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION:-0}\" ENSO_POLYGLOT_YDOC_SERVER=\"${ENSO_POLYGLOT_YDOC_SERVER:-wss://localhost:8080}\" tsx watch.ts \"$@\""
|
"watch:macos": "ENSO_BUILD_IDE=\"${ENSO_BUILD_IDE:-/tmp/enso/dist/ide}\" ENSO_BUILD_PROJECT_MANAGER=\"${ENSO_BUILD_PROJECT_MANAGER:-\"$(pwd)/../../../dist/backend\"}\" ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH=\"${ENSO_BUILD_PROJECT_MANAGER_IN_BUNDLE_PATH:-bin/project-manager}\" ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION=\"${ENSO_BUILD_IDE_BUNDLED_ENGINE_VERSION:-0}\" ENSO_POLYGLOT_YDOC_SERVER=\"${ENSO_POLYGLOT_YDOC_SERVER:-wss://localhost:8080}\" tsx watch.ts \"$@\""
|
||||||
|
@ -16,7 +16,7 @@
|
|||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build": "node src/index.js",
|
"build": "node src/index.js",
|
||||||
"lint": "eslint . --max-warnings=0"
|
"lint": "eslint . --cache --max-warnings=0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"sharp": "^0.31.2",
|
"sharp": "^0.31.2",
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
"compile": "node ./build.mjs build",
|
"compile": "node ./build.mjs build",
|
||||||
"start": "node ./dist/main.mjs",
|
"start": "node ./dist/main.mjs",
|
||||||
"dev:watch": "node ./build.mjs watch",
|
"dev:watch": "node ./build.mjs watch",
|
||||||
"lint": "eslint . --max-warnings=0",
|
"lint": "eslint . --cache --max-warnings=0",
|
||||||
"format": "prettier --version && prettier --write src/ && eslint . --fix"
|
"format": "prettier --version && prettier --write src/ && eslint . --fix"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
"compile": "node ./build.mjs build",
|
"compile": "node ./build.mjs build",
|
||||||
"start": "node ./dist/main.cjs",
|
"start": "node ./dist/main.cjs",
|
||||||
"dev:watch": "node ./build.mjs watch",
|
"dev:watch": "node ./build.mjs watch",
|
||||||
"lint": "eslint . --max-warnings=0"
|
"lint": "eslint . --cache --max-warnings=0"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"ydoc-server": "workspace:*",
|
"ydoc-server": "workspace:*",
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
"test:watch": "vitest",
|
"test:watch": "vitest",
|
||||||
"typecheck": "tsc",
|
"typecheck": "tsc",
|
||||||
"compile": "tsc",
|
"compile": "tsc",
|
||||||
"lint": "eslint . --max-warnings=0"
|
"lint": "eslint . --cache --max-warnings=0"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
"generate:ast-schema": "cargo run -p enso-parser-schema > src/ast/generated/ast-schema.json",
|
"generate:ast-schema": "cargo run -p enso-parser-schema > src/ast/generated/ast-schema.json",
|
||||||
"generate:ast-types": "vite-node ./parser-codegen/index.ts src/ast/generated/ast-schema.json src/ast/generated/ast.ts",
|
"generate:ast-types": "vite-node ./parser-codegen/index.ts src/ast/generated/ast-schema.json src/ast/generated/ast.ts",
|
||||||
"generate:ast-types-lazy": "vite-node ./parser-codegen/index.ts src/ast/generated/ast-schema.json src/ast/generated/ast.ts --if-changed",
|
"generate:ast-types-lazy": "vite-node ./parser-codegen/index.ts src/ast/generated/ast-schema.json src/ast/generated/ast.ts --if-changed",
|
||||||
"lint": "eslint . --max-warnings=0",
|
"lint": "eslint . --cache --max-warnings=0",
|
||||||
"format": "prettier --version && prettier --write src/ && eslint . --fix",
|
"format": "prettier --version && prettier --write src/ && eslint . --fix",
|
||||||
"postinstall": "corepack pnpm run generate:ast-schema && corepack pnpm run generate:ast-types-lazy"
|
"postinstall": "corepack pnpm run generate:ast-schema && corepack pnpm run generate:ast-types-lazy"
|
||||||
},
|
},
|
||||||
|
@ -661,7 +661,6 @@ pub fn gui_tests() -> Result<Workflow> {
|
|||||||
workflow.add(PRIMARY_TARGET, job::Lint);
|
workflow.add(PRIMARY_TARGET, job::Lint);
|
||||||
workflow.add(PRIMARY_TARGET, job::WasmTest);
|
workflow.add(PRIMARY_TARGET, job::WasmTest);
|
||||||
workflow.add(PRIMARY_TARGET, job::NativeTest);
|
workflow.add(PRIMARY_TARGET, job::NativeTest);
|
||||||
workflow.add(PRIMARY_TARGET, job::GuiCheck);
|
|
||||||
Ok(workflow)
|
Ok(workflow)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -396,16 +396,6 @@ impl JobArchetype for NativeTest {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
|
||||||
pub struct GuiCheck;
|
|
||||||
|
|
||||||
impl JobArchetype for GuiCheck {
|
|
||||||
fn job(&self, target: Target) -> Job {
|
|
||||||
plain_job(target, "GUI tests", "gui check")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug)]
|
#[derive(Clone, Copy, Debug)]
|
||||||
pub struct GuiBuild;
|
pub struct GuiBuild;
|
||||||
|
|
||||||
|
@ -556,4 +556,15 @@ export default [
|
|||||||
'no-undef': 'off',
|
'no-undef': 'off',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
files: ['app/gui/src/dashboard/**/*.stories.tsx'],
|
||||||
|
rules: {
|
||||||
|
'no-restricted-syntax': 'off',
|
||||||
|
'jsdoc/require-jsdoc': 'off',
|
||||||
|
'jsdoc/require-param-type': 'off',
|
||||||
|
'jsdoc/require-file-overview': 'off',
|
||||||
|
'@typescript-eslint/no-magic-numbers': 'off',
|
||||||
|
'@typescript-eslint/unbound-method': 'off',
|
||||||
|
},
|
||||||
|
},
|
||||||
]
|
]
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
{
|
{
|
||||||
|
"type": "module",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@typescript-eslint/eslint-plugin": "^8.10.0",
|
"@typescript-eslint/eslint-plugin": "^8.10.0",
|
||||||
"@typescript-eslint/parser": "^8.10.0",
|
"@typescript-eslint/parser": "^8.10.0",
|
||||||
@ -30,10 +31,12 @@
|
|||||||
"format": "prettier --write .",
|
"format": "prettier --write .",
|
||||||
"format:workflows": "prettier --write .github/workflows",
|
"format:workflows": "prettier --write .github/workflows",
|
||||||
"ci-check": "corepack pnpm run --aggregate-output /^ci:/",
|
"ci-check": "corepack pnpm run --aggregate-output /^ci:/",
|
||||||
"ci:prettier": "prettier --check .",
|
"ci:prettier": "prettier --check --cache .",
|
||||||
"ci:lint": "corepack pnpm run -r lint",
|
"ci:lint": "corepack pnpm run -r --parallel lint --output-file eslint_report.json --format json",
|
||||||
"ci:test": "corepack pnpm run -r --parallel test",
|
"ci:test": "corepack pnpm run -r --parallel test",
|
||||||
"ci:typecheck": "corepack pnpm run -r typecheck"
|
"ci:typecheck": "corepack pnpm run -r typecheck",
|
||||||
|
"ci:chromatic:react": "corepack pnpm run -r --filter enso-gui chromatic:react",
|
||||||
|
"ci:chromatic:vue": "corepack pnpm run -r --filter enso-gui chromatic:vue"
|
||||||
},
|
},
|
||||||
"pnpm": {
|
"pnpm": {
|
||||||
"//": "To completely ignore deep dependencies, see .pnpmfile.cjs",
|
"//": "To completely ignore deep dependencies, see .pnpmfile.cjs",
|
||||||
|
1462
pnpm-lock.yaml
1462
pnpm-lock.yaml
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user