diff --git a/.changeset/config.json b/.changeset/config.json index 83c584af40b..78276722d50 100644 --- a/.changeset/config.json +++ b/.changeset/config.json @@ -12,7 +12,6 @@ "iota-wallet", "iota-explorer", "wallet-dashboard", - "@iota/apps-ui-kit", "apps-backend", "@iota/core", "@iota/apps-ui-kit", diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index f9e3cf04ffa..8be2aa0d12b 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -15,7 +15,9 @@ /docker/ @iotaledger/l1-core-infra @iotaledger/core-node @iotaledger/devops-admin /crates/iota-json-rpc*/ @iotaledger/l1-core-infra /crates/iota-graphql*/ @iotaledger/l1-core-infra -/crates/iota-indexer/ @iotaledger/l1-core-infra +/crates/iota-indexer*/ @iotaledger/l1-core-infra +/crates/iota-data-ingestion*/ @iotaledger/l1-core-infra +/crates/iota-analytics-indexer/ @iotaledger/l1-core-infra # core-node team /crates/iota-archival/ @iotaledger/core-node @@ -75,6 +77,8 @@ vercel.json @iotaledger/boxfish @iotaledger/tooling # Scripts /scripts/dependency_graphs/ @muXxer +/scripts/cargo_sort/ @muXxer +/scripts/generate_files/ @muXxer /scripts/codesearch/ @muXxer /scripts/slipstream/ @muXxer diff --git a/.github/ISSUE_TEMPLATE/release.md b/.github/ISSUE_TEMPLATE/release.md index da16cd19358..30e18010ae6 100644 --- a/.github/ISSUE_TEMPLATE/release.md +++ b/.github/ISSUE_TEMPLATE/release.md @@ -10,7 +10,6 @@ title: '[Task(*)]: release version x.y.z' - [ ] Edit `crates/iota-open-rpc/spec/openrpc.json` - [ ] Update `sdk/typescript/src/version.ts` (`pnpm sdk build`) - [ ] Update `Cargo.lock` (`cargo check`) -- [ ] Update `crates/iota-framework/packages/deepbook/Move.lock` - [ ] Update `crates/iota-framework/packages/iota-framework/Move.lock` - [ ] Update `crates/iota-framework/packages/iota-system/Move.lock` - [ ] Update `crates/iota-framework/packages/move-stdlib/Move.lock` diff --git a/.github/actions/diffs/action.yml b/.github/actions/diffs/action.yml index df411e36cb8..13e34f24df5 100644 --- a/.github/actions/diffs/action.yml +++ b/.github/actions/diffs/action.yml @@ -37,6 +37,7 @@ runs: - ".github/workflows/_rust_lints.yml" - ".github/workflows/_external_rust_tests.yml" - ".github/workflows/_cargo_deny.yml" + - "scripts/cargo_sort/cargo_sort.py" - "Cargo.toml" - "Cargo.lock" - ".config/nextest.toml" diff --git a/.github/workflows/_ledgernano.yml b/.github/workflows/_ledgernano.yml new file mode 100644 index 00000000000..0d9484caf47 --- /dev/null +++ b/.github/workflows/_ledgernano.yml @@ -0,0 +1,45 @@ +name: Ledgernano End-to-end Tests + +on: workflow_call + +concurrency: + group: ledgernano-${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} + cancel-in-progress: true + +jobs: + ledgernano: + name: Ledgernano + runs-on: self-hosted + steps: + - uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # Pin v4.1.1 + - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # pin@v4.0.0 + + - name: Install Nodejs + uses: actions/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # pin@v4.0.2 + with: + node-version: "20" + cache: "pnpm" + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Install ledgernano dependencies + run: | + sudo apt-get install -y qemu-user-static + sudo apt-get install -y libxcb-xinerama0 + sudo pip install speculos --break-system-packages + + - name: Download ledgernano bin + run: | + sudo apt-get install -y gh + echo ${{ secrets.LEDGER_APP_TOKEN }} | gh auth login --with-token + gh release list --repo https://github.com/iotaledger/ledger-app-iota + gh release download --repo https://github.com/iotaledger/ledger-app-iota -p nanos.tar.gz untagged-a706a550379839d8db15 + tar -xvf nanos.tar.gz + mv nanos/iota sdk/ledgerjs-hw-app-iota/tests/iota + + - name: Start speculos simulator + run: speculos --api-port 5000 --display headless ./sdk/ledgerjs-hw-app-iota/tests/iota & + + - name: Run TS SDK ledgernano tests + run: pnpm --filter @iota/ledgerjs-hw-app-iota test diff --git a/.github/workflows/_rust_lints.yml b/.github/workflows/_rust_lints.yml index 5b6628cf44f..fb7e75eb51b 100644 --- a/.github/workflows/_rust_lints.yml +++ b/.github/workflows/_rust_lints.yml @@ -27,6 +27,24 @@ jobs: - name: Check Rust formatting run: cargo +nightly ci-fmt + cargo-sort: + if: (!cancelled() && inputs.isRust) + runs-on: [self-hosted] + steps: + - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # pin@v4 + - name: Check Cargo.toml format and sorting + run: | + pushd "scripts/cargo_sort" + ./run.sh --skip-dprint + popd + - name: Check Cargo.toml diffs after formatting + run: | + if git status --porcelain | grep -q "Cargo.toml"; then + echo "Cargo.toml files not formatted and/or sorted properly! Please run the 'scripts/cargo_sort/run.sh' script." + git diff # Show the actual diffs + exit 1 # Fail the workflow + fi + clippy: if: (!cancelled() && !failure() && inputs.isRust) needs: diff --git a/.github/workflows/_turborepo.yml b/.github/workflows/_turborepo.yml index a2a02a18ef9..f1de036a17c 100644 --- a/.github/workflows/_turborepo.yml +++ b/.github/workflows/_turborepo.yml @@ -52,12 +52,6 @@ jobs: - name: (debug-before) Check SDK dist folder continue-on-error: true run: tree ./sdk/typescript/dist - - name: (debug) Lint - continue-on-error: true - run: pnpm turbo lint - - name: (debug-after) Check SDK dist folder - continue-on-error: true - run: tree ./sdk/typescript/dist - name: Lint run: pnpm turbo lint - name: Install wasm-pack for mbf package @@ -73,7 +67,8 @@ jobs: - name: Build run: pnpm turbo build - name: Test - run: pnpm turbo test + # @iota/ledgerjs-hw-app-iota is tested separately + run: pnpm turbo test --filter '!@iota/ledgerjs-hw-app-iota' # Pack wallet extension and upload it as an artifact for easy developer use: - name: Wallet Extension Has Changes? id: wallet-diff diff --git a/.github/workflows/_vercel_deploy.yml b/.github/workflows/_vercel_deploy.yml new file mode 100644 index 00000000000..47f9d854598 --- /dev/null +++ b/.github/workflows/_vercel_deploy.yml @@ -0,0 +1,98 @@ +name: Vercel Deploys + +on: + workflow_call: + inputs: + isExplorer: + type: boolean + required: true + isTypescriptSDK: + type: boolean + required: true + isAppsBackend: + type: boolean + required: true + isAppsUiKit: + type: boolean + required: true + isWalletDashboard: + type: boolean + required: true + shouldDeployPreview: + type: boolean + required: true + isDevelop: + type: boolean + required: true + githubRef: + type: string + required: true + +concurrency: + group: ${{ github.workflow }}-${{ inputs.githubRef }} + cancel-in-progress: true + +jobs: + explorer-preview: + name: Vercel Explorer Preview + if: inputs.shouldDeployPreview && inputs.isExplorer + uses: ./.github/workflows/apps-explorer.deploy.yml + secrets: inherit + with: + isProd: false + + explorer-prod: + name: Vercel Explorer Production + if: inputs.isDevelop + uses: ./.github/workflows/apps-explorer.deploy.yml + secrets: inherit + with: + isProd: true + + ui-kit-preview: + name: Vercel UI Kit Preview + if: inputs.shouldDeployPreview && inputs.isAppsUiKit + uses: ./.github/workflows/apps-ui-kit.deploy.yml + secrets: inherit + with: + isProd: false + + ui-kit-prod: + name: Vercel UI Kit Preview + if: inputs.isDevelop + uses: ./.github/workflows/apps-ui-kit.deploy.yml + secrets: inherit + with: + isProd: true + + wallet-dashboard-preview: + name: Vercel Wallet Dashboard Preview + if: inputs.shouldDeployPreview && inputs.isWalletDashboard + uses: ./.github/workflows/apps-wallet-dashboard.deploy.yml + secrets: inherit + with: + isProd: false + + wallet-dashboard-prod: + name: Vercel Wallet Dashboard Production + if: inputs.isDevelop + uses: ./.github/workflows/apps-wallet-dashboard.deploy.yml + secrets: inherit + with: + isProd: true + + apps-backend-preview: + name: Vercel apps-backend Preview + if: inputs.shouldDeployPreview && inputs.isAppsBackend + uses: ./.github/workflows/apps-backend.deploy.yml + secrets: inherit + with: + isProd: false + + apps-backend-prod: + name: Vercel apps-backend Production + if: inputs.isDevelop + uses: ./.github/workflows/apps-backend.deploy.yml + secrets: inherit + with: + isProd: true diff --git a/.github/workflows/apps-backend-production.deploy.yml b/.github/workflows/apps-backend-production.deploy.yml deleted file mode 100644 index 2e014786e91..00000000000 --- a/.github/workflows/apps-backend-production.deploy.yml +++ /dev/null @@ -1,48 +0,0 @@ -name: Production Deploy for Apps Backend - -env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.APPS_BACKEND_VERCEL_PROJECT_ID }} - -on: - push: - branches: - - develop - paths: - - "apps/apps-backend/**" - - ".github/workflows/apps-backend-production.deploy.yml" - -jobs: - deploy-production: - permissions: - contents: read - pull-requests: write - runs-on: [self-hosted] - steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # pin@v4 - - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # pin@v4 - - name: Install Nodejs - uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # pin@v4 - with: - node-version: "20" - cache: "pnpm" - - name: Install dependencies - run: pnpm install --frozen-lockfile - - name: Turbo Cache - id: turbo-cache - uses: actions/cache@3624ceb22c1c5a301c8db4169662070a689d9ea8 # pin@v4 - with: - path: node_modules/.cache/turbo - key: turbo-${{ runner.os }}-${{ github.sha }} - restore-keys: | - turbo-${{ runner.os }}- - - name: Install Vercel CLI - run: pnpm add --global vercel@canary - - name: Pull Vercel Prod Environment - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - - name: Build the Apps Backend - run: pnpm apps-backend build - - name: Build Project Artifacts - run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} - - name: Deploy Project Artifacts to Vercel - run: vercel deploy --prod --prebuilt --token=${{ secrets.VERCEL_TOKEN }} diff --git a/.github/workflows/apps-backend-preview.deploy.yml b/.github/workflows/apps-backend.deploy.yml similarity index 61% rename from .github/workflows/apps-backend-preview.deploy.yml rename to .github/workflows/apps-backend.deploy.yml index 7c3981195f4..38c919e73f5 100644 --- a/.github/workflows/apps-backend-preview.deploy.yml +++ b/.github/workflows/apps-backend.deploy.yml @@ -1,17 +1,19 @@ -name: Preview Deploy for Apps Backend +name: Deploy for Apps Backend env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} VERCEL_PROJECT_ID: ${{ secrets.APPS_BACKEND_VERCEL_PROJECT_ID }} on: - pull_request: - paths: - - "apps/apps-backend/**" - - ".github/workflows/apps-backend-preview.deploy.yml" + workflow_dispatch: + workflow_call: + inputs: + isProd: + type: boolean + required: true jobs: - deploy-preview: + deploy: permissions: contents: read pull-requests: write @@ -26,6 +28,18 @@ jobs: cache: "pnpm" - name: Install dependencies run: pnpm install --frozen-lockfile + - name: Setup Prod Flag + id: setup_prod_flags + run: | + if [[ "${{ inputs.isProd }}" = "true" ]]; then + echo "PROD_FLAG=--prod" >> $GITHUB_OUTPUT + echo "ENVIRONMENT=production" >> $GITHUB_OUTPUT + echo "VERCEL_OUTPUT=" >> $GITHUB_OUTPUT + else + echo "PROD_FLAG=" >> $GITHUB_OUTPUT + echo "ENVIRONMENT=preview" >> $GITHUB_OUTPUT + echo "VERCEL_OUTPUT=> vercel_output.txt" >> $GITHUB_OUTPUT + fi - name: Turbo Cache id: turbo-cache uses: actions/cache@3624ceb22c1c5a301c8db4169662070a689d9ea8 # pin@v4 @@ -36,18 +50,20 @@ jobs: turbo-${{ runner.os }}- - name: Install Vercel CLI run: pnpm add --global vercel@canary + - name: Pull Vercel Env variables (network configs) + run: vercel pull --yes --environment=${{steps.setup_prod_flags.outputs.ENVIRONMENT}} --token=${{ secrets.VERCEL_TOKEN }} - name: Build the Apps Backend run: pnpm apps-backend build - - name: Pull Vercel Environment - run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} - - name: Build Project Artifacts - run: vercel build --token=${{ secrets.VERCEL_TOKEN }} + - name: Build Vercel Project Artifacts + run: vercel build ${{steps.setup_prod_flags.outputs.PROD_FLAG}} --token=${{ secrets.VERCEL_TOKEN }} - name: Deploy Project Artifacts to Vercel - run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} > vercel_output.txt + run: vercel deploy ${{steps.setup_prod_flags.outputs.PROD_FLAG}} --prebuilt --token=${{ secrets.VERCEL_TOKEN }} ${{ steps.setup_prod_flags.outputs.VERCEL_OUTPUT }} - name: Extract Deploy URL id: deploy_url + if: ${{ inputs.isProd == false }} run: echo "DEPLOY_URL=$(cat vercel_output.txt | awk 'END{print}')" >> $GITHUB_OUTPUT - name: Comment on pull request + if: ${{ inputs.isProd == false }} uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # pin@v7 with: github-token: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/apps-explorer-production.deploy.yml b/.github/workflows/apps-explorer-production.deploy.yml deleted file mode 100644 index 41bd81f1595..00000000000 --- a/.github/workflows/apps-explorer-production.deploy.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Deploy Explorer Prod - -env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.EXPLORER_VERCEL_PROJECT_ID }} - -on: - push: - branches: - - develop - paths: - - "apps/explorer/**" - - ".github/workflows/apps-explorer-production.deploy.yml" - -jobs: - deploy-production: - permissions: - contents: read - pull-requests: write - runs-on: [self-hosted] - steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # pin@v4 - - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # pin@v4 - - name: Install Nodejs - uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # pin@v4 - with: - node-version: "20" - cache: "pnpm" - - name: Install dependencies - run: pnpm install --frozen-lockfile - - name: Turbo Cache - id: turbo-cache - uses: actions/cache@3624ceb22c1c5a301c8db4169662070a689d9ea8 # pin@v4 - with: - path: node_modules/.cache/turbo - key: turbo-${{ runner.os }}-${{ github.sha }} - restore-keys: | - turbo-${{ runner.os }}- - - name: Install Vercel CLI - run: pnpm add --global vercel@canary - - name: Pull Vercel Env variables (network configs) - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - - name: Copy the .env file - run: cp ./.vercel/.env.production.local ./sdk/.env - - name: Build Explorer - run: pnpm explorer build - - name: Build Project Artifacts - run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} - - name: Deploy Project Artifacts to Vercel - run: vercel deploy --prod --prebuilt --token=${{ secrets.VERCEL_TOKEN }} diff --git a/.github/workflows/apps-explorer-preview.deploy.yml b/.github/workflows/apps-explorer.deploy.yml similarity index 62% rename from .github/workflows/apps-explorer-preview.deploy.yml rename to .github/workflows/apps-explorer.deploy.yml index b4b70604832..fe482d68102 100644 --- a/.github/workflows/apps-explorer-preview.deploy.yml +++ b/.github/workflows/apps-explorer.deploy.yml @@ -1,4 +1,4 @@ -name: Preview Deploy for Explorer +name: Deploy for Explorer env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} @@ -6,19 +6,14 @@ env: on: workflow_dispatch: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - paths: - - "apps/explorer/**" - - ".github/workflows/apps-explorer-preview.deploy.yml" - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + workflow_call: + inputs: + isProd: + type: boolean + required: true jobs: - deploy-preview: - if: github.event.pull_request.draft == false + deploy: permissions: contents: read pull-requests: write @@ -33,6 +28,18 @@ jobs: cache: "pnpm" - name: Install dependencies run: pnpm install --frozen-lockfile + - name: Setup Prod Flag + id: setup_prod_flags + run: | + if [[ "${{ inputs.isProd }}" = "true" ]]; then + echo "PROD_FLAG=--prod" >> $GITHUB_OUTPUT + echo "ENVIRONMENT=production" >> $GITHUB_OUTPUT + echo "VERCEL_OUTPUT=" >> $GITHUB_OUTPUT + else + echo "PROD_FLAG=" >> $GITHUB_OUTPUT + echo "ENVIRONMENT=preview" >> $GITHUB_OUTPUT + echo "VERCEL_OUTPUT=> vercel_output.txt" >> $GITHUB_OUTPUT + fi - name: Turbo Cache id: turbo-cache uses: actions/cache@3624ceb22c1c5a301c8db4169662070a689d9ea8 # pin@v4 @@ -44,21 +51,22 @@ jobs: - name: Install Vercel CLI run: pnpm add --global vercel@canary - name: Pull Vercel Env variables (network configs) - run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} + run: vercel pull --yes --environment=${{steps.setup_prod_flags.outputs.ENVIRONMENT}} --token=${{ secrets.VERCEL_TOKEN }} - name: Copy the .env file - run: cp ./.vercel/.env.preview.local ./sdk/.env + run: cp ./.vercel/.env.${{steps.setup_prod_flags.outputs.ENVIRONMENT}}.local ./sdk/.env - name: Build Explorer run: pnpm explorer build - - name: Build Project Artifacts - run: vercel build --token=${{ secrets.VERCEL_TOKEN }} + - name: Build Vercel Project Artifacts + run: vercel build ${{steps.setup_prod_flags.outputs.PROD_FLAG}} --token=${{ secrets.VERCEL_TOKEN }} - name: Deploy Project Artifacts to Vercel - run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} > vercel_output.txt + run: vercel deploy ${{steps.setup_prod_flags.outputs.PROD_FLAG}} --prebuilt --token=${{ secrets.VERCEL_TOKEN }} ${{ steps.setup_prod_flags.outputs.VERCEL_OUTPUT }} - name: Extract Deploy URL id: deploy_url + if: ${{ inputs.isProd == false }} run: echo "DEPLOY_URL=$(cat vercel_output.txt | awk 'END{print}')" >> $GITHUB_OUTPUT - name: Comment on pull request + if: ${{ inputs.isProd == false }} uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # pin@v7 - if: github.event_name == 'pull_request' with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/apps-ui-kit-production.deploy.yml b/.github/workflows/apps-ui-kit-production.deploy.yml deleted file mode 100644 index 6e300bafee2..00000000000 --- a/.github/workflows/apps-ui-kit-production.deploy.yml +++ /dev/null @@ -1,37 +0,0 @@ -name: Production Deploy for Apps UI Kit Storybook - -env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.APPS_UI_KIT_VERCEL_PROJECT_ID }} - -on: - push: - branches: - - develop - paths: - - "apps/ui-kit/**" - - "apps/ui-icons/**" - - ".github/workflows/apps-ui-kit-production.deploy.yml" - -jobs: - deploy-production: - permissions: - contents: read - pull-requests: write - runs-on: [self-hosted] - steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # pin@v4 - - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # pin@v4 - - name: Install Nodejs - uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # pin@v4 - with: - node-version: "20" - cache: "pnpm" - - name: Install Vercel CLI - run: pnpm add --global vercel@canary - - name: Pull Vercel Environment Information - run: vercel pull --cwd ./apps/ui-kit --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - - name: Build Project Artifacts - run: vercel build --prod --cwd ./apps/ui-kit --token=${{ secrets.VERCEL_TOKEN }} - - name: Deploy Project Artifacts to Vercel - run: vercel deploy --cwd ./apps/ui-kit --prod --prebuilt --token=${{ secrets.VERCEL_TOKEN }} diff --git a/.github/workflows/apps-ui-kit-preview.deploy.yml b/.github/workflows/apps-ui-kit.deploy.yml similarity index 58% rename from .github/workflows/apps-ui-kit-preview.deploy.yml rename to .github/workflows/apps-ui-kit.deploy.yml index fb76af6f4fb..bbb003fb875 100644 --- a/.github/workflows/apps-ui-kit-preview.deploy.yml +++ b/.github/workflows/apps-ui-kit.deploy.yml @@ -1,4 +1,4 @@ -name: Preview Deploy for Apps UI Kit Storybook +name: Deploy for Apps UI Kit Storybook env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} @@ -6,20 +6,14 @@ env: on: workflow_dispatch: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - paths: - - "apps/ui-kit/**" - - "apps/ui-icons/**" - - ".github/workflows/apps-ui-kit-preview.deploy.yml" - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + workflow_call: + inputs: + isProd: + type: boolean + required: true jobs: - deploy-preview: - if: github.event.pull_request.draft == false + deploy: permissions: contents: read pull-requests: write @@ -32,20 +26,35 @@ jobs: with: node-version: "20" cache: "pnpm" + - name: Install dependencies + run: pnpm install --frozen-lockfile + - name: Setup Prod Flag + id: setup_prod_flags + run: | + if [[ "${{ inputs.isProd }}" = "true" ]]; then + echo "PROD_FLAG=--prod" >> $GITHUB_OUTPUT + echo "ENVIRONMENT=production" >> $GITHUB_OUTPUT + echo "VERCEL_OUTPUT=" >> $GITHUB_OUTPUT + else + echo "PROD_FLAG=" >> $GITHUB_OUTPUT + echo "ENVIRONMENT=preview" >> $GITHUB_OUTPUT + echo "VERCEL_OUTPUT=> vercel_output.txt" >> $GITHUB_OUTPUT + fi - name: Install Vercel CLI run: pnpm add --global vercel@canary - name: Pull Vercel Environment Information - run: vercel pull --cwd ./apps/ui-kit --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} + run: vercel pull --cwd ./apps/ui-kit --yes --environment=${{steps.setup_prod_flags.outputs.ENVIRONMENT}} --token=${{ secrets.VERCEL_TOKEN }} - name: Build Project Artifacts - run: vercel build --cwd ./apps/ui-kit --token=${{ secrets.VERCEL_TOKEN }} + run: vercel build ${{steps.setup_prod_flags.outputs.PROD_FLAG}} --cwd ./apps/ui-kit --token=${{ secrets.VERCEL_TOKEN }} - name: Deploy Project Artifacts to Vercel - run: vercel deploy --cwd ./apps/ui-kit --prebuilt --token=${{ secrets.VERCEL_TOKEN }} > vercel_output.txt + run: vercel deploy --cwd ./apps/ui-kit ${{steps.setup_prod_flags.outputs.PROD_FLAG}} --prebuilt --token=${{ secrets.VERCEL_TOKEN }} ${{ steps.setup_prod_flags.outputs.VERCEL_OUTPUT }} - name: Extract Deploy URL id: deploy_url + if: ${{ inputs.isProd == false }} run: echo "DEPLOY_URL=$(cat vercel_output.txt | awk 'END{print}')" >> $GITHUB_OUTPUT - name: Comment on pull request + if: ${{ inputs.isProd == false }} uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # pin@v7 - if: github.event_name == 'pull_request' with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/apps-wallet-dashboard-production.deploy.yml b/.github/workflows/apps-wallet-dashboard-production.deploy.yml deleted file mode 100644 index 411aac1f7ef..00000000000 --- a/.github/workflows/apps-wallet-dashboard-production.deploy.yml +++ /dev/null @@ -1,50 +0,0 @@ -name: Production Deploy for Wallet Dashboard - -env: - VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} - VERCEL_PROJECT_ID: ${{ secrets.WALLET_DASHBOARD_VERCEL_PROJECT_ID }} - -on: - push: - branches: - - develop - paths: - - "apps/wallet-dashboard/**" - - ".github/workflows/apps-wallet-dashboard-production.deploy.yml" - -jobs: - deploy-production: - permissions: - contents: read - pull-requests: write - runs-on: [self-hosted] - steps: - - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # pin@v4 - - uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2 # pin@v4 - - name: Install Nodejs - uses: actions/setup-node@0a44ba7841725637a19e28fa30b79a866c81b0a6 # pin@v4 - with: - node-version: "20" - cache: "pnpm" - - name: Install dependencies - run: pnpm install --frozen-lockfile - - name: Turbo Cache - id: turbo-cache - uses: actions/cache@3624ceb22c1c5a301c8db4169662070a689d9ea8 # pin@v4 - with: - path: node_modules/.cache/turbo - key: turbo-${{ runner.os }}-${{ github.sha }} - restore-keys: | - turbo-${{ runner.os }}- - - name: Install Vercel CLI - run: pnpm add --global vercel@canary - - name: Pull Vercel Env variables (network configs) - run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} - - name: Copy the .env file - run: cp ./.vercel/.env.production.local ./sdk/.env - - name: Build Wallet Dashboard Local - run: pnpm wallet-dashboard build - - name: Build Vercel Project Artifacts - run: vercel build --prod --token=${{ secrets.VERCEL_TOKEN }} - - name: Deploy Project Artifacts to Vercel - run: vercel deploy --prod --prebuilt --token=${{ secrets.VERCEL_TOKEN }} diff --git a/.github/workflows/apps-wallet-dashboard-preview.deploy.yml b/.github/workflows/apps-wallet-dashboard.deploy.yml similarity index 62% rename from .github/workflows/apps-wallet-dashboard-preview.deploy.yml rename to .github/workflows/apps-wallet-dashboard.deploy.yml index e7d6b8f0041..97bd8ae6670 100644 --- a/.github/workflows/apps-wallet-dashboard-preview.deploy.yml +++ b/.github/workflows/apps-wallet-dashboard.deploy.yml @@ -1,4 +1,4 @@ -name: Preview Deploy for Wallet Dashboard +name: Deploy for Wallet Dashboard env: VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} @@ -6,19 +6,14 @@ env: on: workflow_dispatch: - pull_request: - types: [opened, synchronize, reopened, ready_for_review] - paths: - - "apps/wallet-dashboard/**" - - ".github/workflows/apps-wallet-dashboard-preview.deploy.yml" - -concurrency: - group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }} - cancel-in-progress: true + workflow_call: + inputs: + isProd: + type: boolean + required: true jobs: - deploy-preview: - if: github.event.pull_request.draft == false + deploy: permissions: contents: read pull-requests: write @@ -33,6 +28,18 @@ jobs: cache: "pnpm" - name: Install dependencies run: pnpm install --frozen-lockfile + - name: Setup Prod Flag + id: setup_prod_flags + run: | + if [[ "${{ inputs.isProd }}" = "true" ]]; then + echo "PROD_FLAG=--prod" >> $GITHUB_OUTPUT + echo "ENVIRONMENT=production" >> $GITHUB_OUTPUT + echo "VERCEL_OUTPUT=" >> $GITHUB_OUTPUT + else + echo "PROD_FLAG=" >> $GITHUB_OUTPUT + echo "ENVIRONMENT=preview" >> $GITHUB_OUTPUT + echo "VERCEL_OUTPUT=> vercel_output.txt" >> $GITHUB_OUTPUT + fi - name: Turbo Cache id: turbo-cache uses: actions/cache@3624ceb22c1c5a301c8db4169662070a689d9ea8 # pin@v4 @@ -44,21 +51,22 @@ jobs: - name: Install Vercel CLI run: pnpm add --global vercel@canary - name: Pull Vercel Env variables (network configs) - run: vercel pull --yes --environment=preview --token=${{ secrets.VERCEL_TOKEN }} + run: vercel pull --yes --environment=${{steps.setup_prod_flags.outputs.ENVIRONMENT}} --token=${{ secrets.VERCEL_TOKEN }} - name: Copy the .env file - run: cp ./.vercel/.env.preview.local ./sdk/.env + run: cp ./.vercel/.env.${{steps.setup_prod_flags.outputs.ENVIRONMENT}}.local ./sdk/.env - name: Build Wallet Dashboard run: pnpm wallet-dashboard build - - name: Build Project Artifacts - run: vercel build --token=${{ secrets.VERCEL_TOKEN }} + - name: Build Vercel Project Artifacts + run: vercel build ${{steps.setup_prod_flags.outputs.PROD_FLAG}} --token=${{ secrets.VERCEL_TOKEN }} - name: Deploy Project Artifacts to Vercel - run: vercel deploy --prebuilt --token=${{ secrets.VERCEL_TOKEN }} > vercel_output.txt + run: vercel deploy ${{steps.setup_prod_flags.outputs.PROD_FLAG}} --prebuilt --token=${{ secrets.VERCEL_TOKEN }} ${{ steps.setup_prod_flags.outputs.VERCEL_OUTPUT }} - name: Extract Deploy URL id: deploy_url + if: ${{ inputs.isProd == false }} run: echo "DEPLOY_URL=$(cat vercel_output.txt | awk 'END{print}')" >> $GITHUB_OUTPUT - name: Comment on pull request + if: ${{ inputs.isProd == false }} uses: actions/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # pin@v7 - if: github.event_name == 'pull_request' with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | diff --git a/.github/workflows/hierarchy.yml b/.github/workflows/hierarchy.yml index f028b93b236..47d92c4ce92 100644 --- a/.github/workflows/hierarchy.yml +++ b/.github/workflows/hierarchy.yml @@ -25,7 +25,11 @@ jobs: isWallet: ${{ (steps.turbo.outputs.packages && contains(fromJson(steps.turbo.outputs.packages), 'iota-wallet')) }} isExplorer: ${{ (steps.turbo.outputs.packages && contains(fromJson(steps.turbo.outputs.packages), 'iota-explorer')) }} isTypescriptSDK: ${{ (steps.turbo.outputs.packages && contains(fromJson(steps.turbo.outputs.packages), '@iota/iota-sdk')) }} + isAppsBackend: ${{ (steps.turbo.outputs.packages && contains(fromJson(steps.turbo.outputs.packages), 'apps-backend')) }} + isAppsUiKit: ${{ (steps.turbo.outputs.packages && contains(fromJson(steps.turbo.outputs.packages), '@iota/apps-ui-kit')) }} + isWalletDashboard: ${{ (steps.turbo.outputs.packages && contains(fromJson(steps.turbo.outputs.packages), 'wallet-dashboard')) }} isGraphQlTransport: ${{ (steps.turbo.outputs.packages && contains(fromJson(steps.turbo.outputs.packages), '@iota/graphql-transport')) }} + isLedgerjs: ${{ (steps.turbo.outputs.packages && contains(fromJson(steps.turbo.outputs.packages), '@iota/ledgerjs-hw-app-iota')) }} steps: - uses: actions/checkout@eef61447b9ff4aafe5dcd4e0bbf5d482be7e7871 # pin@v4 - name: Detect Changes (turbo) @@ -144,3 +148,32 @@ jobs: isTypescriptSDK: ${{ needs.diff.outputs.isTypescriptSDK == 'true' }} isGraphQlTransport: ${{ needs.diff.outputs.isGraphQlTransport == 'true' }} isDevelop: ${{ github.ref_name == 'develop' }} + + vercel-deploy: + if: (!cancelled() && !failure()) + needs: + - diff + - dprint-format + - license-check + - typos + uses: ./.github/workflows/_vercel_deploy.yml + secrets: inherit + with: + shouldDeployPreview: ${{github.event_name == 'pull_request' && github.event.pull_request.draft == false}} + isExplorer: ${{ needs.diff.outputs.isExplorer == 'true' }} + isTypescriptSDK: ${{ needs.diff.outputs.isTypescriptSDK == 'true' }} + isAppsBackend: ${{ needs.diff.outputs.isAppsBackend == 'true' }} + isAppsUiKit: ${{ needs.diff.outputs.isAppsUiKit == 'true' }} + isWalletDashboard: ${{ needs.diff.outputs.isWalletDashboard == 'true' }} + isDevelop: ${{ github.ref_name == 'develop' }} + githubRef: ${{ github.event.pull_request.number || github.ref }} + + ledgernano: + if: (!cancelled() && !failure()) && needs.diff.outputs.isLedgerjs == 'true' && github.event.pull_request.draft == false + needs: + - diff + - dprint-format + - license-check + - typos + uses: ./.github/workflows/_ledgernano.yml + secrets: inherit diff --git a/.gitignore b/.gitignore index 17c1974647f..642158476ae 100644 --- a/.gitignore +++ b/.gitignore @@ -23,7 +23,6 @@ Move.lock !crates/iota-framework/packages/move-stdlib/Move.lock !crates/iota-framework/packages/iota-framework/Move.lock !crates/iota-framework/packages/iota-system/Move.lock -!crates/iota-framework/packages/deepbook/Move.lock !crates/iota-framework/packages/stardust/Move.lock !crates/iota-framework/packages/timelock/Move.lock .trace diff --git a/Cargo.lock b/Cargo.lock index 8627492edc9..8250da9569a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1085,9 +1085,9 @@ dependencies = [ [[package]] name = "aws-lc-rs" -version = "1.10.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdd82dba44d209fddb11c190e0a94b78651f95299598e472215667417a03ff1d" +checksum = "2f95446d919226d587817a7d21379e6eb099b97b45110a7f272a444ca5c54070" dependencies = [ "aws-lc-sys", "mirai-annotations", @@ -1097,9 +1097,9 @@ dependencies = [ [[package]] name = "aws-lc-sys" -version = "0.22.0" +version = "0.21.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df7a4168111d7eb622a31b214057b8509c0a7e1794f44c546d742330dc793972" +checksum = "234314bd569802ec87011d653d6815c6d7b9ffb969e9fee5b8b20ef860e8dce9" dependencies = [ "bindgen 0.69.5", "cc", @@ -1858,7 +1858,7 @@ dependencies = [ "bitflags 2.6.0", "cexpr", "clang-sys", - "itertools 0.10.5", + "itertools 0.12.1", "lazy_static", "lazycell", "log", @@ -8902,7 +8902,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4979f22fdb869068da03c9f7528f8297c6fd2606bc3a4affe42e6a823fdb8da4" dependencies = [ "cfg-if", - "windows-targets 0.48.5", + "windows-targets 0.52.6", ] [[package]] @@ -12010,7 +12010,7 @@ checksum = "0c1318b19085f08681016926435853bbf7858f9c082d0999b80550ff5d9abe15" dependencies = [ "bytes", "heck 0.5.0", - "itertools 0.10.5", + "itertools 0.13.0", "log", "multimap", "once_cell", @@ -12030,7 +12030,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e9552f850d5f0964a4e4d0bf306459ac29323ddfbae05e35a7c0d35cb0803cc5" dependencies = [ "anyhow", - "itertools 0.10.5", + "itertools 0.13.0", "proc-macro2 1.0.86", "quote 1.0.37", "syn 2.0.77", @@ -15100,22 +15100,23 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4ee8877250136bd7e3d2331632810a4df4ea5e004656990d8d66d2f5ee8a67" +checksum = "9557ce109ea773b399c9b9e5dca39294110b74f1f342cb347a80d1fce8c26a11" dependencies = [ "prettyplease", "proc-macro2 1.0.86", "prost-build", + "prost-types", "quote 1.0.37", "syn 2.0.77", ] [[package]] name = "tonic-health" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0a34e6f706bae26b2b490e1da5c3f6a6ff87cae442bcbc7c881bab9631b5a7" +checksum = "1eaf34ddb812120f5c601162d5429933c9b527d901ab0e7f930d3147e33a09b2" dependencies = [ "async-stream", "prost", @@ -15458,7 +15459,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "97fee6b57c6a41524a810daee9286c02d7752c4253064d0b05472833a438f675" dependencies = [ "cfg-if", - "rand 0.7.3", + "rand 0.8.5", "static_assertions", ] diff --git a/Cargo.toml b/Cargo.toml index 6fd5380358f..141904a44f1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,5 @@ [workspace] resolver = "2" - exclude = [ "external-crates/move/crates/bytecode-interpreter-crypto", "external-crates/move/crates/bytecode-verifier-libfuzzer", @@ -61,7 +60,6 @@ exclude = [ "external-crates/move/move-execution/v0/crates/move-vm-runtime", "sdk/move-bytecode-template", ] - members = [ "consensus/config", "consensus/core", diff --git a/apps/apps-backend/src/restricted/restricted.controller.ts b/apps/apps-backend/src/restricted/restricted.controller.ts index 03f77358e06..4ba61ddd045 100644 --- a/apps/apps-backend/src/restricted/restricted.controller.ts +++ b/apps/apps-backend/src/restricted/restricted.controller.ts @@ -9,7 +9,7 @@ export class RestrictedController { @Post('/') @Header('Cache-Control', 'max-age=0, must-revalidate') checkRestrictions(@Res() res: Response) { - // No restrictions implemented yet + // No restrictions implemented yet. res.status(HttpStatus.OK).send(); } } diff --git a/apps/explorer/README.md b/apps/explorer/README.md index 0da36c73bf5..db68127e02e 100644 --- a/apps/explorer/README.md +++ b/apps/explorer/README.md @@ -1,6 +1,6 @@ # IOTA Explorer -[IOTA Explorer](https://explorer.iota.io/) is a network explorer for the IOTA network, similar in functionality to [Etherscan](https://etherscan.io/) or [Solana Explorer](https://explorer.solana.com/). Use IOTA Explorer to see the latest transactions and objects. +[IOTA Explorer](https://explorer.iota.org/) is a network explorer for the IOTA network, similar in functionality to [Etherscan](https://etherscan.io/) or [Solana Explorer](https://explorer.solana.com/). Use IOTA Explorer to see the latest transactions and objects. # Set Up diff --git a/apps/explorer/src/components/IotaTokenCard.tsx b/apps/explorer/src/components/IotaTokenCard.tsx index 7b40e74a859..19bb5fa8286 100644 --- a/apps/explorer/src/components/IotaTokenCard.tsx +++ b/apps/explorer/src/components/IotaTokenCard.tsx @@ -2,9 +2,11 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +import { Panel } from '@iota/apps-ui-kit'; import { COIN_GECKO_IOTA_URL, useIotaCoinData } from '@iota/core'; -import { IotaLogoMark } from '@iota/ui-icons'; -import { ButtonOrLink, Card } from '~/components/ui'; +import { ButtonOrLink, ImageIconSize } from '~/components/ui'; +import { CoinIcon } from './owned-coins'; +import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; export function IotaTokenCard(): JSX.Element { const { data } = useIotaCoinData(); @@ -19,12 +21,12 @@ export function IotaTokenCard(): JSX.Element { return ( - -
-
- + +
+
+
-
+
1 IOTA = {formattedPrice} @@ -33,7 +35,7 @@ export function IotaTokenCard(): JSX.Element {
- + ); } diff --git a/apps/explorer/src/components/activity/EpochsActivityTable.tsx b/apps/explorer/src/components/activity/EpochsActivityTable.tsx index 4974e0c26ac..d3f50c0ad5b 100644 --- a/apps/explorer/src/components/activity/EpochsActivityTable.tsx +++ b/apps/explorer/src/components/activity/EpochsActivityTable.tsx @@ -2,13 +2,13 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { InfoBox, InfoBoxStyle, InfoBoxType, Select } from '@iota/apps-ui-kit'; +import { InfoBox, InfoBoxStyle, InfoBoxType, Select, SelectSize } from '@iota/apps-ui-kit'; import { useIotaClientQuery, useIotaClient, useIotaClientInfiniteQuery } from '@iota/dapp-kit'; import { Warning } from '@iota/ui-icons'; import { useQuery } from '@tanstack/react-query'; import { useState } from 'react'; - import { PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui'; +import { PAGE_SIZES_RANGE_20_60 } from '~/lib/constants'; import { generateEpochsTableColumns } from '~/lib/ui'; import { numberSuffix } from '~/lib/utils'; @@ -71,29 +71,26 @@ export function EpochsActivityTable({ data={data.data} columns={tableColumns} totalLabel={count ? `${numberSuffix(Number(count))} Total` : '-'} - viewAll={!disablePagination ? '/recent?tab=epochs' : undefined} + viewAll="/recent?tab=epochs" paginationOptions={!disablePagination ? pagination : undefined} + pageSizeSelector={ + !disablePagination && ( + { - setLimit(Number(e)); - pagination.onFirst(); - }} - /> - )} -
-
); } diff --git a/apps/explorer/src/components/activity/TransactionsActivityTable.tsx b/apps/explorer/src/components/activity/TransactionsActivityTable.tsx index 6407314dadc..ac46b7e9dc2 100644 --- a/apps/explorer/src/components/activity/TransactionsActivityTable.tsx +++ b/apps/explorer/src/components/activity/TransactionsActivityTable.tsx @@ -5,16 +5,16 @@ import { useIotaClient } from '@iota/dapp-kit'; import { useQuery } from '@tanstack/react-query'; import { useEffect, useRef, useState } from 'react'; - import { PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui'; import { DEFAULT_TRANSACTIONS_LIMIT, useGetTransactionBlocks, } from '~/hooks/useGetTransactionBlocks'; import { numberSuffix } from '~/lib/utils'; -import { InfoBox, InfoBoxStyle, InfoBoxType, Select } from '@iota/apps-ui-kit'; +import { InfoBox, InfoBoxStyle, InfoBoxType, Select, SelectSize } from '@iota/apps-ui-kit'; import { generateTransactionsTableColumns } from '~/lib/ui'; import { Warning } from '@iota/ui-icons'; +import { PAGE_SIZES_RANGE_20_60 } from '~/lib/constants'; interface TransactionsActivityTableProps { disablePagination?: boolean; @@ -76,27 +76,24 @@ export function TransactionsActivityTable({ totalLabel={count ? `${numberSuffix(Number(count))} Total` : '-'} viewAll="/recent" paginationOptions={!disablePagination ? pagination : undefined} + pageSizeSelector={ + !disablePagination && ( + { - setLimit(Number(e)); - pagination.onFirst(); - }} - /> - )} - - ); diff --git a/apps/explorer/src/components/checkpoints/CheckpointsTable.tsx b/apps/explorer/src/components/checkpoints/CheckpointsTable.tsx index 5f045ddefdc..46baed3dd09 100644 --- a/apps/explorer/src/components/checkpoints/CheckpointsTable.tsx +++ b/apps/explorer/src/components/checkpoints/CheckpointsTable.tsx @@ -2,12 +2,13 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { InfoBox, InfoBoxStyle, InfoBoxType, Select } from '@iota/apps-ui-kit'; +import { InfoBox, InfoBoxStyle, InfoBoxType, Select, SelectSize } from '@iota/apps-ui-kit'; import { useIotaClientQuery } from '@iota/dapp-kit'; import { Warning } from '@iota/ui-icons'; import { useMemo, useState } from 'react'; import { PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui'; import { DEFAULT_CHECKPOINTS_LIMIT, useGetCheckpoints } from '~/hooks/useGetCheckpoints'; +import { PAGE_SIZES_RANGE_20_60 } from '~/lib/constants'; import { generateCheckpointsTableColumns } from '~/lib/ui'; import { numberSuffix } from '~/lib/utils'; @@ -81,26 +82,24 @@ export function CheckpointsTable({ } : undefined } + pageSizeSelector={ + !disablePagination && ( + { - setLimit(Number(e)); - pagination.onFirst(); - }} - /> - )} - - ); } diff --git a/apps/explorer/src/components/home-metrics/OnTheNetwork.tsx b/apps/explorer/src/components/home-metrics/OnTheNetwork.tsx index 703c712550c..d98dc4b126f 100644 --- a/apps/explorer/src/components/home-metrics/OnTheNetwork.tsx +++ b/apps/explorer/src/components/home-metrics/OnTheNetwork.tsx @@ -100,8 +100,7 @@ export function OnTheNetwork(): JSX.Element { text={gasPriceFormatted ?? '-'} supportingLabel={gasPriceFormatted !== null ? 'IOTA' : undefined} tooltipPosition={TooltipPosition.Top} - tooltipText=" -The reference gas price in the current epoch." + tooltipText="The reference gas price in the current epoch." />
diff --git a/apps/explorer/src/components/layout/PageLayout.tsx b/apps/explorer/src/components/layout/PageLayout.tsx index dcd7ca952c8..9602bad3c85 100644 --- a/apps/explorer/src/components/layout/PageLayout.tsx +++ b/apps/explorer/src/components/layout/PageLayout.tsx @@ -29,7 +29,7 @@ export function PageLayout({ content, loading }: PageLayoutProps): JSX.Element { request<{ degraded: boolean }>('monitor-network', { project: 'EXPLORER', }), - // Keep cached for 2 minutes: + // Keep cached for 2 minutes staleTime: 2 * 60 * 1000, retry: false, enabled: network === Network.Mainnet, diff --git a/apps/explorer/src/components/owned-coins/CoinIcon.tsx b/apps/explorer/src/components/owned-coins/CoinIcon.tsx index db9c296e83b..a0263d92afe 100644 --- a/apps/explorer/src/components/owned-coins/CoinIcon.tsx +++ b/apps/explorer/src/components/owned-coins/CoinIcon.tsx @@ -3,69 +3,43 @@ // SPDX-License-Identifier: Apache-2.0 import { useCoinMetadata } from '@iota/core'; -import { IotaLogoMark as Iota, Unstake } from '@iota/ui-icons'; +import { IotaLogoMark } from '@iota/ui-icons'; import { IOTA_TYPE_ARG } from '@iota/iota-sdk/utils'; -import { cva, type VariantProps } from 'class-variance-authority'; +import { cx } from 'class-variance-authority'; +import { ImageIcon, ImageIconSize } from '../ui'; -import { ImageIcon } from '~/components/ui'; - -const imageStyle = cva(['flex rounded-2xl'], { - variants: { - size: { - sm: 'w-6 h-6', - md: 'w-7.5 h-7.5', - lg: 'md:w-10 md:h-10 w-8 h-8', - xl: 'md:w-31.5 md:h-31.5 w-16 h-16 ', - }, - }, - defaultVariants: { - size: 'md', - }, -}); - -function IotaCoin(): JSX.Element { - return ( - - ); -} - -interface NonIotaCoinProps extends VariantProps { +interface NonIotaCoinProps { coinType: string; + size?: ImageIconSize; + rounded?: boolean; } -function NonIotaCoin({ coinType, ...styleProps }: NonIotaCoinProps): JSX.Element { +function NonIotaCoin({ coinType, size = ImageIconSize.Full, rounded }: NonIotaCoinProps) { const { data: coinMeta } = useCoinMetadata(coinType); return ( -
- {coinMeta?.iconUrl ? ( - - ) : ( -
- -
- )} +
+
); } - -interface CoinIconProps extends VariantProps { +export interface CoinIconProps { coinType: string; + size?: ImageIconSize; + rounded?: boolean; } -export function CoinIcon({ coinType, ...styleProps }: CoinIconProps): JSX.Element { - return ( -
- {coinType === IOTA_TYPE_ARG ? ( - - ) : ( - - )} +export function CoinIcon({ coinType, size = ImageIconSize.Full, rounded }: CoinIconProps) { + return coinType === IOTA_TYPE_ARG ? ( +
+
+ ) : ( + ); } diff --git a/apps/explorer/src/components/owned-coins/CoinItem.tsx b/apps/explorer/src/components/owned-coins/CoinItem.tsx index a79d7cdf12f..d745b9202c3 100644 --- a/apps/explorer/src/components/owned-coins/CoinItem.tsx +++ b/apps/explorer/src/components/owned-coins/CoinItem.tsx @@ -17,6 +17,7 @@ export default function CoinItem({ coin }: CoinItemProps): JSX.Element { return ( } diff --git a/apps/explorer/src/components/owned-coins/OwnedCoinView.tsx b/apps/explorer/src/components/owned-coins/OwnedCoinView.tsx index 59f3899aed5..5f072935dcb 100644 --- a/apps/explorer/src/components/owned-coins/OwnedCoinView.tsx +++ b/apps/explorer/src/components/owned-coins/OwnedCoinView.tsx @@ -19,6 +19,7 @@ import { ImageType, } from '@iota/apps-ui-kit'; import { ArrowUp, RecognizedBadge } from '@iota/ui-icons'; +import { ImageIconSize } from '../ui'; type OwnedCoinViewProps = { coin: CoinBalanceVerified; @@ -45,8 +46,8 @@ export default function OwnedCoinView({ coin, id }: OwnedCoinViewProps): JSX.Ele > setAreCoinDetailsOpen((prev) => !prev)}> -
- +
+
diff --git a/apps/explorer/src/components/owned-coins/OwnedCoins.tsx b/apps/explorer/src/components/owned-coins/OwnedCoins.tsx index f84956ee770..0a52ca0d270 100644 --- a/apps/explorer/src/components/owned-coins/OwnedCoins.tsx +++ b/apps/explorer/src/components/owned-coins/OwnedCoins.tsx @@ -25,6 +25,7 @@ import { Title, } from '@iota/apps-ui-kit'; import { Pagination } from '../ui'; +import { PAGE_SIZES_RANGE_20_60 } from '~/lib/constants'; export type CoinBalanceVerified = CoinBalance & { isRecognized?: boolean; @@ -197,11 +198,10 @@ export function OwnedCoins({ id }: OwnerCoinsProps): JSX.Element { ({ + options={PAGE_SIZES_RANGE_10_50.map((size) => ({ label: `${size} / page`, id: size.toString(), }))} diff --git a/apps/explorer/src/components/ui/Card.tsx b/apps/explorer/src/components/ui/Card.tsx deleted file mode 100644 index f2d5746b5a1..00000000000 --- a/apps/explorer/src/components/ui/Card.tsx +++ /dev/null @@ -1,84 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// Modifications Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -import { cva, type VariantProps } from 'class-variance-authority'; -import { type ReactNode } from 'react'; - -const cardStyles = cva('overflow-hidden', { - variants: { - bg: { - default: 'bg-gray-40', - highlight: 'bg-success-light', - lightBlue: 'bg-iota/10', - white: 'bg-white', - 'white/80': 'bg-white/80', - }, - height: { - full: 'h-full', - }, - width: { - full: 'w-full', - }, - rounded: { - lg: 'rounded-lg', - xl: 'rounded-xl', - '2xl': 'rounded-2xl', - }, - spacing: { - none: '', - sm: 'px-5 py-4', - md: 'p-5', - lg: 'p-6', - lgGraph: 'p-6 pb-4', - }, - border: { - gray45: 'border border-gray-45', - steel: 'border border-steel', - }, - shadow: { - true: 'shadow-md', - }, - growOnHover: { - true: 'hover:scale-101 ease-in-out duration-200', - }, - }, - defaultVariants: { - bg: 'default', - spacing: 'md', - rounded: 'xl', - }, -}); - -export interface CardProps extends VariantProps { - children?: ReactNode; -} - -export function Card({ - spacing, - rounded, - bg, - border, - shadow, - children, - height, - width, - growOnHover, -}: CardProps): JSX.Element { - return ( -
- {children} -
- ); -} diff --git a/apps/explorer/src/components/ui/ImageIcon.tsx b/apps/explorer/src/components/ui/ImageIcon.tsx index 05ae7adafe5..0366a9c741a 100644 --- a/apps/explorer/src/components/ui/ImageIcon.tsx +++ b/apps/explorer/src/components/ui/ImageIcon.tsx @@ -2,65 +2,71 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { cva, type VariantProps } from 'class-variance-authority'; import { useState } from 'react'; +import cn from 'clsx'; -const imageStyle = cva(['text-white capitalize overflow-hidden bg-gray-40'], { - variants: { - size: { - sm: 'w-6 h-6 font-medium text-subtitleSmallExtra', - md: 'w-8 h-8 text-label-lg', - lg: 'md:w-10 md:h-10 w-8 h-8', - xl: 'md:w-31.5 md:h-31.5 w-16 h-16 font-medium text-heading4 md:text-iconTextLarge', - }, - circle: { - true: 'rounded-full', - false: 'rounded-md', - }, - }, - - defaultVariants: { - circle: false, - size: 'md', - }, -}); +export enum ImageIconSize { + Small = 'w-5 h-5', + Medium = 'w-8 h-8', + Large = 'w-10 h-10', + Full = 'w-full h-full', +} -export interface ImageIconProps extends VariantProps { - src?: string | null; +export interface ImageIconProps { + src: string | null | undefined; label: string; fallback: string; alt?: string; + rounded?: boolean; + size?: ImageIconSize; } -interface FallBackAvatarProps { - fallback: string; -} - -function FallBackAvatar({ fallback }: FallBackAvatarProps): JSX.Element { +function FallBackAvatar({ + str, + rounded, + size = ImageIconSize.Large, +}: { + str: string; + rounded?: boolean; + size?: ImageIconSize; +}) { + function generateTextSize(size: ImageIconSize) { + switch (size) { + case ImageIconSize.Small: + return 'text-label-sm'; + case ImageIconSize.Medium: + return 'text-label-md'; + case ImageIconSize.Large: + return 'text-title-lg'; + case ImageIconSize.Full: + return 'text-display-lg'; + } + } return ( -
- {fallback?.slice(0, 2)} +
+ {str?.slice(0, 2)}
); } -export function ImageIcon({ - src, - label, - alt = label, - fallback, - ...styleProps -}: ImageIconProps): JSX.Element { +export function ImageIcon({ src, label, alt = label, fallback, rounded, size }: ImageIconProps) { const [error, setError] = useState(false); return ( -
+
{error || !src ? ( - + ) : ( {alt} setError(true)} /> )} diff --git a/apps/explorer/src/components/ui/TableCard.tsx b/apps/explorer/src/components/ui/TableCard.tsx index 372ecc0cb36..0804e7755b8 100644 --- a/apps/explorer/src/components/ui/TableCard.tsx +++ b/apps/explorer/src/components/ui/TableCard.tsx @@ -21,7 +21,7 @@ import { useReactTable, } from '@tanstack/react-table'; import clsx from 'clsx'; -import { Fragment, useState } from 'react'; +import { Fragment, type ReactNode, useState } from 'react'; import { Link } from './Link'; export interface TableCardProps { @@ -34,6 +34,7 @@ export interface TableCardProps { paginationOptions?: TablePaginationOptions; totalLabel?: string; viewAll?: string; + pageSizeSelector?: ReactNode; } export function TableCard({ @@ -46,6 +47,7 @@ export function TableCard({ paginationOptions, totalLabel, viewAll, + pageSizeSelector, }: TableCardProps): JSX.Element { const [sorting, setSorting] = useState(defaultSorting || []); @@ -66,7 +68,7 @@ export function TableCard({ }); return ( -
+
row.index)} paginationOptions={paginationOptions} @@ -78,6 +80,7 @@ export function TableCard({ ) : undefined } + pageSizeSelector={pageSizeSelector} > {table.getHeaderGroups().map((headerGroup) => ( diff --git a/apps/explorer/src/components/ui/Tooltip.tsx b/apps/explorer/src/components/ui/Tooltip.tsx deleted file mode 100644 index 5eb6cc61e26..00000000000 --- a/apps/explorer/src/components/ui/Tooltip.tsx +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// Modifications Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -import { - useFloating, - autoUpdate, - offset, - flip, - shift, - useHover, - useFocus, - useDismiss, - useRole, - useInteractions, - FloatingPortal, - arrow, -} from '@floating-ui/react'; -import { AnimatePresence, motion } from 'framer-motion'; -import { useRef, useState } from 'react'; -import type { Placement } from '@floating-ui/react'; -import type { ReactNode, CSSProperties } from 'react'; -import { Info } from '@iota/ui-icons'; - -const TOOLTIP_DELAY = 150; - -interface TooltipProps { - tip: ReactNode; - children: ReactNode; - onOpen?: () => void; - placement?: Placement; -} - -export function Tooltip({ tip, children, onOpen, placement = 'top' }: TooltipProps): JSX.Element { - const [open, setOpen] = useState(false); - const arrowRef = useRef(null); - - const { - x, - y, - refs, - strategy, - context, - middlewareData, - placement: finalPlacement, - } = useFloating({ - placement, - open, - onOpenChange: (updatedIsOpen) => { - if (open !== updatedIsOpen && updatedIsOpen && onOpen) { - onOpen(); - } - setOpen(updatedIsOpen); - }, - whileElementsMounted: autoUpdate, - middleware: [offset(5), flip(), shift(), arrow({ element: arrowRef, padding: 6 })], - }); - - const { getReferenceProps, getFloatingProps } = useInteractions([ - useHover(context, { move: true, delay: TOOLTIP_DELAY }), - useFocus(context), - useRole(context, { role: 'tooltip' }), - useDismiss(context), - ]); - - const animateProperty = - finalPlacement.startsWith('top') || finalPlacement.startsWith('bottom') ? 'y' : 'x'; - - const animateValue = - finalPlacement.startsWith('bottom') || finalPlacement.startsWith('right') - ? 'calc(-50% - 15px)' - : 'calc(50% + 15px)'; - - const arrowStyle: CSSProperties = { - left: middlewareData.arrow?.x, - top: middlewareData.arrow?.y, - }; - - const staticSide = ( - { - top: 'bottom', - right: 'left', - bottom: 'top', - left: 'right', - } as const - )[finalPlacement.split('-')[0]]; - - if (staticSide) { - arrowStyle[staticSide] = '-3px'; - } - - return ( - <> -
- {children} -
- - - {open ? ( - -
- {tip} -
-
- - ) : null} - - - - ); -} - -export type IconTooltipProps = Omit; - -export function IconTooltip(props: IconTooltipProps) { - return ( - - - - ); -} diff --git a/apps/explorer/src/components/ui/index.ts b/apps/explorer/src/components/ui/index.ts index 8db90fc04a6..6cf3f4c845d 100644 --- a/apps/explorer/src/components/ui/index.ts +++ b/apps/explorer/src/components/ui/index.ts @@ -7,7 +7,6 @@ export * from './image'; export * from './modal'; export * from './ButtonOrLink'; -export * from './Card'; export * from './ExpandableList'; export * from './FilterList'; export * from './ImageIcon'; @@ -24,5 +23,4 @@ export * from './ProgressCircle'; export * from './RingChart'; export * from './SplitPanes'; export * from './TableCard'; -export * from './Tooltip'; export * from './VerticalList'; diff --git a/apps/explorer/src/components/validator/ValidatorMeta.tsx b/apps/explorer/src/components/validator/ValidatorMeta.tsx index 489f906780b..386048bdebd 100644 --- a/apps/explorer/src/components/validator/ValidatorMeta.tsx +++ b/apps/explorer/src/components/validator/ValidatorMeta.tsx @@ -6,7 +6,7 @@ import { Badge, BadgeType, KeyValueInfo, Panel } from '@iota/apps-ui-kit'; import { type IotaValidatorSummary } from '@iota/iota-sdk/client'; import toast from 'react-hot-toast'; import { ArrowTopRight } from '@iota/ui-icons'; -import { AddressLink, ImageIcon } from '~/components/ui'; +import { AddressLink, ImageIcon, ImageIconSize } from '~/components/ui'; type ValidatorMetaProps = { validatorData: IotaValidatorSummary; @@ -28,12 +28,14 @@ export function ValidatorMeta({ validatorData }: ValidatorMetaProps): JSX.Elemen
- +
+ +
diff --git a/apps/explorer/src/lib/constants/index.ts b/apps/explorer/src/lib/constants/index.ts index 5c33042b10e..99b4cfa783a 100644 --- a/apps/explorer/src/lib/constants/index.ts +++ b/apps/explorer/src/lib/constants/index.ts @@ -3,3 +3,4 @@ export * from './footer.constants'; export * from './validator.constants'; +export * from './pageSize.constants'; diff --git a/apps/explorer/src/lib/constants/pageSize.constants.ts b/apps/explorer/src/lib/constants/pageSize.constants.ts new file mode 100644 index 00000000000..126a9ed0ee2 --- /dev/null +++ b/apps/explorer/src/lib/constants/pageSize.constants.ts @@ -0,0 +1,5 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +export const PAGE_SIZES_RANGE_10_50 = [10, 20, 30, 40, 50]; +export const PAGE_SIZES_RANGE_20_60 = [20, 40, 60]; diff --git a/apps/explorer/src/lib/ui/utils/generateValidatorsTableColumns.tsx b/apps/explorer/src/lib/ui/utils/generateValidatorsTableColumns.tsx index e175ba717d1..b053b889695 100644 --- a/apps/explorer/src/lib/ui/utils/generateValidatorsTableColumns.tsx +++ b/apps/explorer/src/lib/ui/utils/generateValidatorsTableColumns.tsx @@ -4,11 +4,11 @@ import { Badge, BadgeType, TableCellBase, TableCellText } from '@iota/apps-ui-kit'; import type { ColumnDef } from '@tanstack/react-table'; import { type ApyByValidator, formatPercentageDisplay } from '@iota/core'; - import { ampli, getValidatorMoveEvent, VALIDATOR_LOW_STAKE_GRACE_PERIOD } from '~/lib'; -import { StakeColumn, ValidatorLink, ImageIcon } from '~/components'; +import { StakeColumn } from '~/components'; import type { IotaEvent, IotaValidatorSummary } from '@iota/iota-sdk/dist/cjs/client'; import clsx from 'clsx'; +import { ImageIcon, ImageIconSize, ValidatorLink } from '~/components/ui'; interface generateValidatorsTableColumnsArgs { atRiskValidators: [string, string][]; @@ -41,7 +41,7 @@ function ValidatorWithImage({
diff --git a/apps/explorer/src/lib/utils/sentry.ts b/apps/explorer/src/lib/utils/sentry.ts index c9456beeb7c..95320908fca 100644 --- a/apps/explorer/src/lib/utils/sentry.ts +++ b/apps/explorer/src/lib/utils/sentry.ts @@ -57,7 +57,7 @@ export function initSentry() { //, ], allowUrls: [ - /.*\.iota\.io/i, + /.*\.iota\.org/i, /.*-iota-foundation\.vercel\.app/i, 'explorer-topaz.vercel.app', ], diff --git a/apps/explorer/src/pages/checkpoints/CheckpointTransactionBlocks.tsx b/apps/explorer/src/pages/checkpoints/CheckpointTransactionBlocks.tsx index 029eb40c032..f5370c56255 100644 --- a/apps/explorer/src/pages/checkpoints/CheckpointTransactionBlocks.tsx +++ b/apps/explorer/src/pages/checkpoints/CheckpointTransactionBlocks.tsx @@ -2,13 +2,14 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +import { DropdownPosition, Select, SelectSize } from '@iota/apps-ui-kit'; import { useState } from 'react'; - -import { Pagination, PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui'; +import { PlaceholderTable, TableCard, useCursorPagination } from '~/components/ui'; import { DEFAULT_TRANSACTIONS_LIMIT, useGetTransactionBlocks, } from '~/hooks/useGetTransactionBlocks'; +import { PAGE_SIZES_RANGE_20_60 } from '~/lib/constants'; import { generateTransactionsTableColumns } from '~/lib/ui'; export function CheckpointTransactionBlocks({ id }: { id: string }): JSX.Element { @@ -34,24 +35,28 @@ export function CheckpointTransactionBlocks({ id }: { id: string }): JSX.Element /> ) : (
- + ({ + label: `${size} / page`, + id: size.toString(), + }))} + onValueChange={(value) => { + setLimit(Number(value)); + pagination.onFirst(); + }} + size={SelectSize.Small} + /> + } + />
)} -
- - -
); } diff --git a/apps/explorer/src/pages/transaction-result/transaction-summary/BalanceChanges.tsx b/apps/explorer/src/pages/transaction-result/transaction-summary/BalanceChanges.tsx index 60c63f0675c..f532c0bcecc 100644 --- a/apps/explorer/src/pages/transaction-result/transaction-summary/BalanceChanges.tsx +++ b/apps/explorer/src/pages/transaction-result/transaction-summary/BalanceChanges.tsx @@ -23,7 +23,7 @@ import { } from '@iota/core'; import { RecognizedBadge } from '@iota/ui-icons'; import { useMemo } from 'react'; -import { CoinIcon } from '~/components'; +import { CoinIcon, ImageIconSize } from '~/components'; import { AddressLink, CollapsibleCard } from '~/components/ui'; import { BREAK_POINT, useMediaQuery } from '~/hooks'; @@ -49,7 +49,7 @@ function BalanceChangeEntry({ change }: { change: BalanceChange }): JSX.Element
- + ) { if (!navigator.clipboard) { return; @@ -86,9 +92,13 @@ export function KeyValueInfo({ return (
= { [CardType.Default]: 'border border-transparent', [CardType.Outlined]: 'border border-shader-neutral-light-8 dark:border-shader-primary-dark-8 p-xs', - [CardType.Filled]: 'border border-transparent bg-shader-neutral-light-8 p-xs', + [CardType.Filled]: 'border border-transparent bg-neutral-96 dark:bg-neutral-10 p-xs', }; diff --git a/apps/ui-kit/src/lib/components/organisms/table/Table.tsx b/apps/ui-kit/src/lib/components/organisms/table/Table.tsx index 36d567330f7..a848b0c9937 100644 --- a/apps/ui-kit/src/lib/components/organisms/table/Table.tsx +++ b/apps/ui-kit/src/lib/components/organisms/table/Table.tsx @@ -56,7 +56,7 @@ export type TableProps = { */ paginationOptions?: TablePaginationOptions; /** - * The action component.. + * The action component. */ action?: ReactNode; /** @@ -71,6 +71,10 @@ export type TableProps = { * Numeric indexes of all the rows. */ rowIndexes: number[]; + /** + * The page size selector component. + */ + pageSizeSelector?: ReactNode; }; export function Table({ @@ -80,6 +84,7 @@ export function Table({ selectedRowIndexes = new Set(), rowIndexes, children, + pageSizeSelector, }: PropsWithChildren): JSX.Element { return ( @@ -88,8 +93,10 @@ export function Table({
{children}
{paginationOptions && ( @@ -122,14 +129,19 @@ export function Table({ disabled={!paginationOptions.hasLast} onClick={paginationOptions.onLast} /> + {action}
)} - {action} - {supportingLabel && ( - - {supportingLabel} - - )} + {supportingLabel || pageSizeSelector ? ( +
+ {supportingLabel && ( + + {supportingLabel} + + )} + {pageSizeSelector &&
{pageSizeSelector}
} +
+ ) : null}
diff --git a/apps/ui-kit/tsconfig.base.json b/apps/ui-kit/tsconfig.base.json index 76fac5f8526..187384cd91e 100644 --- a/apps/ui-kit/tsconfig.base.json +++ b/apps/ui-kit/tsconfig.base.json @@ -10,10 +10,14 @@ "noFallthroughCasesInSwitch": true, "moduleResolution": "node", "resolveJsonModule": true, - "noEmit": true, "isolatedModules": true, "sourceMap": true, "jsx": "react-jsx", + "composite": true, + "declaration": true, + "declarationMap": true, + "outDir": "dist", + "emitDeclarationOnly": true, "paths": { "@/*": ["./src/*"], "@/components": ["./src/lib/components"], diff --git a/apps/wallet-dashboard/app/dashboard/layout.tsx b/apps/wallet-dashboard/app/dashboard/layout.tsx index ac56873f2b4..7db89a819c7 100644 --- a/apps/wallet-dashboard/app/dashboard/layout.tsx +++ b/apps/wallet-dashboard/app/dashboard/layout.tsx @@ -2,9 +2,11 @@ // SPDX-License-Identifier: Apache-2.0 'use client'; -import { Button, Notifications, RouteLink } from '@/components/index'; -import React, { useState, type PropsWithChildren } from 'react'; -import { ConnectButton } from '@iota/dapp-kit'; +import { Notifications, RouteLink } from '@/components/index'; +import React, { useEffect, useState, type PropsWithChildren } from 'react'; +import { ConnectButton, useCurrentAccount, useCurrentWallet } from '@iota/dapp-kit'; +import { Button } from '@iota/apps-ui-kit'; +import { useRouter } from 'next/navigation'; const routes = [ { title: 'Home', path: '/dashboard/home' }, @@ -18,7 +20,10 @@ const routes = [ function DashboardLayout({ children }: PropsWithChildren): JSX.Element { const [isDarkMode, setIsDarkMode] = useState(false); + const { connectionStatus } = useCurrentWallet(); + const account = useCurrentAccount(); + const router = useRouter(); const toggleDarkMode = () => { setIsDarkMode(!isDarkMode); if (isDarkMode) { @@ -28,7 +33,12 @@ function DashboardLayout({ children }: PropsWithChildren): JSX.Element { } }; - // TODO: check if the wallet is connected and if not redirect to the welcome screen + useEffect(() => { + if (connectionStatus !== 'connected' && !account) { + router.push('/'); + } + }, [connectionStatus, account, router]); + return ( <>
@@ -36,7 +46,7 @@ function DashboardLayout({ children }: PropsWithChildren): JSX.Element { {routes.map((route) => { return ; })} - +
{children}
diff --git a/apps/wallet-dashboard/app/page.tsx b/apps/wallet-dashboard/app/page.tsx new file mode 100644 index 00000000000..e0940c12afe --- /dev/null +++ b/apps/wallet-dashboard/app/page.tsx @@ -0,0 +1,62 @@ +// Copyright (c) 2024 IOTA Stiftung +// SPDX-License-Identifier: Apache-2.0 + +'use client'; + +import { ConnectButton, useCurrentAccount, useCurrentWallet } from '@iota/dapp-kit'; +import { useEffect } from 'react'; +import { useRouter } from 'next/navigation'; +import { IotaLogoWeb } from '@iota/ui-icons'; + +function HomeDashboardPage(): JSX.Element { + const { connectionStatus } = useCurrentWallet(); + const account = useCurrentAccount(); + const router = useRouter(); + + const CURRENT_YEAR = new Date().getFullYear(); + + useEffect(() => { + if (connectionStatus === 'connected' && account) { + router.push('/dashboard/home'); + } + }, [connectionStatus, account, router]); + + return ( +
+
+ +
+
+ +
+
+ Welcome to +

IOTA Wallet

+ + Connecting you to the decentralized web and IOTA network + +
+
+ +
+
+
+ © IOTA Foundation {CURRENT_YEAR} +
+
+
+ ); +} + +export default HomeDashboardPage; diff --git a/apps/wallet-dashboard/lib/utils/vesting/vesting.ts b/apps/wallet-dashboard/lib/utils/vesting/vesting.ts index 90ee486b504..157914ecca9 100644 --- a/apps/wallet-dashboard/lib/utils/vesting/vesting.ts +++ b/apps/wallet-dashboard/lib/utils/vesting/vesting.ts @@ -145,7 +145,7 @@ export function getVestingOverview( const userType = getSupplyIncreaseVestingUserType([latestPayout]); const vestingPayoutsCount = getSupplyIncreaseVestingPayoutsCount(userType!); - // note: we add the initial payout to the total rewards, 10% of the total rewards are paid out immediately + // Note: we add the initial payout to the total rewards, 10% of the total rewards are paid out immediately const totalVestedAmount = (vestingPayoutsCount * latestPayout.amount) / 0.9; const vestingPortfolio = buildSupplyIncreaseVestingSchedule( latestPayout, diff --git a/apps/wallet-dashboard/next.config.mjs b/apps/wallet-dashboard/next.config.mjs index e40a78b5e98..2727f8fcd80 100644 --- a/apps/wallet-dashboard/next.config.mjs +++ b/apps/wallet-dashboard/next.config.mjs @@ -5,11 +5,6 @@ const nextConfig = { async redirects() { return [ - { - source: '/', - destination: '/dashboard/home', - permanent: true, - }, { source: '/dashboard', destination: '/dashboard/home', diff --git a/apps/wallet-dashboard/package.json b/apps/wallet-dashboard/package.json index 28e910669ac..1398daf9a87 100644 --- a/apps/wallet-dashboard/package.json +++ b/apps/wallet-dashboard/package.json @@ -15,6 +15,7 @@ "node": ">= v18.17.0" }, "dependencies": { + "@iota/apps-ui-kit": "workspace:*", "@iota/core": "workspace:*", "@iota/dapp-kit": "workspace:*", "@iota/iota-sdk": "workspace:*", diff --git a/apps/wallet-dashboard/tailwind.config.ts b/apps/wallet-dashboard/tailwind.config.ts index ca8c6b84b6a..e8c9079ca3a 100644 --- a/apps/wallet-dashboard/tailwind.config.ts +++ b/apps/wallet-dashboard/tailwind.config.ts @@ -2,24 +2,20 @@ // SPDX-License-Identifier: Apache-2.0 import type { Config } from 'tailwindcss'; +// Note: exception for the tailwind preset import +import uiKitResponsivePreset from '../../apps/ui-kit/src/lib/tailwind/responsive.preset'; -const config: Config = { +export default { + presets: [uiKitResponsivePreset], content: [ './app/**/*.{js,ts,jsx,tsx,mdx}', './pages/**/*.{js,ts,jsx,tsx,mdx}', './components/**/*.{js,ts,jsx,tsx,mdx}', + './../ui-kit/src/lib/**/*.{js,jsx,ts,tsx}', ], darkMode: 'class', theme: { - extend: { - backgroundImage: { - 'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))', - 'gradient-conic': - 'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))', - }, - }, + extend: {}, plugins: [], }, -}; - -export default config; +} satisfies Partial; diff --git a/apps/wallet/configs/ts/tsconfig.common.json b/apps/wallet/configs/ts/tsconfig.common.json index 1206d3c9d36..5cd0e3c4128 100644 --- a/apps/wallet/configs/ts/tsconfig.common.json +++ b/apps/wallet/configs/ts/tsconfig.common.json @@ -54,5 +54,6 @@ } }, "include": ["../../src", "../../tests"], - "exclude": ["../../build", "../../node_modules"] + "exclude": ["../../build", "../../node_modules"], + "references": [{ "path": "../ui-kit" }] } diff --git a/apps/wallet/src/manifest/manifest.json b/apps/wallet/src/manifest/manifest.json index f43d531e439..944f62bba9b 100644 --- a/apps/wallet/src/manifest/manifest.json +++ b/apps/wallet/src/manifest/manifest.json @@ -10,11 +10,7 @@ "action": { "default_popup": "ui.html?type=popup" }, - "host_permissions": [ - "http://127.0.0.1:5001/", - "https://fullnode.devnet.iota.io/", - "https://fullnode.staging.iota.io/" - ], + "host_permissions": ["https://fullnode.devnet.iota.org/", "https://fullnode.staging.iota.org/"], "icons": { "16": "manifest/icons/iota-icon-16.png", "32": "manifest/icons/iota-icon-32.png", @@ -32,10 +28,6 @@ { "resources": ["dapp-interface.js"], "matches": [""] - }, - { - "resources": ["ui.html"], - "matches": ["https://*.banxa.com/*"] } ], "content_security_policy": { diff --git a/apps/wallet/src/shared/analytics/ampli/index.ts b/apps/wallet/src/shared/analytics/ampli/index.ts index 321c798c4ee..95be5cc179e 100644 --- a/apps/wallet/src/shared/analytics/ampli/index.ts +++ b/apps/wallet/src/shared/analytics/ampli/index.ts @@ -122,7 +122,7 @@ export interface AddedAccountsProperties { numberOfAccounts: number; } -export interface ClickedBullsharkQuestsCtaProperties { +export interface ClickedAppsBannerProperties { /** * The flow the user came from. */ @@ -392,10 +392,10 @@ export class AddedAccounts implements BaseEvent { } } -export class ClickedBullsharkQuestsCta implements BaseEvent { - event_type = 'clicked bullshark quests cta'; +export class ClickedAppsBannerCta implements BaseEvent { + event_type = 'clicked apps banner cta'; - constructor(public event_properties: ClickedBullsharkQuestsCtaProperties) { + constructor(public event_properties: ClickedAppsBannerProperties) { this.event_properties = event_properties; } } @@ -753,20 +753,18 @@ export class Ampli { } /** - * clicked bullshark quests cta - * * [View in Tracking Plan](https://data.amplitude.com/iotaledger/Iota%20Wallet/events/main/latest/clicked%20bullshark%20quests%20cta) * - * When users click the call-to-action for the Bullshark Quests interstitial/banner. + * When users click the call-to-action for banner. * * @param properties The event's properties (e.g. sourceFlow) * @param options Amplitude event options. */ - clickedBullsharkQuestsCta( - properties: ClickedBullsharkQuestsCtaProperties, + clickedAppsBannerCta( + properties: ClickedAppsBannerProperties, options?: EventOptions, ) { - return this.track(new ClickedBullsharkQuestsCta(properties), options); + return this.track(new ClickedAppsBannerCta(properties), options); } /** diff --git a/apps/wallet/src/shared/utils/url.ts b/apps/wallet/src/shared/utils/url.ts index db39b5e1367..716b9c2e768 100644 --- a/apps/wallet/src/shared/utils/url.ts +++ b/apps/wallet/src/shared/utils/url.ts @@ -3,7 +3,7 @@ import { getUrlWithDeviceId } from '../analytics/amplitude'; -const IOTA_DAPPS = ['iotafrens.com']; +const IOTA_DAPPS: string[] = []; export function isValidUrl(url: string | null) { if (!url) { diff --git a/apps/wallet/src/ui/app/components/IconButton.tsx b/apps/wallet/src/ui/app/components/IconButton.tsx deleted file mode 100644 index a49f4014c53..00000000000 --- a/apps/wallet/src/ui/app/components/IconButton.tsx +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) Mysten Labs, Inc. -// Modifications Copyright (c) 2024 IOTA Stiftung -// SPDX-License-Identifier: Apache-2.0 - -import { cva, type VariantProps } from 'class-variance-authority'; - -import { ButtonOrLink, type ButtonOrLinkProps } from '../shared/utils/ButtonOrLink'; - -interface IconButtonProps extends ButtonOrLinkProps, VariantProps { - icon: JSX.Element; -} - -const buttonStyles = cva( - [ - 'flex items-center rounded-sm bg-transparent border-0 p-0 text-hero-darkest/40 hover:text-hero-darkest/50 transition cursor-pointer', - ], - { - variants: { - variant: { - transparent: '', - subtle: 'hover:bg-hero-darkest/10', - }, - }, - defaultVariants: { - variant: 'subtle', - }, - }, -); - -export function IconButton({ onClick, icon, variant, ...buttonOrLinkProps }: IconButtonProps) { - return ( - - ); -} diff --git a/apps/wallet/src/ui/app/components/PasswordInputDialog.tsx b/apps/wallet/src/ui/app/components/PasswordInputDialog.tsx index fecf3763104..842e31ac7f2 100644 --- a/apps/wallet/src/ui/app/components/PasswordInputDialog.tsx +++ b/apps/wallet/src/ui/app/components/PasswordInputDialog.tsx @@ -3,15 +3,20 @@ // SPDX-License-Identifier: Apache-2.0 import { useBackgroundClient } from '_src/ui/app/hooks/useBackgroundClient'; -import { Button } from '_src/ui/app/shared/ButtonUI'; -import { Text } from '_src/ui/app/shared/text'; import classNames from 'clsx'; import { Form, Formik } from 'formik'; import { toast } from 'react-hot-toast'; import { useNavigate } from 'react-router-dom'; import { object, string as YupString } from 'yup'; -import { ArrowLeft, ArrowRight } from '@iota/ui-icons'; -import { Header, InputType } from '@iota/apps-ui-kit'; +import { ArrowLeft, ArrowRight, Loader } from '@iota/ui-icons'; +import { + Button, + ButtonHtmlType, + ButtonType, + ButtonSize, + Header, + InputType, +} from '@iota/apps-ui-kit'; import { PasswordInputField } from '../shared/input/password'; const validation = object({ @@ -76,20 +81,19 @@ export function PasswordInputDialog({ errorMessage={errors.password} />
- + This is the password you currently use to lock and unlock your IOTA wallet. - +
{showBackButton ? (
diff --git a/apps/wallet/src/ui/app/components/accounts/AccountBalanceItem.tsx b/apps/wallet/src/ui/app/components/accounts/AccountBalanceItem.tsx index fcae444a0ac..a068e239e8e 100644 --- a/apps/wallet/src/ui/app/components/accounts/AccountBalanceItem.tsx +++ b/apps/wallet/src/ui/app/components/accounts/AccountBalanceItem.tsx @@ -1,13 +1,12 @@ // Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Text } from '_src/ui/app/shared/text'; import { formatAddress } from '@iota/iota-sdk/utils'; import { useCopyToClipboard } from '../../hooks/useCopyToClipboard'; -import { IconButton } from '_components'; import { type SerializedUIAccount } from '_src/background/accounts/Account'; import { useBalance, useFormatCoin } from '@iota/core'; import { Copy } from '@iota/ui-icons'; +import { Panel, ButtonUnstyled } from '@iota/apps-ui-kit'; interface AccountBalanceItemProps { account: SerializedUIAccount; @@ -24,27 +23,24 @@ export function AccountBalanceItem({ account }: AccountBalanceItemProps): JSX.El const totalBalance = balance?.totalBalance || '0'; const coinType = balance?.coinType; const [formatted, symbol] = useFormatCoin(BigInt(totalBalance), coinType); - return ( -
-
-
- - {formatAddress(account.address)} - -
- } - onClick={copyAddress} - /> + +
+
+
+ {formatAddress(account.address)} +
+ + + +
-
- - {formatted} {symbol} - + + {formatted} {symbol} + +
-
+ ); } diff --git a/apps/wallet/src/ui/app/components/accounts/AutoLockSelector.tsx b/apps/wallet/src/ui/app/components/accounts/AutoLockSelector.tsx index 94fa1ac49f7..5ae321fa9bf 100644 --- a/apps/wallet/src/ui/app/components/accounts/AutoLockSelector.tsx +++ b/apps/wallet/src/ui/app/components/accounts/AutoLockSelector.tsx @@ -5,9 +5,7 @@ import { useEffect } from 'react'; import { useFormContext } from 'react-hook-form'; import { z } from 'zod'; - import { CheckboxField } from '../../shared/forms/CheckboxField'; -import FormField from '../../shared/forms/FormField'; import { SelectField } from '../../shared/forms/SelectField'; import { Input, InputType, type SelectOption } from '@iota/apps-ui-kit'; @@ -59,24 +57,23 @@ export function AutoLockSelector({ disabled }: AutoLockSelectorProps) { label="Auto-lock after I'm inactive for" disabled={disabled} /> - -
-
- -
-
- -
+
+
+ +
+
+
- +
); } diff --git a/apps/wallet/src/ui/app/components/accounts/ImportRecoveryPhraseForm.tsx b/apps/wallet/src/ui/app/components/accounts/ImportRecoveryPhraseForm.tsx index 1fcdf4fc405..ef3d2620d80 100644 --- a/apps/wallet/src/ui/app/components/accounts/ImportRecoveryPhraseForm.tsx +++ b/apps/wallet/src/ui/app/components/accounts/ImportRecoveryPhraseForm.tsx @@ -124,7 +124,7 @@ export function ImportRecoveryPhraseForm({ })}
-
+
{touchedFields.recoveryPhrase && errors.recoveryPhrase && (
- +
+
- ampli.clickedBullsharkQuestsCta({ sourceFlow: 'Banner - Apps tab' }) - } + onClick={() => ampli.clickedAppsBannerCta({ sourceFlow: 'Banner - Apps tab' })} > +
-
- - {name} - - - {description} - +
+ {name} + {description} {tags?.length && ( -
+
{tags?.map((tag) => ( -
- - {tag} - -
+ ))}
)} diff --git a/apps/wallet/src/ui/app/components/iota-apps/IotaAppEmpty.tsx b/apps/wallet/src/ui/app/components/iota-apps/IotaAppEmpty.tsx index 5f51bce1678..4dc7b6021d8 100644 --- a/apps/wallet/src/ui/app/components/iota-apps/IotaAppEmpty.tsx +++ b/apps/wallet/src/ui/app/components/iota-apps/IotaAppEmpty.tsx @@ -2,13 +2,14 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +import { Placeholder } from '@iota/apps-ui-kit'; import { cva, type VariantProps } from 'class-variance-authority'; -const appEmptyStyle = cva(['flex gap-3 p-3.75 h-28'], { +const appEmptyStyle = cva(['flex gap-3 p-lg h-28'], { variants: { displayType: { full: 'w-full', - card: 'bg-white flex flex-col p-3.75 box-border w-full rounded-2xl h-32 box-border w-full rounded-2xl border border-solid border-gray-40', + card: 'bg-neutral-100 flex flex-col p-lg w-full rounded-2xl h-32 box-border w-full rounded-2xl border border-solid border-shader-primary-dark', }, }, defaultVariants: { @@ -21,18 +22,18 @@ export interface IotaAppEmptyProps extends VariantProps {} export function IotaAppEmpty({ ...styleProps }: IotaAppEmptyProps) { return (
-
+
{styleProps.displayType === 'full' ? ( <> -
-
-
+ {new Array(2).fill(0).map((_, index) => ( + + ))} ) : (
-
-
+ +
)}
diff --git a/apps/wallet/src/ui/app/components/iota-apps/index.tsx b/apps/wallet/src/ui/app/components/iota-apps/index.tsx index f27954c05ef..8633641c5ed 100644 --- a/apps/wallet/src/ui/app/components/iota-apps/index.tsx +++ b/apps/wallet/src/ui/app/components/iota-apps/index.tsx @@ -2,7 +2,6 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 -import { Text } from '_app/shared/text'; import { useAppSelector } from '_hooks'; import { Feature } from '@iota/core'; import { prepareLinkToCompare } from '_src/shared/utils'; @@ -13,7 +12,8 @@ import { permissionsSelectors } from '../../redux/slices/permissions'; import { AppsPageBanner } from './Banner'; import { IotaApp, type DAppEntry } from './IotaApp'; import { IotaAppEmpty } from './IotaAppEmpty'; -import { Header } from '@iota/apps-ui-kit'; +import { InfoBox, InfoBoxStyle, InfoBoxType, Header } from '@iota/apps-ui-kit'; +import { Info } from '@iota/ui-icons'; export function AppsPlayGround() { const ecosystemApps = useFeature(Feature.WalletDapps).value; @@ -46,16 +46,17 @@ export function AppsPlayGround() { {filteredEcosystemApps?.length ? ( -
- - Apps below are actively curated but do not indicate any endorsement or - relationship with IOTA Wallet. Please DYOR. - -
+ } + style={InfoBoxStyle.Elevated} + supportingText="Apps below are actively curated but do not indicate any endorsement or + relationship with IOTA Wallet. Please DYOR." + /> ) : null} {filteredEcosystemApps?.length ? ( -
+
{filteredEcosystemApps.map((app) => ( .line-1 { - top: calc(50% - ($line-height / 2)); - transform: rotate(45deg); - } - - > .line-2 { - transform: rotate(-45deg); - } - - > .line-3 { - opacity: 0; - } -} diff --git a/apps/wallet/src/ui/app/components/menu/button/WalletSettingsButton.tsx b/apps/wallet/src/ui/app/components/menu/button/WalletSettingsButton.tsx index bb875f73ac5..9607f08c8dd 100644 --- a/apps/wallet/src/ui/app/components/menu/button/WalletSettingsButton.tsx +++ b/apps/wallet/src/ui/app/components/menu/button/WalletSettingsButton.tsx @@ -2,9 +2,10 @@ // Modifications Copyright (c) 2024 IOTA Stiftung // SPDX-License-Identifier: Apache-2.0 +import { Button, ButtonSize, ButtonType } from '@iota/apps-ui-kit'; import { Close, Settings } from '@iota/ui-icons'; import { useMenuIsOpen, useNextMenuUrl } from '_components'; -import { ButtonOrLink } from '_src/ui/app/shared/utils/ButtonOrLink'; +import { Link } from 'react-router-dom'; import { cx } from 'class-variance-authority'; export function WalletSettingsButton() { @@ -13,15 +14,16 @@ export function WalletSettingsButton() { const IconComponent = isOpen ? Close : Settings; return ( - - - +
diff --git a/apps/wallet/src/ui/app/pages/approval-request/SignMessageRequest.tsx b/apps/wallet/src/ui/app/pages/approval-request/SignMessageRequest.tsx index a94e583de3f..72b880f9e51 100644 --- a/apps/wallet/src/ui/app/pages/approval-request/SignMessageRequest.tsx +++ b/apps/wallet/src/ui/app/pages/approval-request/SignMessageRequest.tsx @@ -11,14 +11,14 @@ import { useAccountByAddress } from '../../hooks/useAccountByAddress'; import { useSigner } from '../../hooks/useSigner'; import { respondToTransactionRequest } from '../../redux/slices/transaction-requests'; import { PageMainLayoutTitle } from '../../shared/page-main-layout/PageMainLayoutTitle'; -import { Text } from '../../shared/text'; +import { Panel } from '@iota/apps-ui-kit'; export interface SignMessageRequestProps { request: SignMessageApprovalRequest; } export function SignMessageRequest({ request }: SignMessageRequestProps) { - const { message, type } = useMemo(() => toUtf8OrB64(request.tx.message), [request.tx.message]); + const { message } = useMemo(() => toUtf8OrB64(request.tx.message), [request.tx.message]); const { data: account } = useAccountByAddress(request.tx.accountAddress); const signer = useSigner(account); const dispatch = useAppDispatch(); @@ -48,21 +48,16 @@ export function SignMessageRequest({ request }: SignMessageRequestProps) { checkAccountLock > -
+
Message You Are Signing
-
-
- - {message} - + +
+
+ {message} +
-
+ ); } diff --git a/apps/wallet/src/ui/app/pages/home/interstitial/index.tsx b/apps/wallet/src/ui/app/pages/home/interstitial/index.tsx index ca575d1f81d..b435f4d650e 100644 --- a/apps/wallet/src/ui/app/pages/home/interstitial/index.tsx +++ b/apps/wallet/src/ui/app/pages/home/interstitial/index.tsx @@ -50,7 +50,7 @@ function Interstitial({ enabled, dismissKey, imageUrl, bannerUrl, onClose }: Int { - ampli.clickedBullsharkQuestsCta({ sourceFlow: 'Interstitial' }); + ampli.clickedAppsBannerCta({ sourceFlow: 'Interstitial' }); closeInterstitial(); }} className="h-full w-full" @@ -59,7 +59,6 @@ function Interstitial({ enabled, dismissKey, imageUrl, bannerUrl, onClose }: Int )}