configuration-management 0.1.4 → 0.1.8

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/README.md CHANGED
@@ -82,22 +82,34 @@ async function main (params) {
82
82
  Spectrum-based Commerce Admin extension UI for schema-driven system configuration.
83
83
 
84
84
  ```js
85
+ import React from 'react'
85
86
  import { createRoot } from 'react-dom/client'
86
87
  import {
87
88
  ConfigurationManagementApp,
88
- configureWeb,
89
- SystemConfig
89
+ configureWeb
90
90
  } from 'configuration-management/web'
91
- import actionUrls from './config.json' // deploy-time URLs from aio app deploy
91
+ import actionUrls from './config.json'
92
92
  import 'configuration-management/web/styles.css'
93
93
 
94
94
  configureWeb({ actionUrls })
95
95
 
96
96
  createRoot(document.getElementById('root')).render(
97
- <ConfigurationManagementApp runtime={runtime} ims={ims} />
97
+ React.createElement(ConfigurationManagementApp, { runtime, ims })
98
98
  )
99
99
  ```
100
100
 
101
+ The web UI is **pre-built** in the package. Import the JS entry — styles load automatically:
102
+
103
+ ```js
104
+ import { ConfigurationManagementApp, configureWeb } from 'configuration-management/web'
105
+ ```
106
+
107
+ Or import styles separately:
108
+
109
+ ```js
110
+ import 'configuration-management/web/styles.css'
111
+ ```
112
+
101
113
  | Export | Description |
102
114
  |--------|-------------|
103
115
  | `ConfigurationManagementApp` | Full app shell (router + Spectrum provider + UIX registration) |
@@ -115,7 +127,7 @@ OpenWhisk runtime actions and the Commerce Admin extension manifest ship with th
115
127
  #### Automatic wiring on `npm install`
116
128
 
117
129
  The package runs a **postinstall** script that patches your project's `app.config.yaml`
118
- (if it exists) with:
130
+ (if present) with:
119
131
 
120
132
  ```yaml
121
133
  extensions:
@@ -123,7 +135,8 @@ extensions:
123
135
  $include: node_modules/configuration-management/actions/configurations/ext.config.yaml
124
136
  ```
125
137
 
126
- Requirements:
138
+ It does **not** modify your `web-src/` files. Add the UI to your existing App Builder
139
+ bootstrap manually (see React Admin UI above).
127
140
 
128
141
  - Run `npm install` from your App Builder project root (where `app.config.yaml` lives).
129
142
  - Do not use `npm install --ignore-scripts` (that skips postinstall).
@@ -159,11 +172,10 @@ The bundled `ext.config.yaml` declares all actions under the `ConfigurationManag
159
172
 
160
173
  ```
161
174
  my-app/
162
- ├── app.config.yaml ← $include ext.config from node_modules (above)
175
+ ├── app.config.yaml ← $include ext.config (auto-patched on npm install)
163
176
  ├── web-src/
164
- │ ├── index.html
165
177
  │ └── src/
166
- │ ├── index.js ← import ConfigurationManagementApp + configureWeb
178
+ │ ├── index.js ← your app bootstrap + package imports (see above)
167
179
  │ └── config.json ← generated by aio app deploy
168
180
  ├── .env
169
181
  └── package.json ← depends on configuration-management
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "configuration-management",
3
- "version": "0.1.4",
3
+ "version": "0.1.8",
4
4
  "description": "Schema-driven system configuration for Adobe Commerce App Builder sync apps. Magento-style scoped config in Adobe App Builder Database (ABDB) with encryption, Commerce REST helpers, and React Admin UI.",
5
5
  "license": "Apache-2.0",
6
6
  "author": "Adobe Inc.",
@@ -16,10 +16,12 @@
16
16
  ],
17
17
  "main": "./src/index.js",
18
18
  "bin": {
19
- "configuration-management-setup": "./scripts/setup-app-config.js"
19
+ "configuration-management-setup": "./scripts/setup.js"
20
20
  },
