@schandlergarcia/sf-web-components 1.9.87 → 2.0.0

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.
Files changed (41) hide show
  1. package/.a4drules/features/command-center-dashboard-rule.md +1 -1
  2. package/.a4drules/skills/command-center-builder/SKILL.md +33 -36
  3. package/.a4drules/skills/command-center-builder/getting-started.md +64 -104
  4. package/.a4drules/skills/command-center-builder/improved-build-process.md +28 -34
  5. package/.a4drules/skills/command-center-guide/SKILL.md +9 -9
  6. package/.a4drules/skills/command-center-project/SKILL.md +4 -5
  7. package/.a4drules/skills/component-library/SKILL.md +8 -10
  8. package/.a4drules/skills/component-library/card-components.md +3 -3
  9. package/.a4drules/skills/component-library/chat-data.md +4 -6
  10. package/.a4drules/troubleshooting/codegen-overwrites-types.md +21 -162
  11. package/.a4drules/troubleshooting/graphql-introspection-failure.md +13 -264
  12. package/.a4drules/validation-requirements.md +3 -5
  13. package/.a4drules/webapp-data.md +1 -1
  14. package/CHANGELOG.md +30 -0
  15. package/CLAUDE.md +19 -39
  16. package/dist/components/library/cards/ActivityCard.js +9 -9
  17. package/dist/components/library/cards/ActivityCard.js.map +1 -1
  18. package/dist/styles/base.css +112 -27
  19. package/dist/styles/global.css +15 -30
  20. package/package.json +2 -3
  21. package/scripts/postinstall.mjs +39 -178
  22. package/scripts/reset-command-center.sh +67 -406
  23. package/scripts/validate-dashboard.sh +4 -4
  24. package/src/components/library/cards/ActivityCard.jsx +2 -2
  25. package/src/styles/base.css +223 -0
  26. package/src/styles/global.css +223 -0
  27. package/src/templates/config/vite.config.ts.template +0 -18
  28. package/.a4drules/features/engine-dashboard-rule.md +0 -63
  29. package/.a4drules/features/phase2-data-pattern.md +0 -15
  30. package/assets/images/engine_logo.png +0 -0
  31. package/data/README.md +0 -202
  32. package/data/USAGE.md +0 -81
  33. package/data/agentApiConfig.ts +0 -36
  34. package/data/copy-to-webapp.sh +0 -61
  35. package/data/engine-command-center-prd.md +0 -575
  36. package/data/engine-live-data.js +0 -135
  37. package/data/engine-sample-data.js +0 -378
  38. package/data/schema.graphql +0 -292
  39. package/data/useEngineLiveData.ts +0 -49
  40. package/data/useEvaAgent.ts +0 -288
  41. package/scripts/generate-schema-from-sample.mjs +0 -370
@@ -13,274 +13,23 @@ This is an **org-level bug** where at least one field in the Salesforce org has
13
13
 
14
14
  ## What's Broken
15
15
 
16
- - Generating `schema.graphql` from org introspection
17
- - ❌ Full schema with all org objects and fields
18
- - ❌ Some IDE autocomplete features that query the org directly
16
+ The GraphQL server attempts to enumerate every object and field in the org. If ANY field across any object has a null `getDataType()`, the entire introspection fails. This prevents `codegen` from generating types.
19
17
 
20
- ## What Still Works
18
+ ## Workaround
21
19
 
22
- - **Regular GraphQL queries**Queries execute normally despite introspection failure
23
- - All CRUD operations via GraphQL
24
- - ✅ The Data SDK (`createDataSDK()`)
25
- - UI API GraphQL endpoint (`/services/data/v{ver}/graphql`)
26
- - ✅ **Schema generation from sample data** (see Solution below)
20
+ 1. **Use a pre-built `schema.graphql`** If you have one checked into the repo, keep using it
21
+ 2. **Query specific objects** Instead of full introspection, query only the objects you need:
22
+ ```graphql
23
+ { uiapi { query { Account { edges { node { Id Name { value } } } } } } }
24
+ ```
25
+ 3. **Run `get-graphql-schema.mjs`** — This script uses the Salesforce SDK to attempt introspection. If it fails, use the pre-built schema.
27
26
 
28
- **Key insight:** Introspection is just metadata about the schema. It doesn't affect actual query execution.
27
+ ## Key Point
29
28
 
