@conduction/nextcloud-vue 0.1.0-beta.5 → 0.1.0-beta.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@conduction/nextcloud-vue",
3
- "version": "0.1.0-beta.5",
3
+ "version": "0.1.0-beta.6",
4
4
  "description": "Shared Vue component library for Conduction Nextcloud apps — complements @nextcloud/vue with higher-level components, OpenRegister integration, and NL Design System support",
5
5
  "license": "EUPL-1.2",
6
6
  "author": "Conduction B.V. <info@conduction.nl>",
@@ -40,12 +40,14 @@
40
40
  "bootstrap-vue": "^2.23.1",
41
41
  "pinia": "^2.0.0",
42
42
  "vue": "^2.7.0",
43
- "vue-material-design-icons": "^5.0.0",
44
- "vue-frag": "^1.4.3"
43
+ "vue-frag": "^1.4.3",
44
+ "vue-material-design-icons": "^5.0.0"
45
45
  },
46
46
  "devDependencies": {
47
47
  "@babel/core": "^7.29.0",
48
+ "@babel/plugin-transform-typescript": "^7.28.6",
48
49
  "@babel/preset-env": "^7.29.0",
50
+ "@babel/preset-typescript": "^7.28.5",
49
51
  "@eslint/config-helpers": "^0.4.2",
50
52
  "@eslint/eslintrc": "^3.3.4",
51
53
  "@eslint/js": "^9.39.3",
@@ -54,6 +56,7 @@
54
56
  "@nextcloud/vue": "^8.12.0",
55
57
  "@rollup/plugin-commonjs": "^25.0.0",
56
58
  "@rollup/plugin-node-resolve": "^15.0.0",
59
+ "@semantic-release/git": "^10.0.1",
57
60
  "@vue/test-utils": "^1.3.6",
58
61
  "@vue/vue2-jest": "^29.2.6",
59
62
  "babel-jest": "^29.7.0",
@@ -74,9 +77,8 @@
74
77
  "rollup-plugin-vue": "^5.1.9",
75
78
  "stylelint": "^14.16.1",
76
79
  "stylelint-config-recommended": "^9.0.0",
77
- "@semantic-release/git": "^10.0.1",
78
80
  "stylelint-config-recommended-vue": "^1.5.0",
79
81
  "vue": "^2.7.16",
80
82
  "vue-material-design-icons": "^5.2.0"
81
83
  }
82
- }
84
+ }
@@ -14,7 +14,7 @@
14
14
  <div class="cn-object-card__content">
15
15
  <!-- Header: image + title -->
16
16
  <div class="cn-object-card__header">
17
- <img
17
+ <img
18
18
  v-if="imageUrl"
19
19
  :src="imageUrl"
20
20
  :alt="title"
@@ -37,7 +37,7 @@
37
37
  <div v-if="metadataFields.length > 0" class="cn-object-card__metadata">
38
38
  <slot name="metadata" :object="object" :fields="metadataFields">
39
39
  <div
40
- v-for="field in metadataFields"
40
+ v-for="field in metadataFields"
41
41
  :key="field.key"
42
42
  class="cn-object-card__meta-item">
43
43
  <span class="cn-object-card__meta-label">{{ field.label }}</span>
