@cognite/dune 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (52) hide show
  1. package/_templates/app/new/config/eslint.config.mjs.ejs.t +96 -0
  2. package/_templates/app/new/config/tailwind.config.js.ejs.t +1 -5
  3. package/_templates/app/new/config/vite.config.ts.ejs.t +9 -10
  4. package/_templates/app/new/config/vitest.config.ts.ejs.t +4 -5
  5. package/_templates/app/new/config/vitest.setup.ts.ejs.t +1 -2
  6. package/_templates/app/new/cursor/mcp.json.ejs.t +0 -5
  7. package/_templates/app/new/cursor/rules.mdc.ejs.t +1 -2
  8. package/_templates/app/new/prompt.js +29 -29
  9. package/_templates/app/new/root/index.html.ejs.t +3 -3
  10. package/_templates/app/new/root/package.json.ejs.t +11 -5
  11. package/_templates/app/new/src/App.test.tsx.ejs.t +32 -20
  12. package/_templates/app/new/src/App.tsx.ejs.t +118 -7
  13. package/_templates/app/new/src/lib/utils.ts.ejs.t +2 -3
  14. package/_templates/app/new/src/main.tsx.ejs.t +8 -8
  15. package/_templates/app/new/src/styles.css.ejs.t +5 -19
  16. package/bin/auth/authentication-flow.js +16 -14
  17. package/bin/auth/callback-server.js +23 -23
  18. package/bin/auth/certificate-manager.js +13 -13
  19. package/bin/auth/client-credentials.js +31 -32
  20. package/bin/auth/oauth-client.js +7 -7
  21. package/bin/cli.js +31 -30
  22. package/bin/deploy-command.js +32 -32
  23. package/bin/deploy-interactive-command.js +73 -73
  24. package/bin/skills-command.js +28 -28
  25. package/bin/utils/crypto.js +7 -8
  26. package/dist/auth/index.d.ts +10 -13
  27. package/dist/auth/index.js +1 -1
  28. package/dist/{chunk-VIBN7U5H.js → chunk-53VTKDSC.js} +1 -2
  29. package/dist/deploy/index.d.ts +9 -1
  30. package/dist/deploy/index.js +89 -7
  31. package/dist/index.d.ts +2 -2
  32. package/dist/index.js +1 -1
  33. package/dist/vite/index.d.ts +1 -0
  34. package/dist/vite/index.js +5 -2
  35. package/package.json +1 -1
  36. package/src/auth/dune-auth-provider.tsx +17 -16
  37. package/src/auth/index.ts +5 -5
  38. package/src/auth/use-dune.ts +5 -4
  39. package/src/auth/utils.ts +18 -18
  40. package/src/deploy/application-deployer.ts +12 -11
  41. package/src/deploy/application-packager.ts +11 -10
  42. package/src/deploy/deploy.ts +7 -6
  43. package/src/deploy/get-sdk.ts +5 -4
  44. package/src/deploy/index.ts +6 -6
  45. package/src/deploy/login.test.ts +49 -0
  46. package/src/deploy/login.ts +134 -11
  47. package/src/deploy/types.ts +4 -0
  48. package/src/index.ts +1 -1
  49. package/src/vite/fusion-open-plugin.ts +17 -15
  50. package/src/vite/index.ts +1 -1
  51. package/_templates/app/new/config/biome.json.ejs.t +0 -54
  52. package/_templates/app/new/config/components.json.ejs.t +0 -28
