@salesforce/webapp-template-feature-react-chart-experimental 1.13.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.
- package/LICENSE.txt +82 -0
- package/README.md +74 -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/skills/install-feature/SKILL.md +58 -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 +158 -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-chart/.prettierignore +9 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/.prettierrc +11 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/eslint.config.js +113 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/feature-react-chart.webapplication-meta.xml +7 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/index.html +13 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/package-lock.json +8691 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/package.json +50 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/api/graphql-operations-types.ts +127 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/api/utils/query/highRevenueAccountsQuery.graphql +29 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/app.tsx +13 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/appLayout.tsx +9 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/assets/icons/book.svg +3 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/assets/icons/copy.svg +4 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/assets/icons/rocket.svg +3 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/assets/icons/star.svg +3 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/assets/images/codey-1.png +0 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/assets/images/codey-2.png +0 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/assets/images/codey-3.png +0 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/assets/images/vibe-codey.svg +194 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/AnalyticsChart.tsx +111 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ChartContainer.tsx +25 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ui/alert.tsx +65 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ui/button.tsx +56 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ui/card.tsx +77 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ui/field.tsx +111 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ui/index.ts +71 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ui/input.tsx +19 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ui/label.tsx +19 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ui/pagination.tsx +99 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ui/select.tsx +151 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ui/skeleton.tsx +7 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ui/spinner.tsx +21 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ui/table.tsx +114 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/components/ui/tabs.tsx +115 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/index.ts +14 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/lib/utils.ts +6 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/pages/About.tsx +12 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/pages/ChartPage.tsx +51 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/pages/Home.tsx +12 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/pages/NotFound.tsx +18 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/routes.tsx +34 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/styles/global.css +13 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/src/types/chart.ts +22 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/tsconfig.json +36 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/tsconfig.node.json +13 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/vite-env.d.ts +1 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/vite.config.ts +70 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/vitest-env.d.ts +2 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/vitest.config.ts +11 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/vitest.setup.ts +1 -0
- package/dist/force-app/main/default/webapplications/feature-react-chart/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 +40 -0
- package/src/force-app/main/default/webapplications/feature-react-chart/src/components/AnalyticsChart.tsx +111 -0
- package/src/force-app/main/default/webapplications/feature-react-chart/src/components/ChartContainer.tsx +25 -0
- package/src/force-app/main/default/webapplications/feature-react-chart/src/index.ts +14 -0
- package/src/force-app/main/default/webapplications/feature-react-chart/src/pages/ChartPage.tsx +51 -0
- package/src/force-app/main/default/webapplications/feature-react-chart/src/routes.tsx +17 -0
- package/src/force-app/main/default/webapplications/feature-react-chart/src/types/chart.ts +22 -0
- package/src/force-app/main/default/webapplications/feature-react-chart/vite.config.ts +70 -0
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import react from "@vitejs/plugin-react";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { resolve } from "path";
|
|
5
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
6
|
+
import salesforce from "@salesforce/vite-plugin-webapp-experimental";
|
|
7
|
+
|
|
8
|
+
export default defineConfig(({ mode }) => {
|
|
9
|
+
return {
|
|
10
|
+
plugins: [tailwindcss(), react(), salesforce()],
|
|
11
|
+
|
|
12
|
+
build: {
|
|
13
|
+
outDir: resolve(__dirname, "dist"),
|
|
14
|
+
assetsDir: "assets",
|
|
15
|
+
sourcemap: false,
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
resolve: {
|
|
19
|
+
dedupe: ["react", "react-dom"],
|
|
20
|
+
alias: {
|
|
21
|
+
// Single React instance so recharts (and other deps) use the app's React
|
|
22
|
+
react: path.resolve(__dirname, "node_modules/react"),
|
|
23
|
+
"react-dom": path.resolve(__dirname, "node_modules/react-dom"),
|
|
24
|
+
"@": path.resolve(__dirname, "./src"),
|
|
25
|
+
"@api": path.resolve(__dirname, "./src/api"),
|
|
26
|
+
"@components": path.resolve(__dirname, "./src/components"),
|
|
27
|
+
"@utils": path.resolve(__dirname, "./src/utils"),
|
|
28
|
+
"@styles": path.resolve(__dirname, "./src/styles"),
|
|
29
|
+
"@assets": path.resolve(__dirname, "./src/assets"),
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
test: {
|
|
34
|
+
root: resolve(__dirname),
|
|
35
|
+
environment: "jsdom",
|
|
36
|
+
setupFiles: ["./src/test/setup.ts"],
|
|
37
|
+
include: [
|
|
38
|
+
"src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
|
|
39
|
+
"src/**/__tests__/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
|
|
40
|
+
],
|
|
41
|
+
coverage: {
|
|
42
|
+
provider: "v8",
|
|
43
|
+
reporter: ["text", "html", "clover", "json"],
|
|
44
|
+
exclude: [
|
|
45
|
+
"node_modules/",
|
|
46
|
+
"src/test/",
|
|
47
|
+
"src/**/*.d.ts",
|
|
48
|
+
"src/main.tsx",
|
|
49
|
+
"src/vite-env.d.ts",
|
|
50
|
+
"src/components/**/index.ts",
|
|
51
|
+
"**/*.config.ts",
|
|
52
|
+
"build/",
|
|
53
|
+
"dist/",
|
|
54
|
+
"coverage/",
|
|
55
|
+
"eslint.config.js",
|
|
56
|
+
],
|
|
57
|
+
thresholds: {
|
|
58
|
+
global: {
|
|
59
|
+
branches: 85,
|
|
60
|
+
functions: 85,
|
|
61
|
+
lines: 85,
|
|
62
|
+
statements: 85,
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
testTimeout: 10000,
|
|
67
|
+
globals: true,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@salesforce/webapp-template-base-sfdx-project-experimental",
|
|
3
|
+
"version": "1.13.0",
|
|
4
|
+
"description": "Base SFDX project template",
|
|
5
|
+
"private": true,
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"scripts": {
|
|
10
|
+
"build": "echo 'No build required for base-sfdx-project'",
|
|
11
|
+
"clean": "echo 'No clean required for base-sfdx-project'",
|
|
12
|
+
"lint": "eslint **/{aura,lwc}/**/*.js",
|
|
13
|
+
"test": "npm run test:unit",
|
|
14
|
+
"test:unit": "sfdx-lwc-jest -- --passWithNoTests",
|
|
15
|
+
"test:unit:watch": "sfdx-lwc-jest --watch",
|
|
16
|
+
"test:unit:debug": "sfdx-lwc-jest --debug",
|
|
17
|
+
"test:unit:coverage": "sfdx-lwc-jest --coverage",
|
|
18
|
+
"prettier": "prettier --write \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"",
|
|
19
|
+
"prettier:verify": "prettier --check \"**/*.{cls,cmp,component,css,html,js,json,md,page,trigger,xml,yaml,yml}\"",
|
|
20
|
+
"precommit": "lint-staged"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@lwc/eslint-plugin-lwc": "^2.0.0",
|
|
24
|
+
"@prettier/plugin-xml": "^3.2.2",
|
|
25
|
+
"@salesforce/eslint-config-lwc": "^3.2.3",
|
|
26
|
+
"@salesforce/eslint-plugin-aura": "^2.0.0",
|
|
27
|
+
"@salesforce/eslint-plugin-lightning": "^1.0.0",
|
|
28
|
+
"@salesforce/sfdx-lwc-jest": "^7.0.1",
|
|
29
|
+
"eslint": "8.57.1",
|
|
30
|
+
"eslint-plugin-import": "^2.25.4",
|
|
31
|
+
"eslint-plugin-jest": "^28.8.1",
|
|
32
|
+
"husky": "^9.1.5",
|
|
33
|
+
"lint-staged": "^15.1.0",
|
|
34
|
+
"prettier": "^3.1.0",
|
|
35
|
+
"prettier-plugin-apex": "^2.0.1"
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
// Use .apex files to store anonymous Apex.
|
|
2
|
+
// You can execute anonymous Apex in VS Code by selecting the
|
|
3
|
+
// apex text and running the command:
|
|
4
|
+
// SFDX: Execute Anonymous Apex with Currently Selected Text
|
|
5
|
+
// You can also execute the entire file by running the command:
|
|
6
|
+
// SFDX: Execute Anonymous Apex with Editor Contents
|
|
7
|
+
|
|
8
|
+
string tempvar = 'Enter_your_name_here';
|
|
9
|
+
System.debug('Hello World!');
|
|
10
|
+
System.debug('My name is ' + tempvar);
|
package/package.json
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@salesforce/webapp-template-feature-react-chart-experimental",
|
|
3
|
+
"version": "1.13.0",
|
|
4
|
+
"description": "Chart feature with analytics chart components, agent skills, and rules (Recharts)",
|
|
5
|
+
"license": "SEE LICENSE IN LICENSE.txt",
|
|
6
|
+
"author": "",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "src/force-app/main/default/webapplications/feature-react-chart/src/index.ts",
|
|
9
|
+
"types": "src/force-app/main/default/webapplications/feature-react-chart/src/index.ts",
|
|
10
|
+
"exports": {
|
|
11
|
+
".": {
|
|
12
|
+
"types": "./src/force-app/main/default/webapplications/feature-react-chart/src/index.ts",
|
|
13
|
+
"import": "./src/force-app/main/default/webapplications/feature-react-chart/src/index.ts",
|
|
14
|
+
"default": "./src/force-app/main/default/webapplications/feature-react-chart/src/index.ts"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"src"
|
|
20
|
+
],
|
|
21
|
+
"publishConfig": {
|
|
22
|
+
"access": "public"
|
|
23
|
+
},
|
|
24
|
+
"scripts": {
|
|
25
|
+
"build": "npx tsx ../../cli/src/index.ts apply-patches packages/template/feature/feature-react-chart packages/template/base-app/base-react-app packages/template/feature/feature-react-chart/dist --reset",
|
|
26
|
+
"clean": "rm -rf dist",
|
|
27
|
+
"dev": "cd dist/force-app/main/default/webapplications/feature-react-chart && npm install && npm run dev",
|
|
28
|
+
"watch": "npx tsx ../../cli/src/index.ts watch-patches packages/template/feature/feature-react-chart packages/template/base-app/base-react-app packages/template/feature/feature-react-chart/dist"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@salesforce/webapp-experimental": "^1.13.0",
|
|
32
|
+
"@types/react": "^19.2.7",
|
|
33
|
+
"@types/react-dom": "^19.2.3",
|
|
34
|
+
"react-dom": "^19.2.1",
|
|
35
|
+
"react-router": "^7.10.1",
|
|
36
|
+
"recharts": "^2.15.0",
|
|
37
|
+
"vite": "^7.3.1"
|
|
38
|
+
},
|
|
39
|
+
"gitHead": "f5823a67b25f01d2c4510377cb4d2c34e7ace922"
|
|
40
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
import {
|
|
3
|
+
LineChart,
|
|
4
|
+
Line,
|
|
5
|
+
BarChart,
|
|
6
|
+
Bar,
|
|
7
|
+
XAxis,
|
|
8
|
+
YAxis,
|
|
9
|
+
CartesianGrid,
|
|
10
|
+
Tooltip,
|
|
11
|
+
ResponsiveContainer,
|
|
12
|
+
Legend,
|
|
13
|
+
} from "recharts";
|
|
14
|
+
import type {
|
|
15
|
+
ChartTheme,
|
|
16
|
+
TimeSeriesDataPoint,
|
|
17
|
+
CategoricalDataPoint,
|
|
18
|
+
AnalyticsChartProps,
|
|
19
|
+
} from "../types/chart";
|
|
20
|
+
|
|
21
|
+
const THEME_COLORS: Record<ChartTheme, { stroke: string; fill: string }> = {
|
|
22
|
+
red: { stroke: "#dc2626", fill: "#fecaca" },
|
|
23
|
+
green: { stroke: "#16a34a", fill: "#bbf7d0" },
|
|
24
|
+
neutral: { stroke: "#64748b", fill: "#cbd5e1" },
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
function isTimeSeries(data: AnalyticsChartProps["data"]): data is TimeSeriesDataPoint[] {
|
|
28
|
+
return data.length > 0 && "x" in data[0] && "y" in data[0];
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Line (time-series) or bar (categorical) chart with theme. */
|
|
32
|
+
export function AnalyticsChart({
|
|
33
|
+
chartType,
|
|
34
|
+
data,
|
|
35
|
+
theme = "neutral",
|
|
36
|
+
title,
|
|
37
|
+
className = "",
|
|
38
|
+
}: AnalyticsChartProps) {
|
|
39
|
+
const colors = THEME_COLORS[theme];
|
|
40
|
+
|
|
41
|
+
if (!data || data.length === 0) {
|
|
42
|
+
return (
|
|
43
|
+
<div className={className} style={{ padding: "1rem", color: "#64748b" }}>
|
|
44
|
+
{title ? <h3 style={{ margin: "0 0 0.5rem 0" }}>{title}</h3> : null}
|
|
45
|
+
<p style={{ margin: 0 }}>No data to display.</p>
|
|
46
|
+
</div>
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const content =
|
|
51
|
+
chartType === "time-series" && isTimeSeries(data) ? (
|
|
52
|
+
<ResponsiveContainer width="100%" height={300}>
|
|
53
|
+
<LineChart data={data} margin={{ top: 5, right: 20, left: 0, bottom: 5 }}>
|
|
54
|
+
<CartesianGrid strokeDasharray="3 3" stroke="#e2e8f0" />
|
|
55
|
+
<XAxis dataKey="x" stroke="#64748b" fontSize={12} />
|
|
56
|
+
<YAxis stroke="#64748b" fontSize={12} />
|
|
57
|
+
<Tooltip
|
|
58
|
+
contentStyle={{
|
|
59
|
+
backgroundColor: "#fff",
|
|
60
|
+
border: "1px solid #e2e8f0",
|
|
61
|
+
borderRadius: "6px",
|
|
62
|
+
}}
|
|
63
|
+
/>
|
|
64
|
+
<Legend />
|
|
65
|
+
<Line
|
|
66
|
+
type="monotone"
|
|
67
|
+
dataKey="y"
|
|
68
|
+
stroke={colors.stroke}
|
|
69
|
+
strokeWidth={2}
|
|
70
|
+
dot={{ fill: colors.stroke }}
|
|
71
|
+
name="Value"
|
|
72
|
+
/>
|
|
73
|
+
</LineChart>
|
|
74
|
+
</ResponsiveContainer>
|
|
75
|
+
) : (
|
|
76
|
+
<ResponsiveContainer width="100%" height={300}>
|
|
77
|
+
<BarChart
|
|
78
|
+
data={data as CategoricalDataPoint[]}
|
|
79
|
+
margin={{ top: 5, right: 20, left: 0, bottom: 5 }}
|
|
80
|
+
>
|
|
81
|
+
<CartesianGrid strokeDasharray="3 3" stroke="#e2e8f0" />
|
|
82
|
+
<XAxis dataKey="name" stroke="#64748b" fontSize={12} />
|
|
83
|
+
<YAxis stroke="#64748b" fontSize={12} />
|
|
84
|
+
<Tooltip
|
|
85
|
+
contentStyle={{
|
|
86
|
+
backgroundColor: "#fff",
|
|
87
|
+
border: "1px solid #e2e8f0",
|
|
88
|
+
borderRadius: "6px",
|
|
89
|
+
}}
|
|
90
|
+
/>
|
|
91
|
+
<Legend />
|
|
92
|
+
<Bar
|
|
93
|
+
dataKey="value"
|
|
94
|
+
fill={colors.fill}
|
|
95
|
+
stroke={colors.stroke}
|
|
96
|
+
strokeWidth={1}
|
|
97
|
+
name="Value"
|
|
98
|
+
/>
|
|
99
|
+
</BarChart>
|
|
100
|
+
</ResponsiveContainer>
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
return (
|
|
104
|
+
<div className={className} style={{ padding: "1rem" }}>
|
|
105
|
+
{title ? <h3 style={{ margin: "0 0 0.75rem 0", fontSize: "1.125rem" }}>{title}</h3> : null}
|
|
106
|
+
{content}
|
|
107
|
+
</div>
|
|
108
|
+
);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
export default AnalyticsChart;
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import * as React from "react";
|
|
2
|
+
|
|
3
|
+
export interface ChartContainerProps {
|
|
4
|
+
children: React.ReactNode;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
/** Wrapper for chart components (e.g. AnalyticsChart). */
|
|
9
|
+
export function ChartContainer({ children, className = "" }: ChartContainerProps) {
|
|
10
|
+
return (
|
|
11
|
+
<div
|
|
12
|
+
className={className}
|
|
13
|
+
style={{
|
|
14
|
+
border: "1px solid #e2e8f0",
|
|
15
|
+
borderRadius: "8px",
|
|
16
|
+
backgroundColor: "#fff",
|
|
17
|
+
overflow: "hidden",
|
|
18
|
+
}}
|
|
19
|
+
>
|
|
20
|
+
{children}
|
|
21
|
+
</div>
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export default ChartContainer;
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* feature-react-chart – Analytics chart components
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
export { AnalyticsChart } from "./components/AnalyticsChart";
|
|
6
|
+
export { ChartContainer } from "./components/ChartContainer";
|
|
7
|
+
export type {
|
|
8
|
+
AnalyticsChartProps,
|
|
9
|
+
ChartDataType,
|
|
10
|
+
ChartTheme,
|
|
11
|
+
TimeSeriesDataPoint,
|
|
12
|
+
CategoricalDataPoint,
|
|
13
|
+
ChartDataPoint,
|
|
14
|
+
} from "./types/chart";
|
package/src/force-app/main/default/webapplications/feature-react-chart/src/pages/ChartPage.tsx
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ChartContainer } from "../components/ChartContainer";
|
|
2
|
+
import { AnalyticsChart } from "../components/AnalyticsChart";
|
|
3
|
+
import type { TimeSeriesDataPoint, CategoricalDataPoint } from "../types/chart";
|
|
4
|
+
|
|
5
|
+
const sampleTimeSeries: TimeSeriesDataPoint[] = [
|
|
6
|
+
{ x: "Jan", y: 42 },
|
|
7
|
+
{ x: "Feb", y: 38 },
|
|
8
|
+
{ x: "Mar", y: 55 },
|
|
9
|
+
{ x: "Apr", y: 61 },
|
|
10
|
+
{ x: "May", y: 58 },
|
|
11
|
+
{ x: "Jun", y: 72 },
|
|
12
|
+
];
|
|
13
|
+
|
|
14
|
+
const sampleCategorical: CategoricalDataPoint[] = [
|
|
15
|
+
{ name: "Product A", value: 120 },
|
|
16
|
+
{ name: "Product B", value: 85 },
|
|
17
|
+
{ name: "Product C", value: 95 },
|
|
18
|
+
{ name: "Product D", value: 64 },
|
|
19
|
+
{ name: "Product E", value: 110 },
|
|
20
|
+
];
|
|
21
|
+
|
|
22
|
+
export default function ChartPage() {
|
|
23
|
+
return (
|
|
24
|
+
<div className="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12">
|
|
25
|
+
<div className="mb-8">
|
|
26
|
+
<h1 className="text-4xl font-bold text-gray-900 mb-2">Analytics</h1>
|
|
27
|
+
<p className="text-lg text-gray-600">Sample time-series and categorical charts.</p>
|
|
28
|
+
</div>
|
|
29
|
+
|
|
30
|
+
<div className="space-y-8">
|
|
31
|
+
<ChartContainer className="max-w-3xl">
|
|
32
|
+
<AnalyticsChart
|
|
33
|
+
chartType="time-series"
|
|
34
|
+
data={sampleTimeSeries}
|
|
35
|
+
theme="green"
|
|
36
|
+
title="Monthly trend"
|
|
37
|
+
/>
|
|
38
|
+
</ChartContainer>
|
|
39
|
+
|
|
40
|
+
<ChartContainer className="max-w-3xl">
|
|
41
|
+
<AnalyticsChart
|
|
42
|
+
chartType="categorical"
|
|
43
|
+
data={sampleCategorical}
|
|
44
|
+
theme="neutral"
|
|
45
|
+
title="By category"
|
|
46
|
+
/>
|
|
47
|
+
</ChartContainer>
|
|
48
|
+
</div>
|
|
49
|
+
</div>
|
|
50
|
+
);
|
|
51
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { RouteObject } from "react-router";
|
|
2
|
+
import AppLayout from "./appLayout";
|
|
3
|
+
import ChartPage from "./pages/ChartPage";
|
|
4
|
+
|
|
5
|
+
export const routes: RouteObject[] = [
|
|
6
|
+
{
|
|
7
|
+
path: "/",
|
|
8
|
+
element: <AppLayout />,
|
|
9
|
+
children: [
|
|
10
|
+
{
|
|
11
|
+
path: "chart",
|
|
12
|
+
element: <ChartPage />,
|
|
13
|
+
handle: { showInNavigation: true, label: "Chart" },
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
},
|
|
17
|
+
];
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export type ChartDataType = "time-series" | "categorical";
|
|
2
|
+
export type ChartTheme = "red" | "green" | "neutral";
|
|
3
|
+
|
|
4
|
+
export interface TimeSeriesDataPoint {
|
|
5
|
+
x: string;
|
|
6
|
+
y: number;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export interface CategoricalDataPoint {
|
|
10
|
+
name: string;
|
|
11
|
+
value: number;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export type ChartDataPoint = TimeSeriesDataPoint | CategoricalDataPoint;
|
|
15
|
+
|
|
16
|
+
export interface AnalyticsChartProps {
|
|
17
|
+
chartType: ChartDataType;
|
|
18
|
+
data: ChartDataPoint[];
|
|
19
|
+
theme?: ChartTheme;
|
|
20
|
+
title?: string;
|
|
21
|
+
className?: string;
|
|
22
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { defineConfig } from "vite";
|
|
2
|
+
import react from "@vitejs/plugin-react";
|
|
3
|
+
import path from "path";
|
|
4
|
+
import { resolve } from "path";
|
|
5
|
+
import tailwindcss from "@tailwindcss/vite";
|
|
6
|
+
import salesforce from "@salesforce/vite-plugin-webapp-experimental";
|
|
7
|
+
|
|
8
|
+
export default defineConfig(({ mode }) => {
|
|
9
|
+
return {
|
|
10
|
+
plugins: [tailwindcss(), react(), salesforce()],
|
|
11
|
+
|
|
12
|
+
build: {
|
|
13
|
+
outDir: resolve(__dirname, "dist"),
|
|
14
|
+
assetsDir: "assets",
|
|
15
|
+
sourcemap: false,
|
|
16
|
+
},
|
|
17
|
+
|
|
18
|
+
resolve: {
|
|
19
|
+
dedupe: ["react", "react-dom"],
|
|
20
|
+
alias: {
|
|
21
|
+
// Single React instance so recharts (and other deps) use the app's React
|
|
22
|
+
react: path.resolve(__dirname, "node_modules/react"),
|
|
23
|
+
"react-dom": path.resolve(__dirname, "node_modules/react-dom"),
|
|
24
|
+
"@": path.resolve(__dirname, "./src"),
|
|
25
|
+
"@api": path.resolve(__dirname, "./src/api"),
|
|
26
|
+
"@components": path.resolve(__dirname, "./src/components"),
|
|
27
|
+
"@utils": path.resolve(__dirname, "./src/utils"),
|
|
28
|
+
"@styles": path.resolve(__dirname, "./src/styles"),
|
|
29
|
+
"@assets": path.resolve(__dirname, "./src/assets"),
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
|
|
33
|
+
test: {
|
|
34
|
+
root: resolve(__dirname),
|
|
35
|
+
environment: "jsdom",
|
|
36
|
+
setupFiles: ["./src/test/setup.ts"],
|
|
37
|
+
include: [
|
|
38
|
+
"src/**/*.{test,spec}.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
|
|
39
|
+
"src/**/__tests__/**/*.{js,mjs,cjs,ts,mts,cts,jsx,tsx}",
|
|
40
|
+
],
|
|
41
|
+
coverage: {
|
|
42
|
+
provider: "v8",
|
|
43
|
+
reporter: ["text", "html", "clover", "json"],
|
|
44
|
+
exclude: [
|
|
45
|
+
"node_modules/",
|
|
46
|
+
"src/test/",
|
|
47
|
+
"src/**/*.d.ts",
|
|
48
|
+
"src/main.tsx",
|
|
49
|
+
"src/vite-env.d.ts",
|
|
50
|
+
"src/components/**/index.ts",
|
|
51
|
+
"**/*.config.ts",
|
|
52
|
+
"build/",
|
|
53
|
+
"dist/",
|
|
54
|
+
"coverage/",
|
|
55
|
+
"eslint.config.js",
|
|
56
|
+
],
|
|
57
|
+
thresholds: {
|
|
58
|
+
global: {
|
|
59
|
+
branches: 85,
|
|
60
|
+
functions: 85,
|
|
61
|
+
lines: 85,
|
|
62
|
+
statements: 85,
|
|
63
|
+
},
|
|
64
|
+
},
|
|
65
|
+
},
|
|
66
|
+
testTimeout: 10000,
|
|
67
|
+
globals: true,
|
|
68
|
+
},
|
|
69
|
+
};
|
|
70
|
+
});
|