@meddleware/dashboard-ui 0.1.96 → 0.1.98
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +20 -0
- package/README.md +5 -5
- package/index.html +1 -1
- package/package.json +23 -16
- package/src/App.vue +6 -4
- package/src/components/NetworkSelector.vue +6 -8
- package/src/network.ts +64 -0
- package/tsconfig.json +1 -15
- package/vite.config.ts +16 -17
package/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,26 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/); version
|
|
|
5
5
|
[Semantic Versioning](https://semver.org/). Before 0.2.0, breaking changes ship as patch releases.
|
|
6
6
|
Releases before 0.1.85 are recorded in the git history only.
|
|
7
7
|
|
|
8
|
+
## [0.1.98] - 2026-11-08
|
|
9
|
+
|
|
10
|
+
### Changed
|
|
11
|
+
|
|
12
|
+
- The network selector reads the deployment records instead of a hard-coded option: Mainnet is selectable only when every hosted product (Access Gate, Sealed Storage) has a mainnet record, and until then it reads "Mainnet (not open yet)" with a tooltip that says what is missing or that mainnet is coming. A stored mainnet choice goes back to testnet only while mainnet is not open, with or without a wallet connected.
|
|
13
|
+
- Token Issuance no longer carries a committed mainnet fee address: `.env.production` holds testnet only and the mainnet treasury is an optional build argument, so Token Issuance stays closed on mainnet until the build is given one.
|
|
14
|
+
- Takes the embedded tools' 2026-11-07 releases (access-gate-ui 0.1.48, sealed-storage-ui 0.0.48, token-issuance-ui 0.0.46, treasury-ui 0.0.27, walrus-storage-ui 0.1.69), `@meddleware/wallet-adapter` ^0.0.22 (one copy, shared by all five), `@meddleware/ui` ^0.1.40, `@meddleware/web-utils` ^0.0.4 and `@meddleware/frontend-config` ^0.0.7. The explorer link beside the connected address uses wallet-adapter's `explorerNetwork`.
|
|
15
|
+
- Describes the app for the people who use it (five tools, one wallet connection) in `package.json`, the README, `index.html` and CLAUDE.md.
|
|
16
|
+
|
|
17
|
+
### Internal
|
|
18
|
+
|
|
19
|
+
- Shared tooling replaces the local copies: `mw-audit-gate`, `mw-third-party-licenses` and `mw-check-csp-inline` (the `check:dist` script is now `check:csp`, which checks inline scripts against the Dockerfile's CSP by hash), `meddlewareApp`, `vueTestConfig` and the shared tsconfig base. `mw-sync --check` runs in CI; the `chain-wasm` CSP profile is configured in `package.json`.
|
|
20
|
+
- New dependencies `@meddleware/access-gate-client` and `@meddleware/sealed-storage-client` (their deployment records feed the selector). New tests for the availability, the selector and the stored-network guard with the records mocked, and an end-to-end check of the selector.
|
|
21
|
+
|
|
22
|
+
## [0.1.97] - 2026-11-06
|
|
23
|
+
|
|
24
|
+
### Changed
|
|
25
|
+
|
|
26
|
+
- Takes the embedded tools' 2026-11-06 releases (access-gate-ui 0.1.47, sealed-storage-ui 0.0.47, token-issuance-ui 0.0.45, treasury-ui 0.0.26 — now swept with data in its own end-to-end build —, walrus-storage-ui 0.1.68), `@meddleware/ui` ^0.1.39, and the Dependabot merges of 2026-11-06 (image bases, dev tools). Adds a README and a `LICENSE`.
|
|
27
|
+
|
|
8
28
|
## [0.1.96] - 2026-11-06
|
|
9
29
|
|
|
10
30
|
### Changed
|
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# @meddleware/dashboard-ui
|
|
2
2
|
|
|
3
|
-
The
|
|
4
|
-
|
|
5
|
-
Issuance consoles) inside one shell with a chain selector. It holds no financial logic: every number is read from the chain by the embedded tool.
|
|
3
|
+
The Meddleware dashboard, served at [`dash.meddleware.co.uk`](https://dash.meddleware.co.uk): a Vue 3 + Vite single-page app with the five
|
|
4
|
+
tools in one place and one wallet connection for all of them (Treasury, and under *Blockchain* the Walrus Storage, Sealed Storage, Access Gate
|
|
5
|
+
and Token Issuance consoles). Each tool comes from its own package, inside one shell with a chain and network selector. It holds no financial logic: every number is read from the chain by the embedded tool.
|
|
6
6
|
|
|
7
7
|
- **Stack:** Vue 3, Vite, `@meddleware/design-tokens`, `@meddleware/ui`, `@meddleware/wallet-adapter`.
|
|
8
8
|
- **Image:** `quay.io/meddleware-org/dashboard-ui`, built on `quay.io/meddleware-org/static-server` (see `Dockerfile`).
|
|
@@ -17,7 +17,7 @@ npm run dev # Vite dev server
|
|
|
17
17
|
npm test # unit tests (Vitest)
|
|
18
18
|
npm run test:e2e # builds the e2e variant and runs the Playwright sweep (E2E_BROWSERS=all adds Firefox, WebKit and two mobile profiles)
|
|
19
19
|
npm run lint && npm run type-check
|
|
20
|
-
npm run build && npm run check:bundle && npm run check:
|
|
20
|
+
npm run build && npm run check:bundle && npm run check:csp
|
|
21
21
|
```
|
|
22
22
|
|
|
23
|
-
`npm run check:bundle` fails if a test hook reached the production bundle; `npm run check:
|
|
23
|
+
`npm run check:bundle` fails if a test hook reached the production bundle; `npm run check:csp` fails if the build has an inline script the image's Content-Security-Policy would refuse.
|
package/index.html
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
<link rel="icon" type="image/svg+xml" href="/favicon.svg">
|
|
6
6
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
7
7
|
<title>Meddleware</title>
|
|
8
|
-
<meta name="description" content="The Meddleware dashboard: the
|
|
8
|
+
<meta name="description" content="The Meddleware dashboard: the treasury and the Sui tools (Walrus storage, sealed storage, access gates, token issuance) in one place, with one wallet connection for all of them." />
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="app"><p role="status">Loading the Meddleware dashboard…</p></div>
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@meddleware/dashboard-ui",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.98",
|
|
4
4
|
"homepage": "https://docs.meddleware.co.uk/",
|
|
5
|
-
"description": "Meddleware
|
|
5
|
+
"description": "The Meddleware dashboard: the treasury, Walrus storage, sealed storage, access gates and token issuance in one place, with one wallet connection for all five tools. Vue 3 single-page app.",
|
|
6
6
|
"author": "Meddleware <dev@meddleware.co.uk>",
|
|
7
7
|
"license": "0BSD",
|
|
8
8
|
"repository": {
|
|
@@ -31,9 +31,9 @@
|
|
|
31
31
|
"lint:js": "eslint .",
|
|
32
32
|
"lint": "npm run lint:css && npm run lint:js && npm run lint:html",
|
|
33
33
|
"lint:html": "html-validate \"src/**/*.vue\"",
|
|
34
|
-
"licenses": "
|
|
35
|
-
"check:licenses": "
|
|
36
|
-
"check:
|
|
34
|
+
"licenses": "mw-third-party-licenses",
|
|
35
|
+
"check:licenses": "mw-third-party-licenses --check",
|
|
36
|
+
"check:csp": "mw-check-csp-inline @Dockerfile dist",
|
|
37
37
|
"shots": "SHOTS=1 playwright test",
|
|
38
38
|
"lhci": "npm run build && lhci autorun",
|
|
39
39
|
"check:bundle": "check-prod-bundle dist"
|
|
@@ -42,22 +42,24 @@
|
|
|
42
42
|
"access": "public"
|
|
43
43
|
},
|
|
44
44
|
"dependencies": {
|
|
45
|
-
"@meddleware/access-gate-
|
|
45
|
+
"@meddleware/access-gate-client": "^0.0.13",
|
|
46
|
+
"@meddleware/access-gate-ui": "^0.1.48",
|
|
46
47
|
"@meddleware/design-tokens": "^0.1.13",
|
|
47
|
-
"@meddleware/sealed-storage-
|
|
48
|
-
"@meddleware/
|
|
49
|
-
"@meddleware/
|
|
50
|
-
"@meddleware/ui": "^0.
|
|
51
|
-
"@meddleware/
|
|
52
|
-
"@meddleware/
|
|
53
|
-
"@meddleware/
|
|
48
|
+
"@meddleware/sealed-storage-client": "^0.0.26",
|
|
49
|
+
"@meddleware/sealed-storage-ui": "^0.0.48",
|
|
50
|
+
"@meddleware/token-issuance-ui": "^0.0.46",
|
|
51
|
+
"@meddleware/treasury-ui": "^0.0.27",
|
|
52
|
+
"@meddleware/ui": "^0.1.40",
|
|
53
|
+
"@meddleware/wallet-adapter": "^0.0.22",
|
|
54
|
+
"@meddleware/walrus-storage-ui": "^0.1.69",
|
|
55
|
+
"@meddleware/web-utils": "^0.0.4",
|
|
54
56
|
"@mysten/sui": "^2.36.0",
|
|
55
57
|
"vue": "^3.5.44",
|
|
56
58
|
"vue-router": "^5.4.0"
|
|
57
59
|
},
|
|
58
60
|
"devDependencies": {
|
|
59
|
-
"@lhci/cli": "^0.
|
|
60
|
-
"@meddleware/frontend-config": "^0.0.
|
|
61
|
+
"@lhci/cli": "^0.16.0",
|
|
62
|
+
"@meddleware/frontend-config": "^0.0.7",
|
|
61
63
|
"@playwright/test": "~1.64.1",
|
|
62
64
|
"@types/node": "~26.6.5",
|
|
63
65
|
"@vitejs/plugin-vue": "^6.0.10",
|
|
@@ -77,7 +79,7 @@
|
|
|
77
79
|
"stylelint-config-standard": "^40.0.0",
|
|
78
80
|
"typescript": "~6.0.0",
|
|
79
81
|
"vite": "^8.3.4",
|
|
80
|
-
"vitest": "~5.0
|
|
82
|
+
"vitest": "~5.1.0",
|
|
81
83
|
"vue-eslint-parser": "^10.4.1",
|
|
82
84
|
"vue-tsc": "~3.3.13"
|
|
83
85
|
},
|
|
@@ -91,5 +93,10 @@
|
|
|
91
93
|
"basic-ftp": "^6.2.4",
|
|
92
94
|
"tmp": "^0.2.7",
|
|
93
95
|
"zod": "^4.6.7"
|
|
96
|
+
},
|
|
97
|
+
"meddleware": {
|
|
98
|
+
"kind": "app",
|
|
99
|
+
"csp": "chain-wasm",
|
|
100
|
+
"lhci": true
|
|
94
101
|
}
|
|
95
102
|
}
|
package/src/App.vue
CHANGED
|
@@ -24,10 +24,12 @@ import { useNetwork, useWallet } from '@meddleware/wallet-adapter'
|
|
|
24
24
|
import { DEFAULT_CHAIN } from './chains.js'
|
|
25
25
|
import ChainSelector from './components/ChainSelector.vue'
|
|
26
26
|
import NetworkSelector from './components/NetworkSelector.vue'
|
|
27
|
+
import { keepToOpenNetwork } from './network.js'
|
|
27
28
|
|
|
28
29
|
const { mode } = useColorMode('dark')
|
|
29
30
|
const route = useRoute()
|
|
30
|
-
const { network } = useNetwork()
|
|
31
|
+
const { network, explorerNetwork } = useNetwork()
|
|
32
|
+
keepToOpenNetwork()
|
|
31
33
|
|
|
32
34
|
// The sidebar has two modes. Top level shows the organisation sections (Treasury, Blockchain). Entering the Blockchain section swaps it to a
|
|
33
35
|
// chain selector with an up-one-level control that returns to the top level without leaving the page. The mode follows the route (so a
|
|
@@ -60,8 +62,8 @@ const { account, disconnect } = useWallet({ requiredFeatures: ['sui:signTransact
|
|
|
60
62
|
const DOCS_URL = import.meta.env.VITE_DOCS_URL || 'https://docs.meddleware.co.uk/'
|
|
61
63
|
const DEV_URL = import.meta.env.VITE_DEV_URL || 'https://meddleware.dev/'
|
|
62
64
|
|
|
63
|
-
// SuiVision has no localnet explorer, so
|
|
64
|
-
const
|
|
65
|
+
// SuiVision has no localnet explorer, so the address links to it only on a public network; on localnet it is copy-only.
|
|
66
|
+
const hasExplorer = computed(() => network.value !== 'localnet')
|
|
65
67
|
const title = computed(() => (typeof route.meta.title === 'string' ? route.meta.title : 'Meddleware'))
|
|
66
68
|
</script>
|
|
67
69
|
|
|
@@ -111,7 +113,7 @@ const title = computed(() => (typeof route.meta.title === 'string' ? route.meta.
|
|
|
111
113
|
<template #foot>
|
|
112
114
|
<p v-if="account" class="foot">
|
|
113
115
|
<CopyableAddress :address="account.address">
|
|
114
|
-
<ExplorerLink v-if="
|
|
116
|
+
<ExplorerLink v-if="hasExplorer" :href="suiExplorerUrl('account', account.address, explorerNetwork)" :value="account.address" />
|
|
115
117
|
</CopyableAddress>
|
|
116
118
|
<UiButton variant="link" size="sm" @click="disconnect">Disconnect</UiButton>
|
|
117
119
|
</p>
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
// Network selector for the dashboard sidebar. Reads and writes the shared useNetwork() singleton so every embedded tool view reacts to the
|
|
3
|
-
// chosen network immediately. Mainnet is
|
|
4
|
-
|
|
3
|
+
// chosen network immediately. Mainnet is selectable only when the deployment records say it is live (`src/network.ts`); until then it is
|
|
4
|
+
// listed, disabled, with what is missing.
|
|
5
|
+
import { ref, watch } from 'vue'
|
|
5
6
|
import { UiFormField, UiSelect, UiTextField } from '@meddleware/ui'
|
|
6
7
|
import { useNetwork, type MwNetwork } from '@meddleware/wallet-adapter'
|
|
8
|
+
import { networkOptions } from '../network.js'
|
|
7
9
|
|
|
8
10
|
const { network, localnetRpc, setNetwork, setLocalnetRpc } = useNetwork()
|
|
9
11
|
|
|
@@ -22,9 +24,7 @@ function commitLocalnetUrl(): void {
|
|
|
22
24
|
if (url) setLocalnetRpc(url)
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
|
|
26
|
-
if (network.value === 'mainnet') setNetwork('testnet')
|
|
27
|
-
})
|
|
27
|
+
const options = networkOptions()
|
|
28
28
|
</script>
|
|
29
29
|
|
|
30
30
|
<template>
|
|
@@ -32,9 +32,7 @@ onMounted(() => {
|
|
|
32
32
|
<UiFormField id="ns-select" label="Network">
|
|
33
33
|
<template #default="{ attrs }">
|
|
34
34
|
<UiSelect :id="attrs.id" :model-value="network" @change="onNetworkChange">
|
|
35
|
-
<option value="
|
|
36
|
-
<option value="mainnet" disabled title="Coming soon">Mainnet</option>
|
|
37
|
-
<option value="localnet">Localnet</option>
|
|
35
|
+
<option v-for="o in options" :key="o.value" :value="o.value" :disabled="o.disabled" :title="o.title">{{ o.label }}</option>
|
|
38
36
|
</UiSelect>
|
|
39
37
|
</template>
|
|
40
38
|
</UiFormField>
|
package/src/network.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// Which networks the dashboard offers, from the deployment records and nothing else. A tool's record lists the networks it is published on
|
|
2
|
+
// (the keys of its `*_DEPLOYMENTS` object); `networkAvailability` reports a network as `live` only when every product the dashboard hosts
|
|
3
|
+
// has a record there. Adding a `mainnet` key to both records is therefore the one switch that opens mainnet in the selector: no page here
|
|
4
|
+
// states which network is live in prose, and the platform's mainnet-readiness structure check fails on a hand-written disabled option.
|
|
5
|
+
//
|
|
6
|
+
// The two records are the products whose on-chain deployment a network choice depends on: the Access Gate (also read by the Walrus relay
|
|
7
|
+
// gate, Token Issuance and the Treasury) and the Sealed Storage policies. Walrus Storage and Token Issuance have no record of their own.
|
|
8
|
+
import { ACCESS_GATE_DEPLOYMENTS } from '@meddleware/access-gate-client/deployments'
|
|
9
|
+
import { SEAL_POLICIES_DEPLOYMENTS } from '@meddleware/sealed-storage-client/deployments'
|
|
10
|
+
import { networkAvailability, type NetworkAvailability } from '@meddleware/web-utils'
|
|
11
|
+
import { useNetwork, type MwNetwork } from '@meddleware/wallet-adapter'
|
|
12
|
+
|
|
13
|
+
/** The availability of testnet and mainnet, from the records. */
|
|
14
|
+
export const AVAILABILITY = networkAvailability({
|
|
15
|
+
'access gate': Object.keys(ACCESS_GATE_DEPLOYMENTS),
|
|
16
|
+
'sealed storage': Object.keys(SEAL_POLICIES_DEPLOYMENTS),
|
|
17
|
+
})
|
|
18
|
+
|
|
19
|
+
export interface MainnetChoice {
|
|
20
|
+
/** Mainnet can be selected. */
|
|
21
|
+
readonly open: boolean
|
|
22
|
+
/** The option's text. */
|
|
23
|
+
readonly label: string
|
|
24
|
+
/** The option's tooltip: what is missing, or that mainnet is coming. Absent when mainnet is open. */
|
|
25
|
+
readonly title?: string
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** How the mainnet option reads for the given availability (default: the records). */
|
|
29
|
+
export function mainnetChoice(mainnet: NetworkAvailability = AVAILABILITY.mainnet): MainnetChoice {
|
|
30
|
+
switch (mainnet.status) {
|
|
31
|
+
case 'live':
|
|
32
|
+
return { open: true, label: 'Mainnet' }
|
|
33
|
+
case 'partial':
|
|
34
|
+
return { open: false, label: 'Mainnet (not open yet)', title: `Mainnet is not open yet. Still missing: ${mainnet.missing.join(', ')}.` }
|
|
35
|
+
case 'coming':
|
|
36
|
+
return { open: false, label: 'Mainnet (not open yet)', title: 'Mainnet is coming' }
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export interface NetworkOption {
|
|
41
|
+
readonly value: MwNetwork
|
|
42
|
+
readonly label: string
|
|
43
|
+
readonly disabled: boolean
|
|
44
|
+
readonly title?: string
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** The options of the network selector: testnet and localnet always, mainnet as the records allow. */
|
|
48
|
+
export function networkOptions(mainnet: NetworkAvailability = AVAILABILITY.mainnet): NetworkOption[] {
|
|
49
|
+
const choice = mainnetChoice(mainnet)
|
|
50
|
+
return [
|
|
51
|
+
{ value: 'testnet', label: 'Testnet', disabled: false },
|
|
52
|
+
{ value: 'mainnet', label: choice.label, disabled: !choice.open, title: choice.title },
|
|
53
|
+
{ value: 'localnet', label: 'Localnet', disabled: false },
|
|
54
|
+
]
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Keep the shared network on one the dashboard offers: a stored mainnet choice (from a time mainnet was open, or edited by hand) goes back to
|
|
59
|
+
* testnet unless mainnet is live. Every tool view reads the shared choice, so this runs in the shell, with or without a wallet connected.
|
|
60
|
+
*/
|
|
61
|
+
export function keepToOpenNetwork(mainnet: NetworkAvailability = AVAILABILITY.mainnet): void {
|
|
62
|
+
const { network, setNetwork } = useNetwork()
|
|
63
|
+
if (network.value === 'mainnet' && mainnet.status !== 'live') setNetwork('testnet')
|
|
64
|
+
}
|
package/tsconfig.json
CHANGED
|
@@ -1,18 +1,4 @@
|
|
|
1
1
|
{
|
|
2
|
-
"
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "Bundler",
|
|
6
|
-
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
|
7
|
-
"strict": true,
|
|
8
|
-
"esModuleInterop": true,
|
|
9
|
-
"skipLibCheck": true,
|
|
10
|
-
"resolveJsonModule": true,
|
|
11
|
-
"isolatedModules": true,
|
|
12
|
-
"verbatimModuleSyntax": true,
|
|
13
|
-
"jsx": "preserve",
|
|
14
|
-
"types": ["node"],
|
|
15
|
-
"noEmit": true
|
|
16
|
-
},
|
|
2
|
+
"extends": "@meddleware/frontend-config/tsconfig/vue-app.json",
|
|
17
3
|
"include": ["src/**/*.ts", "src/**/*.vue", "src/**/*.d.ts", "tests/**/*.ts", "e2e/**/*.ts", "vite.config.ts", "vitest.config.ts", "playwright.config.ts"]
|
|
18
4
|
}
|
package/vite.config.ts
CHANGED
|
@@ -1,20 +1,19 @@
|
|
|
1
|
-
import { defineConfig } from 'vite'
|
|
2
1
|
import vue from '@vitejs/plugin-vue'
|
|
3
|
-
import {
|
|
2
|
+
import { defineConfig } from 'vite'
|
|
3
|
+
import { meddlewareApp } from '@meddleware/frontend-config/vite'
|
|
4
4
|
|
|
5
|
-
//
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
exclude: ['@mysten/walrus', '@mysten/walrus-wasm', '@meddleware/wallet-adapter'],
|
|
5
|
+
// meddlewareApp refuses VITE_E2E outside the end-to-end mode (`--mode e2e`: a mock wallet and a stub chain; nothing else may include them),
|
|
6
|
+
// sets the browserslist build target and the dark default colour mode, and keeps @meddleware/wallet-adapter (the shared wallet singleton,
|
|
7
|
+
// shipped as TS + .vue source) out of pre-bundling, so dev does not load a second copy of it.
|
|
8
|
+
export default defineConfig(
|
|
9
|
+
meddlewareApp({
|
|
10
|
+
plugins: [vue()],
|
|
11
|
+
config: {
|
|
12
|
+
optimizeDeps: {
|
|
13
|
+
// The Walrus wasm client is dynamically imported inside the inline WalrusStorageView upload flow; keep it out of the eager
|
|
14
|
+
// dep-optimization graph so it stays a lazy chunk.
|
|
15
|
+
exclude: ['@mysten/walrus', '@mysten/walrus-wasm'],
|
|
16
|
+
},
|
|
18
17
|
},
|
|
19
|
-
}
|
|
20
|
-
|
|
18
|
+
}),
|
|
19
|
+
)
|