30
- ## Solution: Pre-built Schema (Already in Repo)
31
-
32
- The `schema.graphql` file is **already checked into the repo** at the project root. It was generated from the sample data file and includes all Engine objects.
33
-
34
- **You don't need to generate anything** — the schema is ready to use.
35
-
36
- **What this provides:**
37
- - ✅ `exploring-webapp-graphql-schema` skill works normally
38
- - ✅ `generating-webapp-graphql-read-query` skill works normally
39
- - ✅ `using-webapp-graphql` skill works normally
40
- - ✅ IDE autocomplete and validation
41
- - ✅ GraphQL codegen
42
- - ✅ Normal Phase 3 workflow without manual workarounds
43
- - ✅ Works in CI/CD without org access
44
-
45
- **Schema contents:**
46
- - Contact (travelers with custom fields)
47
- - Trip__c, Flight__c, Booking__c, Disruption__c, Rebooking_Action__c, Travel_Policy__c
48
- - All fields from `src/data/engine-sample-data.js`
49
-
50
- ## Regenerating the Schema (Optional)
51
-
52
- If you need to update the schema (e.g., after adding new fields to sample data):
53
-
54
- ```bash
55
- # From the webapp directory
56
- npm run graphql:schema:sample
57
- ```
58
-
59
- This regenerates `schema.graphql` from the current sample data file. Then commit the updated schema to git.
60
-
61
- ## Fallback: Copy Working Query Patterns (Manual)
62
-
63
- Since introspection fails but queries work, you can implement GraphQL features by copying working patterns from elsewhere in the codebase.
64
-
65
- ### Step 1: Find a Working Query
66
-
67
- Look for existing GraphQL implementations (e.g., Account search, Contact queries in other features):
68
-
69
- ```bash
70
- cd force-app/main/default/webapplications/reactapp4
71
- grep -r "uiapi {" src/
72
- ```
73
-
74
- ### Step 2: Copy the Pattern
75
-
76
- The working pattern for UI API GraphQL queries:
77
-
78
- ```typescript
79
- import { createDataSDK, gql } from "@salesforce/sdk-data";
80
-
81
- const GET_TRIPS = gql`
82
- query GetTrips {
83
- uiapi {
84
- query {
85
- Trip__c(first: 50) {
86
- edges {
87
- node {
88
- Id
89
- Trip_Name__c @optional { value }
90
- Origin_City__c @optional { value }
91
- Destination_City__c @optional { value }
92
- Contact__c @optional { value }
93
- Start_Date__c @optional { value }
94
- End_Date__c @optional { value }
95
- Status__c @optional { value }
96
- Total_Cost__c @optional { value }
97
- In_Policy__c @optional { value }
98
- Has_Disruption__c @optional { value }
99
- }
100
- }
101
- }
102
- }
103
- }
104
- }
105
- `;
106
- ```
107
-
108
- **Critical elements:**
109
- - `uiapi { query { ... } }` wrapper
110
- - Object name matches Salesforce API name (e.g., `Trip__c`, `Contact`)
111
- - `@optional` directive on ALL fields except `Id` (for FLS resilience)
112
- - Nested field access: `FieldName { value }` for most fields
113
- - Lookup fields: `RelatedObject__c { Name { value } }`
114
-
115
- ### Step 3: Implement Hooks
116
-
117
- Create custom hooks using the Data SDK pattern:
118
-
119
- ```typescript
120
- import { useState, useEffect } from "react";
121
- import { createDataSDK } from "@salesforce/sdk-data";
122
-
123
- export function useTrips() {
124
- const [data, setData] = useState<any[] | null>(null);
125
- const [loading, setLoading] = useState(true);
126
- const [error, setError] = useState<Error | null>(null);
127
-
128
- useEffect(() => {
129
- let mounted = true;
130
-
131
- async function fetchData() {
132
- try {
133
- const sdk = await createDataSDK();
134
- const response = await sdk.graphql?.(GET_TRIPS);
135
-
136
- if (!mounted) return;
137
-
138
- if (response?.errors?.length) {
139
- throw new Error(response.errors.map((e: any) => e.message).join("; "));
140
- }
141
-
142
- const edges = response?.data?.uiapi?.query?.Trip__c?.edges ?? [];
143
- const trips = edges.map((edge: any) => ({
144
- Id: edge.node.Id,
145
- Trip_Name__c: edge.node.Trip_Name__c?.value ?? null,
146
- Origin_City__c: edge.node.Origin_City__c?.value ?? null,
147
- // ... map all fields with optional chaining
148
- }));
149
-
150
- setData(trips);
151
- setError(null);
152
- } catch (err) {
153
- if (mounted) {
154
- setError(err instanceof Error ? err : new Error(String(err)));
155
- }
156
- } finally {
157
- if (mounted) {
158
- setLoading(false);
159
- }
160
- }
161
- }
162
-
163
- fetchData();
164
-
165
- return () => {
166
- mounted = false;
167
- };
168
- }, []);
169
-
170
- return { data, loading, error };
171
- }
172
- ```
173
-
174
- ### Step 4: Get Field Names from Sample Data
175
-
176
- The sample data file already has real Salesforce field names. Read `src/data/engine-sample-data.js` to see which fields exist:
177
-
178
- ```javascript
179
- // File: src/data/engine-sample-data.js
180
- export const TRIPS = [
181
- {
182
- Id: "a00xx000001",
183
- Trip_Name__c: "Q1 Sales Conference - SF",
184
- Origin_City__c: "New York",
185
- Destination_City__c: "San Francisco",
186
- // ... etc
187
- }
188
- ];
189
- ```
190
-
191
- Copy these exact field names into your GraphQL query.
192
-
193
- ### Step 5: Test Your Queries
194
-
195
- Create a test script to verify queries work:
196
-
197
- ```javascript
198
- // scripts/test-engine-query.mjs
199
- import { getOrgInfo } from '@salesforce/webapp-experimental/app';
200
-
201
- async function testQuery(query, objectName) {
202
- const { rawInstanceUrl, apiVersion, accessToken } = await getOrgInfo();
203
-
204
- const response = await fetch(
205
- `${rawInstanceUrl}/services/data/v${apiVersion}/graphql`,
206
- {
207
- method: 'POST',
208
- headers: {
209
- Authorization: `Bearer ${accessToken}`,
210
- 'Content-Type': 'application/json',
211
- 'X-Chatter-Entity-Encoding': 'false',
212
- },
213
- body: JSON.stringify({ query }),
214
- }
215
- );
216
-
217
- const result = await response.json();
218
-
219
- if (result.errors) {
220
- console.error(`❌ ${objectName} query failed:`, result.errors);
221
- return false;
222
- }
223
-
224
- console.log(`✅ ${objectName} query succeeded`);
225
- console.log(` Records found: ${result.data?.uiapi?.query?.[objectName]?.edges?.length}`);
226
- return true;
227
- }
228
-
229
- // Test your queries
230
- await testQuery(`query { uiapi { query { Trip__c(first: 1) { edges { node { Id } } } } } }`, 'Trip__c');
231
- ```
232
-
233
- Run: `node scripts/test-engine-query.mjs`
234
-
235
- ## For Agents Building the Dashboard
236
-
237
- **The schema.graphql file is already in the repo.** Just use the GraphQL skills normally:
238
-
239
- 1. `exploring-webapp-graphql-schema` — Looks up field names
240
- 2. `generating-webapp-graphql-read-query` — Creates queries
241
- 3. `using-webapp-graphql` — Implements hooks
242
-
243
- No schema generation needed during Phase 3.
244
-
245
- ## For Developers Adding Fields
246
-
247
- If you add new fields to `src/data/engine-sample-data.js`, regenerate the schema:
248
-
249
- ```bash
250
- cd force-app/main/default/webapplications/reactapp4
251
- npm run graphql:schema:sample
252
- git add ../../../../../../schema.graphql
253
- git commit -m "Update schema with new fields"
254
- ```
255
-
256
- ## Decision Tree for Schema Updates
257
-
258
- **Do you need to update schema.graphql?**
259
-
260
- - ❌ Building dashboard from existing sample data? → No, use existing schema
261
- - ✅ Added new fields to sample data? → Run `npm run graphql:schema:sample`
262
- - ✅ Added new custom objects? → Update generation script first, then regenerate
263
- - ✅ Want to try org introspection? → Run `npm run graphql:schema` (may fail)
264
-
265
- ## Prevention
266
-
267
- This is an org-level bug that can't be prevented from the web app side. The org admin would need to identify and fix the field(s) with null data types. However, this workaround allows development to continue without waiting for org fixes.
29
+ The introspection failure does NOT affect runtime queries. You can still query any object via GraphQL — only the schema generation step is broken.
268
30
 
