@salesforce/webapp-template-feature-react-nav-menu-experimental 1.3.4
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/LICENSE.txt +82 -0
- package/dist/.a4drules/build-validation.md +81 -0
- package/dist/.a4drules/code-quality.md +150 -0
- package/dist/.a4drules/graphql/tools/knowledge/lds-explore-graphql-schema.md +227 -0
- package/dist/.a4drules/graphql/tools/knowledge/lds-generate-graphql-mutationquery.md +211 -0
- package/dist/.a4drules/graphql/tools/knowledge/lds-generate-graphql-readquery.md +185 -0
- package/dist/.a4drules/graphql/tools/knowledge/lds-guide-graphql.md +205 -0
- package/dist/.a4drules/graphql/tools/schemas/shared.graphqls +1150 -0
- package/dist/.a4drules/graphql.md +98 -0
- package/dist/.a4drules/images.md +13 -0
- package/dist/.a4drules/react.md +361 -0
- package/dist/.a4drules/react_image_processing.md +45 -0
- package/dist/.a4drules/typescript.md +224 -0
- package/dist/.forceignore +15 -0
- package/dist/.husky/pre-commit +4 -0
- package/dist/.prettierignore +11 -0
- package/dist/.prettierrc +17 -0
- package/dist/CHANGELOG.md +19 -0
- package/dist/README.md +18 -0
- package/dist/config/project-scratch-def.json +13 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/.prettierignore +9 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/.prettierrc +11 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/eslint.config.js +113 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/feature-react-nav-menu.webapplication-meta.xml +7 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/index.html +13 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/package.json +42 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/api/graphql-operations-types.ts +127 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/api/utils/query/highRevenueAccountsQuery.graphql +29 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/app.tsx +13 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/appLayout.tsx +11 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/assets/icons/book.svg +3 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/assets/icons/copy.svg +4 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/assets/icons/rocket.svg +3 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/assets/icons/star.svg +3 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/assets/images/codey-1.png +0 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/assets/images/codey-2.png +0 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/assets/images/codey-3.png +0 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/assets/images/vibe-codey.svg +194 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/navigationMenu.tsx +81 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/pages/About.tsx +12 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/pages/Home.tsx +12 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/pages/NotFound.tsx +18 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/pages/about.tsx +10 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/pages/new.tsx +10 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/router-utils.tsx +34 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/routes.tsx +39 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/src/styles/global.css +13 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/tsconfig.json +36 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/tsconfig.node.json +13 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/vite-env.d.ts +1 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/vite.config.ts +82 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/vitest-env.d.ts +2 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/vitest.config.ts +11 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/vitest.setup.ts +1 -0
- package/dist/force-app/main/default/webapplications/feature-react-nav-menu/webapplication.json +7 -0
- package/dist/jest.config.js +6 -0
- package/dist/package.json +37 -0
- package/dist/scripts/apex/hello.apex +10 -0
- package/dist/scripts/soql/account.soql +6 -0
- package/dist/sfdx-project.json +12 -0
- package/package.json +28 -0
|
@@ -0,0 +1,224 @@
|
|
|
1
|
+
# AI Rule: TypeScript Standards
|
|
2
|
+
|
|
3
|
+
Enforces strict TypeScript standards for type-safe React applications.
|
|
4
|
+
|
|
5
|
+
## Targets
|
|
6
|
+
- `**/*.ts`
|
|
7
|
+
- `**/*.tsx`
|
|
8
|
+
|
|
9
|
+
## MANDATORY Configuration
|
|
10
|
+
- `strict: true` - Enable all strict type checking
|
|
11
|
+
- `noUncheckedIndexedAccess: true` - Prevent unsafe array/object access
|
|
12
|
+
- `noUnusedLocals: true` - Report unused variables
|
|
13
|
+
- `noUnusedParameters: true` - Report unused parameters
|
|
14
|
+
|
|
15
|
+
## Function Return Types (REQUIRED)
|
|
16
|
+
```typescript
|
|
17
|
+
// Always specify return types
|
|
18
|
+
function fetchUserData(id: string): Promise<User> {
|
|
19
|
+
return api.get(`/users/${id}`);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const calculateTotal = (items: Item[]): number => {
|
|
23
|
+
return items.reduce((sum, item) => sum + item.price, 0);
|
|
24
|
+
};
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Interface Definitions (REQUIRED)
|
|
28
|
+
```typescript
|
|
29
|
+
// Data structures
|
|
30
|
+
interface User {
|
|
31
|
+
id: string;
|
|
32
|
+
name: string;
|
|
33
|
+
email: string;
|
|
34
|
+
createdAt: Date;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// React component props
|
|
38
|
+
interface ButtonProps {
|
|
39
|
+
variant: 'primary' | 'secondary';
|
|
40
|
+
onClick: () => void;
|
|
41
|
+
disabled?: boolean;
|
|
42
|
+
children: React.ReactNode;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export const Button: React.FC<ButtonProps> = ({ variant, onClick, disabled, children }) => {
|
|
46
|
+
// Implementation
|
|
47
|
+
};
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
## Type Safety Rules
|
|
51
|
+
|
|
52
|
+
### Never Use `any`
|
|
53
|
+
```typescript
|
|
54
|
+
// FORBIDDEN
|
|
55
|
+
const data: any = await fetchData();
|
|
56
|
+
|
|
57
|
+
// REQUIRED: Proper typing
|
|
58
|
+
interface ApiResponse {
|
|
59
|
+
data: User[];
|
|
60
|
+
status: 'success' | 'error';
|
|
61
|
+
}
|
|
62
|
+
const response: ApiResponse = await fetchData();
|
|
63
|
+
|
|
64
|
+
// ACCEPTABLE: Unknown when type is truly unknown
|
|
65
|
+
const parseJson = (input: string): unknown => JSON.parse(input);
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
### Null Safety
|
|
69
|
+
```typescript
|
|
70
|
+
// Handle null/undefined explicitly
|
|
71
|
+
interface UserProfile {
|
|
72
|
+
user: User | null;
|
|
73
|
+
loading: boolean;
|
|
74
|
+
error: string | null;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Use optional chaining and nullish coalescing
|
|
78
|
+
const displayName = user?.name ?? 'Anonymous';
|
|
79
|
+
const avatarUrl = user?.profile?.avatar ?? '/default-avatar.png';
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## React TypeScript Patterns
|
|
83
|
+
|
|
84
|
+
### Event Handlers
|
|
85
|
+
```typescript
|
|
86
|
+
const handleSubmit = (event: React.FormEvent<HTMLFormElement>): void => {
|
|
87
|
+
event.preventDefault();
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
const handleInputChange = (event: React.ChangeEvent<HTMLInputElement>): void => {
|
|
91
|
+
setInputValue(event.target.value);
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
const handleClick = (event: React.MouseEvent<HTMLButtonElement>): void => {
|
|
95
|
+
console.log('Button clicked');
|
|
96
|
+
};
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### State and Hooks
|
|
100
|
+
```typescript
|
|
101
|
+
// Type useState properly
|
|
102
|
+
const [user, setUser] = useState<User | null>(null);
|
|
103
|
+
const [loading, setLoading] = useState<boolean>(false);
|
|
104
|
+
const [errors, setErrors] = useState<string[]>([]);
|
|
105
|
+
|
|
106
|
+
// Type custom hooks
|
|
107
|
+
interface UseApiResult<T> {
|
|
108
|
+
data: T | null;
|
|
109
|
+
loading: boolean;
|
|
110
|
+
error: string | null;
|
|
111
|
+
refetch: () => Promise<void>;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function useApi<T>(url: string): UseApiResult<T> {
|
|
115
|
+
const [data, setData] = useState<T | null>(null);
|
|
116
|
+
const [loading, setLoading] = useState<boolean>(false);
|
|
117
|
+
const [error, setError] = useState<string | null>(null);
|
|
118
|
+
|
|
119
|
+
return { data, loading, error, refetch };
|
|
120
|
+
}
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
## API Types
|
|
124
|
+
|
|
125
|
+
### Salesforce Records
|
|
126
|
+
```typescript
|
|
127
|
+
interface SalesforceRecord {
|
|
128
|
+
Id: string;
|
|
129
|
+
attributes: { type: string; url: string };
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
interface Account extends SalesforceRecord {
|
|
133
|
+
Name: { value: string };
|
|
134
|
+
Industry?: { value: string | null };
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Type API functions
|
|
138
|
+
async function fetchAccount(id: string): Promise<Account> {
|
|
139
|
+
const response = await axios.get<Account>(`/services/data/v62.0/ui-api/records/${id}`);
|
|
140
|
+
return response.data;
|
|
141
|
+
}
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### GraphQL
|
|
145
|
+
```typescript
|
|
146
|
+
interface GraphQLResponse<T> {
|
|
147
|
+
data: T;
|
|
148
|
+
errors?: Array<{ message: string; locations?: Array<{ line: number; column: number }> }>;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
async function executeGraphQL<T>(query: string, variables?: Record<string, unknown>): Promise<T> {
|
|
152
|
+
const response = await axios.post<GraphQLResponse<T>>('/services/data/v62.0/graphql', {
|
|
153
|
+
query,
|
|
154
|
+
variables,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
if (response.data.errors?.length) {
|
|
158
|
+
throw new Error(response.data.errors.map(e => e.message).join('; '));
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
return response.data.data;
|
|
162
|
+
}
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
## Error Handling Types
|
|
166
|
+
```typescript
|
|
167
|
+
interface ApiError {
|
|
168
|
+
message: string;
|
|
169
|
+
status: number;
|
|
170
|
+
code?: string;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
class CustomError extends Error {
|
|
174
|
+
constructor(message: string, public readonly status: number, public readonly code?: string) {
|
|
175
|
+
super(message);
|
|
176
|
+
this.name = 'CustomError';
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
## Anti-Patterns (FORBIDDEN)
|
|
182
|
+
|
|
183
|
+
### Type Assertions
|
|
184
|
+
```typescript
|
|
185
|
+
// FORBIDDEN: Unsafe assertions
|
|
186
|
+
const user = data as User;
|
|
187
|
+
|
|
188
|
+
// REQUIRED: Type guards
|
|
189
|
+
function isUser(obj: unknown): obj is User {
|
|
190
|
+
return typeof obj === 'object' && obj !== null && typeof (obj as User).id === 'string';
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (isUser(data)) {
|
|
194
|
+
console.log(data.name); // Now safely typed
|
|
195
|
+
}
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
### Missing Return Types
|
|
199
|
+
```typescript
|
|
200
|
+
// FORBIDDEN: No return type
|
|
201
|
+
const fetchData = async (id: string) => {
|
|
202
|
+
return await api.get(`/data/${id}`);
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// REQUIRED: Explicit return type
|
|
206
|
+
const fetchData = async (id: string): Promise<ApiResponse> => {
|
|
207
|
+
return await api.get(`/data/${id}`);
|
|
208
|
+
};
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
## Quality Checklist
|
|
212
|
+
Before completing TypeScript code:
|
|
213
|
+
1. All functions have explicit return types
|
|
214
|
+
2. All interfaces are properly defined
|
|
215
|
+
3. No `any` types used (use `unknown` if necessary)
|
|
216
|
+
4. Null/undefined handling is explicit
|
|
217
|
+
5. React components are properly typed
|
|
218
|
+
6. API calls have proper type definitions
|
|
219
|
+
7. `tsc -b` compiles without errors
|
|
220
|
+
|
|
221
|
+
## Enforcement
|
|
222
|
+
- TypeScript errors MUST be fixed before any commit
|
|
223
|
+
- NEVER disable TypeScript strict mode
|
|
224
|
+
- Code reviews MUST check for proper typing
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# List files or directories below to ignore them when running force:source:push, force:source:pull, and force:source:status
|
|
2
|
+
# More information: https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_exclude_source.htm
|
|
3
|
+
#
|
|
4
|
+
|
|
5
|
+
package.xml
|
|
6
|
+
|
|
7
|
+
# LWC configuration files
|
|
8
|
+
**/jsconfig.json
|
|
9
|
+
**/.eslintrc.json
|
|
10
|
+
|
|
11
|
+
# LWC Jest
|
|
12
|
+
**/__tests__/**
|
|
13
|
+
|
|
14
|
+
node_modules/
|
|
15
|
+
.DS_Store
|
package/dist/.prettierrc
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"trailingComma": "none",
|
|
3
|
+
"plugins": [
|
|
4
|
+
"prettier-plugin-apex",
|
|
5
|
+
"@prettier/plugin-xml"
|
|
6
|
+
],
|
|
7
|
+
"overrides": [
|
|
8
|
+
{
|
|
9
|
+
"files": "**/lwc/**/*.html",
|
|
10
|
+
"options": { "parser": "lwc" }
|
|
11
|
+
},
|
|
12
|
+
{
|
|
13
|
+
"files": "*.{cmp,page,component}",
|
|
14
|
+
"options": { "parser": "html" }
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
|
5
|
+
|
|
6
|
+
## [1.3.4](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.3.3...v1.3.4) (2026-01-31)
|
|
7
|
+
|
|
8
|
+
**Note:** Version bump only for package @salesforce/webapp-template-base-sfdx-project-experimental
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
## [1.3.3](https://github.com/salesforce-experience-platform-emu/webapps/compare/v1.3.2...v1.3.3) (2026-01-30)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* enabling npm publish for template packages ([#47](https://github.com/salesforce-experience-platform-emu/webapps/issues/47)) ([a8274f6](https://github.com/salesforce-experience-platform-emu/webapps/commit/a8274f606a2636c1fbdeade58f88a6797a12981e))
|
package/dist/README.md
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# Salesforce DX Project: Next Steps
|
|
2
|
+
|
|
3
|
+
Now that you’ve created a Salesforce DX project, what’s next? Here are some documentation resources to get you started.
|
|
4
|
+
|
|
5
|
+
## How Do You Plan to Deploy Your Changes?
|
|
6
|
+
|
|
7
|
+
Do you want to deploy a set of changes, or create a self-contained application? Choose a [development model](https://developer.salesforce.com/tools/vscode/en/user-guide/development-models).
|
|
8
|
+
|
|
9
|
+
## Configure Your Salesforce DX Project
|
|
10
|
+
|
|
11
|
+
The `sfdx-project.json` file contains useful configuration information for your project. See [Salesforce DX Project Configuration](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_ws_config.htm) in the _Salesforce DX Developer Guide_ for details about this file.
|
|
12
|
+
|
|
13
|
+
## Read All About It
|
|
14
|
+
|
|
15
|
+
- [Salesforce Extensions Documentation](https://developer.salesforce.com/tools/vscode/)
|
|
16
|
+
- [Salesforce CLI Setup Guide](https://developer.salesforce.com/docs/atlas.en-us.sfdx_setup.meta/sfdx_setup/sfdx_setup_intro.htm)
|
|
17
|
+
- [Salesforce DX Developer Guide](https://developer.salesforce.com/docs/atlas.en-us.sfdx_dev.meta/sfdx_dev/sfdx_dev_intro.htm)
|
|
18
|
+
- [Salesforce CLI Command Reference](https://developer.salesforce.com/docs/atlas.en-us.sfdx_cli_reference.meta/sfdx_cli_reference/cli_reference.htm)
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
{
|
|
2
|
+
"orgName": "My Saleforce Org",
|
|
3
|
+
"edition": "Developer",
|
|
4
|
+
"features": ["EnableSetPasswordInApi"],
|
|
5
|
+
"settings": {
|
|
6
|
+
"lightningExperienceSettings": {
|
|
7
|
+
"enableS1DesktopEnabled": true
|
|
8
|
+
},
|
|
9
|
+
"mobileSettings": {
|
|
10
|
+
"enableS1EncryptedStoragePref2": false
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import js from '@eslint/js';
|
|
2
|
+
import tseslint from '@typescript-eslint/eslint-plugin';
|
|
3
|
+
import tsparser from '@typescript-eslint/parser';
|
|
4
|
+
import react from 'eslint-plugin-react';
|
|
5
|
+
import reactHooks from 'eslint-plugin-react-hooks';
|
|
6
|
+
import reactRefresh from 'eslint-plugin-react-refresh';
|
|
7
|
+
import globals from 'globals';
|
|
8
|
+
|
|
9
|
+
export default [
|
|
10
|
+
// Global ignores
|
|
11
|
+
{
|
|
12
|
+
ignores: ['build/**/*', 'dist/**/*', 'coverage/**/*'],
|
|
13
|
+
},
|
|
14
|
+
// Config files and build tools (first to avoid inheritance)
|
|
15
|
+
{
|
|
16
|
+
files: ['*.config.{js,ts}', 'vite.config.ts'],
|
|
17
|
+
languageOptions: {
|
|
18
|
+
parser: tsparser,
|
|
19
|
+
parserOptions: {
|
|
20
|
+
ecmaVersion: 'latest',
|
|
21
|
+
sourceType: 'module',
|
|
22
|
+
},
|
|
23
|
+
globals: {
|
|
24
|
+
...globals.node,
|
|
25
|
+
__dirname: 'readonly',
|
|
26
|
+
process: 'readonly',
|
|
27
|
+
},
|
|
28
|
+
},
|
|
29
|
+
plugins: {
|
|
30
|
+
'@typescript-eslint': tseslint,
|
|
31
|
+
},
|
|
32
|
+
rules: {
|
|
33
|
+
'@typescript-eslint/no-var-requires': 'off',
|
|
34
|
+
},
|
|
35
|
+
},
|
|
36
|
+
// Main TypeScript/React files
|
|
37
|
+
{
|
|
38
|
+
files: ['**/*.{ts,tsx}'],
|
|
39
|
+
ignores: [
|
|
40
|
+
'coverage',
|
|
41
|
+
'dist',
|
|
42
|
+
'node_modules',
|
|
43
|
+
'build',
|
|
44
|
+
'*.config.{js,ts}',
|
|
45
|
+
'vite.config.ts',
|
|
46
|
+
],
|
|
47
|
+
languageOptions: {
|
|
48
|
+
ecmaVersion: 2020,
|
|
49
|
+
sourceType: 'module',
|
|
50
|
+
parser: tsparser,
|
|
51
|
+
parserOptions: {
|
|
52
|
+
ecmaFeatures: {
|
|
53
|
+
jsx: true,
|
|
54
|
+
},
|
|
55
|
+
ecmaVersion: 'latest',
|
|
56
|
+
sourceType: 'module',
|
|
57
|
+
project: './tsconfig.json',
|
|
58
|
+
},
|
|
59
|
+
globals: {
|
|
60
|
+
...globals.browser,
|
|
61
|
+
JSX: 'readonly',
|
|
62
|
+
},
|
|
63
|
+
},
|
|
64
|
+
plugins: {
|
|
65
|
+
react,
|
|
66
|
+
'react-hooks': reactHooks,
|
|
67
|
+
'react-refresh': reactRefresh,
|
|
68
|
+
'@typescript-eslint': tseslint,
|
|
69
|
+
},
|
|
70
|
+
rules: {
|
|
71
|
+
...js.configs.recommended.rules,
|
|
72
|
+
...tseslint.configs.recommended.rules,
|
|
73
|
+
...react.configs.recommended.rules,
|
|
74
|
+
...reactHooks.configs.recommended.rules,
|
|
75
|
+
'react/react-in-jsx-scope': 'off',
|
|
76
|
+
'react/prop-types': 'off',
|
|
77
|
+
'react/jsx-no-comment-textnodes': 'off',
|
|
78
|
+
'react/no-unescaped-entities': 'off',
|
|
79
|
+
'@typescript-eslint/no-unused-vars': [
|
|
80
|
+
'error',
|
|
81
|
+
{ argsIgnorePattern: '^_' },
|
|
82
|
+
],
|
|
83
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
84
|
+
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
85
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
86
|
+
},
|
|
87
|
+
settings: {
|
|
88
|
+
react: {
|
|
89
|
+
version: 'detect',
|
|
90
|
+
},
|
|
91
|
+
},
|
|
92
|
+
},
|
|
93
|
+
// Test files
|
|
94
|
+
{
|
|
95
|
+
files: [
|
|
96
|
+
'**/*.test.{ts,tsx}',
|
|
97
|
+
'**/test/**/*.{ts,tsx}',
|
|
98
|
+
'src/test/**/*.{ts,tsx}',
|
|
99
|
+
],
|
|
100
|
+
languageOptions: {
|
|
101
|
+
parser: tsparser,
|
|
102
|
+
globals: {
|
|
103
|
+
...globals.browser,
|
|
104
|
+
...globals.node,
|
|
105
|
+
global: 'writable',
|
|
106
|
+
JSX: 'readonly',
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
rules: {
|
|
110
|
+
'@typescript-eslint/no-explicit-any': 'off',
|
|
111
|
+
},
|
|
112
|
+
},
|
|
113
|
+
];
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<WebApplication xmlns="http://soap.sforce.com/2006/04/metadata">
|
|
3
|
+
<masterLabel>feature-react-nav-menu</masterLabel>
|
|
4
|
+
<description>A Salesforce web application.</description>
|
|
5
|
+
<isActive>true</isActive>
|
|
6
|
+
<version>1</version>
|
|
7
|
+
</WebApplication>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="UTF-8" />
|
|
5
|
+
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
7
|
+
<title>Welcome to React App</title>
|
|
8
|
+
</head>
|
|
9
|
+
<body>
|
|
10
|
+
<div id="root"></div>
|
|
11
|
+
<script type="module" src="/src/app.tsx"></script>
|
|
12
|
+
</body>
|
|
13
|
+
</html>
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "base-react-app",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"dev": "vite",
|
|
8
|
+
"build": "tsc -b && vite build",
|
|
9
|
+
"lint": "eslint .",
|
|
10
|
+
"preview": "vite preview",
|
|
11
|
+
"test": "vitest"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@salesforce/webapp-experimental": "*",
|
|
15
|
+
"@tailwindcss/vite": "^4.1.17",
|
|
16
|
+
"react": "^19.2.0",
|
|
17
|
+
"react-dom": "^19.2.0",
|
|
18
|
+
"react-router": "^7.10.1",
|
|
19
|
+
"tailwindcss": "^4.1.17"
|
|
20
|
+
},
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"@eslint/js": "^9.39.1",
|
|
23
|
+
"@salesforce/vite-plugin-webapp-experimental": "*",
|
|
24
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
25
|
+
"@testing-library/react": "^16.1.0",
|
|
26
|
+
"@testing-library/user-event": "^14.5.2",
|
|
27
|
+
"@types/node": "^24.10.1",
|
|
28
|
+
"@types/react": "^19.2.5",
|
|
29
|
+
"@types/react-dom": "^19.2.3",
|
|
30
|
+
"@vitejs/plugin-react": "^5.1.1",
|
|
31
|
+
"@vitest/ui": "^4.0.17",
|
|
32
|
+
"eslint": "^9.39.1",
|
|
33
|
+
"eslint-plugin-react-hooks": "^7.0.1",
|
|
34
|
+
"eslint-plugin-react-refresh": "^0.4.24",
|
|
35
|
+
"globals": "^16.5.0",
|
|
36
|
+
"jsdom": "^25.0.1",
|
|
37
|
+
"typescript": "~5.9.3",
|
|
38
|
+
"typescript-eslint": "^8.46.4",
|
|
39
|
+
"vite": "^7.2.4",
|
|
40
|
+
"vitest": "^4.0.17"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
export type Maybe<T> = T | null;
|
|
2
|
+
export type InputMaybe<T> = Maybe<T>;
|
|
3
|
+
export type Exact<T extends { [key: string]: unknown }> = {
|
|
4
|
+
[K in keyof T]: T[K];
|
|
5
|
+
};
|
|
6
|
+
export type MakeOptional<T, K extends keyof T> = Omit<T, K> & {
|
|
7
|
+
[SubKey in K]?: Maybe<T[SubKey]>;
|
|
8
|
+
};
|
|
9
|
+
export type MakeMaybe<T, K extends keyof T> = Omit<T, K> & {
|
|
10
|
+
[SubKey in K]: Maybe<T[SubKey]>;
|
|
11
|
+
};
|
|
12
|
+
export type MakeEmpty<
|
|
13
|
+
T extends { [key: string]: unknown },
|
|
14
|
+
K extends keyof T,
|
|
15
|
+
> = { [_ in K]?: never };
|
|
16
|
+
export type Incremental<T> =
|
|
17
|
+
| T
|
|
18
|
+
| {
|
|
19
|
+
[P in keyof T]?: P extends ' $fragmentName' | '__typename' ? T[P] : never;
|
|
20
|
+
};
|
|
21
|
+
/** All built-in and custom scalars, mapped to their actual values */
|
|
22
|
+
export type Scalars = {
|
|
23
|
+
ID: { input: string; output: string };
|
|
24
|
+
String: { input: string; output: string };
|
|
25
|
+
Boolean: { input: boolean; output: boolean };
|
|
26
|
+
Int: { input: number; output: number };
|
|
27
|
+
Float: { input: number; output: number };
|
|
28
|
+
Base64: { input: any; output: any };
|
|
29
|
+
/** An arbitrary precision signed decimal */
|
|
30
|
+
BigDecimal: { input: any; output: any };
|
|
31
|
+
/** An arbitrary precision signed integer */
|
|
32
|
+
BigInteger: { input: any; output: any };
|
|
33
|
+
/** An 8-bit signed integer */
|
|
34
|
+
Byte: { input: any; output: any };
|
|
35
|
+
/** A UTF-16 code unit; a character on Unicode's BMP */
|
|
36
|
+
Char: { input: any; output: any };
|
|
37
|
+
Currency: { input: any; output: any };
|
|
38
|
+
Date: { input: any; output: any };
|
|
39
|
+
DateTime: { input: any; output: any };
|
|
40
|
+
Double: { input: any; output: any };
|
|
41
|
+
Email: { input: any; output: any };
|
|
42
|
+
EncryptedString: { input: any; output: any };
|
|
43
|
+
/** Can be set to an ID or a Reference to the result of another mutation operation. */
|
|
44
|
+
IdOrRef: { input: any; output: any };
|
|
45
|
+
JSON: { input: any; output: any };
|
|
46
|
+
Latitude: { input: any; output: any };
|
|
47
|
+
/** A 64-bit signed integer */
|
|
48
|
+
Long: { input: any; output: any };
|
|
49
|
+
LongTextArea: { input: any; output: any };
|
|
50
|
+
Longitude: { input: any; output: any };
|
|
51
|
+
MultiPicklist: { input: any; output: any };
|
|
52
|
+
Percent: { input: any; output: any };
|
|
53
|
+
PhoneNumber: { input: any; output: any };
|
|
54
|
+
Picklist: { input: any; output: any };
|
|
55
|
+
RichTextArea: { input: any; output: any };
|
|
56
|
+
/** A 16-bit signed integer */
|
|
57
|
+
Short: { input: any; output: any };
|
|
58
|
+
TextArea: { input: any; output: any };
|
|
59
|
+
Time: { input: any; output: any };
|
|
60
|
+
Url: { input: any; output: any };
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
export enum DataType {
|
|
64
|
+
Address = 'ADDRESS',
|
|
65
|
+
Anytype = 'ANYTYPE',
|
|
66
|
+
Base64 = 'BASE64',
|
|
67
|
+
Boolean = 'BOOLEAN',
|
|
68
|
+
Combobox = 'COMBOBOX',
|
|
69
|
+
Complexvalue = 'COMPLEXVALUE',
|
|
70
|
+
Currency = 'CURRENCY',
|
|
71
|
+
Date = 'DATE',
|
|
72
|
+
Datetime = 'DATETIME',
|
|
73
|
+
Double = 'DOUBLE',
|
|
74
|
+
Email = 'EMAIL',
|
|
75
|
+
Encryptedstring = 'ENCRYPTEDSTRING',
|
|
76
|
+
Int = 'INT',
|
|
77
|
+
Json = 'JSON',
|
|
78
|
+
Junctionidlist = 'JUNCTIONIDLIST',
|
|
79
|
+
Location = 'LOCATION',
|
|
80
|
+
Long = 'LONG',
|
|
81
|
+
Multipicklist = 'MULTIPICKLIST',
|
|
82
|
+
Percent = 'PERCENT',
|
|
83
|
+
Phone = 'PHONE',
|
|
84
|
+
Picklist = 'PICKLIST',
|
|
85
|
+
Reference = 'REFERENCE',
|
|
86
|
+
String = 'STRING',
|
|
87
|
+
Textarea = 'TEXTAREA',
|
|
88
|
+
Time = 'TIME',
|
|
89
|
+
Url = 'URL',
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export enum FieldExtraTypeInfo {
|
|
93
|
+
ExternalLookup = 'EXTERNAL_LOOKUP',
|
|
94
|
+
ImageUrl = 'IMAGE_URL',
|
|
95
|
+
IndirectLookup = 'INDIRECT_LOOKUP',
|
|
96
|
+
Personname = 'PERSONNAME',
|
|
97
|
+
Plaintextarea = 'PLAINTEXTAREA',
|
|
98
|
+
Richtextarea = 'RICHTEXTAREA',
|
|
99
|
+
SwitchablePersonname = 'SWITCHABLE_PERSONNAME',
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
export enum ResultOrder {
|
|
103
|
+
Asc = 'ASC',
|
|
104
|
+
Desc = 'DESC',
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
export type GetHighRevenueAccountsQueryVariables = Exact<{
|
|
108
|
+
minRevenue?: InputMaybe<Scalars['Currency']['input']>;
|
|
109
|
+
}>;
|
|
110
|
+
|
|
111
|
+
export type GetHighRevenueAccountsQuery = {
|
|
112
|
+
uiapi: {
|
|
113
|
+
query: {
|
|
114
|
+
Account?: {
|
|
115
|
+
edges?: Array<{
|
|
116
|
+
node?: {
|
|
117
|
+
Id: string;
|
|
118
|
+
Name?: { value?: string | null } | null;
|
|
119
|
+
AnnualRevenue?: { value?: any | null } | null;
|
|
120
|
+
Industry?: { value?: any | null } | null;
|
|
121
|
+
Website?: { value?: any | null } | null;
|
|
122
|
+
} | null;
|
|
123
|
+
} | null> | null;
|
|
124
|
+
} | null;
|
|
125
|
+
};
|
|
126
|
+
};
|
|
127
|
+
};
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
query GetHighRevenueAccounts($minRevenue: Currency) {
|
|
2
|
+
uiapi {
|
|
3
|
+
query {
|
|
4
|
+
Account(
|
|
5
|
+
where: { AnnualRevenue: { gt: $minRevenue } }
|
|
6
|
+
orderBy: { AnnualRevenue: { order: DESC } }
|
|
7
|
+
first: 50
|
|
8
|
+
) {
|
|
9
|
+
edges {
|
|
10
|
+
node {
|
|
11
|
+
Id
|
|
12
|
+
Name {
|
|
13
|
+
value
|
|
14
|
+
}
|
|
15
|
+
AnnualRevenue {
|
|
16
|
+
value
|
|
17
|
+
}
|
|
18
|
+
Industry {
|
|
19
|
+
value
|
|
20
|
+
}
|
|
21
|
+
Website {
|
|
22
|
+
value
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|