@salesforce/templates 66.17.0-beta.3 → 66.17.1
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/lib/generators/lightningAppGenerator.js +7 -7
- package/lib/generators/lightningAppGenerator.js.map +1 -1
- package/lib/generators/uiBundleGenerator.d.ts +1 -0
- package/lib/generators/uiBundleGenerator.js +12 -0
- package/lib/generators/uiBundleGenerator.js.map +1 -1
- package/lib/generators/visualforceComponentGenerator.js +2 -2
- package/lib/generators/visualforceComponentGenerator.js.map +1 -1
- package/lib/templates/project/angularextapp/_p_/_m_/_w_/_a_/package-lock.json +674 -831
- package/lib/templates/project/angularintapp/_p_/_m_/_w_/_a_/package-lock.json +680 -837
- package/lib/templates/project/reactexternalapp/_p_/_m_/_w_/_a_/package-lock.json +1765 -1639
- package/lib/templates/project/reactinternalapp/_p_/_m_/_w_/_a_/package-lock.json +1771 -1645
- package/lib/templates/uiBundles/angularbasic/package-lock.json +674 -831
- package/lib/templates/uiBundles/reactbasic/package-lock.json +1765 -1639
- package/lib/templates/uiBundles/vuebasic/.forceignore +15 -0
- package/lib/templates/uiBundles/vuebasic/.graphqlrc.yml +2 -0
- package/lib/templates/uiBundles/vuebasic/.prettierignore +9 -0
- package/lib/templates/uiBundles/vuebasic/.prettierrc +11 -0
- package/lib/templates/uiBundles/vuebasic/README.md +43 -0
- package/lib/templates/uiBundles/vuebasic/_uibundle.uibundle-meta.xml +7 -0
- package/lib/templates/uiBundles/vuebasic/codegen.yml +95 -0
- package/lib/templates/uiBundles/vuebasic/components.json +19 -0
- package/lib/templates/uiBundles/vuebasic/eslint.config.js +110 -0
- package/lib/templates/uiBundles/vuebasic/index.html +12 -0
- package/lib/templates/uiBundles/vuebasic/package-lock.json +15489 -0
- package/lib/templates/uiBundles/vuebasic/package.json +72 -0
- package/lib/templates/uiBundles/vuebasic/playwright.config.ts +24 -0
- package/lib/templates/uiBundles/vuebasic/scripts/get-graphql-schema.mjs +71 -0
- package/lib/templates/uiBundles/vuebasic/scripts/rewrite-e2e-assets.mjs +23 -0
- package/lib/templates/uiBundles/vuebasic/src/App.vue +5 -0
- package/lib/templates/uiBundles/vuebasic/src/api/graphqlClient.ts +44 -0
- package/lib/templates/uiBundles/vuebasic/src/appLayout.vue +80 -0
- package/lib/templates/uiBundles/vuebasic/src/components/alerts/status-alert.vue +59 -0
- package/lib/templates/uiBundles/vuebasic/src/components/layouts/card-layout.vue +30 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/alert/Alert.vue +21 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/alert/AlertAction.vue +17 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/alert/AlertDescription.vue +22 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/alert/AlertTitle.vue +22 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/alert/index.ts +25 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/avatar/Avatar.vue +23 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/avatar/AvatarFallback.vue +31 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/avatar/AvatarImage.vue +16 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/avatar/index.ts +3 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/button/Button.vue +33 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/button/index.ts +43 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/card/Card.vue +29 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/card/CardAction.vue +22 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/card/CardContent.vue +17 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/card/CardDescription.vue +17 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/card/CardFooter.vue +22 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/card/CardHeader.vue +22 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/card/CardTitle.vue +22 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/card/index.ts +7 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/checkbox/Checkbox.vue +43 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/checkbox/index.ts +1 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/collapsible/Collapsible.vue +19 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/collapsible/CollapsibleContent.vue +12 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/collapsible/CollapsibleTrigger.vue +12 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/collapsible/index.ts +3 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dialog/Dialog.vue +15 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dialog/DialogClose.vue +12 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dialog/DialogContent.vue +59 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dialog/DialogDescription.vue +31 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dialog/DialogFooter.vue +33 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dialog/DialogHeader.vue +17 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dialog/DialogOverlay.vue +31 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dialog/DialogPortal.vue +12 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dialog/DialogTitle.vue +26 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dialog/DialogTrigger.vue +12 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dialog/index.ts +10 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenu.vue +19 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuCheckboxItem.vue +51 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuContent.vue +47 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuGroup.vue +12 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuItem.vue +44 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuLabel.vue +30 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuPortal.vue +12 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +21 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +52 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuSeparator.vue +26 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuShortcut.vue +19 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuSub.vue +19 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuSubContent.vue +37 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuSubTrigger.vue +38 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/DropdownMenuTrigger.vue +17 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/dropdown-menu/index.ts +15 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/field/Field.vue +27 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/field/FieldContent.vue +22 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/field/FieldDescription.vue +24 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/field/FieldError.vue +48 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/field/FieldGroup.vue +22 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/field/FieldLabel.vue +24 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/field/FieldLegend.vue +29 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/field/FieldSeparator.vue +31 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/field/FieldSet.vue +22 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/field/FieldTitle.vue +22 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/field/index.ts +33 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/index.ts +115 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/input/Input.vue +30 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/input/index.ts +1 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/label/Label.vue +29 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/label/index.ts +1 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/pagination/Pagination.vue +17 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/pagination/PaginationContent.vue +15 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/pagination/PaginationEllipsis.vue +23 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/pagination/PaginationItem.vue +7 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/pagination/PaginationLink.vue +31 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/pagination/PaginationNext.vue +29 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/pagination/PaginationPrevious.vue +29 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/pagination/index.ts +7 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/popover/Popover.vue +15 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/popover/PopoverAnchor.vue +12 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/popover/PopoverContent.vue +44 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/popover/PopoverDescription.vue +17 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/popover/PopoverHeader.vue +17 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/popover/PopoverTitle.vue +14 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/popover/PopoverTrigger.vue +12 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/popover/index.ts +7 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/select/Select.vue +15 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/select/SelectContent.vue +65 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/select/SelectGroup.vue +26 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/select/SelectItem.vue +41 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/select/SelectLabel.vue +26 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/select/SelectScrollDownButton.vue +32 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/select/SelectScrollUpButton.vue +32 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/select/SelectSeparator.vue +24 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/select/SelectTrigger.vue +45 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/select/SelectValue.vue +12 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/select/index.ts +10 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/separator/Separator.vue +33 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/separator/index.ts +1 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/skeleton/Skeleton.vue +15 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/skeleton/index.ts +1 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/sonner/Sonner.vue +29 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/sonner/index.ts +3 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/spinner/Spinner.vue +17 -0
- package/lib/templates/uiBundles/vuebasic/src/components/ui/spinner/index.ts +1 -0
- package/lib/templates/uiBundles/vuebasic/src/composables/useAsyncData.ts +69 -0
- package/lib/templates/uiBundles/vuebasic/src/lib/utils.ts +6 -0
- package/lib/templates/uiBundles/vuebasic/src/main.ts +6 -0
- package/lib/templates/uiBundles/vuebasic/src/pages/Home.vue +10 -0
- package/lib/templates/uiBundles/vuebasic/src/pages/NotFound.vue +18 -0
- package/lib/templates/uiBundles/vuebasic/src/router-utils.ts +32 -0
- package/lib/templates/uiBundles/vuebasic/src/router.ts +40 -0
- package/lib/templates/uiBundles/vuebasic/src/styles/global.css +134 -0
- package/lib/templates/uiBundles/vuebasic/src/test/setup.ts +1 -0
- package/lib/templates/uiBundles/vuebasic/tsconfig.json +45 -0
- package/lib/templates/uiBundles/vuebasic/tsconfig.node.json +13 -0
- package/lib/templates/uiBundles/vuebasic/ui-bundle.json +7 -0
- package/lib/templates/uiBundles/vuebasic/vite-env.d.ts +14 -0
- package/lib/templates/uiBundles/vuebasic/vite.config.ts +106 -0
- package/lib/templates/uiBundles/vuebasic/vitest-env.d.ts +2 -0
- package/lib/utils/constants.d.ts +1 -1
- package/lib/utils/constants.js +1 -1
- package/package.json +3 -1
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "base-vue-app",
|
|
3
|
+
"private": true,
|
|
4
|
+
"version": "1.59.0",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=22"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "vite",
|
|
11
|
+
"dev:design": "vite --mode design",
|
|
12
|
+
"build": "vue-tsc -b && vite build",
|
|
13
|
+
"build:e2e": "npm run build && node scripts/rewrite-e2e-assets.mjs",
|
|
14
|
+
"lint": "eslint .",
|
|
15
|
+
"preview": "vite preview",
|
|
16
|
+
"test": "vitest",
|
|
17
|
+
"graphql:codegen": "graphql-codegen",
|
|
18
|
+
"graphql:schema": "node scripts/get-graphql-schema.mjs"
|
|
19
|
+
},
|
|
20
|
+
"dependencies": {
|
|
21
|
+
"@lucide/vue": "^1.47.0",
|
|
22
|
+
"@salesforce/platform-sdk": "^12.11.0",
|
|
23
|
+
"@salesforce/ui-bundle": "^12.11.0",
|
|
24
|
+
"@tailwindcss/vite": "^4.1.17",
|
|
25
|
+
"class-variance-authority": "^0.7.1",
|
|
26
|
+
"clsx": "^2.1.1",
|
|
27
|
+
"date-fns": "^4.1.0",
|
|
28
|
+
"reka-ui": "^2.5.0",
|
|
29
|
+
"tailwind-merge": "^3.5.0",
|
|
30
|
+
"tailwindcss": "^4.1.17",
|
|
31
|
+
"tw-animate-css": "^1.4.0",
|
|
32
|
+
"vue": "^3.5.13",
|
|
33
|
+
"vue-router": "^4.5.0",
|
|
34
|
+
"vue-sonner": "^2.0.0"
|
|
35
|
+
},
|
|
36
|
+
"devDependencies": {
|
|
37
|
+
"@eslint/js": "^9.39.1",
|
|
38
|
+
"@graphql-codegen/cli": "^6.1.0",
|
|
39
|
+
"@graphql-codegen/typescript": "^5.0.6",
|
|
40
|
+
"@graphql-codegen/typescript-operations": "^5.0.6",
|
|
41
|
+
"@graphql-eslint/eslint-plugin": "^4.1.0",
|
|
42
|
+
"@graphql-tools/utils": "^11.0.0",
|
|
43
|
+
"@playwright/test": "^1.49.0",
|
|
44
|
+
"@salesforce/graphiti": "^12.11.0",
|
|
45
|
+
"@salesforce/vite-plugin-ui-bundle": "^12.11.0",
|
|
46
|
+
"@testing-library/jest-dom": "^6.6.3",
|
|
47
|
+
"@testing-library/user-event": "^14.5.2",
|
|
48
|
+
"@testing-library/vue": "^8.1.0",
|
|
49
|
+
"@types/node": "^24.10.1",
|
|
50
|
+
"@vitejs/plugin-vue": "^6.0.0",
|
|
51
|
+
"@vitest/ui": "^4.1.0",
|
|
52
|
+
"@vue/eslint-config-typescript": "^14.1.4",
|
|
53
|
+
"@vue/test-utils": "^2.4.6",
|
|
54
|
+
"eslint": "^9.39.1",
|
|
55
|
+
"eslint-plugin-vue": "^9.32.0",
|
|
56
|
+
"globals": "^16.5.0",
|
|
57
|
+
"graphql": "^16.11.0",
|
|
58
|
+
"graphql-codegen-typescript-operation-types": "^2.0.2",
|
|
59
|
+
"jsdom": "^25.0.1",
|
|
60
|
+
"serve": "^14.2.5",
|
|
61
|
+
"typescript": "~5.9.3",
|
|
62
|
+
"typescript-eslint": "^8.46.4",
|
|
63
|
+
"vite": "^7.2.4",
|
|
64
|
+
"vite-plugin-graphql-codegen": "^3.6.3",
|
|
65
|
+
"vitest": "^4.1.0",
|
|
66
|
+
"vue-tsc": "^2.2.0"
|
|
67
|
+
},
|
|
68
|
+
"overrides": {
|
|
69
|
+
"lodash": "^4.18.1",
|
|
70
|
+
"undici": "^7.28.0"
|
|
71
|
+
}
|
|
72
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { defineConfig, devices } from '@playwright/test';
|
|
2
|
+
|
|
3
|
+
const E2E_PORT = 5177;
|
|
4
|
+
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
testDir: './e2e',
|
|
7
|
+
fullyParallel: true,
|
|
8
|
+
forbidOnly: !!process.env.CI,
|
|
9
|
+
retries: process.env.CI ? 2 : 0,
|
|
10
|
+
workers: process.env.CI ? 1 : undefined,
|
|
11
|
+
reporter: 'html',
|
|
12
|
+
use: {
|
|
13
|
+
baseURL: `http://localhost:${E2E_PORT}`,
|
|
14
|
+
trace: 'on-first-retry',
|
|
15
|
+
},
|
|
16
|
+
projects: [{ name: 'chromium', use: { ...devices['Desktop Chrome'] } }],
|
|
17
|
+
webServer: {
|
|
18
|
+
// Serve built dist/ with static server so e2e works in CI without SF org (vite preview runs plugin and can fail)
|
|
19
|
+
command: `npx serve dist -l ${E2E_PORT}`,
|
|
20
|
+
url: `http://localhost:${E2E_PORT}`,
|
|
21
|
+
reuseExistingServer: !process.env.CI,
|
|
22
|
+
timeout: process.env.CI ? 120_000 : 60_000,
|
|
23
|
+
},
|
|
24
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Downloads the full GraphQL schema from a connected Salesforce org via introspection.
|
|
3
|
+
*
|
|
4
|
+
* Usage:
|
|
5
|
+
* npm run graphql:schema
|
|
6
|
+
* node scripts/get-graphql-schema.mjs [output-path]
|
|
7
|
+
*
|
|
8
|
+
* The default output path matches the schema location expected by codegen.yml
|
|
9
|
+
* and .graphqlrc.yml so that codegen and IDE tooling resolve it automatically.
|
|
10
|
+
*/
|
|
11
|
+
import { writeFileSync } from 'node:fs';
|
|
12
|
+
import { resolve } from 'node:path';
|
|
13
|
+
import { getOrgInfo } from '@salesforce/ui-bundle/app';
|
|
14
|
+
import { buildClientSchema, getIntrospectionQuery, printSchema } from 'graphql';
|
|
15
|
+
import { pruneSchema } from '@graphql-tools/utils';
|
|
16
|
+
|
|
17
|
+
const DEFAULT_SCHEMA_PATH = '../../../../../schema.graphql';
|
|
18
|
+
const TARGET_ORG = process.env.SF_TARGET_ORG || undefined;
|
|
19
|
+
|
|
20
|
+
async function executeSalesforceGraphQLQuery(query, variables, operationName) {
|
|
21
|
+
const orgInfo = await getOrgInfo(TARGET_ORG);
|
|
22
|
+
if (!orgInfo) {
|
|
23
|
+
throw new Error(
|
|
24
|
+
'Could not resolve a Salesforce org. Set SF_TARGET_ORG or a default org.'
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
const { rawInstanceUrl: instanceUrl, apiVersion, accessToken } = orgInfo;
|
|
28
|
+
|
|
29
|
+
const targetUrl = `${instanceUrl}/services/data/v${apiVersion}/graphql`;
|
|
30
|
+
|
|
31
|
+
console.log(`Executing introspection query against ${targetUrl}`);
|
|
32
|
+
const response = await fetch(targetUrl, {
|
|
33
|
+
method: 'POST',
|
|
34
|
+
headers: {
|
|
35
|
+
Authorization: `Bearer ${accessToken}`,
|
|
36
|
+
'Content-Type': 'application/json',
|
|
37
|
+
'X-Chatter-Entity-Encoding': 'false',
|
|
38
|
+
},
|
|
39
|
+
body: JSON.stringify({ query, variables, operationName }),
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
if (!response.ok) {
|
|
43
|
+
const errorText = await response.text();
|
|
44
|
+
throw new Error(
|
|
45
|
+
`Salesforce GraphQL request failed: ${response.status} ${response.statusText} - ${errorText}`
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return response.json();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
try {
|
|
53
|
+
const outputPath = resolve(process.argv[2] || DEFAULT_SCHEMA_PATH);
|
|
54
|
+
|
|
55
|
+
const introspectionResult = await executeSalesforceGraphQLQuery(
|
|
56
|
+
getIntrospectionQuery(),
|
|
57
|
+
{},
|
|
58
|
+
'IntrospectionQuery'
|
|
59
|
+
);
|
|
60
|
+
|
|
61
|
+
const schema = buildClientSchema(introspectionResult.data);
|
|
62
|
+
const prunedSchema = pruneSchema(schema);
|
|
63
|
+
const sdl = printSchema(prunedSchema);
|
|
64
|
+
|
|
65
|
+
writeFileSync(outputPath, sdl);
|
|
66
|
+
|
|
67
|
+
console.log(`Schema saved to ${outputPath}`);
|
|
68
|
+
} catch (error) {
|
|
69
|
+
console.error('Error:', error.message);
|
|
70
|
+
process.exit(1);
|
|
71
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prepares dist/ for e2e: root-relative asset paths + SPA fallback for serve.
|
|
3
|
+
*/
|
|
4
|
+
import { readFileSync, writeFileSync } from 'node:fs';
|
|
5
|
+
import { join, dirname } from 'node:path';
|
|
6
|
+
import { fileURLToPath } from 'node:url';
|
|
7
|
+
|
|
8
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
9
|
+
const distDir = join(__dirname, '..', 'dist');
|
|
10
|
+
|
|
11
|
+
// Rewrite index.html so asset paths are root-relative (/assets/...)
|
|
12
|
+
const indexPath = join(distDir, 'index.html');
|
|
13
|
+
let html = readFileSync(indexPath, 'utf8');
|
|
14
|
+
html = html.replace(/(src|href)="[^"]*\/assets\//g, '$1="/assets/');
|
|
15
|
+
writeFileSync(indexPath, html);
|
|
16
|
+
|
|
17
|
+
// SPA fallback so /about, /non-existent-route etc. serve index.html
|
|
18
|
+
writeFileSync(
|
|
19
|
+
join(distDir, 'serve.json'),
|
|
20
|
+
JSON.stringify({
|
|
21
|
+
rewrites: [{ source: '**', destination: '/index.html' }],
|
|
22
|
+
})
|
|
23
|
+
);
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Thin GraphQL client: createDataSDK + sdk.graphql with centralized error
|
|
3
|
+
* handling. Mutations are routed to sdk.graphql.mutate and everything else to
|
|
4
|
+
* sdk.graphql.query (the SDK rejects an operation sent to the wrong method).
|
|
5
|
+
* Use with gql-tagged queries and generated operation types for type-safe calls.
|
|
6
|
+
*/
|
|
7
|
+
import { createDataSDK } from '@salesforce/platform-sdk';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* True when the operation's first definition is a `mutation`. Strips GraphQL
|
|
11
|
+
* comments first so a leading `# ...` line can't mask the keyword. Queries
|
|
12
|
+
* (named or anonymous `{ ... }` shorthand) and subscriptions fall through to
|
|
13
|
+
* query().
|
|
14
|
+
*/
|
|
15
|
+
function isMutation(operation: string): boolean {
|
|
16
|
+
return /^\s*mutation\b/.test(operation.replace(/#[^\n\r]*/g, ''));
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export async function executeGraphQL<TData, TVariables>(
|
|
20
|
+
operation: string,
|
|
21
|
+
variables?: TVariables
|
|
22
|
+
): Promise<TData> {
|
|
23
|
+
const data = await createDataSDK();
|
|
24
|
+
const result = isMutation(operation)
|
|
25
|
+
? await data.graphql!.mutate<TData, TVariables>({
|
|
26
|
+
mutation: operation,
|
|
27
|
+
variables: variables,
|
|
28
|
+
})
|
|
29
|
+
: await data.graphql!.query<TData, TVariables>({
|
|
30
|
+
query: operation,
|
|
31
|
+
variables: variables,
|
|
32
|
+
});
|
|
33
|
+
|
|
34
|
+
if (result.errors?.length) {
|
|
35
|
+
const msg = result.errors.map(e => e.message).join('; ');
|
|
36
|
+
throw new Error(`GraphQL Error: ${msg}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (result.data == null) {
|
|
40
|
+
throw new Error('GraphQL response data is null');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return result.data;
|
|
44
|
+
}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, ref } from 'vue';
|
|
3
|
+
import { RouterLink, RouterView, useRoute } from 'vue-router';
|
|
4
|
+
import { getAllRoutes } from '@/router-utils';
|
|
5
|
+
|
|
6
|
+
const isOpen = ref(false);
|
|
7
|
+
const route = useRoute();
|
|
8
|
+
|
|
9
|
+
const toggleMenu = () => {
|
|
10
|
+
isOpen.value = !isOpen.value;
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
const isActive = (path: string) => route.path === path;
|
|
14
|
+
|
|
15
|
+
const navigationRoutes = computed<{ path: string; label: string }[]>(() =>
|
|
16
|
+
getAllRoutes()
|
|
17
|
+
.filter(
|
|
18
|
+
r =>
|
|
19
|
+
r.meta?.showInNavigation === true &&
|
|
20
|
+
r.fullPath !== undefined &&
|
|
21
|
+
r.meta?.label !== undefined
|
|
22
|
+
)
|
|
23
|
+
.map(r => ({
|
|
24
|
+
path: r.fullPath,
|
|
25
|
+
label: r.meta?.label as string,
|
|
26
|
+
}))
|
|
27
|
+
);
|
|
28
|
+
</script>
|
|
29
|
+
|
|
30
|
+
<template>
|
|
31
|
+
<nav class="bg-white border-b border-gray-200">
|
|
32
|
+
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
|
|
33
|
+
<div class="flex justify-between items-center h-16">
|
|
34
|
+
<RouterLink to="/" class="text-xl font-semibold text-gray-900">
|
|
35
|
+
Vue App
|
|
36
|
+
</RouterLink>
|
|
37
|
+
<button
|
|
38
|
+
type="button"
|
|
39
|
+
class="p-2 rounded-md text-gray-700 hover:bg-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
40
|
+
aria-label="Toggle menu"
|
|
41
|
+
@click="toggleMenu"
|
|
42
|
+
>
|
|
43
|
+
<div class="w-6 h-6 flex flex-col justify-center space-y-1.5">
|
|
44
|
+
<span
|
|
45
|
+
class="block h-0.5 w-6 bg-current transition-all"
|
|
46
|
+
:class="{ 'rotate-45 translate-y-2': isOpen }"
|
|
47
|
+
/>
|
|
48
|
+
<span
|
|
49
|
+
class="block h-0.5 w-6 bg-current transition-all"
|
|
50
|
+
:class="{ 'opacity-0': isOpen }"
|
|
51
|
+
/>
|
|
52
|
+
<span
|
|
53
|
+
class="block h-0.5 w-6 bg-current transition-all"
|
|
54
|
+
:class="{ '-rotate-45 -translate-y-2': isOpen }"
|
|
55
|
+
/>
|
|
56
|
+
</div>
|
|
57
|
+
</button>
|
|
58
|
+
</div>
|
|
59
|
+
<div v-if="isOpen" class="pb-4">
|
|
60
|
+
<div class="flex flex-col space-y-2">
|
|
61
|
+
<RouterLink
|
|
62
|
+
v-for="item in navigationRoutes"
|
|
63
|
+
:key="item.path"
|
|
64
|
+
:to="item.path"
|
|
65
|
+
class="px-3 py-2 rounded-md text-sm font-medium transition-colors"
|
|
66
|
+
:class="
|
|
67
|
+
isActive(item.path)
|
|
68
|
+
? 'bg-blue-100 text-blue-700'
|
|
69
|
+
: 'text-gray-700 hover:bg-gray-100'
|
|
70
|
+
"
|
|
71
|
+
@click="isOpen = false"
|
|
72
|
+
>
|
|
73
|
+
{{ item.label }}
|
|
74
|
+
</RouterLink>
|
|
75
|
+
</div>
|
|
76
|
+
</div>
|
|
77
|
+
</div>
|
|
78
|
+
</nav>
|
|
79
|
+
<RouterView />
|
|
80
|
+
</template>
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import { computed, useId } from 'vue';
|
|
3
|
+
import { cva } from 'class-variance-authority';
|
|
4
|
+
import { AlertCircleIcon, CheckCircle2Icon, InfoIcon } from '@lucide/vue';
|
|
5
|
+
import { Alert, AlertDescription } from '@/components/ui/alert';
|
|
6
|
+
|
|
7
|
+
const statusAlertVariants = cva('', {
|
|
8
|
+
variants: {
|
|
9
|
+
variant: {
|
|
10
|
+
error: '',
|
|
11
|
+
success: '',
|
|
12
|
+
info: 'text-blue-700 dark:text-blue-400 *:[svg]:text-current *:data-[slot=alert-description]:text-blue-700 dark:*:data-[slot=alert-description]:text-blue-400',
|
|
13
|
+
},
|
|
14
|
+
},
|
|
15
|
+
defaultVariants: {
|
|
16
|
+
variant: 'error',
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Status alert component for displaying error, success, or info messages.
|
|
22
|
+
* Renders nothing when the default slot is empty.
|
|
23
|
+
*/
|
|
24
|
+
const props = withDefaults(
|
|
25
|
+
defineProps<{
|
|
26
|
+
/** Alert variant type. @default "error" */
|
|
27
|
+
variant?: 'error' | 'success' | 'info';
|
|
28
|
+
}>(),
|
|
29
|
+
{
|
|
30
|
+
variant: 'error',
|
|
31
|
+
}
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
const descriptionId = useId();
|
|
35
|
+
const isError = computed(() => props.variant === 'error');
|
|
36
|
+
const icon = computed(
|
|
37
|
+
() =>
|
|
38
|
+
({
|
|
39
|
+
error: AlertCircleIcon,
|
|
40
|
+
success: CheckCircle2Icon,
|
|
41
|
+
info: InfoIcon,
|
|
42
|
+
})[props.variant]
|
|
43
|
+
);
|
|
44
|
+
</script>
|
|
45
|
+
|
|
46
|
+
<template>
|
|
47
|
+
<Alert
|
|
48
|
+
v-if="$slots.default"
|
|
49
|
+
:variant="isError ? 'destructive' : 'default'"
|
|
50
|
+
:class="statusAlertVariants({ variant })"
|
|
51
|
+
:aria-describedby="descriptionId"
|
|
52
|
+
:role="isError ? 'alert' : 'status'"
|
|
53
|
+
>
|
|
54
|
+
<component :is="icon" aria-hidden="true" />
|
|
55
|
+
<AlertDescription :id="descriptionId">
|
|
56
|
+
<slot />
|
|
57
|
+
</AlertDescription>
|
|
58
|
+
</Alert>
|
|
59
|
+
</template>
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import {
|
|
3
|
+
Card,
|
|
4
|
+
CardContent,
|
|
5
|
+
CardDescription,
|
|
6
|
+
CardHeader,
|
|
7
|
+
CardTitle,
|
|
8
|
+
} from '@/components/ui/card';
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Card layout component for authentication pages.
|
|
12
|
+
* Provides a CardHeader with title and optional description, and CardContent.
|
|
13
|
+
*/
|
|
14
|
+
defineProps<{
|
|
15
|
+
title: string;
|
|
16
|
+
description?: string;
|
|
17
|
+
}>();
|
|
18
|
+
</script>
|
|
19
|
+
|
|
20
|
+
<template>
|
|
21
|
+
<Card>
|
|
22
|
+
<CardHeader>
|
|
23
|
+
<CardTitle class="text-2xl">{{ title }}</CardTitle>
|
|
24
|
+
<CardDescription v-if="description">{{ description }}</CardDescription>
|
|
25
|
+
</CardHeader>
|
|
26
|
+
<CardContent>
|
|
27
|
+
<slot />
|
|
28
|
+
</CardContent>
|
|
29
|
+
</Card>
|
|
30
|
+
</template>
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue';
|
|
3
|
+
import type { AlertVariants } from '.';
|
|
4
|
+
import { cn } from '@/lib/utils';
|
|
5
|
+
import { alertVariants } from '.';
|
|
6
|
+
|
|
7
|
+
const props = defineProps<{
|
|
8
|
+
class?: HTMLAttributes['class'];
|
|
9
|
+
variant?: AlertVariants['variant'];
|
|
10
|
+
}>();
|
|
11
|
+
</script>
|
|
12
|
+
|
|
13
|
+
<template>
|
|
14
|
+
<div
|
|
15
|
+
data-slot="alert"
|
|
16
|
+
role="alert"
|
|
17
|
+
:class="cn(alertVariants({ variant }), props.class)"
|
|
18
|
+
>
|
|
19
|
+
<slot />
|
|
20
|
+
</div>
|
|
21
|
+
</template>
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue';
|
|
3
|
+
import { cn } from '@/lib/utils';
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{
|
|
6
|
+
class?: HTMLAttributes['class'];
|
|
7
|
+
}>();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div
|
|
12
|
+
data-slot="alert-action"
|
|
13
|
+
:class="cn('absolute top-2 right-2', props.class)"
|
|
14
|
+
>
|
|
15
|
+
<slot />
|
|
16
|
+
</div>
|
|
17
|
+
</template>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue';
|
|
3
|
+
import { cn } from '@/lib/utils';
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{
|
|
6
|
+
class?: HTMLAttributes['class'];
|
|
7
|
+
}>();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div
|
|
12
|
+
data-slot="alert-description"
|
|
13
|
+
:class="
|
|
14
|
+
cn(
|
|
15
|
+
'text-muted-foreground text-sm text-balance md:text-pretty [&_p:not(:last-child)]:mb-4 [&_a]:hover:text-foreground [&_a]:underline [&_a]:underline-offset-3',
|
|
16
|
+
props.class
|
|
17
|
+
)
|
|
18
|
+
"
|
|
19
|
+
>
|
|
20
|
+
<slot />
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue';
|
|
3
|
+
import { cn } from '@/lib/utils';
|
|
4
|
+
|
|
5
|
+
const props = defineProps<{
|
|
6
|
+
class?: HTMLAttributes['class'];
|
|
7
|
+
}>();
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<div
|
|
12
|
+
data-slot="alert-title"
|
|
13
|
+
:class="
|
|
14
|
+
cn(
|
|
15
|
+
'font-medium group-has-[>svg]/alert:col-start-2 [&_a]:hover:text-foreground [&_a]:underline [&_a]:underline-offset-3',
|
|
16
|
+
props.class
|
|
17
|
+
)
|
|
18
|
+
"
|
|
19
|
+
>
|
|
20
|
+
<slot />
|
|
21
|
+
</div>
|
|
22
|
+
</template>
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import type { VariantProps } from 'class-variance-authority';
|
|
2
|
+
import { cva } from 'class-variance-authority';
|
|
3
|
+
|
|
4
|
+
export { default as Alert } from './Alert.vue';
|
|
5
|
+
export { default as AlertTitle } from './AlertTitle.vue';
|
|
6
|
+
export { default as AlertDescription } from './AlertDescription.vue';
|
|
7
|
+
export { default as AlertAction } from './AlertAction.vue';
|
|
8
|
+
|
|
9
|
+
export const alertVariants = cva(
|
|
10
|
+
"grid gap-0.5 rounded-lg border px-2.5 py-2 text-left text-sm has-data-[slot=alert-action]:relative has-data-[slot=alert-action]:pr-18 has-[>svg]:grid-cols-[auto_1fr] has-[>svg]:gap-x-2 *:[svg]:row-span-2 *:[svg]:translate-y-0.5 *:[svg]:text-current *:[svg:not([class*='size-'])]:size-4 w-full relative group/alert",
|
|
11
|
+
{
|
|
12
|
+
variants: {
|
|
13
|
+
variant: {
|
|
14
|
+
default: 'bg-card text-card-foreground',
|
|
15
|
+
destructive:
|
|
16
|
+
'text-red-700 dark:text-red-400 bg-card *:data-[slot=alert-description]:text-red-700 dark:*:data-[slot=alert-description]:text-red-400 *:[svg]:text-current',
|
|
17
|
+
},
|
|
18
|
+
},
|
|
19
|
+
defaultVariants: {
|
|
20
|
+
variant: 'default',
|
|
21
|
+
},
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
export type AlertVariants = VariantProps<typeof alertVariants>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { HTMLAttributes } from 'vue';
|
|
3
|
+
import { AvatarRoot } from 'reka-ui';
|
|
4
|
+
import { cn } from '@/lib/utils';
|
|
5
|
+
|
|
6
|
+
const props = defineProps<{
|
|
7
|
+
class?: HTMLAttributes['class'];
|
|
8
|
+
}>();
|
|
9
|
+
</script>
|
|
10
|
+
|
|
11
|
+
<template>
|
|
12
|
+
<AvatarRoot
|
|
13
|
+
data-slot="avatar"
|
|
14
|
+
:class="
|
|
15
|
+
cn(
|
|
16
|
+
'relative flex size-8 shrink-0 overflow-hidden rounded-full',
|
|
17
|
+
props.class
|
|
18
|
+
)
|
|
19
|
+
"
|
|
20
|
+
>
|
|
21
|
+
<slot />
|
|
22
|
+
</AvatarRoot>
|
|
23
|
+
</template>
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { AvatarFallbackProps } from 'reka-ui';
|
|
3
|
+
import type { HTMLAttributes } from 'vue';
|
|
4
|
+
import { computed } from 'vue';
|
|
5
|
+
import { AvatarFallback } from 'reka-ui';
|
|
6
|
+
import { cn } from '@/lib/utils';
|
|
7
|
+
|
|
8
|
+
const props = defineProps<
|
|
9
|
+
AvatarFallbackProps & { class?: HTMLAttributes['class'] }
|
|
10
|
+
>();
|
|
11
|
+
|
|
12
|
+
const delegatedProps = computed(() => {
|
|
13
|
+
const { class: _class, ...rest } = props;
|
|
14
|
+
return rest;
|
|
15
|
+
});
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<template>
|
|
19
|
+
<AvatarFallback
|
|
20
|
+
data-slot="avatar-fallback"
|
|
21
|
+
v-bind="delegatedProps"
|
|
22
|
+
:class="
|
|
23
|
+
cn(
|
|
24
|
+
'bg-muted flex size-full items-center justify-center rounded-full',
|
|
25
|
+
props.class
|
|
26
|
+
)
|
|
27
|
+
"
|
|
28
|
+
>
|
|
29
|
+
<slot />
|
|
30
|
+
</AvatarFallback>
|
|
31
|
+
</template>
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { AvatarImageProps } from 'reka-ui';
|
|
3
|
+
import { AvatarImage } from 'reka-ui';
|
|
4
|
+
|
|
5
|
+
const props = defineProps<AvatarImageProps>();
|
|
6
|
+
</script>
|
|
7
|
+
|
|
8
|
+
<template>
|
|
9
|
+
<AvatarImage
|
|
10
|
+
data-slot="avatar-image"
|
|
11
|
+
v-bind="props"
|
|
12
|
+
class="aspect-square size-full"
|
|
13
|
+
>
|
|
14
|
+
<slot />
|
|
15
|
+
</AvatarImage>
|
|
16
|
+
</template>
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
import type { PrimitiveProps } from 'reka-ui';
|
|
3
|
+
import type { HTMLAttributes } from 'vue';
|
|
4
|
+
import type { ButtonVariants } from '.';
|
|
5
|
+
import { Primitive } from 'reka-ui';
|
|
6
|
+
import { cn } from '@/lib/utils';
|
|
7
|
+
import { buttonVariants } from '.';
|
|
8
|
+
|
|
9
|
+
interface Props extends PrimitiveProps {
|
|
10
|
+
variant?: ButtonVariants['variant'];
|
|
11
|
+
size?: ButtonVariants['size'];
|
|
12
|
+
class?: HTMLAttributes['class'];
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const props = withDefaults(defineProps<Props>(), {
|
|
16
|
+
as: 'button',
|
|
17
|
+
variant: 'default',
|
|
18
|
+
size: 'default',
|
|
19
|
+
});
|
|
20
|
+
</script>
|
|
21
|
+
|
|
22
|
+
<template>
|
|
23
|
+
<Primitive
|
|
24
|
+
data-slot="button"
|
|
25
|
+
:data-variant="variant"
|
|
26
|
+
:data-size="size"
|
|
27
|
+
:as="as"
|
|
28
|
+
:as-child="asChild"
|
|
29
|
+
:class="cn(buttonVariants({ variant, size }), props.class)"
|
|
30
|
+
>
|
|
31
|
+
<slot />
|
|
32
|
+
</Primitive>
|
|
33
|
+
</template>
|