269
31
  ## Related Files
270
32
 
271
- - `.a4drules/features/engine-dashboard-rule.md` — Phase 3 implementation with workaround steps
272
- - `engine-command-center-prd.md` — Phase 3 prompt updated to include fallback approach
273
- - `scripts/get-graphql-schema.mjs` — The script that runs introspection (will fail with this bug)
274
- - `scripts/test-engine-query.mjs` — Test script to verify queries work despite introspection failure
275
-
276
- ## Success Indicators
277
-
278
- You've successfully worked around the issue when:
279
-
280
- - ✅ All custom hooks return data correctly (`{ data, loading, error }`)
281
- - ✅ Dashboard displays live Salesforce data
282
- - ✅ No GraphQL-related errors in browser console
283
- - ✅ Test script shows all queries succeed
284
- - ✅ Loading and error states work properly
285
-
286
- The fact that schema.graphql doesn't exist is fine — it's only needed for introspection-based tooling, not for runtime queries.
33
+ - `scripts/get-graphql-schema.mjs` — The script that runs introspection
34
+ - `schema.graphql` — Pre-built schema (if available)
35
+ - `vite.config.ts` — Codegen plugin configuration (disabled by default to prevent issues)
@@ -176,12 +176,10 @@ Any other output means there are errors that MUST be fixed.
176
176
 
177
177
  ## Integration with Build Phases
178
178
 
179
- For the Engine Travel Command Center (and all 4-phase dashboards):
179
+ Run the validator at the end of each build phase before proceeding to the next:
180
180
 
181
- - **End of Phase 1:** Run validator, fix errors → proceed to Phase 2
182
- - **End of Phase 2:** Run validator, fix errors → proceed to Phase 3
183
- - **End of Phase 3:** Run validator, fix errors → proceed to Phase 4
184
- - **End of Phase 4:** Run validator, fix errors → DONE
181
+ - **End of each phase:** Run validator, fix all errors → proceed to next phase
182
+ - **Final phase:** Run validator, fix all errors → DONE
185
183
 
186
184
  ## Do Not Run These Instead
187
185
 
@@ -64,7 +64,7 @@ const res = await sdk.fetch?.("/services/apexrest/my-resource");
64
64
 
65
65
  The `schema.graphql` file is **already checked into the repo** at the SFDX project root. **Never open or parse it directly.**
66
66
 
67
- - Pre-built from sample data, contains Engine objects (Contact, Trip__c, Flight__c, etc.)
67
+ - Pre-built from sample data, contains standard and custom objects
68
68
  - No generation needed — just use it
69
69
  - If you ever need to regenerate (after adding fields to sample data): `npm run graphql:schema:sample` from webapp dir
70
70
 
