@noy-db/in-nuxt 0.2.0-pre.29 → 0.2.0-pre.30

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.
@@ -36,6 +36,7 @@
36
36
  <div v-if="topTab === 'structure'" class="noydb-panel__body">
37
37
  <VaultSidebar
38
38
  :vault-name="vaultInfo!.id"
39
+ :vault-meta="snapshotMeta"
39
40
  :collections="collections"
40
41
  :selected-name="selectedCollection?.name ?? null"
41
42
  @select="selectCollection"
@@ -78,7 +79,7 @@ import { ref, computed, watch, onMounted, onUnmounted } from 'vue'
78
79
  import { getActiveNoydb } from '@noy-db/in-pinia'
79
80
  import { createInspector } from '@noy-db/in-devtools'
80
81
  import type { Inspector, InspectorCollection, VaultInfo, RecordPage } from '@noy-db/in-devtools'
81
- import type { Vault } from '@noy-db/hub'
82
+ import type { Vault, VaultMeta } from '@noy-db/hub'
82
83
  import type { MeterSnapshot } from '@noy-db/to-meter'
83
84
  import VaultSidebar from './panes/VaultSidebar.vue'
84
85
  import SchemaPane from './panes/SchemaPane.vue'
@@ -101,6 +102,7 @@ const vaults = ref<ReadonlyArray<VaultInfo>>([])
101
102
  const vaultInfo = computed(() => vaults.value[0] ?? null)
102
103
  const openVault = ref<Vault | null>(null)
103
104
  const collections = ref<ReadonlyArray<InspectorCollection>>([])
105
+ const snapshotMeta = ref<VaultMeta | null>(null)
104
106
  const snapshotError = ref<string | undefined>(undefined)
105
107
  const selectedCollection = ref<InspectorCollection | null>(null)
106
108
 