@@ -0,0 +1,96 @@
1
+ ---
2
+ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>eslint.config.mjs'
3
+ ---
4
+ import js from '@eslint/js';
5
+ import importPlugin from 'eslint-plugin-import';
6
+ import noOnlyTestsPlugin from 'eslint-plugin-no-only-tests';
7
+ import reactHooks from 'eslint-plugin-react-hooks';
8
+ import reactRefresh from 'eslint-plugin-react-refresh';
9
+ import globals from 'globals';
10
+ import tseslint from 'typescript-eslint';
11
+
12
+ const sharedRules = {
13
+ 'import/first': 'error',
14
+ 'import/no-duplicates': 'error',
15
+ 'import/order': [
16
+ 'error',
17
+ {
18
+ groups: ['builtin', 'external', 'internal', 'parent', ['sibling', 'index']],
19
+ 'newlines-between': 'always',
20
+ alphabetize: {
21
+ order: 'asc',
22
+ caseInsensitive: true,
23
+ },
24
+ },
25
+ ],
26
+ 'no-only-tests/no-only-tests': 'error',
27
+ quotes: ['error', 'single', { avoidEscape: true }],
28
+ };
29
+
30
+ const noUnusedVarsOptions = {
31
+ argsIgnorePattern: '^_',
32
+ caughtErrorsIgnorePattern: '^_',
33
+ varsIgnorePattern: '^_',
34
+ ignoreRestSiblings: true,
35
+ };
36
+
37
+ export default tseslint.config(
38
+ {
39
+ ignores: ['dist', 'build', '.next', 'coverage', '*.min.js'],
40
+ },
41
+ {
42
+ files: ['**/*.{js,mjs,cjs,ts,tsx}'],
43
+ plugins: {
44
+ import: importPlugin,
45
+ 'no-only-tests': noOnlyTestsPlugin,
46
+ },
47
+ rules: sharedRules,
48
+ },
49
+ {
50
+ files: ['**/*.{js,mjs,cjs}'],
51
+ extends: [js.configs.recommended],
52
+ languageOptions: {
53
+ ecmaVersion: 'latest',
54
+ sourceType: 'module',
55
+ globals: {
56
+ ...globals.browser,
57
+ ...globals.node,
58
+ },
59
+ },
60
+ rules: {
61
+ 'no-unused-vars': ['error', noUnusedVarsOptions],
62
+ },
63
+ },
64
+ {
65
+ files: ['**/*.cjs'],
66
+ languageOptions: {
67
+ sourceType: 'commonjs',
68
+ globals: {
69
+ ...globals.node,
70
+ },
71
+ },
72
+ },
73
+ {
74
+ files: ['**/*.{ts,tsx}'],
75
+ extends: [js.configs.recommended, ...tseslint.configs.recommended],
76
+ languageOptions: {
77
+ ecmaVersion: 'latest',
78
+ globals: {
79
+ ...globals.browser,
80
+ },
81
+ },
82
+ plugins: {
83
+ 'react-hooks': reactHooks,
84
+ 'react-refresh': reactRefresh,
85
+ },
86
+ rules: {
87
+ ...reactHooks.configs.recommended.rules,
88
+ '@typescript-eslint/consistent-type-imports': 'error',
89
+ '@typescript-eslint/no-explicit-any': 'error',
90
+ '@typescript-eslint/no-non-null-assertion': 'off',
91
+ '@typescript-eslint/no-unused-vars': ['error', noUnusedVarsOptions],
92
+ 'no-unused-vars': 'off',
93
+ 'react-refresh/only-export-components': ['error', { allowConstantExport: true }],
94
+ },
95
+ }
96
+ );
@@ -3,13 +3,9 @@ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>tailwind.config.
3
3
  ---
4
4
  /** @type {import('tailwindcss').Config} */
5
5
  export default {
6
- content: ["./index.html", "./src/**/*.{js,ts,jsx,tsx}"],
6
+ content: ['./index.html', './src/**/*.{js,ts,jsx,tsx}'],
7
7
  theme: {
8
8
  extend: {},
9
9
  },
10
10
  plugins: [],
11
- registries: {
12
- "@aura": "https://cognitedata.github.io/aura/r/{name}.json",
13
- },
14
11
  };
15
-
@@ -1,27 +1,26 @@
1
1
  ---
2
2
  to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>vite.config.ts'
3
3
  ---
4
- import path from "node:path";
5
- import react from "@vitejs/plugin-react";
6
- import tailwindcss from "@tailwindcss/vite";
7
- import { defineConfig } from "vite";
8
- import mkcert from "vite-plugin-mkcert";
4
+ import path from 'node:path';
9
5
 
10
- import { fusionOpenPlugin } from "@cognite/dune/vite";
6
+ import { fusionOpenPlugin } from '@cognite/dune/vite';
7
+ import tailwindcss from '@tailwindcss/vite';
8
+ import react from '@vitejs/plugin-react';
9
+ import { defineConfig } from 'vite';
10
+ import mkcert from 'vite-plugin-mkcert';
11
11
 