package/CHANGELOG.md CHANGED
@@ -5,6 +5,36 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [2.0.0] - 2026-04-04
9
+
10
+ ### Changed — Generic framework release
11
+ Stripped all Engine Travel-specific content to make the package a generic component framework anyone can use.
12
+
13
+ - **Postinstall** — removed Engine sample data, Engine PRD, Engine logo, useEvaAgent, agentApiConfig, useEngineLiveData, schema.graphql, and generate-schema-from-sample copies. Now only installs the generic component library, templates, config files, utility scripts, and .a4drules.
14
+ - **Reset script** — removed Engine brand CSS inline write (now copies neutral `global.css` from package), removed Engine data/hook/schema/PRD/logo restores, removed Engine-specific `KEEP_CLASSES` (TCC_TravelMetricsController) from Apex cleanup.
15
+ - **global.css** — replaced Engine brand palette (`--color-engine-*`, teal #5BC8C8) with neutral sky-blue brand tokens (`--color-brand-*`, #0EA5E9). Replaced Engine coral (#FF5722) with standard red (#EF4444) in `.heroui-scope`.
16
+ - **vite.config.ts.template** — removed hardcoded Salesforce org proxy rules (`/sf-oauth`, `/sf-agent` with tdx26-keynote-org URL).
17
+ - **package.json** — removed `data` and `assets` from `files` array. Added `src/styles`.
18
+ - **.a4drules** — deleted `engine-dashboard-rule.md` and `phase2-data-pattern.md`. Generalized all remaining files: removed Engine PRD/data references from SKILL.md, getting-started.md, improved-build-process.md, chat-data.md, webapp-data.md, validation-requirements.md, and command-center-dashboard-rule.md.
19
+ - **CLAUDE.md** — rewrote to describe generic framework without Engine references.
20
+ - **ActivityCard.jsx** — renamed `action.traveler` fallback to `action.description`.
21
+ - **validate-dashboard.sh** — renamed `TRAVEL_DIR` to `CUSTOM_DIR`.
22
+
23
+ ### Removed
24
+ - `scripts/generate-schema-from-sample.mjs` (Engine-specific schema generator)
25
+ - `.a4drules/features/engine-dashboard-rule.md`
26
+ - `.a4drules/features/phase2-data-pattern.md`
27
+
28
+ ### Note
29
+ The `data/` directory still exists in the repository for reference but is no longer published or copied by postinstall.
30
+
31
+ ## [1.9.88] - 2026-04-07
32
+
33
+ ### Fixed
34
+ - **Postinstall `.a4drules` copy** — now copies all root-level `.md` files (`webapp-ui.md`, `webapp-data.md`, `validation-requirements.md`, `RULES.md`) and all subdirectories (`skills/`, `features/`, `troubleshooting/`), not just `skills/` and `features/`. Ensures the full build guide reaches consuming projects.
35
+ - **Postinstall vite proxy injection** — when `vite.config.ts` already exists, the postinstall now checks for and injects the Agent API proxy rules (`/sf-oauth`, `/sf-agent`) if they're missing, rather than silently skipping.
36
+ - **Reset script `.a4drules` restore** — the reset script now force-copies every `.md` file from the package's `.a4drules` to the project root, preventing stale stubs from persisting across resets.
37
+
8
38
  ## [1.9.87] - 2026-04-07
9
39
 
10
40
  ### Changed
package/CLAUDE.md CHANGED
@@ -10,8 +10,7 @@ This file provides guidance to Claude Code when working with the sf-web-componen
10
10
  2. **Templates** - Page templates (Home, Search, NotFound, BlankDashboard) and config templates (routes.tsx, vite.config.ts, dataStrategy.ts)
11
11
  3. **Automation** - Postinstall script that sets up consuming projects automatically
12
12
  4. **Documentation** - `.a4drules` skills and features for AI-assisted development
13
- 5. **Sample data** - Engine Travel sample data and pre-built GraphQL schema
14
- 6. **Scripts** - Reset scripts, validation scripts, schema generation
13
+ 5. **Scripts** - Reset scripts, validation scripts
15
14
 
16
15
  **Primary use case:** Building Salesforce Web Applications with React, specifically for:
17
16
  - Outer app pages (search, navigation) using shadcn/ui + Tailwind
@@ -31,18 +30,18 @@ The package supports **two distinct UI contexts** that must NOT be mixed:
31
30
  - `Input` from `@/components/ui/input`
32
31
  - etc.
33
32
  - **Icons:** Lucide React (`lucide-react`)
34
- - **Styling:** Neutral shadcn theme (slate colors, no Engine branding)
33
+ - **Styling:** Neutral shadcn theme (slate colors)
35
34
  - **File type:** `.tsx`
36
35
 
37
36
  #### 2. Command Center Context
38
- - **Files:** Dashboard pages in `src/pages/` (e.g., BlankDashboard, EngineDashboard)
37
+ - **Files:** Dashboard pages in `src/pages/` (e.g., BlankDashboard, custom dashboards)
39
38
  - **Rendered in:** CommandCenter wrapper with `.heroui-scope` class
40
39
  - **Components:** Library components from `@/components/library`
41
40
  - `UIButton` from `@/components/library/ui/UIButton`
42
41
  - `UIInput` from `@/components/library/ui/UIInput`
43
42
  - `MetricCard`, `ChartCard`, `ListCard`, `TableCard`, etc.
44
43
  - **Icons:** Heroicons (`@heroicons/react`)
45
- - **Styling:** Engine brand colors (teal #5BC8C8, coral, orange) inside `.heroui-scope`
44
+ - **Styling:** Brand colors defined in `global.css` inside `.heroui-scope`
46
45
  - **File type:** `.jsx` or `.tsx`
47
46
 
48
47
  **Common mistake:** Using UIButton/UIInput in outer app pages or shadcn Button/Input in command center dashboards. Check `.a4drules/features/pre-code-checklist.md` for validation rules.
@@ -67,18 +66,14 @@ sf-web-components/
67
66
  │ │ ├── lib/ # dataStrategy.ts.template
68
67
  │ │ └── workspace/ # CommandCenter.tsx.template
69
68
  │ ├── lib/ # Utilities (utils.ts)
70
- │ └── styles/ # global.css with Engine brand tokens
69
+ │ └── styles/ # global.css with neutral brand tokens
71
70
  ├── scripts/
72
71
  │ ├── postinstall.mjs # Runs after npm install in consuming projects
73
72
  │ ├── reset-command-center.sh
74
73
  │ ├── validate-dashboard.sh
75
74
  │ └── verify-consistency.sh
76
- ├── data/
77
- │ ├── engine-sample-data.js
78
- │ ├── schema.graphql
79
- │ └── engine-command-center-prd.md
80
75
  └── .a4drules/
81
- ├── features/ # Dashboard rules, engine-dashboard-rule, etc.
76
+ ├── features/ # Dashboard rules, pre-code checklist
82
77
  ├── skills/ # component-library, command-center-builder, etc.
83
78
  ├── troubleshooting/ # Common issues and solutions
84
79
  ├── validation-requirements.md
@@ -103,9 +98,9 @@ sf-web-components/
103
98
  ```javascript
104
99
  import useDataSource from "@/components/library/data/useDataSource";
105
100
 
106
- const travelers = useDataSource({
107
- sample: SAMPLE_TRAVELERS,
108
- live: liveTravelers ?? []
101
+ const items = useDataSource({
102
+ sample: SAMPLE_DATA,
103
+ live: liveData ?? []
109
104
  });
110
105
  ```
111
106
  - **Configuration:** `src/lib/dataStrategy.ts` controls `ENABLE_SAMPLE_DATA_CACHE`
@@ -149,12 +144,9 @@ When a project installs this package, `scripts/postinstall.mjs` automatically:
149
144
  4. **Copies workspace files** to `src/components/workspace/`
150
145
  5. **Installs page templates** to `src/pages/` (Home.tsx, Search.tsx, NotFound.tsx, BlankDashboard.tsx)
151
146
  6. **Updates imports** in existing files (changes package imports to local `@/components/library` imports)
152
- 7. **Copies sample data** to `src/data/engine-sample-data.js`
153
- 8. **Copies schema** to root `schema.graphql`
154
- 9. **Copies PRD** to root `engine-command-center-prd.md`
155
- 10. **Installs config files** (routes.tsx, vite.config.ts, dataStrategy.ts) if they don't exist
156
- 11. **Adds npm scripts** to package.json (reset:command-center, validate:dashboard, graphql:schema:sample)
157
- 12. **Copies .a4drules** to project root for AI assistant discoverability
147
+ 7. **Installs config files** (routes.tsx, vite.config.ts, dataStrategy.ts) if they don't exist
148
+ 8. **Adds npm scripts** to package.json (reset:command-center, validate:dashboard)
149
+ 9. **Copies .a4drules** to project root for AI assistant discoverability
158
150
 
159
151
  **Important:** Templates are **always overwritten** to ensure latest versions, except for config files (vite.config.ts, dataStrategy.ts) which only install if missing.
160
152
 
@@ -170,8 +162,10 @@ The `scripts/reset-command-center.sh` provides a clean baseline for projects:
170
162
  - Updates routes.tsx to include Home, /accounts, and /accounts/:recordId
171
163
  - Updates appLayout.tsx with nav bar
172
164
  - Clears Vite cache
173
- - Restores Engine-branded global.css
174
- - Restores sample data and schema
165
+ - Restores neutral theme (global.css from package)
166
+ - Restores dataStrategy.ts
167
+ - Restores .a4drules
168
+ - Cleans Apex classes and platform events (if SFDX project)
175
169
 
176
170
  ## Important Files
177
171
 
@@ -184,22 +178,14 @@ Complete history of all changes. ALWAYS update when making changes. Include:
184
178
 
185
179
  ### .a4drules/
186
180
  AI assistant documentation. Key files:
187
- - `features/engine-dashboard-rule.md` - How to build Engine Travel Command Center
188
181
  - `features/command-center-dashboard-rule.md` - Dashboard development rules
189
182
  - `features/pre-code-checklist.md` - Pre-implementation validation
190
183
  - `skills/component-library/` - Component API reference
184
+ - `skills/command-center-builder/` - How to build Command Center dashboards
191
185
  - `validation-requirements.md` - Validation rules
192
186
  - `webapp-data.md` - Data access patterns (GraphQL, REST, SDK usage)
193
187
  - `webapp-ui.md` - UI platform rules
194
188
 
195
- ### data/engine-command-center-prd.md
196
- Product Requirements Document for Engine Travel Command Center. Defines:
197
- - Product overview and users
198
- - Brand tokens (Engine teal #5BC8C8, etc.)
199
- - Layout structure (visualization-hero pattern)
200
- - Component sections and data model
201
- - Phase-by-phase build instructions
202
-
203
189
  ### src/components/library/theme/AppThemeProvider.jsx
204
190
  Theme provider with dark mode toggle. Exports:
205
191
  - **Default:** `AppThemeProvider` component
@@ -235,7 +221,7 @@ Routes need `handle: { showInNavigation: true, showNavBar: true }` for nav bar t
235
221
  ## Testing
236
222
 
237
223
  Before publishing:
238
- 1. Test in a real project (reactapp4, vibes3, etc.)
224
+ 1. Test in a real project
239
225
  2. Run `npm install @schandlergarcia/sf-web-components@latest`
240
226
  3. Verify postinstall behavior
241
227
  4. Check templates are correct
@@ -245,13 +231,7 @@ Before publishing:
245
231
 
246
232
  ## Version History
247
233
 
248
- See CHANGELOG.md for complete history. Recent major changes:
249
- - v1.9.55 - Fixed UIButton/Button confusion in templates
250
- - v1.9.56 - Fixed reset script 404 errors
251
- - v1.9.57 - Restored "Browse All Accounts" button
252
- - v1.9.58 - Fixed reset routes pointing to wrong Home file
253
- - v1.9.59 - Restored navigation bar (showNavBar flag)
254
- - v1.9.60-61 - Synced .a4drules and PRD from reactapp4
234
+ See CHANGELOG.md for complete history.
255
235
 
256
236
  ## Current Version
257
237
 
@@ -1,4 +1,4 @@
1
- import { jsxs as i, jsx as t } from "react/jsx-runtime";
1
+ import { jsxs as r, jsx as t } from "react/jsx-runtime";
2
2
  import "react";
3
3
  import { AnimatePresence as n, motion as o } from "framer-motion";
4
4
  import { ExclamationCircleIcon as c, CheckCircleIcon as d, ClockIcon as m, ArrowPathIcon as p } from "@heroicons/react/24/outline";
@@ -10,7 +10,7 @@ const l = {
10
10
  error: { Icon: c, color: "text-red-500", spin: !1 }
11
11
  };
12
12
  function u({ action: e }) {
13
- const r = l[e.status] ?? l.pending;
13
+ const i = l[e.status] ?? l.pending;
14
14
  return /* @__PURE__ */ t(
15
15
  o.div,
16
16
  {
@@ -18,20 +18,20 @@ function u({ action: e }) {
18
18
  animate: { y: 0, opacity: 1 },
19
19
  exit: { y: -12, opacity: 0 },
20
20
  className: "rounded-lg border border-slate-100 bg-slate-50 p-3 dark:border-slate-800 dark:bg-slate-950/40",
21
- children: /* @__PURE__ */ i("div", { className: "flex items-start gap-2", children: [
22
- /* @__PURE__ */ t(r.Icon, { className: `mt-0.5 h-4 w-4 shrink-0 ${r.color} ${r.spin ? "animate-spin" : ""}` }),
23
- /* @__PURE__ */ i("div", { className: "min-w-0", children: [
21
+ children: /* @__PURE__ */ r("div", { className: "flex items-start gap-2", children: [
22
+ /* @__PURE__ */ t(i.Icon, { className: `mt-0.5 h-4 w-4 shrink-0 ${i.color} ${i.spin ? "animate-spin" : ""}` }),
23
+ /* @__PURE__ */ r("div", { className: "min-w-0", children: [
24
24
  /* @__PURE__ */ t("div", { className: "text-xs font-medium text-slate-700 dark:text-slate-200", children: e.title ?? e.action }),
25
- (e.subtitle ?? e.traveler ?? e.timestamp ?? e.startedAt) && /* @__PURE__ */ t("div", { className: "mt-0.5 text-[10px] text-slate-400", children: [e.subtitle, e.traveler, e.timestamp ?? e.startedAt].filter(Boolean).join(" · ") })
25
+ (e.subtitle ?? e.description ?? e.timestamp ?? e.startedAt) && /* @__PURE__ */ t("div", { className: "mt-0.5 text-[10px] text-slate-400", children: [e.subtitle, e.description, e.timestamp ?? e.startedAt].filter(Boolean).join(" · ") })
26
26
  ] })
27
27
  ] })
28
28
  }
29
29
  );
30
30
  }
31
- function b({ title: e = "Activity", actions: r = [], className: a = "" }) {
32
- return r.length === 0 ? null : /* @__PURE__ */ i("div", { className: a, children: [
31
+ function b({ title: e = "Activity", actions: i = [], className: a = "" }) {
32
+ return i.length === 0 ? null : /* @__PURE__ */ r("div", { className: a, children: [
33
33
  e && /* @__PURE__ */ t(x, { as: "div", size: "xs", weight: "semibold", muted: !0, className: "mb-2 uppercase tracking-wider", children: e }),
34
- /* @__PURE__ */ t("div", { className: "space-y-2", children: /* @__PURE__ */ t(n, { children: r.map((s) => /* @__PURE__ */ t(u, { action: s }, s.id)) }) })
34
+ /* @__PURE__ */ t("div", { className: "space-y-2", children: /* @__PURE__ */ t(n, { children: i.map((s) => /* @__PURE__ */ t(u, { action: s }, s.id)) }) })
35
35
  ] });
36
36
  }
37
37
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"ActivityCard.js","sources":["../../../../src/components/library/cards/ActivityCard.jsx"],"sourcesContent":["import React from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { ArrowPathIcon, CheckCircleIcon, ExclamationCircleIcon, ClockIcon } from \"@heroicons/react/24/outline\";\nimport UIText from \"../ui/Text\";\n\nconst STATUS_ICON = {\n working: { Icon: ArrowPathIcon, color: \"text-indigo-500\", spin: true },\n pending: { Icon: ClockIcon, color: \"text-slate-400\", spin: false },\n complete: { Icon: CheckCircleIcon, color: \"text-emerald-500\", spin: false },\n error: { Icon: ExclamationCircleIcon, color: \"text-red-500\", spin: false },\n};\n\nfunction ActionItem({ action }) {\n const s = STATUS_ICON[action.status] ?? STATUS_ICON.pending;\n return (\n <motion.div\n initial={{ y: 12, opacity: 0 }}\n animate={{ y: 0, opacity: 1 }}\n exit={{ y: -12, opacity: 0 }}\n className=\"rounded-lg border border-slate-100 bg-slate-50 p-3 dark:border-slate-800 dark:bg-slate-950/40\"\n >\n <div className=\"flex items-start gap-2\">\n <s.Icon className={`mt-0.5 h-4 w-4 shrink-0 ${s.color} ${s.spin ? \"animate-spin\" : \"\"}`} />\n <div className=\"min-w-0\">\n <div className=\"text-xs font-medium text-slate-700 dark:text-slate-200\">{action.title ?? action.action}</div>\n {(action.subtitle ?? action.traveler ?? action.timestamp ?? action.startedAt) && (\n <div className=\"mt-0.5 text-[10px] text-slate-400\">\n {[action.subtitle, action.traveler, action.timestamp ?? action.startedAt].filter(Boolean).join(\" · \")}\n </div>\n )}\n </div>\n </div>\n </motion.div>\n );\n}\n\nexport default function ActivityCard({ title = \"Activity\", actions = [], className = \"\" }) {\n if (actions.length === 0) return null;\n\n return (\n <div className={className}>\n {title && (\n <UIText as=\"div\" size=\"xs\" weight=\"semibold\" muted className=\"mb-2 uppercase tracking-wider\">\n {title}\n </UIText>\n )}\n <div className=\"space-y-2\">\n <AnimatePresence>\n {actions.map(a => (\n <ActionItem key={a.id} action={a} />\n ))}\n </AnimatePresence>\n </div>\n </div>\n );\n}\n"],"names":["STATUS_ICON","ArrowPathIcon","ClockIcon","CheckCircleIcon","ExclamationCircleIcon","ActionItem","action","s","jsx","motion","jsxs","ActivityCard","title","actions","className","UIText","AnimatePresence","a"],"mappings":";;;;;AAKA,MAAMA,IAAc;AAAA,EAClB,SAAU,EAAE,MAAMC,GAAsB,OAAO,mBAAoB,MAAM,GAAA;AAAA,EACzE,SAAU,EAAE,MAAMC,GAAsB,OAAO,kBAAoB,MAAM,GAAA;AAAA,EACzE,UAAU,EAAE,MAAMC,GAAsB,OAAO,oBAAoB,MAAM,GAAA;AAAA,EACzE,OAAU,EAAE,MAAMC,GAAuB,OAAO,gBAAoB,MAAM,GAAA;AAC5E;AAEA,SAASC,EAAW,EAAE,QAAAC,KAAU;AAC9B,QAAMC,IAAIP,EAAYM,EAAO,MAAM,KAAKN,EAAY;AACpD,SACE,gBAAAQ;AAAA,IAACC,EAAO;AAAA,IAAP;AAAA,MACC,SAAS,EAAE,GAAG,IAAI,SAAS,EAAA;AAAA,MAC3B,SAAS,EAAE,GAAG,GAAG,SAAS,EAAA;AAAA,MAC1B,MAAM,EAAE,GAAG,KAAK,SAAS,EAAA;AAAA,MACzB,WAAU;AAAA,MAEV,UAAA,gBAAAC,EAAC,OAAA,EAAI,WAAU,0BACb,UAAA;AAAA,QAAA,gBAAAF,EAACD,EAAE,MAAF,EAAO,WAAW,2BAA2BA,EAAE,KAAK,IAAIA,EAAE,OAAO,iBAAiB,EAAE,GAAA,CAAI;AAAA,QACzF,gBAAAG,EAAC,OAAA,EAAI,WAAU,WACb,UAAA;AAAA,UAAA,gBAAAF,EAAC,SAAI,WAAU,0DAA0D,UAAAF,EAAO,SAASA,EAAO,QAAO;AAAA,WACrGA,EAAO,YAAYA,EAAO,YAAYA,EAAO,aAAaA,EAAO,cACjE,gBAAAE,EAAC,OAAA,EAAI,WAAU,qCACZ,UAAA,CAACF,EAAO,UAAUA,EAAO,UAAUA,EAAO,aAAaA,EAAO,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,KAAK,EAAA,CACtG;AAAA,QAAA,EAAA,CAEJ;AAAA,MAAA,EAAA,CACF;AAAA,IAAA;AAAA,EAAA;AAGN;AAEA,SAAwBK,EAAa,EAAE,OAAAC,IAAQ,YAAY,SAAAC,IAAU,IAAI,WAAAC,IAAY,MAAM;AACzF,SAAID,EAAQ,WAAW,IAAU,OAG/B,gBAAAH,EAAC,SAAI,WAAAI,GACF,UAAA;AAAA,IAAAF,KACC,gBAAAJ,EAACO,GAAA,EAAO,IAAG,OAAM,MAAK,MAAK,QAAO,YAAW,OAAK,IAAC,WAAU,iCAC1D,UAAAH,GACH;AAAA,sBAED,OAAA,EAAI,WAAU,aACb,UAAA,gBAAAJ,EAACQ,KACE,UAAAH,EAAQ,IAAI,CAAAI,MACX,gBAAAT,EAACH,KAAsB,QAAQY,EAAA,GAAdA,EAAE,EAAe,CACnC,GACH,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;"}
1
+ {"version":3,"file":"ActivityCard.js","sources":["../../../../src/components/library/cards/ActivityCard.jsx"],"sourcesContent":["import React from \"react\";\nimport { motion, AnimatePresence } from \"framer-motion\";\nimport { ArrowPathIcon, CheckCircleIcon, ExclamationCircleIcon, ClockIcon } from \"@heroicons/react/24/outline\";\nimport UIText from \"../ui/Text\";\n\nconst STATUS_ICON = {\n working: { Icon: ArrowPathIcon, color: \"text-indigo-500\", spin: true },\n pending: { Icon: ClockIcon, color: \"text-slate-400\", spin: false },\n complete: { Icon: CheckCircleIcon, color: \"text-emerald-500\", spin: false },\n error: { Icon: ExclamationCircleIcon, color: \"text-red-500\", spin: false },\n};\n\nfunction ActionItem({ action }) {\n const s = STATUS_ICON[action.status] ?? STATUS_ICON.pending;\n return (\n <motion.div\n initial={{ y: 12, opacity: 0 }}\n animate={{ y: 0, opacity: 1 }}\n exit={{ y: -12, opacity: 0 }}\n className=\"rounded-lg border border-slate-100 bg-slate-50 p-3 dark:border-slate-800 dark:bg-slate-950/40\"\n >\n <div className=\"flex items-start gap-2\">\n <s.Icon className={`mt-0.5 h-4 w-4 shrink-0 ${s.color} ${s.spin ? \"animate-spin\" : \"\"}`} />\n <div className=\"min-w-0\">\n <div className=\"text-xs font-medium text-slate-700 dark:text-slate-200\">{action.title ?? action.action}</div>\n {(action.subtitle ?? action.description ?? action.timestamp ?? action.startedAt) && (\n <div className=\"mt-0.5 text-[10px] text-slate-400\">\n {[action.subtitle, action.description, action.timestamp ?? action.startedAt].filter(Boolean).join(\" · \")}\n </div>\n )}\n </div>\n </div>\n </motion.div>\n );\n}\n\nexport default function ActivityCard({ title = \"Activity\", actions = [], className = \"\" }) {\n if (actions.length === 0) return null;\n\n return (\n <div className={className}>\n {title && (\n <UIText as=\"div\" size=\"xs\" weight=\"semibold\" muted className=\"mb-2 uppercase tracking-wider\">\n {title}\n </UIText>\n )}\n <div className=\"space-y-2\">\n <AnimatePresence>\n {actions.map(a => (\n <ActionItem key={a.id} action={a} />\n ))}\n </AnimatePresence>\n </div>\n </div>\n );\n}\n"],"names":["STATUS_ICON","ArrowPathIcon","ClockIcon","CheckCircleIcon","ExclamationCircleIcon","ActionItem","action","s","jsx","motion","jsxs","ActivityCard","title","actions","className","UIText","AnimatePresence","a"],"mappings":";;;;;AAKA,MAAMA,IAAc;AAAA,EAClB,SAAU,EAAE,MAAMC,GAAsB,OAAO,mBAAoB,MAAM,GAAA;AAAA,EACzE,SAAU,EAAE,MAAMC,GAAsB,OAAO,kBAAoB,MAAM,GAAA;AAAA,EACzE,UAAU,EAAE,MAAMC,GAAsB,OAAO,oBAAoB,MAAM,GAAA;AAAA,EACzE,OAAU,EAAE,MAAMC,GAAuB,OAAO,gBAAoB,MAAM,GAAA;AAC5E;AAEA,SAASC,EAAW,EAAE,QAAAC,KAAU;AAC9B,QAAMC,IAAIP,EAAYM,EAAO,MAAM,KAAKN,EAAY;AACpD,SACE,gBAAAQ;AAAA,IAACC,EAAO;AAAA,IAAP;AAAA,MACC,SAAS,EAAE,GAAG,IAAI,SAAS,EAAA;AAAA,MAC3B,SAAS,EAAE,GAAG,GAAG,SAAS,EAAA;AAAA,MAC1B,MAAM,EAAE,GAAG,KAAK,SAAS,EAAA;AAAA,MACzB,WAAU;AAAA,MAEV,UAAA,gBAAAC,EAAC,OAAA,EAAI,WAAU,0BACb,UAAA;AAAA,QAAA,gBAAAF,EAACD,EAAE,MAAF,EAAO,WAAW,2BAA2BA,EAAE,KAAK,IAAIA,EAAE,OAAO,iBAAiB,EAAE,GAAA,CAAI;AAAA,QACzF,gBAAAG,EAAC,OAAA,EAAI,WAAU,WACb,UAAA;AAAA,UAAA,gBAAAF,EAAC,SAAI,WAAU,0DAA0D,UAAAF,EAAO,SAASA,EAAO,QAAO;AAAA,WACrGA,EAAO,YAAYA,EAAO,eAAeA,EAAO,aAAaA,EAAO,cACpE,gBAAAE,EAAC,OAAA,EAAI,WAAU,qCACZ,UAAA,CAACF,EAAO,UAAUA,EAAO,aAAaA,EAAO,aAAaA,EAAO,SAAS,EAAE,OAAO,OAAO,EAAE,KAAK,KAAK,EAAA,CACzG;AAAA,QAAA,EAAA,CAEJ;AAAA,MAAA,EAAA,CACF;AAAA,IAAA;AAAA,EAAA;AAGN;AAEA,SAAwBK,EAAa,EAAE,OAAAC,IAAQ,YAAY,SAAAC,IAAU,IAAI,WAAAC,IAAY,MAAM;AACzF,SAAID,EAAQ,WAAW,IAAU,OAG/B,gBAAAH,EAAC,SAAI,WAAAI,GACF,UAAA;AAAA,IAAAF,KACC,gBAAAJ,EAACO,GAAA,EAAO,IAAG,OAAM,MAAK,MAAK,QAAO,YAAW,OAAK,IAAC,WAAU,iCAC1D,UAAAH,GACH;AAAA,sBAED,OAAA,EAAI,WAAU,aACb,UAAA,gBAAAJ,EAACQ,KACE,UAAAH,EAAQ,IAAI,CAAAI,MACX,gBAAAT,EAACH,KAAsB,QAAQY,EAAA,GAAdA,EAAE,EAAe,CACnC,GACH,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;"}