@corva/create-app 0.0.0-2576df8
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 +218 -0
- package/bin/cca.js +5 -0
- package/bin/create-corva-app.cjs +25 -0
- package/common/node/.env +15 -0
- package/common/node/.env.sample +26 -0
- package/common/node/gitignore +130 -0
- package/common/package.json +3 -0
- package/common/python/.env +5 -0
- package/common/python/.env.sample +7 -0
- package/common/python/Makefile +15 -0
- package/common/python/gitignore +161 -0
- package/common/python/requirements.txt +2 -0
- package/lib/commands/attach.js +28 -0
- package/lib/commands/create.js +463 -0
- package/lib/commands/release.js +58 -0
- package/lib/commands/rerun.js +34 -0
- package/lib/commands/zip.js +39 -0
- package/lib/constants/cache.js +5 -0
- package/lib/constants/cli.js +35 -0
- package/lib/constants/manifest.js +263 -0
- package/lib/constants/messages.js +15 -0
- package/lib/constants/package.js +288 -0
- package/lib/flow.js +53 -0
- package/lib/flows/attach.js +8 -0
- package/lib/flows/lib/api.js +385 -0
- package/lib/flows/lib/create-zip-archive.js +83 -0
- package/lib/flows/lib/json.js +30 -0
- package/lib/flows/lib/manifest.js +81 -0
- package/lib/flows/lib/notification.js +142 -0
- package/lib/flows/lib/step-error.js +10 -0
- package/lib/flows/lib/waitForMs.js +3 -0
- package/lib/flows/prepare.js +6 -0
- package/lib/flows/release.js +26 -0
- package/lib/flows/rerun.js +8 -0
- package/lib/flows/steps/attach/add-app-to-stream.js +23 -0
- package/lib/flows/steps/attach/get-all-live-assets.js +135 -0
- package/lib/flows/steps/attach/index.js +5 -0
- package/lib/flows/steps/attach/prepare-data.js +19 -0
- package/lib/flows/steps/prepare-load-app-files.js +12 -0
- package/lib/flows/steps/release/add-label.js +10 -0
- package/lib/flows/steps/release/add-notes.js +10 -0
- package/lib/flows/steps/release/get-config.js +41 -0
- package/lib/flows/steps/release/prepare-data.js +12 -0
- package/lib/flows/steps/release/publish.js +11 -0
- package/lib/flows/steps/release/remove-failed-upload.js +21 -0
- package/lib/flows/steps/release/upload-zip-to-corva.js +136 -0
- package/lib/flows/steps/release/wait-for-build.js +36 -0
- package/lib/flows/steps/rerun/create-task.js +77 -0
- package/lib/flows/steps/rerun/ensure-that-app-in-stream.js +68 -0
- package/lib/flows/steps/rerun/get-app-version.js +111 -0
- package/lib/flows/steps/rerun/prepare-data.js +162 -0
- package/lib/flows/steps/rerun/prepare-well-and-stream-data.js +188 -0
- package/lib/flows/steps/rerun/rerun.js +13 -0
- package/lib/flows/steps/zip-cleanup.js +17 -0
- package/lib/flows/steps/zip-create-archive.js +15 -0
- package/lib/flows/steps/zip-file-list-resolve.js +266 -0
- package/lib/flows/steps/zip-prepare.js +20 -0
- package/lib/flows/steps/zip.js +6 -0
- package/lib/flows/zip-simple.js +6 -0
- package/lib/flows/zip.js +7 -0
- package/lib/helpers/cli-version.js +150 -0
- package/lib/helpers/commands.js +13 -0
- package/lib/helpers/logger.js +35 -0
- package/lib/helpers/manifest.js +82 -0
- package/lib/helpers/resolve-app-runtime.js +132 -0
- package/lib/helpers/utils.js +97 -0
- package/lib/helpers/versioning.js +94 -0
- package/lib/main.js +64 -0
- package/lib/options/api-key.js +6 -0
- package/lib/options/app-key.js +6 -0
- package/lib/options/app-version.js +3 -0
- package/lib/options/bump-version.js +19 -0
- package/lib/options/cache.js +11 -0
- package/lib/options/env.js +3 -0
- package/lib/options/original-cwd.js +3 -0
- package/lib/options/silent.js +3 -0
- package/package.json +1 -0
- package/template_extensions/corva/.commitlintrc.json +6 -0
- package/template_extensions/corva/.eslintrc +32 -0
- package/template_extensions/corva/.github/pull_request_template.md +14 -0
- package/template_extensions/corva/.github/workflows/code-checks.yml +15 -0
- package/template_extensions/corva/.github/workflows/develop.yml +19 -0
- package/template_extensions/corva/.github/workflows/feat-fix-delete.yml +14 -0
- package/template_extensions/corva/.github/workflows/feat-fix.yml +23 -0
- package/template_extensions/corva/.github/workflows/release-fix-X.X.X.yml +16 -0
- package/template_extensions/corva/.github/workflows/validate-pr-title.yml +19 -0
- package/template_extensions/corva/.husky/commit-msg +5 -0
- package/template_extensions/corva/.husky/pre-commit +4 -0
- package/template_extensions/corva/.release-please-manifest.json +3 -0
- package/template_extensions/corva/release-please-config.json +10 -0
- package/templates/scheduler_data-time/javascript/README.md +19 -0
- package/templates/scheduler_data-time/javascript/__tests__/processor.spec.js +15 -0
- package/templates/scheduler_data-time/javascript/index.js +15 -0
- package/templates/scheduler_data-time/python/README.md +31 -0
- package/templates/scheduler_data-time/python/lambda_function.py +7 -0
- package/templates/scheduler_data-time/python/test/__init__.py +0 -0
- package/templates/scheduler_data-time/python/test/app_test.py +10 -0
- package/templates/scheduler_data-time/typescript/README.md +25 -0
- package/templates/scheduler_data-time/typescript/__tests__/processor.spec.ts +15 -0
- package/templates/scheduler_data-time/typescript/index.ts +8 -0
- package/templates/scheduler_depth/javascript/README.md +19 -0
- package/templates/scheduler_depth/javascript/__tests__/processor.spec.js +17 -0
- package/templates/scheduler_depth/javascript/index.js +15 -0
- package/templates/scheduler_depth/python/README.md +31 -0
- package/templates/scheduler_depth/python/lambda_function.py +7 -0
- package/templates/scheduler_depth/python/test/__init__.py +0 -0
- package/templates/scheduler_depth/python/test/app_test.py +10 -0
- package/templates/scheduler_depth/typescript/README.md +25 -0
- package/templates/scheduler_depth/typescript/__tests__/processor.spec.ts +17 -0
- package/templates/scheduler_depth/typescript/index.ts +8 -0
- package/templates/scheduler_natural-time/javascript/README.md +19 -0
- package/templates/scheduler_natural-time/javascript/__tests__/processor.spec.js +15 -0
- package/templates/scheduler_natural-time/javascript/index.js +15 -0
- package/templates/scheduler_natural-time/python/README.md +31 -0
- package/templates/scheduler_natural-time/python/lambda_function.py +7 -0
- package/templates/scheduler_natural-time/python/test/__init__.py +0 -0
- package/templates/scheduler_natural-time/python/test/app_test.py +10 -0
- package/templates/scheduler_natural-time/typescript/README.md +25 -0
- package/templates/scheduler_natural-time/typescript/__tests__/processor.spec.ts +15 -0
- package/templates/scheduler_natural-time/typescript/index.ts +8 -0
- package/templates/stream_depth/javascript/README.md +19 -0
- package/templates/stream_depth/javascript/__tests__/processor.spec.js +20 -0
- package/templates/stream_depth/javascript/index.js +14 -0
- package/templates/stream_depth/python/README.md +31 -0
- package/templates/stream_depth/python/lambda_function.py +7 -0
- package/templates/stream_depth/python/test/__init__.py +0 -0
- package/templates/stream_depth/python/test/app_test.py +16 -0
- package/templates/stream_depth/typescript/README.md +25 -0
- package/templates/stream_depth/typescript/__tests__/processor.spec.ts +20 -0
- package/templates/stream_depth/typescript/index.ts +8 -0
- package/templates/stream_time/javascript/README.md +19 -0
- package/templates/stream_time/javascript/__tests__/processor.spec.js +14 -0
- package/templates/stream_time/javascript/index.js +14 -0
- package/templates/stream_time/python/README.md +31 -0
- package/templates/stream_time/python/lambda_function.py +7 -0
- package/templates/stream_time/python/test/__init__.py +0 -0
- package/templates/stream_time/python/test/app_test.py +16 -0
- package/templates/stream_time/typescript/README.md +25 -0
- package/templates/stream_time/typescript/__tests__/processor.spec.ts +14 -0
- package/templates/stream_time/typescript/index.ts +8 -0
- package/templates/task/javascript/README.md +19 -0
- package/templates/task/javascript/__tests__/processor.spec.js +16 -0
- package/templates/task/javascript/index.js +15 -0
- package/templates/task/python/README.md +31 -0
- package/templates/task/python/lambda_function.py +7 -0
- package/templates/task/python/test/__init__.py +0 -0
- package/templates/task/python/test/app_test.py +8 -0
- package/templates/task/typescript/README.md +25 -0
- package/templates/task/typescript/__tests__/processor.spec.ts +16 -0
- package/templates/task/typescript/index.ts +8 -0
- package/templates/ui/javascript/.codex/config.toml +3 -0
- package/templates/ui/javascript/.cursor/mcp.json +8 -0
- package/templates/ui/javascript/.eslintrc +11 -0
- package/templates/ui/javascript/.mcp.json +8 -0
- package/templates/ui/javascript/.prettierrc +1 -0
- package/templates/ui/javascript/AGENTS.md +304 -0
- package/templates/ui/javascript/CLAUDE.md +1 -0
- package/templates/ui/javascript/README.md +31 -0
- package/templates/ui/javascript/config/jest/babelTransform.js +16 -0
- package/templates/ui/javascript/config/jest/cssTransform.js +16 -0
- package/templates/ui/javascript/config/jest/fileTransform.js +48 -0
- package/templates/ui/javascript/config/jest/globalSetup.js +5 -0
- package/templates/ui/javascript/config/jest/setupTests.js +30 -0
- package/templates/ui/javascript/config-overrides.js +10 -0
- package/templates/ui/javascript/gitignore +27 -0
- package/templates/ui/javascript/src/App.completion.js +52 -0
- package/templates/ui/javascript/src/App.drilling.js +49 -0
- package/templates/ui/javascript/src/App.scss +17 -0
- package/templates/ui/javascript/src/AppSettings.js +28 -0
- package/templates/ui/javascript/src/__tests__/App.test.js +26 -0
- package/templates/ui/javascript/src/__tests__/AppSettings.test.js +28 -0
- package/templates/ui/javascript/src/__tests__/TestsExample.test.js +37 -0
- package/templates/ui/javascript/src/assets/logo.svg +7 -0
- package/templates/ui/javascript/src/constants.js +3 -0
- package/templates/ui/javascript/src/index.js +8 -0
- package/templates/ui/typescript/.codex/config.toml +3 -0
- package/templates/ui/typescript/.cursor/mcp.json +8 -0
- package/templates/ui/typescript/.eslintrc +28 -0
- package/templates/ui/typescript/.mcp.json +8 -0
- package/templates/ui/typescript/.prettierrc +1 -0
- package/templates/ui/typescript/AGENTS.md +344 -0
- package/templates/ui/typescript/CLAUDE.md +1 -0
- package/templates/ui/typescript/README.md +31 -0
- package/templates/ui/typescript/config/jest/babelTransform.js +16 -0
- package/templates/ui/typescript/config/jest/cssTransform.js +16 -0
- package/templates/ui/typescript/config/jest/fileTransform.js +48 -0
- package/templates/ui/typescript/config/jest/globalSetup.js +5 -0
- package/templates/ui/typescript/config/jest/setupTests.js +30 -0
- package/templates/ui/typescript/config-overrides.js +10 -0
- package/templates/ui/typescript/gitignore +27 -0
- package/templates/ui/typescript/src/App.completion.tsx +52 -0
- package/templates/ui/typescript/src/App.drilling.tsx +49 -0
- package/templates/ui/typescript/src/App.scss +17 -0
- package/templates/ui/typescript/src/AppSettings.tsx +28 -0
- package/templates/ui/typescript/src/__mocks__/mockData.ts +22 -0
- package/templates/ui/typescript/src/__tests__/App.test.tsx +27 -0
- package/templates/ui/typescript/src/__tests__/AppSettings.test.tsx +28 -0
- package/templates/ui/typescript/src/__tests__/TestsExample.test.tsx +37 -0
- package/templates/ui/typescript/src/assets/logo.svg +7 -0
- package/templates/ui/typescript/src/constants.ts +3 -0
- package/templates/ui/typescript/src/custom.d.ts +19 -0
- package/templates/ui/typescript/src/index.js +8 -0
- package/templates/ui/typescript/src/types.ts +3 -0
- package/templates/ui/typescript/tsconfig.json +7 -0
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Corva.AI platform UI app — a React dashboard widget scaffolded by `create-corva-app`.
|
|
4
|
+
Deployed to the Corva platform via `yarn release`.
|
|
5
|
+
|
|
6
|
+
## Critical Rules
|
|
7
|
+
|
|
8
|
+
These constraints are enforced by the platform. Violating them breaks the build or runtime.
|
|
9
|
+
|
|
10
|
+
1. **Root export** — `src/index.js` MUST default-export `{ component: App, settings: AppSettings }`. The component may also be a `ParentApp` wrapper (e.g., `{ component: ParentApp, settings: AppSettings }`) that wraps `App` with Context.Providers and prop initialization. This is the platform loader contract.
|
|
11
|
+
2. **UI components** — Use only `@corva/ui` components. Import from `@corva/ui/componentsV2`; fall back to `@corva/ui/components` only when a V2 version doesn't exist yet. `@material-ui/core` v4 is available as the underlying library.
|
|
12
|
+
3. **HTTP clients** — Use `corvaDataAPI` / `corvaAPI` from `@corva/ui/clients` for all network requests.
|
|
13
|
+
4. **Do not rename or delete** `App.tsx`, `AppSettings.tsx`, or `index.js` — they are platform entry points.
|
|
14
|
+
|
|
15
|
+
## Project Structure
|
|
16
|
+
|
|
17
|
+
```
|
|
18
|
+
src/
|
|
19
|
+
App.tsx — Main app component (default export required)
|
|
20
|
+
AppSettings.tsx — Settings panel component (default export required)
|
|
21
|
+
index.js — Root export: { component, settings }
|
|
22
|
+
constants.ts — Default settings values
|
|
23
|
+
types.ts — Custom app settings interface
|
|
24
|
+
custom.d.ts — Module declarations for CSS/SVG imports
|
|
25
|
+
App.scss — Component styles (SCSS modules)
|
|
26
|
+
__tests__/ — Jest test files
|
|
27
|
+
__mocks__/mockData.ts — Mock data for tests
|
|
28
|
+
assets/ — Static assets (SVGs, images)
|
|
29
|
+
config/jest/ — Jest setup (setupTests, transforms)
|
|
30
|
+
config-overrides.js — Webpack 5 customization
|
|
31
|
+
tsconfig.json — TypeScript configuration
|
|
32
|
+
manifest.json — Corva platform app metadata (generated at scaffold time)
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Key Patterns
|
|
36
|
+
|
|
37
|
+
### Component Structure
|
|
38
|
+
|
|
39
|
+
- Use `useAppCommons()` from `@corva/ui/effects` to access platform data: `appKey`, `appSettings`, `well`, `rig`, `fracFleet`, `wells`, `currentUser`, `onSettingChange`, `onSettingsChange`, etc.
|
|
40
|
+
- Define custom app settings shape in `src/types.ts` (`CustomAppSettings`).
|
|
41
|
+
- Platform types (Well, Rig, FracFleet, User, etc.) are typed in `@corva/ui` — do NOT duplicate them.
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
// App component pattern — use useAppCommons() instead of props
|
|
45
|
+
const App = () => {
|
|
46
|
+
const { appKey, well, rig, appSettings } = useAppCommons();
|
|
47
|
+
const { isExampleCheckboxChecked } = appSettings || {};
|
|
48
|
+
// ...
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// AppSettings component pattern — same hook
|
|
52
|
+
const AppSettings = () => {
|
|
53
|
+
const { appSettings, onSettingChange } = useAppCommons();
|
|
54
|
+
// ...
|
|
55
|
+
};
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Styling
|
|
59
|
+
|
|
60
|
+
The preferred way to write styles is SCSS (`.scss` files).
|
|
61
|
+
|
|
62
|
+
Every `.scss` file must import the shared utilities:
|
|
63
|
+
|
|
64
|
+
```scss
|
|
65
|
+
@import '@corva/ui/styles/common';
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
This provides all functions, variables, and mixins below.
|
|
69
|
+
|
|
70
|
+
For custom shared variables or mixins specific to the project, create a `src/styles/` directory (e.g. `_variables.scss`, `_common.scss`) and import them alongside the `@corva/ui` import.
|
|
71
|
+
|
|
72
|
+
**`spacing($top, $right?, $bottom?, $left?)`** — 8px base unit:
|
|
73
|
+
|
|
74
|
+
```scss
|
|
75
|
+
padding: spacing(2); // 16px
|
|
76
|
+
margin: spacing(1, 0); // 8px 0
|
|
77
|
+
gap: spacing(0.5); // 4px
|
|
78
|
+
padding: spacing(2, 1, 2, 1); // 16px 8px 16px 8px
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
**`colorAlpha($color, $opacity)`** — transparency:
|
|
82
|
+
|
|
83
|
+
```scss
|
|
84
|
+
background: colorAlpha($palette_t1, 0.08); // white at 8% opacity
|
|
85
|
+
border: 1px solid colorAlpha($palette_t1, 0.12);
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
**`transition($properties...)`** — standard `cubic-bezier(0.4, 0, 0.2, 1) 0.15s`:
|
|
89
|
+
|
|
90
|
+
```scss
|
|
91
|
+
transition: transition(opacity);
|
|
92
|
+
transition: transition(color, background-color);
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
**Full example:**
|
|
96
|
+
|
|
97
|
+
```scss
|
|
98
|
+
@import '@corva/ui/styles/common';
|
|
99
|
+
|
|
100
|
+
.container {
|
|
101
|
+
padding: spacing(2);
|
|
102
|
+
background: $palette_b5;
|
|
103
|
+
color: $palette_t1;
|
|
104
|
+
transition: transition(opacity, background-color);
|
|
105
|
+
|
|
106
|
+
&:hover {
|
|
107
|
+
background: colorAlpha($palette_t1, 0.08);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.label {
|
|
112
|
+
color: $palette_t7;
|
|
113
|
+
font-size: 12px;
|
|
114
|
+
}
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
**Import in component:**
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
import styles from './App.scss';
|
|
121
|
+
// Use: <div className={styles.container}>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
**Colors & Theming:**
|
|
125
|
+
|
|
126
|
+
NEVER hardcode color values (hex, rgb, hsl). Always use `@corva/ui` theme colors:
|
|
127
|
+
|
|
128
|
+
- In SCSS: use SCSS variables from `@corva/ui/styles/common` like `$palette_t1`, `$palette_b5`, `$palette_t7`
|
|
129
|
+
- Use `colorAlpha($color, $opacity)` for transparency instead of raw `rgba()`
|
|
130
|
+
- Run MCP tool `get_theme_docs` (section: "variables") to see all available theme variables
|
|
131
|
+
- Run MCP tool `get_theme_docs` (section: "palette") to see available palette colors with hex values
|
|
132
|
+
|
|
133
|
+
**Rules:**
|
|
134
|
+
|
|
135
|
+
- No inline `style={{...}}` unless absolutely necessary for dynamic values
|
|
136
|
+
- Use `classnames` for conditional/composed classes, never manual string joins
|
|
137
|
+
- No global selectors (tag selectors like `div`, `span`) — use `:global()` only when absolutely necessary
|
|
138
|
+
- No `!important`
|
|
139
|
+
- Use a descriptive camelCase class as the root selector (e.g. `.toolbar`, `.chartPanel`) instead of generic `.root`
|
|
140
|
+
|
|
141
|
+
### State Management (Zustand)
|
|
142
|
+
|
|
143
|
+
The Corva platform can render multiple instances of the same app simultaneously. If a Zustand store is created at module level (singleton), all instances share the same state. To avoid this, always create store instances inside a React Context provider.
|
|
144
|
+
|
|
145
|
+
**Store factory + context** — create a factory function and a context to hold the store instance:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
// store/createAppStore.ts
|
|
149
|
+
import { createContext } from 'react';
|
|
150
|
+
import { create } from 'zustand';
|
|
151
|
+
|
|
152
|
+
import { AppStore } from '~/types';
|
|
153
|
+
|
|
154
|
+
export const createAppStore = (initProps?: Partial<SavedSettings>) => {
|
|
155
|
+
return create<AppStore>()((set, get) => ({
|
|
156
|
+
// Compose sub-stores
|
|
157
|
+
...createSettingsStore(initProps?.settings)(set, get),
|
|
158
|
+
...createDataStore()(set, get),
|
|
159
|
+
}));
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
export const StoreContext = createContext<ReturnType<typeof createAppStore> | null>(null);
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Provider** — create the store once per app mount and pass it via context:
|
|
166
|
+
|
|
167
|
+
```typescript
|
|
168
|
+
// StoreProvider.tsx
|
|
169
|
+
import { FC, PropsWithChildren, useState } from 'react';
|
|
170
|
+
|
|
171
|
+
import { StoreContext, createAppStore } from '~/store/createAppStore';
|
|
172
|
+
|
|
173
|
+
export const StoreProvider: FC<PropsWithChildren<{ savedSettings: SavedSettings }>> = ({
|
|
174
|
+
children,
|
|
175
|
+
savedSettings,
|
|
176
|
+
}) => {
|
|
177
|
+
const [appStore] = useState(() => createAppStore(savedSettings));
|
|
178
|
+
|
|
179
|
+
return <StoreContext.Provider value={appStore}>{children}</StoreContext.Provider>;
|
|
180
|
+
};
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
**Consumer hooks** — read from context, never from a global store:
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
// hooks/useAppStore.ts
|
|
187
|
+
import { useContext } from 'react';
|
|
188
|
+
import { useStore } from 'zustand';
|
|
189
|
+
import { useStoreWithEqualityFn } from 'zustand/traditional';
|
|
190
|
+
|
|
191
|
+
import { StoreContext } from '~/store/createAppStore';
|
|
192
|
+
import { AppStore } from '~/types';
|
|
193
|
+
|
|
194
|
+
/** Read a single top-level key from the store. */
|
|
195
|
+
export const useAppStore = <T extends keyof AppStore>(key: T): AppStore[T] => {
|
|
196
|
+
const store = useContext(StoreContext);
|
|
197
|
+
if (!store) throw new Error('useAppStore must be used within StoreProvider');
|
|
198
|
+
return useStore(store, state => state[key]);
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
/** Subscribe to a derived value with optional custom equality. */
|
|
202
|
+
export const useAppStoreSelector = <R>(
|
|
203
|
+
selector: (state: AppStore) => R,
|
|
204
|
+
equalityFn?: (a: R, b: R) => boolean
|
|
205
|
+
): R => {
|
|
206
|
+
const store = useContext(StoreContext);
|
|
207
|
+
if (!store) throw new Error('useAppStoreSelector must be used within StoreProvider');
|
|
208
|
+
return useStoreWithEqualityFn(store, selector, equalityFn);
|
|
209
|
+
};
|
|
210
|
+
```
|
|
211
|
+
|
|
212
|
+
**Usage in components:**
|
|
213
|
+
|
|
214
|
+
```typescript
|
|
215
|
+
const isLegendVisible = useAppStore('isLegendVisible');
|
|
216
|
+
const selectedChannels = useAppStoreSelector(state => state.selectedChannels);
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
**Wire it up in `ParentApp`** (see full example with `QueryClientProvider` in the Data Fetching section below).
|
|
220
|
+
|
|
221
|
+
General rules:
|
|
222
|
+
|
|
223
|
+
- Name stores `use[Name]Store` (e.g., `useWellDataStore`)
|
|
224
|
+
- Use selectors: `const value = useAppStore('value')`
|
|
225
|
+
- Keep business logic in store actions
|
|
226
|
+
|
|
227
|
+
### Data Fetching (React Query v4)
|
|
228
|
+
|
|
229
|
+
Same as Zustand: the platform runs multiple app instances, so each must have its own `QueryClient`. Never create a `QueryClient` at module level — use a hook with `useState` to create it once per mount.
|
|
230
|
+
|
|
231
|
+
**`useQueryClient` hook** — creates an isolated `QueryClient` per app instance:
|
|
232
|
+
|
|
233
|
+
```typescript
|
|
234
|
+
// hooks/useQueryClient.ts
|
|
235
|
+
import { useState } from 'react';
|
|
236
|
+
import { QueryCache, QueryClient } from '@tanstack/react-query';
|
|
237
|
+
import { showErrorNotification } from '@corva/ui/utils';
|
|
238
|
+
|
|
239
|
+
export const useQueryClient = () => {
|
|
240
|
+
const [queryClient] = useState(
|
|
241
|
+
new QueryClient({
|
|
242
|
+
queryCache: new QueryCache({
|
|
243
|
+
onError: (error: unknown) => {
|
|
244
|
+
if (typeof error === 'object' && error !== null && 'message' in error) {
|
|
245
|
+
showErrorNotification(`Something went wrong: ${String(error.message)}`);
|
|
246
|
+
}
|
|
247
|
+
},
|
|
248
|
+
}),
|
|
249
|
+
defaultOptions: {
|
|
250
|
+
queries: {
|
|
251
|
+
refetchOnWindowFocus: false,
|
|
252
|
+
refetchOnReconnect: false,
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
})
|
|
256
|
+
);
|
|
257
|
+
|
|
258
|
+
return queryClient;
|
|
259
|
+
};
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Wire it up in `ParentApp`** — wrap the app tree with `QueryClientProvider`:
|
|
263
|
+
|
|
264
|
+
```typescript
|
|
265
|
+
import { QueryClientProvider } from '@tanstack/react-query';
|
|
266
|
+
|
|
267
|
+
const ParentApp = () => {
|
|
268
|
+
const { appSettings, onSettingsChange } = useAppCommons();
|
|
269
|
+
const queryClient = useQueryClient();
|
|
270
|
+
|
|
271
|
+
return (
|
|
272
|
+
<QueryClientProvider client={queryClient}>
|
|
273
|
+
<StoreProvider savedSettings={appSettings?.savedSettings}>
|
|
274
|
+
<App />
|
|
275
|
+
</StoreProvider>
|
|
276
|
+
</QueryClientProvider>
|
|
277
|
+
);
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
export default { component: ParentApp, settings: AppSettings };
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
General rules:
|
|
284
|
+
|
|
285
|
+
- Encapsulate queries in custom hooks (e.g., `useWellData`)
|
|
286
|
+
- Use typed query keys (array format)
|
|
287
|
+
- Always handle `isLoading` and `isError` states
|
|
288
|
+
|
|
289
|
+
## Naming Conventions
|
|
290
|
+
|
|
291
|
+
- Boolean variables: prefix with `is`, `has`, or `should`
|
|
292
|
+
- Non-empty array checks: `!!array.length` (not `array.length > 0`)
|
|
293
|
+
- Zustand stores: `use[StoreName]Store`
|
|
294
|
+
- TypeScript props: use `interface` (not `type`)
|
|
295
|
+
|
|
296
|
+
## Testing
|
|
297
|
+
|
|
298
|
+
- **Framework:** Jest + React Testing Library
|
|
299
|
+
- **Wrapper:** Use `AppTestWrapper` from `@corva/ui/testing` to wrap components — it provides `useAppCommons()` context
|
|
300
|
+
- **Pattern:** Pass data via `AppTestWrapper` props, render components with no props
|
|
301
|
+
- **Mocking:** Mock network requests (jest mocks or msw), never call real APIs
|
|
302
|
+
- **Timezone:** UTC is enforced (`process.env.TZ = 'UTC'`)
|
|
303
|
+
- **Mocked globals:** `ResizeObserver`, `MutationObserver` (in `setupTests.js`)
|
|
304
|
+
|
|
305
|
+
```tsx
|
|
306
|
+
// Test pattern — data flows through AppTestWrapper context
|
|
307
|
+
render(
|
|
308
|
+
<AppTestWrapper appSettings={{ isExampleCheckboxChecked: true }} well={mockWell}>
|
|
309
|
+
<App />
|
|
310
|
+
</AppTestWrapper>
|
|
311
|
+
);
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
## Commands
|
|
315
|
+
|
|
316
|
+
```
|
|
317
|
+
yarn start Dev server at http://app.local.corva.ai:8080/
|
|
318
|
+
yarn build Production bundle
|
|
319
|
+
yarn test Run tests
|
|
320
|
+
yarn lint ESLint check
|
|
321
|
+
yarn zip Create deployment ZIP
|
|
322
|
+
yarn release Release to Corva platform
|
|
323
|
+
```
|
|
324
|
+
|
|
325
|
+
## @corva/ui Documentation
|
|
326
|
+
|
|
327
|
+
Local documentation for `@corva/ui` is bundled at `node_modules/@corva/ui/docs/`.
|
|
328
|
+
Before implementing any UI component, data fetch, or API call, read the relevant doc file:
|
|
329
|
+
|
|
330
|
+
- **V2 Components:** `node_modules/@corva/ui/docs/01-components-v2/` — Props, examples, usage
|
|
331
|
+
- **V1 Components:** `node_modules/@corva/ui/docs/02-components-v1/` — Legacy components reference
|
|
332
|
+
- **Hooks:** `node_modules/@corva/ui/docs/03-hooks/` — Parameters, return types, examples
|
|
333
|
+
- **API Clients:** `node_modules/@corva/ui/docs/04-clients/` — corvaAPI, corvaDataAPI endpoints
|
|
334
|
+
- **Theme:** `node_modules/@corva/ui/docs/05-theme/` — Color palette, CSS variables
|
|
335
|
+
- **Utilities:** `node_modules/@corva/ui/docs/06-utilities/` — Helper functions
|
|
336
|
+
- **Constants:** `node_modules/@corva/ui/docs/07-constants/` — Platform constants
|
|
337
|
+
|
|
338
|
+
Start with `node_modules/@corva/ui/docs/README.md` for the full index.
|
|
339
|
+
Do NOT guess `@corva/ui` APIs — read the local docs first.
|
|
340
|
+
|
|
341
|
+
## MCP Server (Interactive Fallback)
|
|
342
|
+
|
|
343
|
+
The `corva-ui` MCP server is pre-configured (`.mcp.json`, `.cursor/mcp.json`, `.codex/config.toml`).
|
|
344
|
+
Use it for interactive queries when the local docs are insufficient or you need to search across components.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@AGENTS.md
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
# Getting Started with Create Corva App
|
|
2
|
+
|
|
3
|
+
## Available Scripts
|
|
4
|
+
|
|
5
|
+
In the project directory, you can run:
|
|
6
|
+
|
|
7
|
+
### `yarn start`
|
|
8
|
+
|
|
9
|
+
Runs the app in the development mode.\
|
|
10
|
+
Open [http://app.local.corva.ai:8080](http://app.local.corva.ai:8080/) to view it in the browser.
|
|
11
|
+
|
|
12
|
+
The page will reload if you make edits.\
|
|
13
|
+
You will also see any lint errors in the console.
|
|
14
|
+
|
|
15
|
+
### `yarn build`
|
|
16
|
+
|
|
17
|
+
Bundles the app into static files for production.
|
|
18
|
+
|
|
19
|
+
### `yarn zip`
|
|
20
|
+
|
|
21
|
+
Bundles the app into ZIP file in app root directory
|
|
22
|
+
|
|
23
|
+
### `yarn release`
|
|
24
|
+
|
|
25
|
+
Releases the app into Corva
|
|
26
|
+
|
|
27
|
+
## Documentation
|
|
28
|
+
|
|
29
|
+
- [Dev Center documentation](https://dc-docs.corva.ai/) – information about development process
|
|
30
|
+
- [Component Library](https://dc-docs.corva.ai/docs/Frontend/Data%20visualization/Components%20library)
|
|
31
|
+
- [Datasets documentation](https://dc-docs.corva.ai/docs/Datasets/Link%20App%20to%20Dataset)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
|
|
3
|
+
const babelJest = require('babel-jest').default;
|
|
4
|
+
|
|
5
|
+
module.exports = babelJest.createTransformer({
|
|
6
|
+
presets: [
|
|
7
|
+
[
|
|
8
|
+
require.resolve('babel-preset-react-app'),
|
|
9
|
+
{
|
|
10
|
+
runtime: 'automatic',
|
|
11
|
+
},
|
|
12
|
+
],
|
|
13
|
+
],
|
|
14
|
+
babelrc: false,
|
|
15
|
+
configFile: false,
|
|
16
|
+
});
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
|
|
3
|
+
// This is a custom Jest transformer turning style imports into empty objects.
|
|
4
|
+
// http://facebook.github.io/jest/docs/en/webpack.html
|
|
5
|
+
|
|
6
|
+
module.exports = {
|
|
7
|
+
process() {
|
|
8
|
+
return {
|
|
9
|
+
code: 'module.exports = {};',
|
|
10
|
+
};
|
|
11
|
+
},
|
|
12
|
+
getCacheKey() {
|
|
13
|
+
// The output is always the same.
|
|
14
|
+
return 'cssTransform';
|
|
15
|
+
},
|
|
16
|
+
};
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
|
|
3
|
+
const path = require('path');
|
|
4
|
+
|
|
5
|
+
// This is a custom Jest transformer turning file imports into filenames.
|
|
6
|
+
// http://facebook.github.io/jest/docs/en/webpack.html
|
|
7
|
+
|
|
8
|
+
const toPascalCase = str => {
|
|
9
|
+
const allWordsIterator = str.matchAll(/\w+/g);
|
|
10
|
+
|
|
11
|
+
return Array.from(allWordsIterator).reduce((acc, matchResult) => {
|
|
12
|
+
const word = matchResult[0];
|
|
13
|
+
return acc + word[0].toUpperCase() + word.slice(1).toLowerCase();
|
|
14
|
+
}, '');
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
module.exports = {
|
|
18
|
+
process(src, filename) {
|
|
19
|
+
const assetFilename = JSON.stringify(path.basename(filename));
|
|
20
|
+
|
|
21
|
+
if (filename.match(/\.svg$/)) {
|
|
22
|
+
// Based on how SVGR generates a component name:
|
|
23
|
+
// https://github.com/smooth-code/svgr/blob/01b194cf967347d43d4cbe6b434404731b87cf27/packages/core/src/state.js#L6
|
|
24
|
+
const pascalCaseFilename = toPascalCase(path.parse(filename).name);
|
|
25
|
+
const componentName = `Svg${pascalCaseFilename}`;
|
|
26
|
+
return {
|
|
27
|
+
code: `const React = require('react');
|
|
28
|
+
module.exports = {
|
|
29
|
+
__esModule: true,
|
|
30
|
+
default: ${assetFilename},
|
|
31
|
+
ReactComponent: React.forwardRef(function ${componentName}(props, ref) {
|
|
32
|
+
return {
|
|
33
|
+
$$typeof: Symbol.for('react.element'),
|
|
34
|
+
type: 'svg',
|
|
35
|
+
ref: ref,
|
|
36
|
+
key: null,
|
|
37
|
+
props: Object.assign({}, props, {
|
|
38
|
+
children: ${assetFilename}
|
|
39
|
+
})
|
|
40
|
+
};
|
|
41
|
+
}),
|
|
42
|
+
};`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
return { code: `module.exports = ${assetFilename};` };
|
|
47
|
+
},
|
|
48
|
+
};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/* eslint-disable */
|
|
2
|
+
|
|
3
|
+
// jest-dom adds custom jest matchers for asserting on DOM nodes.
|
|
4
|
+
// allows you to do things like:
|
|
5
|
+
// expect(element).toHaveTextContent(/react/i)
|
|
6
|
+
// learn more: https://github.com/testing-library/jest-dom
|
|
7
|
+
// eslint-disable-next-line
|
|
8
|
+
import '@testing-library/jest-dom/extend-expect';
|
|
9
|
+
|
|
10
|
+
// Set UTC timezone for tests to not use the environment timezone
|
|
11
|
+
process.env.TZ = 'UTC';
|
|
12
|
+
|
|
13
|
+
// Mock ResizeObserver & MutationObserver
|
|
14
|
+
class FakeObserver {
|
|
15
|
+
observe() {}
|
|
16
|
+
unobserve() {}
|
|
17
|
+
disconnect() {}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
global.ResizeObserver = FakeObserver;
|
|
21
|
+
global.MutationObserver = FakeObserver;
|
|
22
|
+
|
|
23
|
+
// Suppressing "Could not parse CSS stylesheet" from JSDOM
|
|
24
|
+
const originalConsoleError = global.console.error;
|
|
25
|
+
global.console.error = (message, ...optionalParams) => {
|
|
26
|
+
if (message.includes('Could not parse CSS stylesheet')) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
originalConsoleError(message, ...optionalParams);
|
|
30
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const { getWebpackConfig } = require('@corva/dc-platform-shared/cjs');
|
|
2
|
+
const { merge } = require('webpack-merge');
|
|
3
|
+
|
|
4
|
+
module.exports = (env, argv) => {
|
|
5
|
+
return merge(
|
|
6
|
+
getWebpackConfig(env, argv),
|
|
7
|
+
// NOTE: Custom webpack 5 plugins and module rules can be provided here
|
|
8
|
+
{}
|
|
9
|
+
);
|
|
10
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
|
2
|
+
|
|
3
|
+
# dependencies
|
|
4
|
+
/node_modules
|
|
5
|
+
/.pnp
|
|
6
|
+
.pnp.js
|
|
7
|
+
|
|
8
|
+
# testing
|
|
9
|
+
/coverage
|
|
10
|
+
|
|
11
|
+
# production
|
|
12
|
+
/build
|
|
13
|
+
/dist
|
|
14
|
+
|
|
15
|
+
# misc
|
|
16
|
+
.env
|
|
17
|
+
.DS_Store
|
|
18
|
+
.env.local
|
|
19
|
+
.env.development.local
|
|
20
|
+
.env.test.local
|
|
21
|
+
.env.production.local
|
|
22
|
+
.idea
|
|
23
|
+
|
|
24
|
+
npm-debug.log*
|
|
25
|
+
yarn-debug.log*
|
|
26
|
+
yarn-error.log*
|
|
27
|
+
.eslintcache
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { AppContainer, AppHeader } from '@corva/ui/componentsV2';
|
|
2
|
+
import { useAppCommons } from '@corva/ui/effects';
|
|
3
|
+
|
|
4
|
+
import { DEFAULT_SETTINGS } from './constants';
|
|
5
|
+
import logo from './assets/logo.svg';
|
|
6
|
+
|
|
7
|
+
import styles from './App.scss';
|
|
8
|
+
|
|
9
|
+
const App = () => {
|
|
10
|
+
const { appKey, fracFleet, well, wells, appSettings } = useAppCommons();
|
|
11
|
+
const { isExampleCheckboxChecked = DEFAULT_SETTINGS.isExampleCheckboxChecked } =
|
|
12
|
+
appSettings || {};
|
|
13
|
+
// NOTE: On general type dashboard app receives wells array
|
|
14
|
+
// on asset type dashboard app receives well object
|
|
15
|
+
const wellsList = wells || [well];
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<AppContainer header={<AppHeader />} testId={appKey}>
|
|
19
|
+
<div className={styles.container}>
|
|
20
|
+
<img src={logo} alt="logo" className={styles.logo} />
|
|
21
|
+
<p>
|
|
22
|
+
Edit <code>src/App.js</code> and save to reload.
|
|
23
|
+
<br />
|
|
24
|
+
<br />
|
|
25
|
+
</p>
|
|
26
|
+
<p>
|
|
27
|
+
Frac Fleet: <span data-testid="fracFleet">{fracFleet?.name || 'No Frac Fleet'}</span>
|
|
28
|
+
<br />
|
|
29
|
+
Wells: <span data-testid="wellsList">{wellsList.map(well => well?.name).join(', ')}</span>
|
|
30
|
+
</p>
|
|
31
|
+
<a
|
|
32
|
+
className="App-link"
|
|
33
|
+
href="https://reactjs.org"
|
|
34
|
+
target="_blank"
|
|
35
|
+
rel="noopener noreferrer"
|
|
36
|
+
>
|
|
37
|
+
Learn React
|
|
38
|
+
</a>
|
|
39
|
+
</div>
|
|
40
|
+
<div>
|
|
41
|
+
Settings "Example" checkbox is{' '}
|
|
42
|
+
<span data-testid="exampleCheckboxState">
|
|
43
|
+
{isExampleCheckboxChecked ? 'checked' : 'unchecked'}
|
|
44
|
+
</span>
|
|
45
|
+
</div>
|
|
46
|
+
</AppContainer>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
// Important: Do not change root component default export (App.js). Use it as container
|
|
51
|
+
// for your App. It's required to make build and zip scripts work as expected;
|
|
52
|
+
export default App;
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { AppContainer, AppHeader } from '@corva/ui/componentsV2';
|
|
2
|
+
import { useAppCommons } from '@corva/ui/effects';
|
|
3
|
+
|
|
4
|
+
import { DEFAULT_SETTINGS } from './constants';
|
|
5
|
+
import logo from './assets/logo.svg';
|
|
6
|
+
|
|
7
|
+
import styles from './App.scss';
|
|
8
|
+
|
|
9
|
+
const App = () => {
|
|
10
|
+
const { appKey, rig, well, appSettings } = useAppCommons();
|
|
11
|
+
const { isExampleCheckboxChecked = DEFAULT_SETTINGS.isExampleCheckboxChecked } =
|
|
12
|
+
appSettings || {};
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<AppContainer header={<AppHeader />} testId={appKey}>
|
|
16
|
+
<div className={styles.container}>
|
|
17
|
+
<img src={logo} alt="logo" className={styles.logo} />
|
|
18
|
+
<p>
|
|
19
|
+
Edit <code>src/App.js</code> and save to reload.
|
|
20
|
+
<br />
|
|
21
|
+
<br />
|
|
22
|
+
</p>
|
|
23
|
+
<p>
|
|
24
|
+
Rig: <span data-testid="rig">{rig?.name}</span>
|
|
25
|
+
<br />
|
|
26
|
+
Well: <span data-testid="well">{well?.name}</span>
|
|
27
|
+
</p>
|
|
28
|
+
<a
|
|
29
|
+
className="App-link"
|
|
30
|
+
href="https://reactjs.org"
|
|
31
|
+
target="_blank"
|
|
32
|
+
rel="noopener noreferrer"
|
|
33
|
+
>
|
|
34
|
+
Learn React
|
|
35
|
+
</a>
|
|
36
|
+
</div>
|
|
37
|
+
<div>
|
|
38
|
+
Settings "Example" checkbox is{' '}
|
|
39
|
+
<span data-testid="exampleCheckboxState">
|
|
40
|
+
{isExampleCheckboxChecked ? 'checked' : 'unchecked'}
|
|
41
|
+
</span>
|
|
42
|
+
</div>
|
|
43
|
+
</AppContainer>
|
|
44
|
+
);
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
// Important: Do not change root component default export (App.js). Use it as container
|
|
48
|
+
// for your App. It's required to make build and zip scripts work as expected;
|
|
49
|
+
export default App;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Checkbox, FormControlLabel } from '@material-ui/core';
|
|
2
|
+
import { useAppCommons } from '@corva/ui/effects';
|
|
3
|
+
|
|
4
|
+
import { DEFAULT_SETTINGS } from './constants';
|
|
5
|
+
|
|
6
|
+
const AppSettings = () => {
|
|
7
|
+
const { appSettings, onSettingChange } = useAppCommons();
|
|
8
|
+
const settings = { ...DEFAULT_SETTINGS, ...appSettings };
|
|
9
|
+
|
|
10
|
+
return (
|
|
11
|
+
<div>
|
|
12
|
+
<FormControlLabel
|
|
13
|
+
label="Example checkbox"
|
|
14
|
+
control={
|
|
15
|
+
<Checkbox
|
|
16
|
+
data-testid="exampleCheckbox"
|
|
17
|
+
checked={settings.isExampleCheckboxChecked}
|
|
18
|
+
onChange={e => onSettingChange('isExampleCheckboxChecked', e.target.checked)}
|
|
19
|
+
/>
|
|
20
|
+
}
|
|
21
|
+
/>
|
|
22
|
+
</div>
|
|
23
|
+
);
|
|
24
|
+
};
|
|
25
|
+
|
|
26
|
+
// Important: Do not change root component default export (AppSettings.js). Use it as container
|
|
27
|
+
// for your App Settings. It's required to make build and zip scripts work as expected;
|
|
28
|
+
export default AppSettings;
|