12
12
  export default defineConfig({
13
- base: "./",
13
+ base: './',
14
14
  plugins: [react(), mkcert(), fusionOpenPlugin(), tailwindcss()],
15
15
  resolve: {
16
16
  alias: {
17
- "@": path.resolve(__dirname, "./src"),
17
+ '@': path.resolve(__dirname, './src'),
18
18
  },
19
19
  },
20
20
  server: {
21
21
  port: 3001,
22
22
  },
23
23
  worker: {
24
- format: "es",
24
+ format: 'es',
25
25
  },
26
26
  });
27
-
@@ -1,15 +1,14 @@
1
1
  ---
2
2
  to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>vitest.config.ts'
3
3
  ---
4
- import react from "@vitejs/plugin-react";
5
- import { defineConfig } from "vitest/config";
4
+ import react from '@vitejs/plugin-react';
5
+ import { defineConfig } from 'vitest/config';
6
6
 
7
7
  export default defineConfig({
8
8
  plugins: [react()],
9
9
  test: {
10
10
  globals: true,
11
- environment: "happy-dom",
12
- setupFiles: ["./vitest.setup.ts"],
11
+ environment: 'happy-dom',
12
+ setupFiles: ['./vitest.setup.ts'],
13
13
  },
14
14
  });
15
-
@@ -1,5 +1,4 @@
1
1
  ---
2
2
  to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>vitest.setup.ts'
3
3
  ---
4
- import "@testing-library/jest-dom/vitest";
5
-
4
+ import '@testing-library/jest-dom/vitest';
@@ -3,13 +3,8 @@ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>.cursor/mcp.json
3
3
  ---
4
4
  {
5
5
  "mcpServers": {
6
- "shadcn": {
7
- "command": "npx",
8
- "args": ["shadcn@latest", "mcp"]
9
- },
10
6
  "cdf-datamodeling-mcp": {
11
7
  "command": "npx cdf-datamodelling-mcp-server"
12
8
  }
13
9
  }
14
10
  }
15
-
@@ -6,7 +6,6 @@ description: Describes global rules
6
6
  alwaysApply: true
7
7
  ---
8
8
 
9
- - Use @aura shadcn components as much as possible. Stick with the style guide provided.
9
+ - Use direct `@cognite/aura/components` exports whenever Aura provides the component you need. Fall back to custom markup only when Aura does not expose an equivalent primitive.
10
10
  - Look at the PRD.md file at the root for requirements. If the file is empty, write some yourself as the first thing, and confirm with the user the requirements.
11
11
  - The PRD.md file should contain the following: 1.1 Purpose, 1.2 Scope, 1.3 Target Audience, 2. Functional Requirements, 3. Non-Functional Requirements, 4. Data Models & Integration, 4.1 CDF Data Model, 4.1.1 Existing views, 4.1.2 New views, 4.1.3 Spaces, 5. User Stories