@@ -148,6 +150,7 @@ async function loadSnapshot() {
148
150
  try {
149
151
  const snap = await inspector.value.snapshot(openVault.value)
150
152
  collections.value = snap.collections
153
+ snapshotMeta.value = snap.meta ?? null
151
154
  selectedCollection.value = snap.collections[0] ?? null
152
155
  snapshotError.value = undefined
153
156
  } catch (e) {
@@ -12,6 +12,12 @@
12
12
  <button :disabled="!canPrev" @click="$emit('prev')">◀ prev</button>
13
13
  <button :disabled="!canNext" @click="$emit('next')">next ▶</button>
14
14
  </div>
15
+ <button
16
+ v-if="hasSensitiveFields"
17
+ class="noydb-records__reveal-all"
18
+ data-reveal-all
19
+ @click="revealAll = !revealAll"
20
+ >{{ revealAll ? 'hide all' : 'reveal all' }}</button>
15
21
  </div>
16
22
  <template v-if="page && fields.length > 0">
17
23
  <div class="noydb-records__cols">
@@ -19,14 +25,22 @@
19
25
  </div>
20
26
  <div v-if="page.rows.length === 0" class="noydb-records__empty">No records</div>
21
27
  <div v-for="(row, i) in page.rows" :key="i" class="noydb-records__row">
22
- <span v-for="f in fields" :key="f">{{ cell(row, f) }}</span>
28
+ <span v-for="f in fields" :key="f">
29
+ <template v-if="isVisible(f)">{{ cell(row, f) }}</template>
30
+ <button
31
+ v-else
32
+ class="noydb-records__mask"
33
+ :data-reveal="f"
34
+ @click="reveal(f)"
35
+ >••••</button>
36
+ </span>
23
37
  </div>
24
38
  </template>
25
39
  </div>
26
40
  </template>
27
41
 
28
42
  <script setup lang="ts">
29
- import { computed } from 'vue'
43
+ import { computed, ref, watch } from 'vue'
30
44
  import type { InspectorCollection, RecordPage } from '@noy-db/in-devtools'
31
45
 
32
46
  const props = defineProps<{
@@ -42,6 +56,43 @@ const fields = computed(() => Object.keys(props.collection.fields))
42
56
  const canPrev = computed(() => !!props.page && props.page.offset > 0)
43
57
  const canNext = computed(() => !!props.page && props.page.offset + props.page.limit < props.page.total)
44
58
 
59
+ // ── PII masking ────────────────────────────────────────────────────────────
60
+
61
+ /** Set of field keys that are sensitive (pii or secret) per collection.described. */
62
+ const sensitiveFields = computed((): Set<string> => {
63
+ const described = props.collection.described
64
+ if (!described) return new Set()
65
+ const s = new Set<string>()
66
+ for (const d of described) {
67
+ if (d.sensitivity !== undefined && d.sensitivity !== 'public') {
68
+ s.add(d.key)
69
+ }
70
+ }
71
+ return s
72
+ })
73
+
74
+ const hasSensitiveFields = computed(() => sensitiveFields.value.size > 0)
75
+
76
+ /** Tracks which individual fields the user has revealed. */
77
+ const revealed = ref(new Set<string>())
78
+
79
+ /** When true, all sensitive fields are shown. */
80
+ const revealAll = ref(false)
81
+
82
+ // Reset reveal state when the viewed collection changes (prevent PII from one
83
+ // collection lingering when the user navigates to another).
84
+ watch(() => props.collection, () => { revealed.value = new Set(); revealAll.value = false })
85
+
86
+ function isVisible(field: string): boolean {
87
+ if (!sensitiveFields.value.has(field)) return true
88
+ if (revealAll.value) return true
89
+ return revealed.value.has(field)
90
+ }
91
+
92
+ function reveal(field: string): void {
93
+ revealed.value = new Set([...revealed.value, field])
94
+ }
95
+
45
96
  function cell(row: unknown, field: string): string {
46
97
  if (row === null || row === undefined || typeof row !== 'object') return '·'
47
98
  const val = (row as Record<string, unknown>)[field]
@@ -1,16 +1,70 @@
1
1
  <template>
2
2
  <div class="noydb-schema">
3
3
  <template v-if="collection">
4
- <div class="noydb-schema__label">Fields</div>
5
- <div
6
- v-for="[name, field] in fieldEntries"
7
- :key="name"
8
- class="noydb-schema__row"
9
- >
10
- <span class="noydb-schema__name">{{ name }}</span>
11
- <span class="noydb-schema__type">{{ (field as { type?: string }).type ?? '—' }}</span>
12
- <span class="noydb-schema__flag">{{ isIndexed(name) ? 'idx' : '' }}</span>
4
+ <!-- Collection meta header -->
5
+ <div class="noydb-schema__meta-header">
6
+ <span class="noydb-schema__meta-label">{{ collectionLabel }}</span>
7
+ <span
8
+ v-if="collection.meta?.description"
9
+ class="noydb-schema__meta-desc"
10
+ :title="collection.meta.description"
11
+ >{{ collection.meta.description }}</span>
13
12
  </div>
13
+
14
+ <!-- Config strip (badges for active config options) -->
15
+ <div v-if="configBadges.length" class="noydb-schema__config-strip">
16
+ <span
17
+ v-for="badge in configBadges"
18
+ :key="badge"
19
+ class="noydb-schema__config-badge"
20
+ >{{ badge }}</span>
21
+ </div>
22
+
23
+ <div class="noydb-schema__label noydb-schema__label--mt">Fields</div>
24
+
25
+ <!-- Rich rows from described (when present) -->
26
+ <template v-if="collection.described && collection.described.length">
27
+ <div
28
+ v-for="field in collection.described"
29
+ :key="field.key"
30
+ class="noydb-schema__row"
31
+ >
32
+ <span class="noydb-schema__name">{{ field.label }}</span>
33
+ <span class="noydb-schema__name noydb-schema__name--key" :title="field.key">{{ field.key }}</span>
34
+ <span class="noydb-schema__type">{{ field.type }}</span>
35
+ <span v-if="field.semanticType || field.widget" class="noydb-schema__badge noydb-schema__badge--semantic">
36
+ {{ field.semanticType ?? field.widget }}
37
+ </span>
38
+ <span v-if="field.money?.currency" class="noydb-schema__badge noydb-schema__badge--money">
39
+ {{ field.money.currency }}
40
+ </span>
41
+ <span v-if="field.dict" class="noydb-schema__badge noydb-schema__badge--dict">
42
+ dict{{ field.dict.values ? ` ×${field.dict.values.length}` : '' }}
43
+ </span>
44
+ <span v-if="field.sensitivity === 'pii'" class="noydb-schema__badge noydb-schema__badge--pii">pii</span>
45
+ <span v-if="field.sensitivity === 'secret'" class="noydb-schema__badge noydb-schema__badge--secret">secret</span>
46
+ <span v-if="field.i18n" class="noydb-schema__badge noydb-schema__badge--i18n">i18n</span>
47
+ <span v-if="field.ref" class="noydb-schema__badge noydb-schema__badge--ref" :title="`→ ${field.ref.target}`">
48
+ → {{ field.ref.target }}
49
+ </span>
50
+ <span v-if="!field.editable" class="noydb-schema__badge noydb-schema__badge--readonly">read-only</span>
51
+ <span class="noydb-schema__flag">{{ isIndexed(field.key) ? 'idx' : '' }}</span>
52
+ </div>
53
+ </template>
54
+
55
+ <!-- Fallback rows from fields (back-compat) -->
56
+ <template v-else>
57
+ <div
58
+ v-for="[name, field] in fieldEntries"
59
+ :key="name"
60
+ class="noydb-schema__row"
61
+ >
62
+ <span class="noydb-schema__name">{{ name }}</span>
63
+ <span class="noydb-schema__type">{{ (field as { type?: string }).type ?? '—' }}</span>
64
+ <span class="noydb-schema__flag">{{ isIndexed(name) ? 'idx' : '' }}</span>
65
+ </div>
66
+ </template>
67
+
14
68
  <div class="noydb-schema__label noydb-schema__label--mt">Stats</div>
15
69
  <div class="noydb-schema__stat">
16
70
  docs <strong>{{ collection.stats?.count ?? '—' }}</strong>
@@ -28,10 +82,31 @@ import type { InspectorCollection } from '@noy-db/in-devtools'
28
82
 
29
83
  const props = defineProps<{ collection: InspectorCollection | null }>()
30
84
 
85
+ const collectionLabel = computed(() =>
86
+ props.collection?.meta?.label ?? props.collection?.name ?? ''
87
+ )
88
+
31
89
  const fieldEntries = computed(() =>
32
90
  props.collection ? Object.entries(props.collection.fields) : []
33
91
  )
34
92
 
93
+ /** Build small text badges for whichever config options are active. */
94
+ const configBadges = computed((): string[] => {
95
+ const cfg = props.collection?.config
96
+ if (!cfg) return []
97
+ const badges: string[] = []
98
+ if (cfg.embeddings) badges.push('embeddings')
99
+ if (cfg.textIndexes && cfg.textIndexes.length) badges.push('text-index')
100
+ if (cfg.crdt) badges.push(`crdt:${cfg.crdt}`)
101
+ if (cfg.provenance) badges.push('provenance')
102
+ if (cfg.archive) badges.push('archive')
103
+ if (cfg.tiers && cfg.tiers.length) badges.push(`tiers:${cfg.tiers.length}`)
104
+ if (cfg.perRecordKeys) badges.push('per-record-keys')
105
+ if (cfg.history) badges.push('history')
106
+ if (cfg.schemaUpdate && cfg.schemaUpdate.length) badges.push('schema-update')
107
+ return badges
108
+ })
109
+
35
110
  function isIndexed(name: string): boolean {
36
111
  return props.collection?.indexes?.some((idx) => {
37
112
  const fields = (idx as { fields?: string | string[] }).fields
@@ -2,14 +2,17 @@
2
2
  <aside class="noydb-sidebar">
3
3
  <div class="noydb-sidebar__header">Vault</div>
4
4
  <template v-if="vaultName">
5
- <div class="noydb-sidebar__vault">▸ {{ vaultName }}</div>
5
+ <div
6
+ class="noydb-sidebar__vault"
7
+ :title="vaultMeta?.description ?? vaultName ?? undefined"
8
+ >▸ {{ vaultMeta?.label ?? vaultName }}</div>
6
9
  <button
7
10
  v-for="coll in collections"
8
11
  :key="coll.name"
9
12
  :class="['noydb-sidebar__item', { 'noydb-sidebar__item--selected': coll.name === selectedName }]"
10
13
  @click="$emit('select', coll)"
11
14
  >
12
- <span>{{ coll.name }}</span>
15
+ <span>{{ coll.meta?.label ?? coll.name }}</span>
13
16
  <span v-if="coll.stats?.count" class="noydb-sidebar__badge">{{ coll.stats.count }}</span>
14
17
  </button>
15
18
  </template>
@@ -19,9 +22,11 @@
19
22
 
20
23
  <script setup lang="ts">
21
24
  import type { InspectorCollection } from '@noy-db/in-devtools'
25
+ import type { VaultMeta } from '@noy-db/hub'
22
26
 
23
27
  defineProps<{
24
28
  vaultName: string | null
29
+ vaultMeta?: VaultMeta | null
25
30
  collections: ReadonlyArray<InspectorCollection>
26
31
  selectedName: string | null
27
32
  }>()
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@noy-db/in-nuxt",
3
- "version": "0.2.0-pre.29",
3
+ "version": "0.2.0-pre.30",
4
4
  "description": "Nuxt 4 module for noy-db — auto-imports, SSR-safe runtime plugin, and the @noy-db/in-pinia bridge",
5
5
  "license": "MIT",
6
6
  "author": "vLannaAi <vicio@lanna.ai>",
@@ -34,10 +34,10 @@
34
34
  },
35
35
  "peerDependencies": {
36
36
  "nuxt": "^4.0.0",
37
- "@noy-db/hub": "0.2.0-pre.29",
38
- "@noy-db/in-pinia": "0.2.0-pre.29",
39
- "@noy-db/in-rest": "0.2.0-pre.29",
40
- "@noy-db/in-vue": "0.2.0-pre.29"
37
+ "@noy-db/hub": "0.2.0-pre.30",
38
+ "@noy-db/in-rest": "0.2.0-pre.30",
39
+ "@noy-db/in-vue": "0.2.0-pre.30",
40
+ "@noy-db/in-pinia": "0.2.0-pre.30"
41
41
  },
42
42
  "peerDependenciesMeta": {
43
43
  "@noy-db/in-rest": {
@@ -45,7 +45,7 @@
45
45
  }
46
46
  },
47
47
  "dependencies": {
48
- "@noy-db/in-devtools": "0.2.0-pre.29"
48
+ "@noy-db/in-devtools": "0.2.0-pre.30"
49
49
  },
50
50
  "devDependencies": {
51
51
  "@nuxt/kit": "^4.4.2",
@@ -56,10 +56,10 @@
56
56
  "happy-dom": "^17.4.4",
57
57
  "nuxt": "^4.4.2",
58
58
  "vue": "^3.5.32",
59
- "@noy-db/in-pinia": "0.2.0-pre.29",
60
- "@noy-db/in-rest": "0.2.0-pre.29",
61
- "@noy-db/hub": "0.2.0-pre.29",
62
- "@noy-db/in-vue": "0.2.0-pre.29"
59
+ "@noy-db/hub": "0.2.0-pre.30",
60
+ "@noy-db/in-rest": "0.2.0-pre.30",
61
+ "@noy-db/in-pinia": "0.2.0-pre.30",
62
+ "@noy-db/in-vue": "0.2.0-pre.30"
63
63
  },
64
64
  "keywords": [
65
65
  "noy-db",