@conduction/nextcloud-vue 2.2.0-vue3.12 → 2.2.0-vue3.14

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.
@@ -0,0 +1,116 @@
1
+ #!/usr/bin/env node
2
+ // SPDX-License-Identifier: AGPL-3.0-or-later
3
+ //
4
+ // update-fleet-manifest-fixtures.js — refresh the vendored fleet-manifest
5
+ // corpus used by tests/schemas/fleet-manifest-regression.spec.js.
6
+ //
7
+ // Why (2026-07-06 manifest fleet audit, item 15): a schema change in this
8
+ // library can silently invalidate a manifest already deployed in a fleet app
9
+ // — the exact drift the audit chased (installed schema generations spanned
10
+ // beta.30..beta.155). The regression spec validates every deployed manifest
11
+ // against the CURRENT candidate schema on every PR, so a breaking schema
12
+ // change fails HERE, before release, instead of surfacing as install drift.
13
+ //
14
+ // The corpus is a vendored snapshot (CI has no fleet checkout). This script
15
+ // refreshes it from the sibling app checkouts. Run it after a deliberate,
16
+ // reviewed manifest change lands in a fleet app — never to make a failing
17
+ // regression test pass (that would defeat the guard).
18
+ //
19
+ // Usage:
20
+ // node scripts/update-fleet-manifest-fixtures.js [fleet-root]
21
+ // fleet-root — dir whose children are the app checkouts
22
+ // (default: the parent of this library's checkout).
23
+ //
24
+ // Output: writes tests/fixtures/fleet-manifests/<app>.json for every app
25
+ // that ships src/manifest.json, plus an index.json manifest (app -> bytes,
26
+ // $schema, sha256) so the spec can report drift precisely.
27
+
28
+ 'use strict'
29
+
30
+ const fs = require('fs')
31
+ const path = require('path')
32
+ const crypto = require('crypto')
33
+ const { execFileSync } = require('child_process')
34
+
35
+ const REPO_ROOT = path.resolve(__dirname, '..')
36
+ const FLEET_ROOT = process.argv[2]
37
+ ? path.resolve(process.argv[2])
38
+ : path.resolve(REPO_ROOT, '..')
39
+ const OUT_DIR = path.join(REPO_ROOT, 'tests', 'fixtures', 'fleet-manifests')
40
+
41
+ // Non-app sibling dirs that may carry a src/manifest.json but are not fleet
42
+ // apps we want to gate on (this library's own examples, etc.).
43
+ const SKIP = new Set(['nextcloud-vue'])
44
+
45
+ function sha256(buf) {
46
+ return crypto.createHash('sha256').update(buf).digest('hex')
47
+ }
48
+
49
+ function main() {
50
+ if (fs.existsSync(OUT_DIR) === false) {
51
+ fs.mkdirSync(OUT_DIR, { recursive: true })
52
+ }
53
+
54
+ const index = {}
55
+ let written = 0
56
+
57
+ for (const app of fs.readdirSync(FLEET_ROOT).sort()) {
58
+ if (SKIP.has(app)) {
59
+ continue
60
+ }
61
+ const appDir = path.join(FLEET_ROOT, app)
62
+ const manifestPath = path.join(appDir, 'src', 'manifest.json')
63
+ if (fs.existsSync(manifestPath) === false) {
64
+ continue
65
+ }
66
+
67
+ // The corpus must reflect the DEPLOYED manifest — what is merged to the
68
+ // app's integration branch — not whatever a local checkout happens to
69
+ // have on a feature branch. Prefer the committed origin/development (or
70
+ // origin/main) blob; fall back to the working tree only if git can't
71
+ // resolve one (e.g. a shallow CI checkout).
72
+ let raw = null
73
+ for (const ref of ['origin/development', 'origin/main']) {
74
+ try {
75
+ raw = execFileSync('git', ['-C', appDir, 'show', `${ref}:src/manifest.json`], { maxBuffer: 32 * 1024 * 1024 })
76
+ break
77
+ } catch (_) { /* try next ref */ }
78
+ }
79
+ if (raw === null) {
80
+ try {
81
+ raw = fs.readFileSync(manifestPath)
82
+ console.error(` (note: ${app} — no origin/development|main blob, snapshotting working tree)`)
83
+ } catch (_) {
84
+ continue
85
+ }
86
+ }
87
+
88
+ // Validate it is parseable JSON before vendoring — never snapshot
89
+ // a corrupt file into the corpus.
90
+ let parsed
91
+ try {
92
+ parsed = JSON.parse(raw)
93
+ } catch (e) {
94
+ console.error(`SKIP ${app}: manifest.json is not valid JSON (${e.message})`)
95
+ continue
96
+ }
97
+
98
+ const pretty = JSON.stringify(parsed, null, '\t') + '\n'
99
+ fs.writeFileSync(path.join(OUT_DIR, `${app}.json`), pretty)
100
+ index[app] = {
101
+ bytes: Buffer.byteLength(pretty),
102
+ $schema: typeof parsed.$schema === 'string' ? parsed.$schema : null,
103
+ sha256: sha256(pretty),
104
+ }
105
+ written += 1
106
+ console.log(` ${app} (${index[app].bytes} bytes)`)
107
+ }
108
+
109
+ fs.writeFileSync(
110
+ path.join(OUT_DIR, 'index.json'),
111
+ JSON.stringify(index, null, '\t') + '\n',
112
+ )
113
+ console.log(`\nWrote ${written} fleet manifests + index.json to ${path.relative(REPO_ROOT, OUT_DIR)}`)
114
+ }
115
+
116
+ main()
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Vue 3 compile-readiness sweep (ADR-066, openspec vue-3-migration).
3
+ *
4
+ * Compiles every SFC template + script under src/ with @vue/compiler-sfc in
5
+ * @vue/compat MODE 2, and reports which components fail to COMPILE on Vue 3.
6
+ * This is the fastest signal for the migration: compile failures are hard
7
+ * blockers, and this needs no bundle/install of the runtime deps.
8
+ *
9
+ * Requires the Vue 3 toolchain (`npm i -D @vue/compiler-sfc@^3.5`). Run:
10
+ * node scripts/vue3-compile-sweep.cjs (or: npm run check:vue3-compile)
11
+ *
12
+ * Exit code is the number of failing components (0 = all clean).
13
+ *
14
+ * NOTE: a clean sweep does NOT mean runtime-correct. Plain Vue 3 silently
15
+ * mis-compiles `.sync` and `{{x|f}}` (see BUILD-VUE3.md); compat MODE 2 keeps
16
+ * them correct here, but every such site must still be rewritten (tasks 2.2/2.6)
17
+ * before the compat flags come off.
18
+ */
19
+ const fs = require('fs')
20
+ const path = require('path')
21
+
22
+ let sfc
23
+ try {
24
+ sfc = require('@vue/compiler-sfc')
25
+ } catch (e) {
26
+ console.error('[vue3-compile-sweep] @vue/compiler-sfc not found — install the Vue 3 toolchain first (npm i -D @vue/compiler-sfc@^3.5).')
27
+ process.exit(2)
28
+ }
29
+
30
+ const root = path.resolve(__dirname, '..', 'src')
31
+ const compat = { compatConfig: { MODE: 2, COMPILER_FILTERS: true } }
32
+
33
+ function walk(dir, out = []) {
34
+ for (const e of fs.readdirSync(dir, { withFileTypes: true })) {
35
+ const p = path.join(dir, e.name)
36
+ if (e.isDirectory()) walk(p, out)
37
+ else if (e.name.endsWith('.vue')) out.push(p)
38
+ }
39
+ return out
40
+ }
41
+
42
+ const files = walk(root)
43
+ let clean = 0
44
+ const failed = []
45
+
46
+ for (const f of files) {
47
+ const src = fs.readFileSync(f, 'utf8')
48
+ const errs = []
49
+ try {
50
+ const { descriptor, errors } = sfc.parse(src, { filename: f })
51
+ errs.push(...(errors || []).map((e) => 'parse: ' + (e.message || e)))
52
+ if (descriptor.template) {
53
+ const t = sfc.compileTemplate({ source: descriptor.template.content, filename: f, id: 'x', compilerOptions: compat })
54
+ errs.push(...(t.errors || []).map((e) => 'tmpl: ' + (e.message || String(e)).slice(0, 100)))
55
+ }
56
+ if (descriptor.script || descriptor.scriptSetup) {
57
+ try {
58
+ sfc.compileScript(descriptor, { id: 'x', templateOptions: { compilerOptions: compat } })
59
+ } catch (e) {
60
+ errs.push('script: ' + (e.message || String(e)).slice(0, 100))
61
+ }
62
+ }
63
+ } catch (e) {
64
+ errs.push('fatal: ' + (e.message || String(e)).slice(0, 100))
65
+ }
66
+ if (errs.length === 0) clean++
67
+ else failed.push({ f: path.relative(root, f), errs })
68
+ }
69
+
70
+ console.log(`Vue 3 compile sweep (compat MODE 2) — ${files.length} components`)
71
+ console.log(` clean : ${clean}`)
72
+ console.log(` failed: ${failed.length}`)
73
+ if (failed.length) {
74
+ console.log('')
75
+ for (const x of failed) console.log(` ✗ ${x.f}\n ${x.errs[0]}`)
76
+ }
77
+ process.exit(failed.length)
@@ -223,11 +223,24 @@
223
223
  *