12
-
@@ -1,56 +1,56 @@
1
1
  export default [
2
2
  {
3
- type: "input",
4
- name: "name",
5
- message: "What is the app name? (use kebab-case, e.g., my-awesome-app)",
6
- initial: "my-dune-app",
3
+ type: 'input',
4
+ name: 'name',
5
+ message: 'What is the app name? (use kebab-case, e.g., my-awesome-app)',
6
+ initial: 'my-dune-app',
7
7
  validate: (input) => {
8
- if (!input) return "App name is required";
8
+ if (!input) return 'App name is required';
9
9
  if (!/^[a-z][a-z0-9-]*$/.test(input)) {
10
- return "App name must be kebab-case (lowercase, hyphens only)";
10
+ return 'App name must be kebab-case (lowercase, hyphens only)';
11
11
  }
12
12
  return true;
13
13
  },
14
14
  },
15
15
  {
16
- type: "input",
17
- name: "displayName",
18
- message: "What is the display name? (e.g., My Awesome App)",
19
- initial: "My Dune app",
16
+ type: 'input',
17
+ name: 'displayName',
18
+ message: 'What is the display name? (e.g., My Awesome App)',
19
+ initial: 'My Dune app',
20
20
  },
21
21
  {
22
- type: "input",
23
- name: "description",
24
- message: "What is the app description?",
25
- initial: "A Dune application",
22
+ type: 'input',
23
+ name: 'description',
24
+ message: 'What is the app description?',
25
+ initial: 'A Dune application',
26
26
  },
27
27
  {
28
- type: "input",
29
- name: "org",
30
- message: "Deployment org? (e.g., cog-demo, cog-atlas)",
31
- initial: "cog-demo",
28
+ type: 'input',
29
+ name: 'org',
30
+ message: 'Deployment org? (e.g., cog-demo, cog-atlas)',
31
+ initial: 'cog-demo',
32
32
  validate: (input) => {
33
- if (!input) return "Org is required";
33
+ if (!input) return 'Org is required';
34
34
  return true;
35
35
  },
36
36
  },
37
37
  {
38
- type: "input",
39
- name: "project",
40
- message: "Deployment project? (e.g., lervik-industries, atlas-greenfield)",
41
- initial: "lervik-industries",
38
+ type: 'input',
39
+ name: 'project',
40
+ message: 'Deployment project? (e.g., lervik-industries, atlas-greenfield)',
41
+ initial: 'lervik-industries',
42
42
  validate: (input) => {
43
- if (!input) return "Project is required";
43
+ if (!input) return 'Project is required';
44
44
  return true;
45
45
  },
46
46
  },
47
47
  {
48
- type: "input",
49
- name: "cluster",
50
- message: "Cluster/baseUrl? (e.g., greenfield, westeurope-1, api)",
51
- initial: "api",
48
+ type: 'input',
49
+ name: 'cluster',
50
+ message: 'Cluster/baseUrl? (e.g., greenfield, westeurope-1, api)',
51
+ initial: 'api',
52
52
  validate: (input) => {
53
- if (!input) return "Cluster is required";
53
+ if (!input) return 'Cluster is required';
54
54
  return true;
55
55
  },
56
56
  },
@@ -20,17 +20,17 @@ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>index.html'
20
20
  <!-- PWA Manifest -->
21
21
  <link rel="manifest" href="/manifest.json" />
22
22
 
23
- <!-- Fonts -->
23
+ <!-- Aura typography compatibility -->
24
24
  <link rel="preconnect" href="https://fonts.googleapis.com" />
25
25
  <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
26
26
  <link
27
- href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&family=Source+Code+Pro:wght@500&display=swap"
27
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&family=Space+Grotesk:wght@300..700&family=Source+Code+Pro:wght@200..900&display=swap"
28
28
  rel="stylesheet"
29
29
  />
30
+
30
31
  </head>
31
32
  <body>
32
33
  <div id="root"></div>
33
34
  <script type="module" src="/src/main.tsx"></script>
34
35
  </body>
35
36
  </html>
36
-
@@ -15,12 +15,13 @@ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>package.json'
15
15
  "test": "vitest run",
16
16
  "test:watch": "vitest",
17
17
  "test:ui": "vitest --ui",
18
- "lint": "biome check .",
19
- "lint:fix": "biome check --write .",
18
+ "lint": "eslint . --ext .js,.mjs,.cjs,.ts,.tsx",
19
+ "lint:fix": "eslint . --fix --ext .js,.mjs,.cjs,.ts,.tsx",
20
20
  "deploy": "dune deploy:interactive --published",
21
21
  "deploy-preview": "dune deploy:interactive"
22
22
  },
23
23
  "dependencies": {
24
+ "@cognite/aura": "^0.1.1",
24
25
  "@cognite/sdk": "^10.3.0",
25
26
  "@cognite/dune": "^0.2.4",
26
27
  "@tanstack/react-query": "^5.90.10",
@@ -30,7 +31,7 @@ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>package.json'
30
31
  "tailwind-merge": "^3.4.0"
31
32
  },