21
21
  "scripts": {
22
- "postinstall": "node ./scripts/setup-app-config.js"
22
+ "build": "node ./scripts/build-web.js",
23
+ "prepublishOnly": "node ./scripts/build-web.js",
24
+ "postinstall": "node ./scripts/build-web.js && node ./scripts/setup.js"
23
25
  },
24
26
  "exports": {
25
27
  ".": "./src/index.js",
@@ -30,7 +32,8 @@
30
32
  "./oauth1a": "./src/oauth1a.js",
31
33
  "./web": "./web/index.js",
32
34
  "./web/index.js": "./web/index.js",
33
- "./web/styles.css": "./web/src/styles/index.css",
35
+ "./web/styles.css": "./web/styles.css",
36
+ "./web/dist/index.css": "./web/dist/index.css",
34
37
  "./web/src/styles/index.css": "./web/src/styles/index.css",
35
38
  "./actions/utils": "./actions/utils.js",
36
39
  "./actions/ext.config.yaml": "./actions/configurations/ext.config.yaml"
@@ -61,6 +64,7 @@
61
64
  "react-router-dom": "^6.8.1"
62
65
  },
63
66
  "dependencies": {
67
+ "esbuild": "^0.25.12",
64
68
  "got": "^11.8.5",
65
69
  "oauth-1.0a": "^2.2.6"
66
70
  },
@@ -0,0 +1,58 @@
1
+ #!/usr/bin/env node
2
+ /*
3
+ Copyright 2025 Adobe. All rights reserved.
4
+ Licensed under the Apache License, Version 2.0
5
+ */
6
+
7
+ const fs = require('fs')
8
+ const path = require('path')
9
+
10
+ async function main () {
11
+ let esbuild
12
+ try {
13
+ esbuild = require('esbuild')
14
+ } catch {
15
+ console.error('[configuration-management] esbuild is required to build the web UI. Run npm install in the package directory.')
16
+ process.exit(1)
17
+ }
18
+
19
+ const pkgRoot = path.join(__dirname, '..')
20
+ const entry = path.join(pkgRoot, 'web/src/index.js')
21
+ const outdir = path.join(pkgRoot, 'web/dist')
22
+ const outfile = path.join(outdir, 'index.js')
23
+ const stylesSrc = path.join(pkgRoot, 'web/src/styles/index.css')
24
+ const stylesFlat = path.join(pkgRoot, 'web/styles.css')
25
+
26
+ fs.mkdirSync(outdir, { recursive: true })
27
+
28
+ await esbuild.build({
29
+ entryPoints: [entry],
30
+ bundle: true,
31
+ format: 'esm',
32
+ platform: 'browser',
33
+ outfile,
34
+ packages: 'external',
35
+ jsx: 'automatic',
36
+ loader: { '.js': 'jsx', '.css': 'css' },
37
+ target: ['chrome79', 'firefox85', 'safari13'],
38
+ logLevel: 'info'
39
+ })
40
+
41
+ // Parcel does not resolve nested @import inside node_modules — ship a flat file.
42
+ fs.copyFileSync(stylesSrc, stylesFlat)
43
+
44
+ console.log('[configuration-management] built web/dist/index.js')
45
+ if (fs.existsSync(path.join(outdir, 'index.css'))) {
46
+ console.log('[configuration-management] built web/dist/index.css')
47
+ }
48
+ console.log('[configuration-management] copied web/styles.css')
49
+ }
50
+
51
+ if (require.main === module) {
52
+ main().catch((err) => {
53
+ console.error('[configuration-management] build-web failed:', err.message)
54
+ process.exit(1)
55
+ })
56
+ }
57
+
58
+ module.exports = { main }
@@ -52,9 +52,6 @@ function buildExtensionBlock () {
52
52
  ].join('\n')
53
53
  }
54
54
 