224
224
  * `NcSelect` wraps vue-select, whose `.vs__search` is the type-to-filter input
225
225
  * that sits BESIDE the selected value inside one control. Stock vue-select
226
- * gives it no border, but Nextcloud's global `input` styling does — so every
227
- * single-select rendered an empty bordered box to the right of its own value,
228
- * which reads as a second, broken field. Visible on every Provider, Agent and
226
+ * gives it a transparent border; the LA SUITE theme sets
227
+ *
228
+ * input[type="text"], input[type="search"], … {
229
+ * border: 1px solid var(--lasuite-color-gray-300) !important;
230
+ * }
231
+ *
232
+ * which lands on it and draws an empty bordered box to the right of the
233
+ * selected value — a second, broken-looking field on every Provider, Agent and
229
234
  * Execution dropdown in the fleet.
230
235
  *
236
+ * `!important` is REQUIRED here and not laziness: the theme's rule carries it,
237
+ * so no amount of specificity can win. The override is narrow — `.vs__search`
238
+ * is never a standalone input, always the inner field of a composite control —
239
+ * so this cannot reach a real text box the theme meant to style.
240
+ *
241
+ * The root cause is the theme reaching into a composite control it does not
242
+ * own; fixing it there would be better, and this stays until it does.
243
+ *
231
244
  * Unscoped and here rather than in a component, because the control belongs to
232
245
  * @nextcloud/vue: no Conduction component owns the element, and each app
233
246
  * patching it locally is the same rule written sixteen times.
@@ -237,8 +250,8 @@
237
250
  */
238
251
  .v-select .vs__search,
239
252
  .v-select .vs__search:focus {
240
- border: none;
241
- box-shadow: none;
253
+ border: none !important;
254
+ box-shadow: none !important;
242
255
  min-height: unset;
243
256
  background-color: transparent;
244
257
  }