32
33
  "devDependencies": {
33
- "@biomejs/biome": "^1.9.4",
34
+ "@eslint/js": "9.39.2",
34
35
  "@tailwindcss/vite": "^4.1.17",
35
36
  "@testing-library/jest-dom": "^6.6.3",
36
37
  "@testing-library/react": "^16.1.0",
@@ -41,14 +42,19 @@ to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>package.json'
41
42
  "@vitejs/plugin-react": "^5.1.1",
42
43
  "@vitest/ui": "^2.1.8",
43
44
  "autoprefixer": "^10.4.22",
45
+ "eslint": "9.39.2",
46
+ "eslint-plugin-import": "^2.32.0",
47
+ "eslint-plugin-no-only-tests": "^3.3.0",
48
+ "eslint-plugin-react-hooks": "^7.0.1",
49
+ "eslint-plugin-react-refresh": "^0.4.24",
50
+ "globals": "^16.5.0",
44
51
  "happy-dom": "^20.0.2",
45
52
  "postcss": "^8.5.6",
46
- "shadcn": "^3.5.2",
47
53
  "tailwindcss": "^4.1.17",
48
54
  "typescript": "^5.0.0",
55
+ "typescript-eslint": "^8.46.4",
49
56
  "vite": "^7.2.4",
50
57
  "vite-plugin-mkcert": "^1.17.9",
51
58
  "vitest": "^2.1.8"
52
59
  }
53
60
  }
54
-
@@ -1,38 +1,50 @@
1
1
  ---
2
2
  to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>src/App.test.tsx'
3
3
  ---
4
- import * as duneAuth from "@cognite/dune";
5
- import { render, screen } from "@testing-library/react";
6
- import { beforeEach, describe, expect, it, vi } from "vitest";
7
- import App from "./App";
4
+ import { useDune } from '@cognite/dune';
5
+ import { CogniteClient } from '@cognite/sdk';
6
+ import { render, screen } from '@testing-library/react';
7
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
8
+
9
+ import App from './App';
8
10
 
9
11
  // Mock the @cognite/dune module