55
- /**
56
- * Update an existing `commerce/backend-ui/1` block in place (never add a duplicate key).
57
- */
58
55
  function updateExistingExtensionBlock (content) {
59
56
  const match = content.match(/^([ \t]*)commerce\/backend-ui\/1:/m)
60
57
  if (!match) return null
@@ -106,6 +103,22 @@ function patchAppConfig (content) {
106
103
  return { content, changed: false, reason: 'no-change' }
107
104
  }
108
105
 
106
+ function setupAppConfig (projectRoot) {
107
+ const appConfigPath = path.join(projectRoot, 'app.config.yaml')
108
+ if (!fs.existsSync(appConfigPath)) {
109
+ return { changed: false, reason: 'no-app-config' }
110
+ }
111
+
112
+ const original = fs.readFileSync(appConfigPath, 'utf8')
113
+ const { content, changed, reason } = patchAppConfig(original)
114
+ if (!changed) {
115
+ return { changed: false, reason }
116
+ }
117
+
118
+ fs.writeFileSync(appConfigPath, content, 'utf8')
119
+ return { changed: true, reason, detail: INCLUDE_REL }
120
+ }
121
+
109
122
  function main () {
110
123
  if (process.env.CONFIGURATION_MANAGEMENT_SKIP_SETUP === '1') {
111
124
  return
@@ -114,26 +127,22 @@ function main () {
114
127
  const projectRoot = resolveProjectRoot()
115
128
  if (!projectRoot) {
116
129
  console.log(
117
- '[configuration-management] No app.config.yaml found — skip auto-link. ' +
118
- 'Run `npx configuration-management-setup` after creating your App Builder app.'
130
+ '[configuration-management] No App Builder project found — skip setup. ' +
131
+ 'Run `npx configuration-management-setup` from your project root after `aio app init`.'
119
132
  )
120
133
  return
121
134
  }
122
135
 
123
- const appConfigPath = path.join(projectRoot, 'app.config.yaml')
124
- const original = fs.readFileSync(appConfigPath, 'utf8')
125
- const { content, changed, reason } = patchAppConfig(original)
126
-
127
- if (!changed) {
128
- console.log(`[configuration-management] app.config.yaml unchanged (${reason}).`)
136
+ const app = setupAppConfig(projectRoot)
137
+ if (app.changed) {
138
+ console.log(
139
+ `[configuration-management] Updated app.config.yaml (${app.reason}):\n` +
140
+ ` $include: ${app.detail}`
141
+ )
129
142
  return
130
143
  }
131
144
 
132
- fs.writeFileSync(appConfigPath, content, 'utf8')
133
- console.log(
134
- `[configuration-management] Updated app.config.yaml (${reason}):\n` +
135
- ` $include: ${INCLUDE_REL}`
136
- )
145
+ console.log('[configuration-management] app.config.yaml already configured.')
137
146
  }
138
147
 
139
148
  if (require.main === module) {
@@ -147,8 +156,7 @@ if (require.main === module) {
147
156
 
148
157
  module.exports = {
149
158
  patchAppConfig,
159
+ setupAppConfig,
150
160
  INCLUDE_REL,
151
- EXTENSION_POINT,
152
- alreadyLinked,
153
- hasExtensionPoint
161
+ EXTENSION_POINT
154
162
  }
@@ -0,0 +1,294 @@
1
+ /* web/src/styles/index.css */
2
+ :root {
3
+ --sm-color-bg: #f7f8fa;
4
+ --sm-color-surface: #ffffff;
5
+ --sm-color-surface-muted: #f3f4f6;
6
+ --sm-color-surface-subtle: #fafbfc;
7
+ --sm-color-border: #e5e7eb;
8
+ --sm-color-border-strong: #d1d5db;
9
+ --sm-color-text: #111827;
10
+ --sm-color-text-muted: #6b7280;
11
+ --sm-color-text-inverse: #ffffff;
12
+ --sm-color-accent: #1473e6;
13
+ --sm-color-accent-hover: #0f5fc4;
14
+ --sm-color-accent-soft: #e8f1fc;
15
+ --sm-color-success: #22863a;
16
+ --sm-color-success-hover: #1a6e2f;
17
+ --sm-color-success-soft: #ecfdf5;
18
+ --sm-color-warning: #b58105;
19
+ --sm-color-warning-hover: #946c04;
20
+ --sm-color-warning-soft: #fff7ed;
21
+ --sm-color-warning-border: #fde68a;
22
+ --sm-color-warning-text: #92400e;
23
+ --sm-color-warning-tint: #fef3c7;
24
+ --sm-color-danger: #c0392b;
25
+ --sm-color-danger-hover: #a32d20;
26
+ --sm-color-danger-soft: #fef2f2;
27
+ --sm-color-danger-tint: #fee2e2;
28
+ --sm-color-accent-tint: #dbeafe;
29
+ --sm-color-neutral-soft: #eef2f7;
30
+ --sm-color-neutral-text: #374151;
31
+ --sm-color-text-strong: #1f2937;
32
+ --sm-color-text-soft: #475569;
33
+ --sm-color-surface-panel: #f9fafb;
34
+ --sm-color-overlay: rgba(15, 23, 42, 0.45);
35
+ --sm-radius-sm: 4px;
36
+ --sm-radius-md: 8px;
37
+ --sm-radius-lg: 10px;
38
+ --sm-radius-xl: 12px;
39
+ --sm-radius-2xl: 14px;
40
+ --sm-radius-pill: 999px;
41
+ --sm-space-1: 4px;
42
+ --sm-space-2: 8px;
43
+ --sm-space-3: 12px;
44
+ --sm-space-4: 16px;
45
+ --sm-space-5: 20px;
46
+ --sm-space-6: 24px;
47
+ --sm-shadow-xs: 0 1px 2px rgba(15, 23, 42, 0.03);
48
+ --sm-shadow-sm: 0 1px 4px rgba(15, 23, 42, 0.04);
49
+ --sm-shadow-md: 0 1px 3px rgba(15, 23, 42, 0.12), 0 1px 1px rgba(15, 23, 42, 0.06);
50
+ --sm-shadow-pill: 0 1px 3px rgba(15, 23, 42, 0.10), 0 1px 1px rgba(15, 23, 42, 0.06);
51
+ --sm-shadow-floating: 0 4px 14px rgba(15, 23, 42, 0.08);
52
+ --sm-shadow-dropdown: 0 12px 28px rgba(15, 23, 42, 0.16), 0 2px 4px rgba(15, 23, 42, 0.06);
53
+ --sm-shadow-modal: 0 24px 60px rgba(15, 23, 42, 0.25), 0 2px 8px rgba(15, 23, 42, 0.08);
54
+ --sm-shadow-inset: inset 0 1px 2px rgba(15, 23, 42, 0.04);
55
+ --sm-font-family:
56
+ adobe-clean,
57
+ "Source Sans Pro",
58
+ -apple-system,
59
+ BlinkMacSystemFont,
60
+ "Segoe UI",
61
+ Roboto,
62
+ sans-serif;
63
+ --sm-font-mono:
64
+ ui-monospace,
65
+ SFMono-Regular,
66
+ Menlo,
67
+ Consolas,
68
+ monospace;
69
+ --sm-font-size-xs: 11px;
70
+ --sm-font-size-sm: 12px;
71
+ --sm-font-size-md: 13px;
72
+ --sm-font-size-lg: 14px;
73
+ --sm-font-weight-regular: 400;
74
+ --sm-font-weight-medium: 500;
75
+ --sm-font-weight-semibold:600;
76
+ --sm-font-weight-bold: 700;
77
+ --sm-control-height-sm: 28px;
78
+ --sm-control-height-md: 32px;
79
+ --sm-control-height-lg: 40px;
80
+ --sm-control-padding-x: 16px;
81
+ --sm-z-nav: 30;
82
+ --sm-z-sticky: 20;
83
+ --sm-z-modal: 100;
84
+ --spectrum-accent-color-900: var(--sm-color-accent);
85
+ --spectrum-accent-color-1000: var(--sm-color-accent-hover);
86
+ color-scheme: light;
87
+ }
88
+ html,
89
+ body,
90
+ #root {
91
+ margin: 0;
92
+ min-height: 100%;
93
+ background: var(--sm-color-bg);
94
+ color: var(--sm-color-text);
95
+ font-family: var(--sm-font-family);
96
+ }
97
+ .sm-provider {
98
+ background: var(--sm-color-bg);
99
+ min-height: 100vh;
100
+ }
101
+ .sm-card {
102
+ background: var(--sm-color-surface);
103
+ border: 1px solid var(--sm-color-border);
104
+ border-radius: var(--sm-radius-lg);
105
+ box-shadow: var(--sm-shadow-xs);
106
+ padding: var(--sm-space-5);
107
+ }
108
+ .sm-card--flush {
109
+ padding: 0;
110
+ }
111
+ .sm-pill {
112
+ display: inline-flex;
113
+ align-items: center;
114
+ gap: var(--sm-space-1);
115
+ padding: 2px var(--sm-space-2);
116
+ border-radius: var(--sm-radius-pill);
117
+ background: var(--sm-color-neutral-soft);
118
+ color: var(--sm-color-neutral-text);
119
+ font-size: var(--sm-font-size-xs);
120
+ font-weight: var(--sm-font-weight-semibold);
121
+ line-height: 16px;
122
+ letter-spacing: 0.2px;
123
+ white-space: nowrap;
124
+ }
125
+ .sm-pill--accent {
126
+ background: var(--sm-color-accent-soft);
127
+ color: var(--sm-color-accent);
128
+ }
129
+ .sm-pill--success {
130
+ background: var(--sm-color-success-soft);
131
+ color: var(--sm-color-success);
132
+ }
133
+ .sm-pill--warning {
134
+ background: var(--sm-color-warning-soft);
135
+ color: var(--sm-color-warning);
136
+ }
137
+ .sm-pill--danger {
138
+ background: var(--sm-color-danger-soft);
139
+ color: var(--sm-color-danger);
140
+ }
141
+ .sm-tab-bar {
142
+ position: sticky;
143
+ top: 0;
144
+ z-index: var(--sm-z-nav);
145
+ background: var(--sm-color-surface);
146
+ border-bottom: 1px solid var(--sm-color-border);
147
+ padding: 10px var(--sm-space-4);
148
+ box-shadow: var(--sm-shadow-sm);
149
+ box-sizing: border-box;
150
+ max-width: 100%;
151
+ }
152
+ .sm-tab-bar__track {
153
+ display: inline-flex;
154
+ padding: var(--sm-space-1);
155
+ background: var(--sm-color-surface-muted);
156
+ border: 1px solid var(--sm-color-border);
157
+ border-radius: var(--sm-radius-pill);
158
+ box-shadow: var(--sm-shadow-inset);
159
+ gap: 2px;
160
+ font-family: var(--sm-font-family);
161
+ }
162
+ .sm-tab {
163
+ display: inline-flex;
164
+ align-items: center;
165
+ gap: var(--sm-space-2);
166
+ padding: var(--sm-space-2) var(--sm-control-padding-x);
167
+ border: 0;
168
+ border-radius: var(--sm-radius-pill);
169
+ background: transparent;
170
+ color: var(--sm-color-neutral-text);
171
+ font-size: var(--sm-font-size-md);
172
+ font-weight: var(--sm-font-weight-semibold);
173
+ letter-spacing: 0.1px;
174
+ cursor: pointer;
175
+ transition:
176
+ background 140ms ease,
177
+ color 140ms ease,
178
+ box-shadow 140ms ease;
179
+ }
180
+ .sm-tab:hover {
181
+ background: var(--sm-color-surface);
182
+ color: var(--sm-color-text);
183
+ }
184
+ .sm-tab.is-active {
185
+ background: var(--sm-color-surface);
186
+ color: var(--sm-color-accent);
187
+ font-weight: var(--sm-font-weight-bold);
188
+ box-shadow: var(--sm-shadow-pill);
189
+ cursor: default;
190
+ }
191
+ .sm-tab__icon {
192
+ display: inline-flex;
193
+ opacity: 0.75;
194
+ }
195
+ .sm-tab.is-active .sm-tab__icon {
196
+ opacity: 1;
197
+ }
198
+ .sm-textarea textarea {
199
+ height: 160px !important;
200
+ max-height: 160px !important;
201
+ min-height: 160px !important;
202
+ overflow-y: auto !important;
203
+ resize: none !important;
204
+ font-family: var(--sm-font-mono);
205
+ font-size: var(--sm-font-size-sm);
206
+ }
207
+ .sm-note {
208
+ margin-top: var(--sm-space-3);
209
+ padding: var(--sm-space-3);
210
+ border-radius: var(--sm-radius-md);
211
+ background: var(--sm-color-surface-muted);
212
+ border: 1px solid var(--sm-color-border);
213
+ color: var(--sm-color-text);
214
+ font-size: var(--sm-font-size-md);
215
+ white-space: pre-line;
216
+ font-family: var(--sm-font-mono);
217
+ }
218
+ .sm-note--warning {
219
+ background: var(--sm-color-warning-soft);
220
+ border-color: var(--sm-color-warning-border);
221
+ color: var(--sm-color-warning-text);
222
+ font-family: var(--sm-font-family);
223
+ }
224
+ @keyframes sm-pulse {
225
+ 0%, 100% {
226
+ opacity: 1;
227
+ }
228
+ 50% {
229
+ opacity: 0.3;
230
+ }
231
+ }
232
+ @keyframes sm-indeterminate {
233
+ 0% {
234
+ left: -40%;
235
+ width: 40%;
236
+ }
237
+ 50% {
238
+ left: 30%;
239
+ width: 40%;
240
+ }
241
+ 100% {
242
+ left: 100%;
243
+ width: 40%;
244
+ }
245
+ }
246
+ @keyframes sm-fade-in {
247
+ from {
248
+ opacity: 0;
249
+ }
250
+ to {
251
+ opacity: 1;
252
+ }
253
+ }
254
+ @keyframes sm-pop-in {
255
+ from {
256
+ opacity: 0;
257
+ transform: translateY(8px) scale(0.98);
258
+ }
259
+ to {
260
+ opacity: 1;
261
+ transform: translateY(0) scale(1);
262
+ }
263
+ }
264
+ .SideNav {
265
+ list-style-type: none;
266
+ margin: 0;
267
+ padding: 0;
268
+ outline: none;
269
+ height: 100%;
270
+ }
271
+ .SideNav-item {
272
+ list-style-type: none;
273
+ margin: var(--spectrum-global-dimension-size-50) 0;
274
+ }
275
+ .SideNav-itemLink {
276
+ position: relative;
277
+ display: inline-flex;
278
+ align-items: center;
279
+ box-sizing: border-box;
280
+ width: 100%;
281
+ padding: var(--sm-space-2) var(--sm-space-3);
282
+ border-radius: var(--sm-radius-sm);
283
+ font-size: var(--sm-font-size-lg);
284
+ font-weight: var(--sm-font-weight-regular);
285
+ text-decoration: none;
286
+ word-break: break-word;
287
+ cursor: pointer;
288
+ background: transparent;
289
+ color: var(--sm-color-text);
290
+ }
291
+ .SideNav-itemLink.is-selected {
292
+ color: var(--sm-color-accent);
293
+ background: var(--sm-color-accent-soft);
294
+ }