@@ -0,0 +1,235 @@
1
+ # ESLint Setup — How Red Lines and Auto-fix Work
2
+
3
+ Exact files, exact settings, no guessing. This is the working setup in OpenRegister.
4
+
5
+ ---
6
+
7
+ ## Required VSCode Extension
8
+
9
+ **`dbaeumer.vscode-eslint`** (version 3.0.24)
10
+
11
+ This is the only extension involved in linting and formatting `.vue` and `.js` files. It does two things:
12
+ 1. Runs ESLint in the background and draws red/yellow underlines (diagnostics)
13
+ 2. Acts as the formatter — fixes the code when you save
14
+
15
+ ---
16
+
17
+ ## The 6 Files That Matter
18
+
19
+ ### 1. `.vscode/settings.json`
20
+
21
+ Tells VSCode to use ESLint as the formatter for all files (including `.vue`) and to run it on save.
22
+
23
+ ```json
24
+ {
25
+ "editor.defaultFormatter": "dbaeumer.vscode-eslint",
26
+ "editor.formatOnSave": true,
27
+ "eslint.format.enable": true,
28
+
29
+ "[javascript]": {
30
+ "editor.defaultFormatter": "dbaeumer.vscode-eslint"
31
+ },
32
+ "[css]": {
33
+ "editor.defaultFormatter": "esbenp.prettier-vscode"
34
+ },
35
+ "[php]": {
36
+ "editor.defaultFormatter": "DEVSENSE.phptools-vscode"
37
+ }
38
+ }
39
+ ```
40
+
41
+ - No `[vue]` block exists. Vue falls back to the top-level `editor.defaultFormatter` = ESLint.
42
+ - `eslint.format.enable: true` is what makes ESLint able to **fix** on save, not just show errors.
43
+ - `editor.formatOnSave: true` triggers that fix every Ctrl+S.
44
+
45
+ ---
46
+
47
+ ### 2. `eslint.config.js`
48
+
49
+ The ESLint flat config entry point. The extension finds this automatically at the project root.
50
+
51
+ ```js
52
+ const { defineConfig } = require('@eslint/config-helpers')
53
+ const js = require('@eslint/js')
54
+ const { FlatCompat } = require('@eslint/eslintrc')
55
+
56
+ const compat = new FlatCompat({
57
+ baseDirectory: __dirname,
58
+ recommendedConfig: js.configs.recommended,
59
+ allConfig: js.configs.all,
60
+ })
61
+
62
+ module.exports = defineConfig([{
63
+ extends: compat.extends('@nextcloud'),
64
+
65
+ settings: {
66
+ 'import/resolver': {
67
+ alias: {
68
+ map: [
69
+ ['@', './src'],
70
+ ['@floating-ui/dom-actual', './node_modules/@floating-ui/dom'],
71
+ ['@conduction/nextcloud-vue', '../nextcloud-vue/src'],
72
+ ],
73
+ extensions: ['.js', '.ts', '.vue', '.json', '.css'],
74
+ },
75
+ },
76
+ },
77
+
78
+ rules: {
79
+ 'no-unused-vars': ['error', { varsIgnorePattern: '^(t|n)$', argsIgnorePattern: '^_' }],
80
+ 'jsdoc/require-jsdoc': 'off',
81
+ 'vue/first-attribute-linebreak': 'off',
82
+ '@typescript-eslint/no-explicit-any': 'off',
83
+ 'n/no-missing-import': 'off',
84
+ 'import/namespace': 'off',
85
+ 'import/default': 'off',
86
+ 'import/no-named-as-default': 'off',
87
+ 'import/no-named-as-default-member': 'off',
88
+ },
89
+ }])
90
+ ```
91
+
92
+ - Uses **flat config** format (ESLint 8.57.0).
93
+ - Uses `FlatCompat` to bridge `@nextcloud/eslint-config` which is still in legacy format.
94
+ - Works with `require()` because `package.json` has **no** `"type": "module"`.
95
+
96
+ ---
97
+
98
+ ### 3. `.babelrc`
99
+
100
+ The Babel config used by `@babel/eslint-parser` to parse `.js` and `.vue` `<script>` blocks. This is a **project-root** `.babelrc` file, not a `babel.config.js`.
101
+
102
+ ```json
103
+ {
104
+ "presets": [
105
+ "@babel/preset-env",
106
+ "@babel/preset-typescript"
107
+ ],
108
+ "plugins": [
109
+ "@babel/plugin-transform-typescript"
110
+ ]
111
+ }
112
+ ```
113
+
114
+ - `@babel/preset-env` — handles modern JS syntax without a `targets` restriction, so it supports ES module syntax (`export default`, `import`, etc.).
115
+ - `@babel/preset-typescript` + `@babel/plugin-transform-typescript` — allows TypeScript syntax in `.vue` `<script lang="ts">` blocks.
116
+ - No `"type": "module"` in `package.json` means this `.babelrc` is loaded as JSON without any module format issues.
117
+
118
+ ---
119
+
120
+ ### 4. `node_modules/@nextcloud/eslint-config/index.js` (v8.4.1)
121
+
122
+ Loaded by `compat.extends('@nextcloud')`. Combines three parts:
123
+
124
+ ```js
125
+ module.exports = {
126
+ ...base, // parts/base.js
127
+ overrides: [
128
+ { ...typescriptOverrides }, // parts/typescript.js
129
+ { ...vueOverrides }, // parts/vue.js
130
+ ],
131
+ }
132
+ ```
133
+
134
+ ---
135
+
136
+ ### 5. `node_modules/@nextcloud/eslint-config/parts/base.js`
137
+
138
+ Applies to all files. Contains the indent rules that cause **red lines in `<script>` blocks**.
139
+
140
+ ```js
141
+ parser: '@babel/eslint-parser',
142
+ parserOptions: {
143
+ requireConfigFile: false, // won't crash if no babel config — but .babelrc IS present and IS used
144
+ },
145
+
146
+ rules: {
147
+ indent: ['error', 'tab'], // red line: spaces used instead of tabs
148
+ 'no-tabs': ['error', { allowIndentationTabs: true }], // red line: tabs used outside indentation
149
+ 'no-mixed-spaces-and-tabs': ['error', 'smart-tabs'], // red line: mixed
150
+ ...
151
+ }
152
+ ```
153
+
154
+ `'error'` = **red underline**. `'warn'` = yellow. Auto-fix on save corrects all of these.
155
+
156
+ ---
157
+
158
+ ### 6. `node_modules/@nextcloud/eslint-config/parts/vue.js`
159
+
160
+ Applies **only** to `**/*.vue` files. Contains the indent rule that causes **red lines in `<template>` blocks**.
161
+
162
+ ```js
163
+ files: ['**/*.vue'],
164
+ parser: 'vue-eslint-parser', // parses the full .vue file structure
165
+ parserOptions: {
166
+ parser: '@babel/eslint-parser', // delegates <script> parsing to Babel (picks up .babelrc)
167
+ },
168
+ extends: ['plugin:vue/recommended'],
169
+
170
+ rules: {
171
+ 'vue/html-indent': ['error', 'tab'], // red line: wrong indentation in <template>
172
+ 'vue/component-name-in-template-casing': ['error', 'PascalCase'],
173
+ 'vue/html-closing-bracket-spacing': 'error',
174
+ 'vue/html-closing-bracket-newline': ['error', { multiline: 'never' }],
175
+ 'vue/max-attributes-per-line': ['error', { singleline: 3, multiline: 1 }],
176
+ 'vue/multi-word-component-names': ['off'],
177
+ ...
178
+ }
179
+ ```
180
+
181
+ - `vue-eslint-parser` is what lets ESLint understand `<template>`, `<script>`, `<style>` as separate blocks.
182
+ - `vue/html-indent: ['error', 'tab']` → red line on wrong indentation inside `<template>`.
183
+ - `indent: ['error', 'tab']` from base.js → red line on wrong indentation inside `<script>`.
184
+
185
+ ---
186
+
187
+ ## The Full Chain
188
+
189
+ ```
190
+ You open a .vue file in VSCode
191
+
192
+
193
+ dbaeumer.vscode-eslint extension starts
194
+ reads .vscode/settings.json
195
+ → editor.defaultFormatter = ESLint for .vue (no [vue] override, falls back to global)
196
+ → eslint.format.enable = true (ESLint can fix, not just report)
197
+
198
+
199
+ ESLint loads eslint.config.js
200
+ → FlatCompat bridges @nextcloud/eslint-config (legacy → flat)
201
+ → index.js loads base.js + vue.js
202
+
203
+
204
+ For <template> block:
205
+ vue-eslint-parser handles the HTML
206
+ Rule: vue/html-indent ['error', 'tab']
207
+ Wrong indent → RED UNDERLINE
208
+
209
+ For <script> block:
210
+ @babel/eslint-parser handles the JS
211
+ Picks up .babelrc (preset-env + preset-typescript)
212
+ Rule: indent ['error', 'tab']
213
+ Wrong indent → RED UNDERLINE
214
+
215
+
216
+ You press Ctrl+S
217
+ editor.formatOnSave triggers ESLint formatter
218
+ ESLint runs --fix internally
219
+ → replaces wrong indentation with tabs in both blocks
220
+ → fixes bracket spacing, trailing commas, etc.
221
+ File saved with corrected formatting
222
+ ```
223
+
224
+ ---
225
+
226
+ ## Key Reason This Works and nextcloud-vue Does Not
227
+
228
+ | | OpenRegister | nextcloud-vue |
229
+ |---|---|---|
230
+ | `package.json` `"type"` field | not set (defaults to CommonJS) | `"type": "module"` |
231
+ | `eslint.config.js` uses `require()` | works fine | **crashes** — `require` not defined in ES module scope |
232
+ | Babel config file | `.babelrc` (JSON, no module issues) | `babel.config.js` (treated as ESM, crashes Babel sync load) |
233
+ | ESLint server in VSCode | starts, lints, shows red lines | hangs on startup, times out, shows nothing |
234
+
235
+ The fix for nextcloud-vue is to rename both files to `.cjs` so Node treats them as CommonJS regardless of `"type": "module"`, and ensure `babel.config.cjs` uses `module.exports` (not `export default`) with `sourceType: 'unambiguous'` at the top level.
@@ -0,0 +1,132 @@
1
+ {
2
+ "name": "openregister",
3
+ "version": "1.0.0",
4
+ "license": "EUPL-1.2",
5
+ "engines": {
6
+ "node": "^20.0.0",
7
+ "npm": "^10.0.0"
8
+ },
9
+ "scripts": {
10
+ "build": "webpack --config webpack.config.js --progress --mode production",
11
+ "dev": "NODE_ENV=development webpack --config webpack.config.js --progress",
12
+ "watch": "NODE_ENV=development webpack --config webpack.config.js --progress --watch",
13
+ "lint": "eslint src",
14
+ "lint-fix": "npm run lint -- --fix",
15
+ "test": "jest --silent",
16
+ "test-coverage": "jest --silent --coverage",
17
+ "stylelint": "stylelint src/**/*.vue src/**/*.scss src/**/*.css",
18
+ "validate-oas": "spectral lint oas-*.json --fail-severity error",
19
+ "download-oas": "scripts/download-oas.sh"
20
+ },
21
+ "browserslist": ["extends @nextcloud/browserslist-config"],
22
+ "sideEffects": true,
23
+ "peerDependencies": {
24
+ "vue": "^2.6 || ^3.0",
25
+ "vue-frag": "^1.0.0"
26
+ },
27
+ "peerDependenciesMeta": {
28
+ "vue-frag": {
29
+ "optional": true
30
+ }
31
+ },
32
+ "dependencies": {
33
+ "@codemirror/lang-json": "^6.0.1",
34
+ "@conduction/nextcloud-vue": "0.1.0-beta.5",
35
+ "@fortawesome/fontawesome-svg-core": "^6.5.2",
36
+ "@fortawesome/free-solid-svg-icons": "^6.5.2",
37
+ "@nextcloud/axios": "^2.5.0",
38
+ "@nextcloud/dialogs": "^6.1.1",
39
+ "@nextcloud/initial-state": "^2.2.0",
40
+ "@nextcloud/l10n": "^3.2.0",
41
+ "@nextcloud/router": "^3.0.0",
42
+ "@nextcloud/vue": "^8.16.0",
43
+ "@vueuse/core": "^10.7.2",
44
+ "apexcharts": "^3.45.0",
45
+ "axios": "^1.7.3",
46
+ "bootstrap": "^5.3.2",
47
+ "bootstrap-vue": "^2.23.1",
48
+ "css-loader": "^6.8.1",
49
+ "lodash": "^4.17.21",
50
+ "marked": "^16.4.0",
51
+ "pinia": "^2.1.7",
52
+ "remark-cli": "^11.0.0",
53
+ "remark-lint-list-item-indent": "^3.1.1",
54
+ "remark-preset-lint-consistent": "^5.1.1",
55
+ "remark-preset-lint-recommended": "^6.1.2",
56
+ "style-loader": "^3.3.3",
57
+ "vue": "^2.7.16",
58
+ "vue-apexcharts": "^1.6.2",
59
+ "vue-codemirror6": "^1.1.5",
60
+ "vue-draggable-plus": "^0.2.6",
61
+ "vue-frag": "^1.4.3",
62
+ "vue-loader": "^15.11.1",
63
+ "vue-loading-overlay": "^6.0.3",
64
+ "vue-material-design-icons": "^5.2.0",
65
+ "vue-template-compiler": "^2.7.16",
66
+ "zod": "^3.22.4"
67
+ },
68
+ "devDependencies": {
69
+ "@babel/core": "^7.23.9",
70
+ "@babel/plugin-transform-typescript": "^7.26.8",
71
+ "@babel/preset-env": "^7.23.9",
72
+ "@babel/preset-typescript": "^7.26.0",
73
+ "@babel/traverse": "^7.23.9",
74
+ "@cyclonedx/cyclonedx-npm": "^4.2.1",
75
+ "@eslint/config-helpers": "^0.4.2",
76
+ "@eslint/eslintrc": "^3.3.1",
77
+ "@eslint/js": "^9.39.1",
78
+ "@nextcloud/browserslist-config": "^2.3.0",
79
+ "@nextcloud/eslint-config": "^8.4.1",
80
+ "@nextcloud/stylelint-config": "^2.4.0",
81
+ "@nextcloud/webpack-vue-config": "^5.5.0",
82
+ "@pinia/testing": "^0.1.3",
83
+ "@stoplight/spectral-cli": "^6.15.0",
84
+ "@types/jest": "^29.5.12",
85
+ "@types/node": "^20.17.23",
86
+ "@vue/test-utils": "^2.4.4",
87
+ "@vue/vue2-jest": "^29.2.6",
88
+ "babel-jest": "^29.7.0",
89
+ "babel-loader": "^9.1.3",
90
+ "eslint": "^8.56.0",
91
+ "eslint-import-resolver-alias": "^1.1.2",
92
+ "eslint-plugin-import": "^2.29.1",
93
+ "eslint-plugin-n": "^16.6.2",
94
+ "eslint-plugin-promise": "^6.1.1",
95
+ "eslint-plugin-vue": "^9.21.1",
96
+ "eslint-webpack-plugin": "^4.0.1",
97
+ "jest": "^29.7.0",
98
+ "jest-environment-jsdom": "^29.7.0",
99
+ "jest-transform-stub": "^2.0.0",
100
+ "postcss": "^8.4.31",
101
+ "stylelint": "^15.11.0",
102
+ "stylelint-webpack-plugin": "^4.1.1",
103
+ "ts-jest": "^29.1.2",
104
+ "ts-loader": "^9.5.1",
105
+ "typescript": "^5.8.2",
106
+ "vue-router": "^3.6.5"
107
+ },
108
+ "overrides": {
109
+ "vue": "^2.7.16",
110
+ "@nextcloud/vue": "^8.16.0",
111
+ "stylelint": "^15.11.0",
112
+ "eslint": "^8.56.0",
113
+ "postcss": "^8.4.31",
114
+ "json5": "^2.2.3",
115
+ "@babel/traverse": "^7.23.9",
116
+ "babel-jest": "^29.7.0",
117
+ "vue-template-compiler": "^2.7.16",
118
+ "@vue/test-utils": "^2.4.4",
119
+ "bootstrap": "^5.3.2",
120
+ "vue-demi": "^0.14.6",
121
+ "minimatch": ">=3.1.5",
122
+ "rollup": ">=2.80.0"
123
+ },
124
+ "resolutions": {
125
+ "postcss": "^8.4.31",
126
+ "json5": "^2.2.3",
127
+ "@babel/traverse": "^7.23.9",
128
+ "vue-template-compiler": "^2.7.16",
129
+ "bootstrap": "^5.3.2",
130
+ "vue-demi": "^0.14.6"
131
+ }
132
+ }
@@ -39,8 +39,8 @@ export function buildHeaders(contentType = 'application/json') {
39
39
  /**
40
40
  * Build a query string from a params object.
41
41
  *
42
- * Handles _order serialization (JSON.stringify for objects) and skips
43
- * null/undefined/empty values.
42
+ * Handles array values by appending each item separately, plain object values
43
+ * by JSON-serializing them, and skips null/undefined/empty values.
44
44
  *
45
45
  * @param {object} params Key-value pairs for query parameters
46
46
  * @return {string} Query string including leading '?' or empty string
@@ -50,13 +50,15 @@ export function buildQueryString(params = {}) {
50
50
 
51
51
  for (const [key, value] of Object.entries(params)) {
52
52
  if (value === undefined || value === null || value === '') continue
53
+ if (Array.isArray(value) && value.length === 0) continue
54
+ if (typeof value === 'object' && !Array.isArray(value) && Object.keys(value).length === 0) continue
53
55
  if (Array.isArray(value)) {
54
56
  for (const item of value) {
55
57
  if (item !== undefined && item !== null && item !== '') {
56
58
  queryParams.append(key, String(item))
57
59
  }
58
60
  }
59
- } else if (key === '_order' && typeof value === 'object') {
61
+ } else if (typeof value === 'object') {
60
62
  queryParams.set(key, JSON.stringify(value))
61
63
  } else {
62
64
  queryParams.set(key, String(value))