10
- vi.mock(import("@cognite/dune"));
12
+ vi.mock(import('@cognite/dune'));
13
+
14
+ function mockUseDune(project: string, isLoading: boolean): ReturnType<typeof useDune> {
15
+ const sdk = new CogniteClient({
16
+ appId: 'dune-template-test',
17
+ project,
18
+ baseUrl: 'https://api.cognitedata.com',
19
+ oidcTokenProvider: async () => '',
20
+ });
11
21
 
12
- describe("App", () => {
22
+ const contextValue = {
23
+ sdk,
24
+ isLoading,
25
+ } satisfies ReturnType<typeof useDune>;
26
+
27
+ return contextValue;
28
+ }
29
+
30
+ describe('App', () => {
13
31
  beforeEach(() => {
14
32
  vi.clearAllMocks();
15
33
  });
16
34
 
17
- it("renders loading state", () => {
18
- vi.mocked(duneAuth.useDune).mockReturnValue({
19
- sdk: { project: "test-project" } as any,
20
- isLoading: true,
21
- });
35
+ it('renders loading state', () => {
36
+ vi.mocked(useDune).mockReturnValue(mockUseDune('test-project', true));
22
37
 
23
38
  render(<App />);
24
- expect(screen.getByText("Loading...")).toBeInTheDocument();
39
+ expect(screen.getByText('Loading project...')).toBeInTheDocument();
25
40
  });
26
41
 
27
- it("renders app with project name", () => {
28
- vi.mocked(duneAuth.useDune).mockReturnValue({
29
- sdk: { project: "my-test-project" } as any,
30
- isLoading: false,
31
- });
42
+ it('renders app with project name', () => {
43
+ vi.mocked(useDune).mockReturnValue(mockUseDune('my-test-project', false));
32
44
 
33
45
  render(<App />);
34
- expect(screen.getByText("Welcome to my-test-project")).toBeInTheDocument();
35
- expect(screen.getByText("Your Dune app is ready.")).toBeInTheDocument();
46
+ expect(screen.getByText('Welcome to my-test-project')).toBeInTheDocument();
47
+ expect(screen.getByText('Open starter config')).toBeInTheDocument();
48
+ expect(screen.getByText('<%= org %> / <%= project %>')).toBeInTheDocument();
36
49
  });
37
50
  });
38
-
@@ -1,22 +1,133 @@
1
1
  ---
2
2
  to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>src/App.tsx'
3
3
  ---
4
- import { useDune } from "@cognite/dune";
4
+ import {
5
+ Badge,
6
+ CodeBlock,
7
+ Dialog,
8
+ DialogContent,
9
+ DialogDescription,
10
+ DialogFooter,
11
+ DialogHeader,
12
+ DialogTitle,
13
+ DialogTrigger,
14
+ Loader,
15
+ Separator,
16
+ buttonVariants,
17
+ } from '@cognite/aura/components';
18
+ import { useDune } from '@cognite/dune';
19
+ import appConfig from '../app.json';
20
+
21
+ const deploymentChecklist = [
22
+ 'Confirm org, project, and cluster in app.json.',
23
+ 'Replace the starter workflow with your first real query.',
24
+ 'Deploy with dune deploy:interactive when the shell is ready.',
25
+ ];
26
+
27
+ function getCluster(baseUrl?: string) {
28
+ return baseUrl?.replace(/^https?:\/\//, '').replace(/\.cognitedata\.com$/, '') ?? '';
29
+ }
5
30
 
6
31
  function App() {
7
32
  const { sdk, isLoading } = useDune();
8
33
 
9
34
  if (isLoading) {
10
- return <div>Loading...</div>;
35
+ return (
36
+ <main className="min-h-screen bg-[linear-gradient(145deg,var(--background)_0%,var(--mountain-50)_55%,var(--mountain-100)_100%)] text-foreground">
37
+ <section className="mx-auto grid min-h-screen w-full max-w-[58rem] place-content-center p-4 sm:p-8">
38
+ <div
39
+ className="mx-auto grid w-full max-w-sm justify-items-center gap-6 rounded-3xl border border-border bg-card p-5 shadow-xl backdrop-blur-lg sm:p-8"
40
+ aria-label="Loading project"
41
+ aria-live="polite"
42
+ >
43
+ <div className="inline-flex items-center gap-3 text-muted-foreground">
44
+ <Loader size={20} />
45
+ <span>Loading project...</span>
46
+ </div>
47
+ </div>
48
+ </section>
49
+ </main>
50
+ );
11
51
  }
12
52
 
53
+ const deployment = appConfig.deployments?.[0];
54
+ const deploymentLabel = [deployment?.org, deployment?.project ?? sdk.project].filter(Boolean).join(' / ');
55
+ const starterConfigPreview = JSON.stringify(
56
+ {
57
+ org: deployment?.org ?? '',
58
+ project: deployment?.project ?? sdk.project,
59
+ cluster: getCluster(deployment?.baseUrl),
60
+ },
61
+ null,
62
+ 2
63
+ );
64
+
13
65
  return (
14
- <div>
15
- <h1>Welcome to {sdk.project}</h1>
16
- <p>Your Dune app is ready.</p>
17
- </div>
66
+ <main className="min-h-screen bg-[linear-gradient(145deg,var(--background)_0%,var(--mountain-50)_55%,var(--mountain-100)_100%)] text-foreground">
67
+ <section className="mx-auto grid min-h-screen w-full max-w-[58rem] place-content-center p-4 sm:p-8">
68
+ <div className="grid gap-6 rounded-3xl border border-border bg-card p-5 shadow-xl backdrop-blur-lg sm:p-8">
69
+ <div className="flex flex-col gap-4 lg:flex-row lg:items-start lg:justify-between">
70
+ <div>
71
+ <h1 className="text-[clamp(2rem,4vw,3rem)] leading-none font-semibold tracking-[-0.04em]">
72
+ Welcome to {sdk.project}
73
+ </h1>
74
+ <div className="mt-3">
75
+ <Badge variant="fjord" background>
76
+ {deploymentLabel}
77
+ </Badge>
78
+ </div>
79
+ </div>
80
+ <Dialog>
81
+ <DialogTrigger className={buttonVariants()}>Open starter config</DialogTrigger>
82
+ <DialogContent className="max-w-xl">
83
+ <DialogHeader>
84
+ <DialogTitle>Starter config</DialogTitle>
85
+ <DialogDescription>Current starter values as JSON.</DialogDescription>
86
+ </DialogHeader>
87
+ <div className="grid gap-2">
88
+ <div className="overflow-hidden rounded-2xl border border-border bg-background">
89
+ <CodeBlock code={starterConfigPreview} language="json" />
90
+ </div>
91
+ </div>
92
+ <DialogFooter>
93
+ <Badge variant="fjord" background>{sdk.project}</Badge>
94
+ </DialogFooter>
95
+ </DialogContent>
96
+ </Dialog>
97
+ </div>
98
+
99
+ <Separator />
100
+
101
+ <div className="grid gap-4">
102
+ <div id="deployment-checklist" className="rounded-2xl border border-border bg-muted p-4">
103
+ <div className="flex items-center justify-between gap-3">
104
+ <div>
105
+ <p className="text-sm font-semibold">Deployment checklist</p>
106
+ <p className="mt-1 text-sm text-muted-foreground">Use this to turn the starter into a deployable app.</p>
107
+ </div>
108
+ <Badge variant="fjord" background>
109
+ 3 steps
110
+ </Badge>
111
+ </div>
112
+ <div className="mt-4 grid gap-2">
113
+ {deploymentChecklist.map((item, index) => (
114
+ <div
115
+ key={item}
116
+ className="grid grid-cols-[auto_1fr] items-start gap-3 rounded-xl border border-border bg-card px-3 py-2"
117
+ >
118
+ <span className="inline-flex h-6 w-6 items-center justify-center rounded-full bg-foreground text-xs font-semibold text-background">
119
+ {index + 1}
120
+ </span>
121
+ <p className="text-sm text-card-foreground">{item}</p>
122
+ </div>
123
+ ))}
124
+ </div>
125
+ </div>
126
+ </div>
127
+ </div>
128
+ </section>
129
+ </main>
18
130
  );
19
131
  }
20
132
 
21
133
  export default App;
22
-
@@ -1,10 +1,9 @@
1
1
  ---
2
2
  to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>src/lib/utils.ts'
3
3
  ---
4
- import { type ClassValue, clsx } from "clsx";
5
- import { twMerge } from "tailwind-merge";
4
+ import { type ClassValue, clsx } from 'clsx';
5
+ import { twMerge } from 'tailwind-merge';
6
6
 
7
7
  export function cn(...inputs: ClassValue[]) {
8
8
  return twMerge(clsx(inputs));
9
9
  }
10
-
@@ -1,13 +1,14 @@
1
1
  ---
2
2
  to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>src/main.tsx'
3
3
  ---
4
- import { DuneAuthProvider } from "@cognite/dune";
5
- import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
6
- import React from "react";
7
- import ReactDOM from "react-dom/client";
8
- import App from "./App.tsx";
4
+ import { DuneAuthProvider } from '@cognite/dune';
5
+ import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
6
+ import React from 'react';
7
+ import ReactDOM from 'react-dom/client';
9
8
 
10
- import "./styles.css";
9
+ import App from './App.tsx';
10
+
11
+ import './styles.css';
11
12
 
12
13
  const queryClient = new QueryClient({
13
14
  defaultOptions: {
@@ -18,7 +19,7 @@ const queryClient = new QueryClient({
18
19
  },
19
20
  });
20
21
 
21
- ReactDOM.createRoot(document.getElementById("root")!).render(
22
+ ReactDOM.createRoot(document.getElementById('root')!).render(
22
23
  <React.StrictMode>
23
24
  <QueryClientProvider client={queryClient}>
24
25
  <DuneAuthProvider>
@@ -27,4 +28,3 @@ ReactDOM.createRoot(document.getElementById("root")!).render(
27
28
  </QueryClientProvider>
28
29
  </React.StrictMode>
29
30
  );
30
-
@@ -1,25 +1,11 @@
1
1
  ---
2
2
  to: '<%= useCurrentDir ? "" : ((directoryName || name) + "/") %>src/styles.css'
3
3
  ---
4
+ @import "@cognite/aura/styles.css";
4
5
  @import "tailwindcss";
5
6
 
6
- body {
7
- font-family: system-ui, -apple-system, sans-serif;
8
- min-height: 100vh;
9
- display: flex;
10
- align-items: center;
11
- justify-content: center;
12
- background: linear-gradient(135deg, #f5f7fa 0%, #e4e8ec 100%);
7
+ :root {
8
+ --font-inter: "Inter", ui-sans-serif, system-ui, sans-serif;
9
+ --font-source-code-pro: "Source Code Pro", ui-monospace, SFMono-Regular, Menlo, Monaco, Consolas,
10
+ "Liberation Mono", "Courier New", monospace;
13
11
  }
14
-
15
- h1 {
16
- font-size: 2rem;
17
- font-weight: 600;
18
- color: #1a1a2e;
19
- margin-bottom: 0.5rem;
20
- }
21
-
22
- p {
23
- color: #6b7280;
24
- }
25
-