@osdk/create-app 0.17.0-main-20240530094422 → 0.18.0-beta.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.
Files changed (134) hide show
  1. package/CHANGELOG.md +60 -1
  2. package/build/browser/esm-5B4R5BF5.js +248 -0
  3. package/build/browser/esm-5B4R5BF5.js.map +1 -0
  4. package/build/browser/esm-7ZL7DCMH.js +451 -0
  5. package/build/browser/esm-7ZL7DCMH.js.map +1 -0
  6. package/build/browser/esm-WPXIOIG2.js +1170 -0
  7. package/build/browser/esm-WPXIOIG2.js.map +1 -0
  8. package/build/browser/esm-ZCTE2SEE.js +377 -0
  9. package/build/browser/esm-ZCTE2SEE.js.map +1 -0
  10. package/build/browser/esm-ZDRBH2ME.js +901 -0
  11. package/build/browser/esm-ZDRBH2ME.js.map +1 -0
  12. package/build/browser/index.js +26 -19
  13. package/build/browser/index.js.map +1 -1
  14. package/build/cjs/esm-2ZIGIHPI.cjs +379 -0
  15. package/build/cjs/esm-2ZIGIHPI.cjs.map +1 -0
  16. package/build/cjs/esm-JBGUEJ46.cjs +250 -0
  17. package/build/cjs/esm-JBGUEJ46.cjs.map +1 -0
  18. package/build/cjs/esm-RRFVZF4X.cjs +1172 -0
  19. package/build/cjs/esm-RRFVZF4X.cjs.map +1 -0
  20. package/build/cjs/esm-VSENADXB.cjs +903 -0
  21. package/build/cjs/esm-VSENADXB.cjs.map +1 -0
  22. package/build/cjs/esm-YRGJOBTV.cjs +453 -0
  23. package/build/cjs/esm-YRGJOBTV.cjs.map +1 -0
  24. package/build/cjs/index.cjs +26 -20
  25. package/build/cjs/index.cjs.map +1 -1
  26. package/build/esm/esm-5B4R5BF5.js +248 -0
  27. package/build/esm/esm-5B4R5BF5.js.map +1 -0
  28. package/build/esm/esm-7ZL7DCMH.js +451 -0
  29. package/build/esm/esm-7ZL7DCMH.js.map +1 -0
  30. package/build/esm/esm-WPXIOIG2.js +1170 -0
  31. package/build/esm/esm-WPXIOIG2.js.map +1 -0
  32. package/build/esm/esm-ZCTE2SEE.js +377 -0
  33. package/build/esm/esm-ZCTE2SEE.js.map +1 -0
  34. package/build/esm/esm-ZDRBH2ME.js +901 -0
  35. package/build/esm/esm-ZDRBH2ME.js.map +1 -0
  36. package/build/esm/index.js +26 -19
  37. package/build/esm/index.js.map +1 -1
  38. package/build/esm/run.d.ts.map +1 -1
  39. package/build/esm/templates.d.ts +7 -0
  40. package/build/esm/templates.d.ts.map +1 -1
  41. package/package.json +18 -9
  42. package/templates/template-next-static-export/.eslintrc.json +0 -4
  43. package/templates/template-next-static-export/README.md.hbs +0 -35
  44. package/templates/template-next-static-export/_gitignore +0 -36
  45. package/templates/template-next-static-export/next.config.js.hbs +0 -17
  46. package/templates/template-next-static-export/package.json.hbs +0 -25
  47. package/templates/template-next-static-export/public/next.svg +0 -20
  48. package/templates/template-next-static-export/public/palantir.svg +0 -3
  49. package/templates/template-next-static-export/src/app/auth/callback/page.tsx +0 -25
  50. package/templates/template-next-static-export/src/app/globals.css +0 -81
  51. package/templates/template-next-static-export/src/app/icon.svg +0 -20
  52. package/templates/template-next-static-export/src/app/layout.module.css +0 -11
  53. package/templates/template-next-static-export/src/app/layout.tsx +0 -51
  54. package/templates/template-next-static-export/src/app/login/page.tsx +0 -43
  55. package/templates/template-next-static-export/src/app/page.module.css +0 -7
  56. package/templates/template-next-static-export/src/app/page.tsx.hbs +0 -53
  57. package/templates/template-next-static-export/src/lib/client.ts.hbs +0 -31
  58. package/templates/template-next-static-export/src/lib/useAuthenticated.ts +0 -25
  59. package/templates/template-next-static-export/tsconfig.json +0 -27
  60. package/templates/template-react/.eslintrc.cjs +0 -18
  61. package/templates/template-react/README.md.hbs +0 -35
  62. package/templates/template-react/_gitignore +0 -24
  63. package/templates/template-react/index.html +0 -15
  64. package/templates/template-react/package.json.hbs +0 -30
  65. package/templates/template-react/public/palantir.svg +0 -3
  66. package/templates/template-react/public/react.svg +0 -1
  67. package/templates/template-react/src/AuthCallback.tsx +0 -24
  68. package/templates/template-react/src/AuthenticatedRoute.tsx +0 -33
  69. package/templates/template-react/src/Home.module.css +0 -7
  70. package/templates/template-react/src/Home.tsx.hbs +0 -47
  71. package/templates/template-react/src/Layout.module.css +0 -10
  72. package/templates/template-react/src/Layout.tsx +0 -29
  73. package/templates/template-react/src/Login.tsx +0 -40
  74. package/templates/template-react/src/client.ts.hbs +0 -31
  75. package/templates/template-react/src/index.css +0 -81
  76. package/templates/template-react/src/main.tsx +0 -33
  77. package/templates/template-react/src/vite-env.d.ts +0 -1
  78. package/templates/template-react/tsconfig.json +0 -25
  79. package/templates/template-react/tsconfig.node.json +0 -10
  80. package/templates/template-react/vite.config.ts.hbs +0 -19
  81. package/templates/template-tutorial-todo-app/.eslintrc.cjs +0 -18
  82. package/templates/template-tutorial-todo-app/README.md.hbs +0 -33
  83. package/templates/template-tutorial-todo-app/index.html +0 -15
  84. package/templates/template-tutorial-todo-app/package.json.hbs +0 -31
  85. package/templates/template-tutorial-todo-app/public/todo-app.svg +0 -4
  86. package/templates/template-tutorial-todo-app/src/AuthCallback.tsx +0 -24
  87. package/templates/template-tutorial-todo-app/src/AuthenticatedRoute.tsx +0 -33
  88. package/templates/template-tutorial-todo-app/src/CreateProjectButton.tsx +0 -33
  89. package/templates/template-tutorial-todo-app/src/CreateProjectDialog.tsx +0 -56
  90. package/templates/template-tutorial-todo-app/src/CreateTaskButton.tsx +0 -35
  91. package/templates/template-tutorial-todo-app/src/CreateTaskDialog.tsx +0 -52
  92. package/templates/template-tutorial-todo-app/src/DeleteProjectButton.tsx +0 -34
  93. package/templates/template-tutorial-todo-app/src/DeleteProjectDialog.tsx +0 -46
  94. package/templates/template-tutorial-todo-app/src/Dialog.module.css +0 -5
  95. package/templates/template-tutorial-todo-app/src/Dialog.tsx +0 -19
  96. package/templates/template-tutorial-todo-app/src/Home.module.css +0 -35
  97. package/templates/template-tutorial-todo-app/src/Home.tsx +0 -62
  98. package/templates/template-tutorial-todo-app/src/Layout.module.css +0 -16
  99. package/templates/template-tutorial-todo-app/src/Layout.tsx +0 -21
  100. package/templates/template-tutorial-todo-app/src/Login.module.css +0 -5
  101. package/templates/template-tutorial-todo-app/src/Login.tsx +0 -42
  102. package/templates/template-tutorial-todo-app/src/ProjectSelect.tsx +0 -40
  103. package/templates/template-tutorial-todo-app/src/TaskList.module.css +0 -6
  104. package/templates/template-tutorial-todo-app/src/TaskList.tsx +0 -38
  105. package/templates/template-tutorial-todo-app/src/TaskListItem.module.css +0 -3
  106. package/templates/template-tutorial-todo-app/src/TaskListItem.tsx +0 -37
  107. package/templates/template-tutorial-todo-app/src/client.ts.hbs +0 -31
  108. package/templates/template-tutorial-todo-app/src/index.css +0 -80
  109. package/templates/template-tutorial-todo-app/src/main.tsx +0 -33
  110. package/templates/template-tutorial-todo-app/src/mocks.ts +0 -137
  111. package/templates/template-tutorial-todo-app/src/useProjectTasks.ts +0 -55
  112. package/templates/template-tutorial-todo-app/src/useProjects.ts +0 -43
  113. package/templates/template-tutorial-todo-app/src/vite-env.d.ts +0 -1
  114. package/templates/template-tutorial-todo-app/tsconfig.json +0 -25
  115. package/templates/template-tutorial-todo-app/tsconfig.node.json +0 -10
  116. package/templates/template-tutorial-todo-app/vite.config.ts.hbs +0 -19
  117. package/templates/template-vue/.vscode/extensions.json +0 -3
  118. package/templates/template-vue/README.md.hbs +0 -35
  119. package/templates/template-vue/_gitignore +0 -24
  120. package/templates/template-vue/index.html +0 -15
  121. package/templates/template-vue/package.json.hbs +0 -22
  122. package/templates/template-vue/public/palantir.svg +0 -3
  123. package/templates/template-vue/public/vue.svg +0 -1
  124. package/templates/template-vue/src/AuthCallback.vue +0 -22
  125. package/templates/template-vue/src/Home.vue.hbs +0 -38
  126. package/templates/template-vue/src/Layout.vue +0 -26
  127. package/templates/template-vue/src/Login.vue +0 -36
  128. package/templates/template-vue/src/client.ts.hbs +0 -31
  129. package/templates/template-vue/src/main.ts +0 -35
  130. package/templates/template-vue/src/style.css +0 -81
  131. package/templates/template-vue/src/vite-env.d.ts +0 -1
  132. package/templates/template-vue/tsconfig.json +0 -25
  133. package/templates/template-vue/tsconfig.node.json +0 -10
  134. package/templates/template-vue/vite.config.ts.hbs +0 -24
@@ -0,0 +1,1172 @@
1
+ 'use strict';
2
+
3
+ // ../create-app.template.tutorial-todo-aip-app/build/esm/index.js
4
+ var files = /* @__PURE__ */ new Map([[".eslintrc.cjs", {
5
+ type: "raw",
6
+ body: `module.exports = {
7
+ root: true,
8
+ env: { browser: true, es2020: true },
9
+ extends: [
10
+ "eslint:recommended",
11
+ "plugin:@typescript-eslint/recommended",
12
+ "plugin:react-hooks/recommended",
13
+ ],
14
+ ignorePatterns: ["dist", ".eslintrc.cjs"],
15
+ parser: "@typescript-eslint/parser",
16
+ plugins: ["react-refresh"],
17
+ rules: {
18
+ "react-refresh/only-export-components": [
19
+ "warn",
20
+ { allowConstantExport: true },
21
+ ],
22
+ },
23
+ };
24
+ `
25
+ }], ["README.md.hbs", {
26
+ type: "raw",
27
+ body: `# {{project}}
28
+
29
+
30
+ This project was generated with \`@osdk/create-app\` and is intended to be used alongside the Developer Console tutorial for creating an AIP Logic backed To Do App against a reference Ontology.
31
+
32
+ ## Developing
33
+
34
+ Run the following command or equivalent with your preferred package manager to start a local development server on \`http://localhost:8080\`:
35
+
36
+ \`\`\`sh
37
+ npm run dev
38
+ \`\`\`
39
+
40
+ Development configuration is stored in \`.env.development\`.
41
+
42
+ {{#if corsProxy}}
43
+ In order to make API requests to Foundry, a CORS proxy has been set up for local development which may be removed if the stack is configured to allow \`http://localhost:8080\` to load resources. The configured OAuth client must also allow \`http://localhost:8080/auth/callback\` as a redirect URL.
44
+ {{else}}
45
+ In order to make API requests to Foundry, CORS must be configured for the stack to allow \`http://localhost:8080\` to load resources. The configured OAuth client must also allow \`http://localhost:8080/auth/callback\` as a redirect URL.
46
+ {{/if}}
47
+
48
+ ## Deploying
49
+
50
+ Run the following command or equivalent with your preferred package manager to create a production build of your application:
51
+
52
+ \`\`\`sh
53
+ npm run build
54
+ \`\`\`
55
+
56
+ Production configuration is stored in \`.env.production\`.
57
+
58
+ If you did not fill in the URL your production application will be hosted on you will need to fill in the \`VITE_FOUNDRY_REDIRECT_URL\` in \`.env.production\`.
59
+
60
+ In order to make API requests to Foundry, CORS must be configured for the stack to allow the production origin to load resources. The configured OAuth client must also allow the production origin auth callback as a redirect URL.
61
+ `
62
+ }], [".gitignore", {
63
+ type: "raw",
64
+ body: `# Logs
65
+ logs
66
+ *.log
67
+ npm-debug.log*
68
+ yarn-debug.log*
69
+ yarn-error.log*
70
+ pnpm-debug.log*
71
+ lerna-debug.log*
72
+
73
+ node_modules
74
+ dist
75
+ dist-ssr
76
+ *.local
77
+
78
+ # Editor directories and files
79
+ .vscode/*
80
+ !.vscode/extensions.json
81
+ .idea
82
+ .DS_Store
83
+ *.suo
84
+ *.ntvs*
85
+ *.njsproj
86
+ *.sln
87
+ *.sw?
88
+ `
89
+ }], ["index.html", {
90
+ type: "raw",
91
+ body: `<!doctype html>
92
+ <html lang="en">
93
+ <head>
94
+ <meta charset="UTF-8" />
95
+ <link rel="icon" type="image/svg+xml" href="/todo-aip-app.svg" />
96
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
97
+ <title>Ontology SDK Tutorial - To do AIP App</title>
98
+ </head>
99
+ <body>
100
+ <div id="root-container">
101
+ <div id="root"></div>
102
+ </div>
103
+ <script type="module" src="/src/main.tsx"></script>
104
+ </body>
105
+ </html>
106
+ `
107
+ }], ["package.json.hbs", {
108
+ type: "raw",
109
+ body: `{
110
+ "name": "{{project}}",
111
+ "private": true,
112
+ "version": "0.0.0",
113
+ "type": "module",
114
+ "scripts": {
115
+ "dev": "vite",
116
+ "build": "tsc && vite build",
117
+ "lint": "eslint . --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
118
+ "preview": "vite preview"
119
+ },
120
+ "dependencies": {
121
+ "{{osdkPackage}}": "latest",
122
+ "react": "^18",
123
+ "react-dom": "^18",
124
+ "react-router-dom": "^6.23.1",
125
+ "swr": "^2.2.5"
126
+ },
127
+ "devDependencies": {
128
+ "@types/react": "^18",
129
+ "@types/react-dom": "^18",
130
+ "@typescript-eslint/eslint-plugin": "^7.16.0",
131
+ "@typescript-eslint/parser": "^7.16.0",
132
+ "@vitejs/plugin-react": "^4.2.0",
133
+ "eslint": "^8.57.0",
134
+ "eslint-plugin-react-hooks": "^4.6.2",
135
+ "eslint-plugin-react-refresh": "^0.4.6",
136
+ "typescript": "^5.5.4",
137
+ "vite": "^5.3.4"
138
+ }
139
+ }`
140
+ }], ["public/aip-icon.svg", {
141
+ "type": "base64",
142
+ "body": "PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHZpZXdCb3g9IjAgMCAxNiAxNiIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik03Ljk5OTQ5IDFIMi4wNjE4NkMwLjQ3NzI5NCAxIC0wLjUxMzI3NiAyLjY2NjI0IDAuMjc4NTY1IDMuOTk5NjhMMi42NTQwOSA4TDAuMjc4NTY1IDEyLjAwMDNDLTAuNTEzMjc2IDEzLjMzMzggMC40NzcyOTUgMTUgMi4wNjE4NiAxNUgxMy45MzgxQzE1LjUyMjcgMTUgMTYuNTEzMyAxMy4zMzM4IDE1LjcyMTQgMTIuMDAwM0wxMy4zNDU5IDhMMTUuNzIxNCAzLjk5OTY4QzE2LjUxMzMgMi42NjYyNCAxNS41MjI3IDEgMTMuOTM4MSAxSDguMDAwNTFINy45OTk0OVpNNi4yMTcwNCAyLjAwMDA4SDIuMDYxODZDMS4yNjk1NyAyLjAwMDA4IDAuNzc0Mjg5IDIuODMzMiAxLjE3MDIxIDMuNDk5OTJMMy4yNDgzIDYuOTk5MzdMNi4yMTcwNCAyLjAwMDA4Wk0zLjI0ODMgOS4wMDA2M0wxLjE3MDIxIDEyLjUwMDFDMC43NzQyOSAxMy4xNjY4IDEuMjY5NTcgMTMuOTk5OSAyLjA2MTg2IDEzLjk5OTlINi4yMTcwNEwzLjI0ODMgOS4wMDA2M1pNOS43ODI5NiAxMy45OTk5SDEzLjkzODFDMTQuNzMwNCAxMy45OTk5IDE1LjIyNTcgMTMuMTY2OCAxNC44Mjk4IDEyLjUwMDFMMTIuNzUxNyA5LjAwMDYzTDkuNzgyOTYgMTMuOTk5OVpNMTIuMTU3NSA4TDguODkxNjQgMTMuNDk5NkM4LjQ5NTUgMTQuMTY2NyA3LjUwNDUgMTQuMTY2NyA3LjEwODM2IDEzLjQ5OTZMMy44NDI1MSA4TDcuMTA4MzYgMi41MDA0QzcuNTA0NSAxLjgzMzMxIDguNDk1NTEgMS44MzMzMSA4Ljg5MTY1IDIuNTAwNEwxMi4xNTc1IDhaTTEyLjc1MTcgNi45OTkzNkwxNC44Mjk4IDMuNDk5OTJDMTUuMjI1NyAyLjgzMzIgMTQuNzMwNCAyLjAwMDA4IDEzLjkzODEgMi4wMDAwOEg5Ljc4Mjk2TDEyLjc1MTcgNi45OTkzNloiIGZpbGw9IndoaXRlIi8+Cjwvc3ZnPgo="
143
+ }], ["public/todo-aip-app.svg", {
144
+ "type": "base64",
145
+ "body": "PHN2ZyB3aWR0aD0iNTAiIGhlaWdodD0iNTAiIHZpZXdCb3g9IjAgMCA1MCA1MCIgZmlsbD0ibm9uZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj4KPGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzM1NzJfNjIxOTUpIj4KPHJlY3Qgb3BhY2l0eT0iMC4xIiB3aWR0aD0iNTAiIGhlaWdodD0iNTAiIGZpbGw9IiM5ODgxRjMiLz4KPHJlY3QgeD0iNyIgeT0iMTEiIHdpZHRoPSIxMiIgaGVpZ2h0PSIxMiIgcng9IjIiIGZpbGw9IiM3OTYxREIiLz4KPHJlY3QgeD0iNy41IiB5PSIxMS41IiB3aWR0aD0iMTEiIGhlaWdodD0iMTEiIHJ4PSIxLjUiIHN0cm9rZT0id2hpdGUiIHN0cm9rZS1vcGFjaXR5PSIwLjEiLz4KPHBhdGggZmlsbC1ydWxlPSJldmVub2RkIiBjbGlwLXJ1bGU9ImV2ZW5vZGQiIGQ9Ik0xNiAxNC4zNzVDMTUuNzkgMTQuMzc1IDE1LjYwMjUgMTQuNDU3NSAxNS40Njc1IDE0LjU5MjVMMTIuMjUgMTcuODE3NUwxMC41MzI1IDE2LjA5MjVDMTAuMzk3NSAxNS45NTc1IDEwLjIxIDE1Ljg3NSAxMCAxNS44NzVDOS41ODc1IDE1Ljg3NSA5LjI1IDE2LjIxMjUgOS4yNSAxNi42MjVDOS4yNSAxNi44MzUgOS4zMzI1IDE3LjAyMjUgOS40Njc1IDE3LjE1NzVMMTEuNzE3NSAxOS40MDc1QzExLjg1MjUgMTkuNTQyNSAxMi4wNCAxOS42MjUgMTIuMjUgMTkuNjI1QzEyLjQ2IDE5LjYyNSAxMi42NDc1IDE5LjU0MjUgMTIuNzgyNSAxOS40MDc1TDE2LjUzMjUgMTUuNjU3NUMxNi42Njc1IDE1LjUyMjUgMTYuNzUgMTUuMzM1IDE2Ljc1IDE1LjEyNUMxNi43NSAxNC43MTI1IDE2LjQxMjUgMTQuMzc1IDE2IDE0LjM3NVoiIGZpbGw9IndoaXRlIi8+CjxyZWN0IG9wYWNpdHk9IjAuNSIgeD0iMjIiIHk9IjE1IiB3aWR0aD0iMTIiIGhlaWdodD0iNSIgcng9IjIuNSIgZmlsbD0iIzYzNERCRiIvPgo8cmVjdCBvcGFjaXR5PSIwLjUiIHg9IjM2IiB5PSIxNSIgd2lkdGg9IjkiIGhlaWdodD0iNSIgcng9IjIuNSIgZmlsbD0iIzYzNERCRiIvPgo8cmVjdCB4PSI3LjUiIHk9IjI4LjUiIHdpZHRoPSIxMSIgaGVpZ2h0PSIxMSIgcng9IjEuNSIgZmlsbD0iI0E3OUJEQSIgZmlsbC1vcGFjaXR5PSIwLjEiLz4KPHJlY3QgeD0iNy41IiB5PSIyOC41IiB3aWR0aD0iMTEiIGhlaWdodD0iMTEiIHJ4PSIxLjUiIHN0cm9rZT0iI0EzOUNDMSIvPgo8cmVjdCBvcGFjaXR5PSIwLjUiIHg9IjIzIiB5PSIzMiIgd2lkdGg9IjYiIGhlaWdodD0iNSIgcng9IjIuNSIgZmlsbD0iIzYzNERCRiIvPgo8cGF0aCBvcGFjaXR5PSIwLjUiIGQ9Ik0zMSAzNC41QzMxIDMzLjExOTMgMzIuMzIyOCAzMiAzMy45NTQ1IDMySDQxLjA0NTVDNDIuNjc3MiAzMiA0NCAzMy4xMTkzIDQ0IDM0LjVDNDQgMzUuODgwNyA0Mi42NzcyIDM3IDQxLjA0NTUgMzdIMzMuOTU0NUMzMi4zMjI4IDM3IDMxIDM1Ljg4MDcgMzEgMzQuNVoiIGZpbGw9IiM2MzREQkYiLz4KPC9nPgo8ZGVmcz4KPGNsaXBQYXRoIGlkPSJjbGlwMF8zNTcyXzYyMTk1Ij4KPHJlY3Qgd2lkdGg9IjUwIiBoZWlnaHQ9IjUwIiByeD0iNCIgZmlsbD0id2hpdGUiLz4KPC9jbGlwUGF0aD4KPC9kZWZzPgo8L3N2Zz4K"
146
+ }], ["src/AuthCallback.tsx", {
147
+ type: "raw",
148
+ body: `import { useEffect, useState } from "react";
149
+ import { useNavigate } from "react-router-dom";
150
+ import client from "./client";
151
+
152
+ /**
153
+ * Component to render at \`/auth/callback\`
154
+ * This calls signIn() again to save the token, and then navigates the user back to the home page.
155
+ */
156
+ function AuthCallback() {
157
+ const [error, setError] = useState<string | undefined>(undefined);
158
+ const navigate = useNavigate();
159
+
160
+ // This effect conflicts with React 18 strict mode in development
161
+ // https://react.dev/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development
162
+ useEffect(() => {
163
+ client.auth
164
+ .signIn()
165
+ .then(() => navigate("/", { replace: true }))
166
+ .catch((e: unknown) => setError((e as Error).message ?? e));
167
+ }, [navigate]);
168
+ return <div>{error != null ? error : "Authenticating\u2026"}</div>;
169
+ }
170
+
171
+ export default AuthCallback;
172
+ `
173
+ }], ["src/AuthenticatedRoute.tsx", {
174
+ type: "raw",
175
+ body: `import { useEffect, useState } from "react";
176
+ import { Outlet, useNavigate } from "react-router-dom";
177
+ import client from "./client";
178
+
179
+ /**
180
+ * A component that can be used to wrap routes that require authentication.
181
+ * Nested routes may assume that a valid token is present.
182
+ */
183
+ function AuthenticatedRoute() {
184
+ const navigate = useNavigate();
185
+ const [token, setToken] = useState(client.auth.token);
186
+ useEffect(() => {
187
+ if (client.auth.token == null || client.auth.token.isExpired) {
188
+ client.auth
189
+ .refresh()
190
+ .then(() => {
191
+ setToken(client.auth.token);
192
+ })
193
+ .catch(() => {
194
+ // If we cannot refresh the token (i.e. the user is not logged in) we redirect to the login page
195
+ navigate("/login");
196
+ });
197
+ }
198
+ }, [navigate]);
199
+
200
+ if (token == null || token.isExpired) {
201
+ return null;
202
+ }
203
+
204
+ return <Outlet />;
205
+ }
206
+
207
+ export default AuthenticatedRoute;
208
+ `
209
+ }], ["src/CreateProjectButton.module.css", {
210
+ "type": "base64",
211
+ "body": "LmJ1dHRvbiB7CiAgYm9yZGVyOiAxcHggc29saWQgI2NjYzsKfQo="
212
+ }], ["src/CreateProjectButton.tsx", {
213
+ type: "raw",
214
+ body: `import { useCallback, useState } from "react";
215
+ import css from "./CreateProjectButton.module.css";
216
+ import CreateProjectDialog from "./CreateProjectDialog";
217
+ import useProjects from "./useProjects";
218
+
219
+ interface CreateProjectButtonProps {
220
+ onProjectCreated?: (projectId: string) => void;
221
+ }
222
+
223
+ function CreateProjectButton({ onProjectCreated }: CreateProjectButtonProps) {
224
+ const { isLoading: isLoadingProjects, isError: isErrorProjects } =
225
+ useProjects();
226
+
227
+ const [isOpen, setIsOpen] = useState(false);
228
+ const handleOpen = useCallback(() => setIsOpen(true), []);
229
+ const handleClose = useCallback(() => setIsOpen(false), []);
230
+
231
+ if (isLoadingProjects || isErrorProjects) {
232
+ return null;
233
+ }
234
+
235
+ return (
236
+ <>
237
+ <button onClick={handleOpen} className={css.button}>
238
+ Create Project
239
+ </button>
240
+ <CreateProjectDialog
241
+ isOpen={isOpen}
242
+ onClose={handleClose}
243
+ onProjectCreated={onProjectCreated}
244
+ />
245
+ </>
246
+ );
247
+ }
248
+
249
+ export default CreateProjectButton;
250
+ `
251
+ }], ["src/CreateProjectDialog.module.css", {
252
+ "type": "base64",
253
+ "body": "LnByb2plY3QgewogICAgZGlzcGxheTogZmxleDsKICAgIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47CiAgICBhbGlnbi1jb250ZW50OiBzcGFjZS1iZXR3ZWVuOwogICAgZ2FwOiAxMHB4Owp9Ci5sYWJlbCB7CiAgZGlzcGxheTogZmxleDsKICBqdXN0aWZ5LWNvbnRlbnQ6IHNwYWNlLWJldHdlZW47CiAgZ2FwOiA1cHg7Cn0KCi5idXR0b24gewogIGJvcmRlcjogMXB4IHNvbGlkICNjY2M7Cn0K"
254
+ }], ["src/CreateProjectDialog.tsx", {
255
+ type: "raw",
256
+ body: `import type { ChangeEvent } from "react";
257
+ import { useCallback, useEffect, useState } from "react";
258
+ import css from "./CreateProjectDialog.module.css";
259
+
260
+ import Dialog from "./Dialog";
261
+ import useProjects from "./useProjects";
262
+
263
+ interface CreateProjectDialogProps {
264
+ isOpen: boolean;
265
+ onClose: () => void;
266
+ onProjectCreated?: (projectId: string) => void;
267
+ }
268
+
269
+ function CreateProjectDialog({
270
+ isOpen,
271
+ onClose,
272
+ onProjectCreated,
273
+ }: CreateProjectDialogProps) {
274
+ const { createProject } = useProjects();
275
+
276
+ const [name, setName] = useState<string>("New project");
277
+
278
+ const handleChangeProjectName = useCallback(
279
+ (e: ChangeEvent<HTMLInputElement>) => setName(e.target.value),
280
+ [],
281
+ );
282
+
283
+ useEffect(() => setName("New project"), [isOpen]);
284
+
285
+ const [isCreating, setIsCreating] = useState(false);
286
+
287
+ const handleSubmit = useCallback(async () => {
288
+ setIsCreating(true);
289
+ try {
290
+ const projectId = await createProject(name);
291
+ onProjectCreated?.(projectId);
292
+ } finally {
293
+ setIsCreating(false);
294
+ onClose();
295
+ }
296
+ }, [onProjectCreated, onClose, createProject, name]);
297
+
298
+ return (
299
+ <Dialog
300
+ isOpen={isOpen}
301
+ buttons={[
302
+ <button
303
+ disabled={isCreating}
304
+ onClick={onClose}
305
+ key="cancel"
306
+ className={css.button}
307
+ >
308
+ Cancel
309
+ </button>,
310
+ <button
311
+ disabled={isCreating}
312
+ onClick={handleSubmit}
313
+ key="create"
314
+ className={css.button}
315
+ >
316
+ Create project
317
+ </button>,
318
+ ]}
319
+ >
320
+ <div className={css.project}>
321
+ <label className={css.label}>
322
+ Project name:{" "}
323
+ <input type="text" value={name} onChange={handleChangeProjectName} />
324
+ </label>
325
+ </div>
326
+ </Dialog>
327
+ );
328
+ }
329
+ export default CreateProjectDialog;
330
+ `
331
+ }], ["src/CreateTaskButton.module.css", {
332
+ "type": "base64",
333
+ "body": "LmJ1dHRvbiB7CiAgYm9yZGVyOiAxcHggc29saWQgI2NjYzsKfQo="
334
+ }], ["src/CreateTaskButton.tsx", {
335
+ type: "raw",
336
+ body: `import { useCallback, useState } from "react";
337
+ import css from "./CreateTaskButton.module.css";
338
+ import CreateTaskDialog from "./CreateTaskDialog";
339
+ import type { MockProject } from "./mocks";
340
+ import { useProjectTasks } from "./useProjectTasks";
341
+
342
+ interface CreateTaskButtonProps {
343
+ project: MockProject;
344
+ onTaskCreated: (taskId: string) => void;
345
+ }
346
+
347
+ function CreateTaskButton({ project, onTaskCreated }: CreateTaskButtonProps) {
348
+ const { isLoading: isLoadingTasks, isError: isErrorTasks } = useProjectTasks(
349
+ project,
350
+ );
351
+
352
+ const [isOpen, setIsOpen] = useState(false);
353
+ const handleOpen = useCallback(() => setIsOpen(true), []);
354
+ const handleClose = useCallback(() => setIsOpen(false), []);
355
+
356
+ if (isLoadingTasks || isErrorTasks) {
357
+ return null;
358
+ }
359
+
360
+ return (
361
+ <>
362
+ <button onClick={handleOpen} className={css.button}>Create Task</button>
363
+ <CreateTaskDialog
364
+ project={project}
365
+ isOpen={isOpen}
366
+ onClose={handleClose}
367
+ onTaskCreated={onTaskCreated}
368
+ />
369
+ </>
370
+ );
371
+ }
372
+
373
+ export default CreateTaskButton;
374
+ `
375
+ }], ["src/CreateTaskDialog.module.css", {
376
+ "type": "base64",
377
+ "body": "LnRhc2sgewogICAgZGlzcGxheTogZ3JpZDsKICAgIGdyaWQtdGVtcGxhdGUtY29sdW1uczogMWZyIDFmcjsKICAgIGdyaWQtdGVtcGxhdGUtcm93czogYXV0byBtaW4tY29udGVudDsKICAgIGdhcDogMTBweDsKICAgIHdpZHRoOiA1MDBweDsKfQoubGFiZWwgewogIGRpc3BsYXk6IGZsZXg7CiAgZ2FwOiA1cHg7CiAgcmVzaXplOiBub25lOwp9CgouaW5wdXQgewogIHdpZHRoOiAzMDBweDsKICBib3JkZXI6IDFweCBzb2xpZCBncmF5OwogIGJvcmRlci1yYWRpdXM6IDVweDsKfQoKLnRleHRBcmVhIHsKICB3aWR0aDogMzAwcHg7CiAgcmVzaXplOiB2ZXJ0aWNhbDsKICBib3JkZXI6IDFweCBzb2xpZCBncmF5OwogIGJvcmRlci1yYWRpdXM6IDVweDsKICBwYWRkaW5nOiA1cHg7Cn0KCi5haXAgewogIGJhY2tncm91bmQtY29sb3I6ICM3OTYxREI7CiAgYm9yZGVyOiAxcHggc29saWQgI2NjYzsKICBwYWRkaW5nOiAycHggNXB4OwogIGRpc3BsYXk6IGZsZXg7CiAganVzdGlmeS1jb250ZW50OiBjZW50ZXI7CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKfQoKLnByb2Nlc3NpbmcgewogIGN1cnNvcjogcHJvZ3Jlc3M7Cn0KCi5pbWFnZSB7CiAgd2lkdGg6IDE2cHg7CiAgaGVpZ2h0OiAxNnB4Owp9CgouY29udGFpbmVyIHsKICBkaXNwbGF5OiBmbGV4OwogIGFsaWduLWl0ZW1zOmZsZXgtc3RhcnQ7CiAgZ2FwOiA1cHg7Cn0KCi5kaWFsb2dDb250YWluZXIgewogIHBvc2l0aW9uOiBmaXhlZDsKICB0b3A6IDA7CiAgcmlnaHQ6IDA7CiAgYm90dG9tOiAwOwogIGxlZnQ6IDA7CiAgZGlzcGxheTogZmxleDsKICBqdXN0aWZ5LWNvbnRlbnQ6IGNlbnRlcjsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGJhY2tncm91bmQtY29sb3I6IHJnYmEoMCwgMCwgMCwgMC41KTsgLyogT3B0aW9uYWw6IGZvciBkaW1tZWQgYmFja2dyb3VuZCAqLwp9CgouYnV0dG9uIHsKICBib3JkZXI6IDFweCBzb2xpZCAjY2NjOwp9Cg=="
378
+ }], ["src/CreateTaskDialog.tsx", {
379
+ type: "raw",
380
+ body: `import aipLogo from "/aip-icon.svg";
381
+ import type { ChangeEvent } from "react";
382
+ import { useCallback, useEffect, useRef, useState } from "react";
383
+ import css from "./CreateTaskDialog.module.css";
384
+ import Dialog from "./Dialog";
385
+ import type { MockProject } from "./mocks";
386
+ import { useProjectTasks } from "./useProjectTasks";
387
+
388
+ interface CreateTaskDialogProps {
389
+ project: MockProject;
390
+ isOpen: boolean;
391
+ onClose: () => void;
392
+ onTaskCreated: (taskId: string) => void;
393
+ }
394
+
395
+ function CreateTaskDialog(
396
+ { project, isOpen, onClose, onTaskCreated }: CreateTaskDialogProps,
397
+ ) {
398
+ const { createTask, getRecommendedTaskDescription } = useProjectTasks(
399
+ project,
400
+ );
401
+
402
+ const [name, setName] = useState<string>("New task");
403
+ const [description, setDescription] = useState<string>("");
404
+ const [isProcessing, setIsProcessing] = useState<boolean>(false);
405
+ const [isCreating, setIsCreating] = useState(false);
406
+ const textAreaRef = useRef<HTMLTextAreaElement>(null);
407
+
408
+ const handleChangeTaskName = useCallback(
409
+ (e: ChangeEvent<HTMLInputElement>) => setName(e.target.value),
410
+ [],
411
+ );
412
+
413
+ const handleChangeTaskDescription = useCallback(
414
+ (e: ChangeEvent<HTMLTextAreaElement>) => setDescription(e.target.value),
415
+ [],
416
+ );
417
+
418
+ const handleTaskDescriptionRecommendation = useCallback(async () => {
419
+ setIsProcessing(true);
420
+ const recommendedDescription = await getRecommendedTaskDescription(name);
421
+ setDescription(recommendedDescription);
422
+ setIsProcessing(false);
423
+ }, [getRecommendedTaskDescription, name]);
424
+
425
+ useEffect(() => {
426
+ setName("New task");
427
+ setDescription("");
428
+ }, [isOpen]);
429
+ useEffect(() => {
430
+ if (textAreaRef.current) {
431
+ const textArea = textAreaRef.current;
432
+ textArea.style.height = "auto";
433
+ textArea.style.height = \`\${textArea.scrollHeight}px\`;
434
+ }
435
+ }, [description]);
436
+
437
+ const handleSubmit = useCallback(async () => {
438
+ setIsCreating(true);
439
+ try {
440
+ const taskId = await createTask(name, description);
441
+ if (taskId != null) {
442
+ onTaskCreated(taskId);
443
+ }
444
+ } finally {
445
+ setIsCreating(false);
446
+ onClose();
447
+ }
448
+ }, [onClose, createTask, onTaskCreated, name, description]);
449
+
450
+ return (
451
+ <>
452
+ {isOpen && (
453
+ <div className={css.dialogContainer}>
454
+ <Dialog
455
+ isOpen={isOpen}
456
+ buttons={[
457
+ <button
458
+ disabled={isCreating}
459
+ onClick={onClose}
460
+ key="cancel"
461
+ className={css.button}
462
+ >
463
+ Cancel
464
+ </button>,
465
+ <button
466
+ disabled={isCreating}
467
+ onClick={handleSubmit}
468
+ key="create"
469
+ className={css.button}
470
+ >
471
+ Create task
472
+ </button>,
473
+ ]}
474
+ >
475
+ <div className={css.task}>
476
+ <label className={css.label}>
477
+ Task name:{" "}
478
+ </label>
479
+ <input
480
+ type="text"
481
+ value={name}
482
+ onChange={handleChangeTaskName}
483
+ className={css.input}
484
+ />
485
+
486
+ <label className={css.label}>
487
+ Task description:{" "}
488
+ </label>
489
+ <div className={css.container}>
490
+ <textarea
491
+ ref={textAreaRef}
492
+ value={description}
493
+ onChange={handleChangeTaskDescription}
494
+ className={css.textArea}
495
+ rows={2}
496
+ />
497
+ <button
498
+ disabled={isProcessing}
499
+ className={\`\${css.aip} \${isProcessing ? css.processing : ""}\`}
500
+ title="Click here to get AIP task description recommendation"
501
+ type="button"
502
+ onClick={handleTaskDescriptionRecommendation}
503
+ >
504
+ <img
505
+ src={aipLogo}
506
+ alt="AIP"
507
+ className={css.image}
508
+ />
509
+ </button>
510
+ </div>
511
+ </div>
512
+ </Dialog>
513
+ </div>
514
+ )}
515
+ </>
516
+ );
517
+ }
518
+
519
+ export default CreateTaskDialog;
520
+ `
521
+ }], ["src/DeleteProjectButton.module.css", {
522
+ "type": "base64",
523
+ "body": "LmJ1dHRvbiB7CiAgYm9yZGVyOiAxcHggc29saWQgI2NjYzsKfQo="
524
+ }], ["src/DeleteProjectButton.tsx", {
525
+ type: "raw",
526
+ body: `import { useCallback, useState } from "react";
527
+ import css from "./DeleteProjectButton.module.css";
528
+ import DeleteProjectDialog from "./DeleteProjectDialog";
529
+ import type { MockProject } from "./mocks";
530
+ import useProjects from "./useProjects";
531
+
532
+ interface DeleteProjectButtonProps {
533
+ project: MockProject;
534
+ }
535
+
536
+ function DeleteProjectButton({ project }: DeleteProjectButtonProps) {
537
+ const { isLoading: isLoadingProjects, isError: isErrorProjects } =
538
+ useProjects();
539
+
540
+ const [isOpen, setIsOpen] = useState(false);
541
+ const handleOpen = useCallback(() => setIsOpen(true), []);
542
+ const handleClose = useCallback(() => setIsOpen(false), []);
543
+
544
+ if (isLoadingProjects || isErrorProjects) {
545
+ return null;
546
+ }
547
+
548
+ return (
549
+ <>
550
+ <button onClick={handleOpen} className={css.button}>
551
+ Delete Project
552
+ </button>
553
+ <DeleteProjectDialog
554
+ project={project}
555
+ isOpen={isOpen}
556
+ onClose={handleClose}
557
+ />
558
+ </>
559
+ );
560
+ }
561
+
562
+ export default DeleteProjectButton;
563
+ `
564
+ }], ["src/DeleteProjectDialog.module.css", {
565
+ "type": "base64",
566
+ "body": "LmJ1dHRvbiB7CiAgYm9yZGVyOiAxcHggc29saWQgI2NjYzsKfQo="
567
+ }], ["src/DeleteProjectDialog.tsx", {
568
+ type: "raw",
569
+ body: `import { useCallback, useState } from "react";
570
+ import css from "./DeleteProjectDialog.module.css";
571
+ import Dialog from "./Dialog";
572
+ import type { MockProject } from "./mocks";
573
+ import useProjects from "./useProjects";
574
+
575
+ interface DeleteProjectDialogProps {
576
+ project: MockProject;
577
+ isOpen: boolean;
578
+ onClose: () => void;
579
+ }
580
+
581
+ function DeleteProjectDialog({
582
+ project,
583
+ isOpen,
584
+ onClose,
585
+ }: DeleteProjectDialogProps) {
586
+ const { deleteProject } = useProjects();
587
+
588
+ const [isDeleting, setIsDeleting] = useState(false);
589
+ const handleSubmit = useCallback(async () => {
590
+ setIsDeleting(true);
591
+ try {
592
+ await deleteProject(project);
593
+ } finally {
594
+ setIsDeleting(false);
595
+ onClose();
596
+ }
597
+ }, [deleteProject, onClose, project]);
598
+
599
+ return (
600
+ <Dialog
601
+ isOpen={isOpen}
602
+ buttons={[
603
+ <button
604
+ disabled={isDeleting}
605
+ onClick={onClose}
606
+ key="cancel"
607
+ className={css.button}
608
+ >
609
+ Cancel
610
+ </button>,
611
+ <button
612
+ disabled={isDeleting}
613
+ onClick={handleSubmit}
614
+ key="delete"
615
+ className={css.button}
616
+ >
617
+ Delete
618
+ </button>,
619
+ ]}
620
+ >
621
+ Are you sure you want to delete this project?
622
+ </Dialog>
623
+ );
624
+ }
625
+ export default DeleteProjectDialog;
626
+ `
627
+ }], ["src/Dialog.module.css", {
628
+ "type": "base64",
629
+ "body": "LmJ1dHRvbnMgewogIGRpc3BsYXk6IGZsZXg7CiAgZ2FwOiAxZW07CiAgbWFyZ2luLXRvcDogMWVtOwogIGp1c3RpZnktY29udGVudDogZmxleC1lbmQ7Cn0KCi5kaWFsb2cgewogIGJvcmRlcjogMXB4IHNvbGlkIGJsYWNrOwogIGJvcmRlci1yYWRpdXM6IDEwcHg7Cn0K"
630
+ }], ["src/Dialog.tsx", {
631
+ type: "raw",
632
+ body: `import { PropsWithChildren } from "react";
633
+ import css from "./Dialog.module.css";
634
+
635
+ interface DialogProps {
636
+ isOpen: boolean;
637
+ buttons?: React.ReactElement[];
638
+ }
639
+
640
+ function Dialog({ children, isOpen, buttons }: PropsWithChildren<DialogProps>) {
641
+ return (
642
+ <dialog open={isOpen} className={css.dialog}>
643
+ {children}
644
+ {buttons != null && buttons.length > 0 && (
645
+ <div className={css.buttons}>{buttons}</div>
646
+ )}
647
+ </dialog>
648
+ );
649
+ }
650
+ export default Dialog;
651
+ `
652
+ }], ["src/Home.module.css", {
653
+ "type": "base64",
654
+ "body": "LnR1dG9yaWFsQmFubmVyV3JhcHBlciB7CiAgZGlzcGxheTogZmxleDsKICBtYXJnaW46IDJlbTsKfQoKLnR1dG9yaWFsQmFubmVyIHsKICBmbGV4OiAxOwogIHdpZHRoOiAwOwogIGJhY2tncm91bmQ6IHJnYmEoMTIxLCA5NywgMjE5LCAwLjcpOwogIGNvbG9yOiAjZmZmZmZmOwogIGJvcmRlci1yYWRpdXM6IDFlbTsKICBwYWRkaW5nOiAxZW07CiAgYm94LXNoYWRvdzogMCAxMHB4IDE1cHggLTNweCByZ2IoMCAwIDAgLyAwLjEpLCAwIDRweCA2cHggLTRweCByZ2IoMCAwIDAgLyAwLjEpOwp9CgoudHV0b3JpYWxCYW5uZXJUaXRsZSB7CiAgbWFyZ2luLXRvcDogMDsKICBmb250LXdlaWdodDogNjAwOwp9CgoucHJvamVjdFNlbGVjdCB7CiAgZGlzcGxheTogZmxleDsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIGdhcDogMWVtOwogIG1hcmdpbjogMmVtOwogIGZvbnQtd2VpZ2h0OiA2MDA7Cn0KCg=="
655
+ }], ["src/Home.tsx", {
656
+ type: "raw",
657
+ body: `import { useCallback, useEffect, useState } from "react";
658
+ import CreateProjectButton from "./CreateProjectButton";
659
+ import DeleteProjectButton from "./DeleteProjectButton";
660
+ import css from "./Home.module.css";
661
+ import Layout from "./Layout";
662
+ import type { MockProject } from "./mocks";
663
+ import { ProjectDetails } from "./ProjectDetails";
664
+ import ProjectSelect from "./ProjectSelect";
665
+ import useProjects from "./useProjects";
666
+
667
+ function Home() {
668
+ const [projectId, setProjectId] = useState<string | undefined>(undefined);
669
+ const { projects } = useProjects();
670
+
671
+ const project = projects?.find((p) => p.id === projectId);
672
+
673
+ const handleSelectProject = useCallback(
674
+ (p: MockProject) => setProjectId(p.id),
675
+ [],
676
+ );
677
+
678
+ useEffect(() => {
679
+ if (project == null && projects != null && projects.length > 0) {
680
+ setProjectId(projects[0].id);
681
+ }
682
+ }, [project, projects]);
683
+
684
+ const handleOnProjectCreated = useCallback(
685
+ (projectId: string | undefined) => {
686
+ setProjectId(projectId);
687
+ },
688
+ [],
689
+ );
690
+
691
+ return (
692
+ <Layout>
693
+ <div className={css.tutorialBannerWrapper}>
694
+ <div className={css.tutorialBanner}>
695
+ <p className={css.tutorialBannerTitle}>
696
+ \u{1F4A1} Welcome to the To Do AIP App tutorial!
697
+ </p>
698
+ <p>
699
+ The application is implemented with mock in memory data.
700
+ <br />Can you solve how to change it to use the Ontology SDK
701
+ instead?
702
+ </p>
703
+ </div>
704
+ </div>
705
+ <div className={css.projectSelect}>
706
+ <span>Project:</span>
707
+ <ProjectSelect
708
+ project={project}
709
+ projects={projects ?? []}
710
+ onSelectProject={handleSelectProject}
711
+ />
712
+ <CreateProjectButton onProjectCreated={handleOnProjectCreated} />
713
+ {project != null && <DeleteProjectButton project={project} />}
714
+ </div>
715
+ {project != null && <ProjectDetails project={project} />}
716
+ </Layout>
717
+ );
718
+ }
719
+
720
+ export default Home;
721
+ `
722
+ }], ["src/Layout.module.css", {
723
+ "type": "base64",
724
+ "body": "LmhlYWRlciB7CiAgZGlzcGxheTogZmxleDsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIG1hcmdpbjogMmVtOwp9CgoubG9nbyB7CiAgaGVpZ2h0OiA0ZW07CiAgYWxpZ24taXRlbXM6IGNlbnRlcjsKICBtYXJnaW4tcmlnaHQ6IDFlbTsKfQoKLnRpdGxlIHsKICBmb250LXdlaWdodDogNjAwOwogIGZvbnQtc2l6ZTogMS41ZW07Cn0K"
725
+ }], ["src/Layout.tsx", {
726
+ type: "raw",
727
+ body: `import todoAppLogo from "/todo-aip-app.svg";
728
+ import React from "react";
729
+ import css from "./Layout.module.css";
730
+
731
+ interface LayoutProps {
732
+ children?: React.ReactNode;
733
+ }
734
+
735
+ function Layout({ children }: LayoutProps) {
736
+ return (
737
+ <>
738
+ <div className={css.header}>
739
+ <img src={todoAppLogo} className={css.logo} alt="Todo App logo" />
740
+ <div className={css.title}>
741
+ Ontology SDK Tutorial - To Do App Powered by AIP
742
+ </div>
743
+ </div>
744
+ {children}
745
+ </>
746
+ );
747
+ }
748
+
749
+ export default Layout;
750
+ `
751
+ }], ["src/Login.module.css", {
752
+ "type": "base64",
753
+ "body": "LmxvZ2luQnV0dG9uIHsKICBkaXNwbGF5OiBmbGV4OwogIGp1c3RpZnktY29udGVudDogY2VudGVyOwogIG1hcmdpbjogMmVtOwp9Cg=="
754
+ }], ["src/Login.tsx", {
755
+ type: "raw",
756
+ body: `import { useCallback, useState } from "react";
757
+ import { Navigate } from "react-router-dom";
758
+ import client from "./client";
759
+ import Layout from "./Layout";
760
+ import css from "./Login.module.css";
761
+
762
+ function Login() {
763
+ const [isLoggingIn, setIsLoggingIn] = useState(false);
764
+ const [error, setError] = useState<string | undefined>(undefined);
765
+ const token = client.auth.token;
766
+
767
+ const handleLogin = useCallback(async () => {
768
+ setIsLoggingIn(true);
769
+ try {
770
+ // Initiate the OAuth flow, which will redirect the user to log into Foundry
771
+ // Once the login has completed, the user will be redirected back to the route defined via the
772
+ // FOUNDRY_REDIRECT_URL variable in .env.development
773
+ await client.auth.signIn();
774
+ } catch (e: unknown) {
775
+ console.error(e);
776
+ setError((e as Error).message ?? e);
777
+ } finally {
778
+ setIsLoggingIn(false);
779
+ }
780
+ }, []);
781
+
782
+ // If the token exists but a user tries to load /login, redirect to the home page instead
783
+ if (token != null) {
784
+ return <Navigate to="/" replace={true} />;
785
+ }
786
+
787
+ return (
788
+ <Layout>
789
+ <div className={css.loginButton}>
790
+ <button onClick={handleLogin}>
791
+ {isLoggingIn ? "Logging in\u2026" : "Log in "}
792
+ </button>
793
+ </div>
794
+ {error && <div>Unable to log in: {error}</div>}
795
+ </Layout>
796
+ );
797
+ }
798
+
799
+ export default Login;
800
+ `
801
+ }], ["src/ProjectDetails.module.css", {
802
+ "type": "base64",
803
+ "body": "LnByb2plY3RDYXJkIHsKICBtYXJnaW46IDJlbTsKICBwYWRkaW5nOiAwLjVlbTsKICBib3JkZXI6IDFweCBzb2xpZCAjY2NjOwogIC8qIG1hcmdpbjogMC41ZW07ICovCiAgZ2FwOiAwLjVlbTsKICBib3JkZXItcmFkaXVzOiA1cHg7Cgp9CgoucHJvamVjdFRpdGxlIHsKICBmb250LXNpemU6IDEuNWVtOwp9CgouZGVzY3JpcHRpb24gewogIGRpc3BsYXk6IGZsZXg7CiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsKICBnYXA6IDVweDsKfQoKLmltYWdlIHsKICBoZWlnaHQ6IDE2cHg7CiAgd2lkdGg6IDE2cHg7Cn0KCi5haXAgewogIGJhY2tncm91bmQtY29sb3I6ICM3OTYxREI7CiAgY29sb3I6ICNmZmZmZmY7CiAgYm9yZGVyOiAxcHggc29saWQgI2NjYzsKICBwYWRkaW5nOiAycHg7CiAgZ2FwOiAxMHB4OwogIGhlaWdodDogMzBweDsKfQoKLnByb2Nlc3NpbmcgewogIGN1cnNvcjogcHJvZ3Jlc3M7Cn0KCi5haXBUZXh0IHsKICBkaXNwbGF5OiBmbGV4OwogIGp1c3RpZnktY29udGVudDogY2VudGVyOwogIGdhcDogMTBweDsKICBhbGlnbi1pdGVtczogY2VudGVyOwogIHBhZGRpbmc6IDAgMTBweDsKfQoKLnRleHRBcmVhIHsKICBib3JkZXI6IG5vbmU7CiAgY29sb3I6IGdyYXk7CiAgcmVzaXplOiBub25lOwogIG92ZXJmbG93OiBoaWRkZW47CiAgcG9pbnRlci1ldmVudHM6IG5vbmU7Cn0K"
804
+ }], ["src/ProjectDetails.tsx", {
805
+ type: "raw",
806
+ body: `import aipLogo from "/aip-icon.svg";
807
+ import { useCallback, useEffect, useRef, useState } from "react";
808
+ import CreateTaskButton from "./CreateTaskButton";
809
+ import type { MockProject } from "./mocks";
810
+ import css from "./ProjectDetails.module.css";
811
+ import TaskList from "./TaskList";
812
+ import useProjects from "./useProjects";
813
+ import { useProjectTasks } from "./useProjectTasks";
814
+
815
+ interface ProjectDetailsProps {
816
+ project: MockProject;
817
+ }
818
+
819
+ export function ProjectDetails({ project }: ProjectDetailsProps) {
820
+ const [projectHasTasks, setProjectHasTasks] = useState<boolean>(false);
821
+ const [isProcessing, setIsProcessing] = useState<boolean>(false);
822
+ const { updateProjectDescription } = useProjects();
823
+ const tasks = useProjectTasks(project).tasks;
824
+ const textAreaRef = useRef<HTMLTextAreaElement>(null);
825
+
826
+ useEffect(() => {
827
+ setProjectHasTasks(tasks == null ? false : tasks.length > 0);
828
+ }, [project, tasks]);
829
+
830
+ const handleProjectDescriptionRecommendation = useCallback(async () => {
831
+ if (project == null) {
832
+ return;
833
+ }
834
+ setIsProcessing(true);
835
+ await updateProjectDescription(project);
836
+ setIsProcessing(false);
837
+ }, [project, updateProjectDescription]);
838
+
839
+ useEffect(() => {
840
+ if (textAreaRef.current) {
841
+ const textArea = textAreaRef.current;
842
+ textArea.style.height = "auto";
843
+ textArea.style.height = \`\${textArea.scrollHeight}px\`;
844
+ }
845
+ }, [project.description]);
846
+
847
+ const handleOnTaskCreated = useCallback(() => {
848
+ setProjectHasTasks(true);
849
+ }, []);
850
+
851
+ const handleOnTaskDeleted = useCallback(() => {
852
+ if (tasks?.length === 0) {
853
+ setProjectHasTasks(false);
854
+ }
855
+ }, [tasks]);
856
+
857
+ return (
858
+ <div className={css.projectCard} key={project.id}>
859
+ <h1 className={css.projectTitle}>{project.name}</h1>
860
+ {projectHasTasks && (
861
+ <div className={css.description}>
862
+ <textarea
863
+ ref={textAreaRef}
864
+ readOnly
865
+ value={project.description}
866
+ className={css.textArea}
867
+ />
868
+ <button
869
+ disabled={isProcessing}
870
+ className={\`\${css.aip} \${isProcessing ? css.processing : ""}\`}
871
+ title="Click here to update project description based on AIP Logic"
872
+ type="button"
873
+ onClick={handleProjectDescriptionRecommendation}
874
+ >
875
+ <div className={css.aipText}>
876
+ <img
877
+ src={aipLogo}
878
+ alt="AIP"
879
+ className={css.image}
880
+ />
881
+ Get description recommendation
882
+ </div>
883
+ </button>
884
+ </div>
885
+ )}
886
+ <TaskList project={project} onTaskDeleted={handleOnTaskDeleted} />
887
+ <CreateTaskButton
888
+ project={project}
889
+ onTaskCreated={handleOnTaskCreated}
890
+ />
891
+ </div>
892
+ );
893
+ }
894
+ `
895
+ }], ["src/ProjectSelect.tsx", {
896
+ type: "raw",
897
+ body: `import { ChangeEvent, useCallback } from "react";
898
+ import { MockProject } from "./mocks";
899
+
900
+ interface ProjectSelectProps {
901
+ project: MockProject | undefined;
902
+ projects: MockProject[];
903
+ onSelectProject: (project: MockProject) => void;
904
+ }
905
+
906
+ function ProjectSelect({
907
+ project,
908
+ projects,
909
+ onSelectProject,
910
+ }: ProjectSelectProps) {
911
+ const handleSelect = useCallback(
912
+ (e: ChangeEvent<HTMLSelectElement>) => {
913
+ const nextProject = projects.find((p) => \`\${p.id}\` === e.target.value);
914
+ if (nextProject != null) {
915
+ onSelectProject(nextProject);
916
+ }
917
+ },
918
+ [projects, onSelectProject],
919
+ );
920
+
921
+ return (
922
+ <select value={project?.id} onChange={handleSelect}>
923
+ <option hidden disabled value="">
924
+ -- select a project --
925
+ </option>
926
+
927
+ {projects.map((p) => (
928
+ <option key={p.id} value={p.id}>
929
+ {p.name}
930
+ </option>
931
+ ))}
932
+ </select>
933
+ );
934
+ }
935
+
936
+ export default ProjectSelect;
937
+ `
938
+ }], ["src/TaskList.module.css", {
939
+ "type": "base64",
940
+ "body": "LnRhc2tMaXN0IHsKICBsaXN0LXN0eWxlOiBub25lOwogIHBhZGRpbmc6IDA7CiAgbWFyZ2luLXRvcDogMWVtOwogIG1hcmdpbi1ib3R0b206IDFlbTsKICB3aWR0aDogMTAwJTsKfQo="
941
+ }], ["src/TaskList.tsx", {
942
+ type: "raw",
943
+ body: `import type { MockProject } from "./mocks";
944
+ import css from "./TaskList.module.css";
945
+ import TaskListItem from "./TaskListItem";
946
+ import { useProjectTasks } from "./useProjectTasks";
947
+
948
+ interface TaskListProps {
949
+ project: MockProject;
950
+ onTaskDeleted: (taskId: string | undefined) => void;
951
+ }
952
+
953
+ function TaskList({ project, onTaskDeleted }: TaskListProps) {
954
+ const {
955
+ tasks,
956
+ isLoading: isLoadingTasks,
957
+ isError: isErrorTasks,
958
+ deleteTask,
959
+ } = useProjectTasks(project);
960
+
961
+ if (isErrorTasks) {
962
+ return <div className={css.taskList}>Error loading tasks!</div>;
963
+ } else if (isLoadingTasks) {
964
+ return null;
965
+ }
966
+
967
+ const data = tasks ?? [];
968
+ if (data.length === 0) {
969
+ return <div className={css.taskList}>No tasks found</div>;
970
+ }
971
+
972
+ return (
973
+ <ul className={css.taskList}>
974
+ {data.map((task) => (
975
+ <TaskListItem
976
+ key={task.id}
977
+ task={task}
978
+ deleteTask={deleteTask}
979
+ onTaskDeleted={onTaskDeleted}
980
+ />
981
+ ))}
982
+ </ul>
983
+ );
984
+ }
985
+
986
+ export default TaskList;
987
+ `
988
+ }], ["src/TaskListItem.module.css", {
989
+ "type": "base64",
990
+ "body": "LmxpIHsKICBkaXNwbGF5OiBmbGV4OwogIGZsZXgtZGlyZWN0aW9uOiByb3c7CiAgYWxpZ24taXRlbXM6IGZsZXgtc3RhcnQ7CiAgcGFkZGluZzogNXB4OwogIGJvcmRlcjogMXB4IHNvbGlkICNjY2M7CiAgZ2FwOiA1cHg7CiAgYm9yZGVyLXJhZGl1czogNXB4OwogIGJhY2tncm91bmQtY29sb3I6ICNmOWY5Zjk7CiAgbWFyZ2luOiAxMHB4IDA7Cn0KCi5jaGVja2VkIHsKICB0ZXh0LWRlY29yYXRpb246IGxpbmUtdGhyb3VnaDsKfQoKLmRlbGV0ZSB7CiAgYm9yZGVyOiAxcHggc29saWQgI2NjYzsKICBwYWRkaW5nOiAycHg7Cn0KCi50YXNrIHsKICBkaXNwbGF5OiBmbGV4OwogIGZsZXgtZGlyZWN0aW9uOiBjb2x1bW47CiAgd2lkdGg6IDEwMCU7Cn0KCi50ZXh0QXJlYSB7CiAgYm9yZGVyOiBub25lOwogIGJhY2tncm91bmQtY29sb3I6ICNmOWY5Zjk7CiAgY29sb3I6IGdyYXk7CiAgcmVzaXplOiBub25lOwogIG92ZXJmbG93OiBoaWRkZW47CiAgcG9pbnRlci1ldmVudHM6IG5vbmU7Cn0K"
991
+ }], ["src/TaskListItem.tsx", {
992
+ type: "raw",
993
+ body: `import { useCallback, useEffect, useRef, useState } from "react";
994
+ import type { MockTask } from "./mocks";
995
+ import css from "./TaskListItem.module.css";
996
+
997
+ interface TaskListItemProps {
998
+ task: MockTask;
999
+ deleteTask: (task: MockTask) => Promise<void>;
1000
+ onTaskDeleted: (taskId: string | undefined) => void;
1001
+ }
1002
+
1003
+ function TaskListItem({ task, deleteTask, onTaskDeleted }: TaskListItemProps) {
1004
+ const [isDeleting, setIsDeleting] = useState(false);
1005
+ const textAreaRef = useRef<HTMLTextAreaElement>(null);
1006
+
1007
+ const handleClick = useCallback(async () => {
1008
+ setIsDeleting(true);
1009
+ try {
1010
+ await deleteTask(task);
1011
+ } finally {
1012
+ onTaskDeleted(task.id);
1013
+ setIsDeleting(false);
1014
+ }
1015
+ }, [deleteTask, task, onTaskDeleted]);
1016
+
1017
+ useEffect(() => {
1018
+ if (textAreaRef.current) {
1019
+ const textArea = textAreaRef.current;
1020
+ textArea.style.height = "auto";
1021
+ textArea.style.height = \`\${textArea.scrollHeight}px\`;
1022
+ }
1023
+ }, [task.description]);
1024
+ const cleanDescription = task.description?.trim();
1025
+ return (
1026
+ <li className={css.li}>
1027
+ <input
1028
+ type="checkbox"
1029
+ onChange={handleClick}
1030
+ checked={isDeleting}
1031
+ className={css.delete}
1032
+ title="Delete task"
1033
+ />
1034
+ <div className={\`\${css.task} \${isDeleting ? css.checked : ""}\`}>
1035
+ <span>{task.title}</span>
1036
+ {cleanDescription != null && (
1037
+ <textarea
1038
+ ref={textAreaRef}
1039
+ readOnly
1040
+ value={task.description}
1041
+ className={css.textArea}
1042
+ rows={1}
1043
+ />
1044
+ )}
1045
+ </div>
1046
+ </li>
1047
+ );
1048
+ }
1049
+
1050
+ export default TaskListItem;
1051
+ `
1052
+ }], ["src/client.ts.hbs", {
1053
+ type: "raw",
1054
+ body: `import { FoundryClient, PublicClientAuth } from "{{osdkPackage}}";
1055
+
1056
+ const url = import.meta.env.VITE_FOUNDRY_API_URL;
1057
+ const clientId = import.meta.env.VITE_FOUNDRY_CLIENT_ID;
1058
+ const redirectUrl = import.meta.env.VITE_FOUNDRY_REDIRECT_URL;
1059
+ checkEnv(url, "VITE_FOUNDRY_API_URL");
1060
+ checkEnv(clientId, "VITE_FOUNDRY_CLIENT_ID");
1061
+ checkEnv(redirectUrl, "VITE_FOUNDRY_REDIRECT_URL");
1062
+
1063
+ function checkEnv(
1064
+ value: string | undefined,
1065
+ name: string,
1066
+ ): asserts value is string {
1067
+ if (value == null) {
1068
+ throw new Error(\`Missing environment variable: \${name}\`);
1069
+ }
1070
+ }
1071
+
1072
+ /**
1073
+ * Initialize the client to interact with the Ontology SDK
1074
+ */
1075
+ const client = new FoundryClient({
1076
+ url,
1077
+ auth: new PublicClientAuth({
1078
+ clientId,
1079
+ url,
1080
+ redirectUrl,
1081
+ }),
1082
+ });
1083
+
1084
+ export default client;
1085
+ `
1086
+ }], ["src/index.css", {
1087
+ "type": "base64",
1088
+ "body": "OnJvb3QgewogIGZvbnQtZmFtaWx5OiBJbnRlciwgc3lzdGVtLXVpLCBBdmVuaXIsIEhlbHZldGljYSwgQXJpYWwsIHNhbnMtc2VyaWY7CiAgbGluZS1oZWlnaHQ6IDEuNTsKICBmb250LXdlaWdodDogNDAwOwoKICBmb250LXN5bnRoZXNpczogbm9uZTsKICB0ZXh0LXJlbmRlcmluZzogb3B0aW1pemVMZWdpYmlsaXR5OwogIC13ZWJraXQtZm9udC1zbW9vdGhpbmc6IGFudGlhbGlhc2VkOwogIC1tb3otb3N4LWZvbnQtc21vb3RoaW5nOiBncmF5c2NhbGU7Cn0KCiNyb290LWNvbnRhaW5lciB7CiAgZGlzcGxheTogZmxleDsKICBmbGV4OiAxOwogIGFsaWduLWl0ZW1zOiBjZW50ZXI7Cn0KCiNyb290IHsKICBtYXgtd2lkdGg6IDEyODBweDsKICBtYXJnaW46IDJyZW0gYXV0bzsKICBwYWRkaW5nOiAycmVtOwp9CgphIHsKICBmb250LXdlaWdodDogNTAwOwogIGNvbG9yOiAjNjQ2Y2ZmOwogIHRleHQtZGVjb3JhdGlvbjogaW5oZXJpdDsKfQphOmhvdmVyIHsKICBjb2xvcjogIzUzNWJmMjsKfQoKYm9keSB7CiAgbWFyZ2luOiAwOwogIGRpc3BsYXk6IGZsZXg7CiAgZmxleC1kaXJlY3Rpb246IGNvbHVtbjsKICBtaW4td2lkdGg6IDMyMHB4OwogIG1pbi1oZWlnaHQ6IDEwMHZoOwp9CgpoMSB7CiAgZm9udC1zaXplOiAzLjJlbTsKICBsaW5lLWhlaWdodDogMS4xOwp9CgpidXR0b24gewogIGJvcmRlci1yYWRpdXM6IDhweDsKICBib3JkZXI6IDFweCBzb2xpZCB0cmFuc3BhcmVudDsKICBwYWRkaW5nOiAwLjZlbSAxLjJlbTsKICBmb250LXNpemU6IDFlbTsKICBmb250LXdlaWdodDogNTAwOwogIGZvbnQtZmFtaWx5OiBpbmhlcml0OwogIGN1cnNvcjogcG9pbnRlcjsKICB0cmFuc2l0aW9uOiBib3JkZXItY29sb3IgMC4yNXM7Cn0KYnV0dG9uOmhvdmVyIHsKICBib3JkZXItY29sb3I6ICM2NDZjZmY7Cn0KYnV0dG9uOmZvY3VzLApidXR0b246Zm9jdXMtdmlzaWJsZSB7CiAgb3V0bGluZTogNHB4IGF1dG8gLXdlYmtpdC1mb2N1cy1yaW5nLWNvbG9yOwp9CgpAbWVkaWEgKHByZWZlcnMtY29sb3Itc2NoZW1lOiBsaWdodCkgewogIDpyb290IHsKICAgIGNvbG9yOiAjMjEzNTQ3OwogICAgYmFja2dyb3VuZC1jb2xvcjogI2ZmZmZmZjsKICB9CiAgYTpob3ZlciB7CiAgICBjb2xvcjogIzc0N2JmZjsKICB9CiAgYnV0dG9uIHsKICAgIGJhY2tncm91bmQtY29sb3I6ICNmOWY5Zjk7CiAgfQp9Cg=="
1089
+ }], ["src/main.tsx", {
1090
+ type: "raw",
1091
+ body: `import ReactDOM from "react-dom/client";
1092
+ import { createBrowserRouter, RouterProvider } from "react-router-dom";
1093
+ import AuthCallback from "./AuthCallback";
1094
+ import AuthenticatedRoute from "./AuthenticatedRoute";
1095
+ import Home from "./Home";
1096
+ import Login from "./Login";
1097
+ import "./index.css";
1098
+
1099
+ const router = createBrowserRouter(
1100
+ [
1101
+ {
1102
+ path: "/",
1103
+ element: <AuthenticatedRoute />,
1104
+ children: [
1105
+ {
1106
+ path: "/",
1107
+ element: <Home />,
1108
+ },
1109
+ ],
1110
+ },
1111
+ {
1112
+ path: "/login",
1113
+ element: <Login />,
1114
+ },
1115
+ {
1116
+ // This is the route defined in your application's redirect URL
1117
+ path: "/auth/callback",
1118
+ element: <AuthCallback />,
1119
+ },
1120
+ ],
1121
+ { basename: import.meta.env.BASE_URL },
1122
+ );
1123
+
1124
+ ReactDOM.createRoot(document.getElementById("root")!).render(
1125
+ <RouterProvider router={router} />,
1126
+ );
1127
+ `
1128
+ }], ["src/mocks.ts", {
1129
+ "type": "base64",
1130
+ "body": "ZXhwb3J0IGludGVyZmFjZSBNb2NrUHJvamVjdCB7CiAgJGFwaU5hbWU6IHN0cmluZzsKICAkcHJpbWFyeUtleTogc3RyaW5nOwogIGlkOiBzdHJpbmc7CiAgbmFtZTogc3RyaW5nOwogIGRlc2NyaXB0aW9uOiBzdHJpbmc7CiAgdGFza3M6IE1vY2tUYXNrW107Cn0KCmV4cG9ydCBpbnRlcmZhY2UgTW9ja1Rhc2sgewogICRhcGlOYW1lOiBzdHJpbmc7CiAgJHByaW1hcnlLZXk6IHN0cmluZzsKICBpZDogc3RyaW5nOwogIHRpdGxlOiBzdHJpbmc7CiAgZGVzY3JpcHRpb246IHN0cmluZzsKfQoKY29uc3QgcHJvamVjdHM6IE1vY2tQcm9qZWN0W10gPSBbCiAgewogICAgJGFwaU5hbWU6ICJNb2NrUHJvamVjdCIsCiAgICAkcHJpbWFyeUtleTogIjEiLAogICAgaWQ6ICIxIiwKICAgIG5hbWU6ICJNb2NrIHByb2plY3QiLAogICAgZGVzY3JpcHRpb246ICJUaGlzIGlzIGEgbW9jayBkZXNjcmlwdGlvbiIsCiAgICB0YXNrczogWwogICAgICB7CiAgICAgICAgJGFwaU5hbWU6ICJNb2NrVGFzayIsCiAgICAgICAgJHByaW1hcnlLZXk6ICIxIiwKICAgICAgICBpZDogIjEiLAogICAgICAgIHRpdGxlOiAiVHJ5IHRvIiwKICAgICAgICBkZXNjcmlwdGlvbjogInRhc2sgZGVzY3JpcHRpb24gMSIsCiAgICAgIH0sCiAgICAgIHsKICAgICAgICAkYXBpTmFtZTogIk1vY2tUYXNrIiwKICAgICAgICAkcHJpbWFyeUtleTogIjIiLAogICAgICAgIGlkOiAiMiIsCiAgICAgICAgdGl0bGU6ICJJbXBsZW1lbnQgdGhpcyIsCiAgICAgICAgZGVzY3JpcHRpb246ICJ0YXNrIGRlc2NyaXB0aW9uIDIiLAogICAgICB9LAogICAgICB7CiAgICAgICAgJGFwaU5hbWU6ICJNb2NrVGFzayIsCiAgICAgICAgJHByaW1hcnlLZXk6ICIzIiwKICAgICAgICBpZDogIjMiLAogICAgICAgIHRpdGxlOiAiV2l0aCB0aGUgT250b2xvZ3kgU0RLISIsCiAgICAgICAgZGVzY3JpcHRpb246ICJ0YXNrIGRlc2NyaXB0aW9uIDMiLAogICAgICB9LAogICAgXSwKICB9LAogIHsKICAgICRhcGlOYW1lOiAiTW9ja1Byb2plY3QiLAogICAgJHByaW1hcnlLZXk6ICIyIiwKICAgIGlkOiAiMiIsCiAgICBuYW1lOiAiWWV0IGFub3RoZXIgbW9jayBwcm9qZWN0IiwKICAgIGRlc2NyaXB0aW9uOiAiVGhpcyBpcyBhbm90aGVyIG1vY2sgZGVzY3JpcHRpb24iLAogICAgdGFza3M6IFsKICAgICAgewogICAgICAgICRhcGlOYW1lOiAiTW9ja1Rhc2siLAogICAgICAgICRwcmltYXJ5S2V5OiAiNCIsCiAgICAgICAgaWQ6ICI0IiwKICAgICAgICB0aXRsZTogIk1vcmUgdGFza3MgaGVyZSIsCiAgICAgICAgZGVzY3JpcHRpb246ICJNb3JlIHRhc2sgZGVzY3JpcHRpb24iLAogICAgICB9LAogICAgXSwKICB9LApdOwoKYXN5bmMgZnVuY3Rpb24gZGVsYXkoKTogUHJvbWlzZTx2b2lkPiB7CiAgcmV0dXJuIG5ldyBQcm9taXNlKChyZXNvbHZlKSA9PgogICAgc2V0VGltZW91dCgoKSA9PiByZXNvbHZlKCksIDUwMCArIE1hdGgucmFuZG9tKCkgKiAxMDAwKQogICk7Cn0KCi8vIEdvb2QgZW5vdWdoIHJhbmRvbSBpZCBmb3IgbW9ja3MKZnVuY3Rpb24gcmFuZG9tSWQoKTogc3RyaW5nIHsKICByZXR1cm4gYCR7TWF0aC5mbG9vcihNYXRoLnJhbmRvbSgpICogMiAqKiAzMSl9YDsKfQoKYXN5bmMgZnVuY3Rpb24gZ2V0UHJvamVjdHMoKTogUHJvbWlzZTxNb2NrUHJvamVjdFtdPiB7CiAgYXdhaXQgZGVsYXkoKTsKICBjb25zdCByZXN1bHQgPSBbLi4ucHJvamVjdHNdOwogIHJlc3VsdC5zb3J0KChwMSwgcDIpID0+IHAxLm5hbWUubG9jYWxlQ29tcGFyZShwMi5uYW1lKSk7CiAgcmV0dXJuIHJlc3VsdDsKfQoKYXN5bmMgZnVuY3Rpb24gY3JlYXRlUHJvamVjdCh7CiAgbmFtZSwKICBkZXNjcmlwdGlvbiA9ICIiLAp9OiB7CiAgbmFtZTogc3RyaW5nOwogIGRlc2NyaXB0aW9uPzogc3RyaW5nOwp9KTogUHJvbWlzZTxNb2NrUHJvamVjdFsiJHByaW1hcnlLZXkiXT4gewogIGF3YWl0IGRlbGF5KCk7CiAgY29uc3QgaWQgPSByYW5kb21JZCgpOwogIHByb2plY3RzLnB1c2goewogICAgJGFwaU5hbWU6ICJNb2NrUHJvamVjdCIsCiAgICAkcHJpbWFyeUtleTogaWQsCiAgICBpZCwKICAgIG5hbWUsCiAgICBkZXNjcmlwdGlvbiwKICAgIHRhc2tzOiBbXSwKICB9KTsKICByZXR1cm4gaWQ7Cn0KCmFzeW5jIGZ1bmN0aW9uIGdldFJlY29tbWVuZGVkUHJvamVjdERlc2NyaXB0aW9uKAogIHByb2plY3Q6IE1vY2tQcm9qZWN0LAopOiBQcm9taXNlPHN0cmluZz4gewogIGF3YWl0IGRlbGF5KCk7CiAgaWYgKHByb2plY3QudGFza3MgIT0gbnVsbCAmJiBwcm9qZWN0LnRhc2tzLmxlbmd0aCA9PT0gMCkgewogICAgdGhyb3cgbmV3IEVycm9yKCJQcm9qZWN0IGRlc2NyaXB0aW9uIHJlY29tbWVuZGF0aW9uIHJlcXVpcmVzIHRhc2tzIik7CiAgfQogIHJldHVybiBgQUlQIExvZ2ljIG1vY2sgZGVzY3JpcHRpb24gZm9yIHByb2plY3RgOwp9Cgphc3luYyBmdW5jdGlvbiB1cGRhdGVQcm9qZWN0RGVzY3JpcHRpb24oCiAgcHJvamVjdDogTW9ja1Byb2plY3QsCik6IFByb21pc2U8dm9pZD4gewogIGF3YWl0IGRlbGF5KCk7CiAgcHJvamVjdC5kZXNjcmlwdGlvbiA9IGF3YWl0IGdldFJlY29tbWVuZGVkUHJvamVjdERlc2NyaXB0aW9uKHByb2plY3QpOwp9Cgphc3luYyBmdW5jdGlvbiBkZWxldGVQcm9qZWN0KGlkOiBzdHJpbmcpOiBQcm9taXNlPHZvaWQ+IHsKICBhd2FpdCBkZWxheSgpOwogIGNvbnN0IGlkeCA9IHByb2plY3RzLmZpbmRJbmRleCgocCkgPT4gcC5pZCA9PT0gaWQpOwogIGlmIChpZHggIT09IC0xKSB7CiAgICBwcm9qZWN0cy5zcGxpY2UoaWR4LCAxKTsKICB9Cn0KCmFzeW5jIGZ1bmN0aW9uIGNyZWF0ZVRhc2soewogIHRpdGxlLAogIGRlc2NyaXB0aW9uID0gIiIsCiAgcHJvamVjdElkLAp9OiB7CiAgdGl0bGU6IHN0cmluZzsKICBkZXNjcmlwdGlvbjogc3RyaW5nOwogIHByb2plY3RJZDogc3RyaW5nOwp9KTogUHJvbWlzZTxNb2NrVGFza1siJHByaW1hcnlLZXkiXT4gewogIGF3YWl0IGRlbGF5KCk7CiAgY29uc3QgcHJvamVjdCA9IHByb2plY3RzLmZpbmQoKHApID0+IHAuaWQgPT09IHByb2plY3RJZCk7CiAgaWYgKHByb2plY3QgPT0gbnVsbCkgewogICAgdGhyb3cgbmV3IEVycm9yKGBQcm9qZWN0ICR7cHJvamVjdElkfSBub3QgZm91bmQhYCk7CiAgfQogIGNvbnN0IGlkID0gcmFuZG9tSWQoKTsKICBwcm9qZWN0LnRhc2tzLnVuc2hpZnQoewogICAgJGFwaU5hbWU6ICJNb2NrVGFzayIsCiAgICAkcHJpbWFyeUtleTogaWQsCiAgICBpZCwKICAgIHRpdGxlLAogICAgZGVzY3JpcHRpb24sCiAgfSk7CiAgcmV0dXJuIGlkOwp9Cgphc3luYyBmdW5jdGlvbiBnZXRSZWNvbW1lbmRlZFRhc2tEZXNjcmlwdGlvbigKICB0YXNrTmFtZTogc3RyaW5nLAopOiBQcm9taXNlPHN0cmluZz4gewogIGF3YWl0IGRlbGF5KCk7CiAgaWYgKHRhc2tOYW1lLmxlbmd0aCA9PT0gMCkgewogICAgdGhyb3cgbmV3IEVycm9yKCJUYXNrIG5hbWUgbXVzdCBub3QgYmUgZW1wdHkiKTsKICB9CiAgcmV0dXJuIGBNb2NrIEFJUCBkZXNjcmlwdGlvbiBmb3IgdGFza2A7Cn0KCmFzeW5jIGZ1bmN0aW9uIGRlbGV0ZVRhc2soaWQ6IHN0cmluZyk6IFByb21pc2U8dm9pZD4gewogIGF3YWl0IGRlbGF5KCk7CiAgZm9yIChjb25zdCBwcm9qZWN0IG9mIHByb2plY3RzKSB7CiAgICBjb25zdCBpZHggPSBwcm9qZWN0LnRhc2tzLmZpbmRJbmRleCgodCkgPT4gdC5pZCA9PT0gaWQpOwogICAgaWYgKGlkeCAhPT0gLTEpIHsKICAgICAgcHJvamVjdC50YXNrcy5zcGxpY2UoaWR4LCAxKTsKICAgIH0KICB9Cn0KCmNvbnN0IE1vY2tzID0gewogIGdldFByb2plY3RzLAogIGNyZWF0ZVByb2plY3QsCiAgZ2V0UmVjb21tZW5kZWRQcm9qZWN0RGVzY3JpcHRpb24sCiAgZGVsZXRlUHJvamVjdCwKICBjcmVhdGVUYXNrLAogIGRlbGV0ZVRhc2ssCiAgZ2V0UmVjb21tZW5kZWRUYXNrRGVzY3JpcHRpb24sCiAgdXBkYXRlUHJvamVjdERlc2NyaXB0aW9uLAp9OwoKZXhwb3J0IGRlZmF1bHQgTW9ja3M7Cg=="
1131
+ }], ["src/useProjectTasks.ts", {
1132
+ "type": "base64",
1133
+ "body": "aW1wb3J0IHsgdXNlQ2FsbGJhY2sgfSBmcm9tICJyZWFjdCI7CmltcG9ydCB1c2VTV1IgZnJvbSAic3dyIjsKaW1wb3J0IE1vY2tzLCB7IE1vY2tQcm9qZWN0LCBNb2NrVGFzayB9IGZyb20gIi4vbW9ja3MiOwoKZXhwb3J0IGZ1bmN0aW9uIHVzZVByb2plY3RUYXNrcyhwcm9qZWN0OiBNb2NrUHJvamVjdCB8IHVuZGVmaW5lZCkgewogIGNvbnN0IHsgZGF0YSwgaXNMb2FkaW5nLCBpc1ZhbGlkYXRpbmcsIGVycm9yLCBtdXRhdGUgfSA9IHVzZVNXUjxNb2NrVGFza1tdPigKICAgIHByb2plY3QgIT0gbnVsbCA/IGBwcm9qZWN0cy8ke3Byb2plY3QuaWR9L3Rhc2tzYCA6IG51bGwsCiAgICAvLyBUcnkgdG8gaW1wbGVtZW50IHRoaXMgd2l0aCB0aGUgT250b2xvZ3kgU0RLIQogICAgYXN5bmMgKCkgPT4gewogICAgICBpZiAocHJvamVjdCA9PSBudWxsKSB7CiAgICAgICAgcmV0dXJuIFtdOwogICAgICB9CiAgICAgIHJldHVybiBwcm9qZWN0LnRhc2tzOwogICAgfSwKICApOwoKICBjb25zdCBjcmVhdGVUYXNrOiAoCiAgICB0aXRsZTogc3RyaW5nLAogICAgZGVzY3JpcHRpb246IHN0cmluZywKICApID0+IFByb21pc2U8TW9ja1Rhc2tbIiRwcmltYXJ5S2V5Il0gfCB1bmRlZmluZWQ+ID0gdXNlQ2FsbGJhY2soCiAgICBhc3luYyAodGl0bGU6IHN0cmluZywgZGVzY3JpcHRpb246IHN0cmluZykgPT4gewogICAgICBpZiAocHJvamVjdCA9PSBudWxsKSB7CiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDsKICAgICAgfQogICAgICAvLyBUcnkgdG8gaW1wbGVtZW50IHRoaXMgd2l0aCB0aGUgT250b2xvZ3kgU0RLIQogICAgICBjb25zdCBpZCA9IGF3YWl0IE1vY2tzLmNyZWF0ZVRhc2soewogICAgICAgIHRpdGxlLAogICAgICAgIGRlc2NyaXB0aW9uLAogICAgICAgIHByb2plY3RJZDogcHJvamVjdC4kcHJpbWFyeUtleSwKICAgICAgfSk7CiAgICAgIGF3YWl0IG11dGF0ZSgpOwogICAgICByZXR1cm4gaWQ7CiAgICB9LAogICAgW3Byb2plY3QsIG11dGF0ZV0sCiAgKTsKCiAgY29uc3QgZGVsZXRlVGFzazogKHRhc2s6IE1vY2tUYXNrKSA9PiBQcm9taXNlPHZvaWQ+ID0gdXNlQ2FsbGJhY2soCiAgICBhc3luYyAodGFzaykgPT4gewogICAgICBpZiAocHJvamVjdCA9PSBudWxsKSB7CiAgICAgICAgcmV0dXJuOwogICAgICB9CiAgICAgIGF3YWl0IHNsZWVwKDEwMDApOwogICAgICAvLyBUcnkgdG8gaW1wbGVtZW50IHRoaXMgd2l0aCB0aGUgT250b2xvZ3kgU0RLIQogICAgICBhd2FpdCBNb2Nrcy5kZWxldGVUYXNrKHRhc2suJHByaW1hcnlLZXkpOwogICAgICBhd2FpdCBtdXRhdGUoKTsKICAgIH0sCiAgICBbcHJvamVjdCwgbXV0YXRlXSwKICApOwoKICBjb25zdCBnZXRSZWNvbW1lbmRlZFRhc2tEZXNjcmlwdGlvbjogKHRhc2tOYW1lOiBzdHJpbmcpID0+IFByb21pc2U8c3RyaW5nPiA9CiAgICB1c2VDYWxsYmFjaygKICAgICAgYXN5bmMgKHRhc2tOYW1lOiBzdHJpbmcpID0+IHsKICAgICAgICAvLyBUcnkgdG8gaW1wbGVtZW50IHRoaXMgd2l0aCB0aGUgT250b2xvZ3kgU0RLIQogICAgICAgIGNvbnN0IHJlY29tbWVuZGVkVGFza0Rlc2NyaXB0aW9uID0gYXdhaXQgTW9ja3MKICAgICAgICAgIC5nZXRSZWNvbW1lbmRlZFRhc2tEZXNjcmlwdGlvbih0YXNrTmFtZSk7CiAgICAgICAgYXdhaXQgbXV0YXRlKCk7CiAgICAgICAgcmV0dXJuIHJlY29tbWVuZGVkVGFza0Rlc2NyaXB0aW9uOwogICAgICB9LAogICAgICBbbXV0YXRlXSwKICAgICk7CgogIHJldHVybiB7CiAgICB0YXNrczogZGF0YSwKICAgIGlzTG9hZGluZywKICAgIGlzVmFsaWRhdGluZywKICAgIGlzRXJyb3I6IGVycm9yLAogICAgY3JlYXRlVGFzaywKICAgIGRlbGV0ZVRhc2ssCiAgICBnZXRSZWNvbW1lbmRlZFRhc2tEZXNjcmlwdGlvbiwKICB9Owp9CgpmdW5jdGlvbiBzbGVlcChtczogbnVtYmVyKSB7CiAgcmV0dXJuIG5ldyBQcm9taXNlKHJlc29sdmUgPT4gc2V0VGltZW91dChyZXNvbHZlLCBtcykpOwp9Cg=="
1134
+ }], ["src/useProjects.ts", {
1135
+ "type": "base64",
1136
+ "body": "aW1wb3J0IHsgdXNlQ2FsbGJhY2sgfSBmcm9tICJyZWFjdCI7CmltcG9ydCB1c2VTV1IgZnJvbSAic3dyIjsKaW1wb3J0IHR5cGUgeyBNb2NrUHJvamVjdCB9IGZyb20gIi4vbW9ja3MiOwppbXBvcnQgTW9ja3MgZnJvbSAiLi9tb2NrcyI7CgpmdW5jdGlvbiB1c2VQcm9qZWN0cygpIHsKICBjb25zdCB7IGRhdGEsIGlzTG9hZGluZywgaXNWYWxpZGF0aW5nLCBlcnJvciwgbXV0YXRlIH0gPSB1c2VTV1I8CiAgICBNb2NrUHJvamVjdFtdCiAgPigicHJvamVjdHMiLCBhc3luYyAoKSA9PiB7CiAgICAvLyBUcnkgdG8gaW1wbGVtZW50IHRoaXMgd2l0aCB0aGUgT250b2xvZ3kgU0RLIQogICAgcmV0dXJuIE1vY2tzLmdldFByb2plY3RzKCk7CiAgfSk7CgogIGNvbnN0IGNyZWF0ZVByb2plY3Q6ICgKICAgIG5hbWU6IHN0cmluZywKICApID0+IFByb21pc2U8TW9ja1Byb2plY3RbIiRwcmltYXJ5S2V5Il0+ID0gdXNlQ2FsbGJhY2soCiAgICBhc3luYyAobmFtZTogc3RyaW5nKSA9PiB7CiAgICAgIC8vIFRyeSB0byBpbXBsZW1lbnQgdGhpcyB3aXRoIHRoZSBPbnRvbG9neSBTREshCiAgICAgIGNvbnN0IGlkID0gYXdhaXQgTW9ja3MuY3JlYXRlUHJvamVjdCh7IG5hbWUgfSk7CiAgICAgIGF3YWl0IG11dGF0ZSgpOwogICAgICByZXR1cm4gaWQ7CiAgICB9LAogICAgW211dGF0ZV0sCiAgKTsKCiAgY29uc3QgdXBkYXRlUHJvamVjdERlc2NyaXB0aW9uOiAoCiAgICBwcm9qZWN0OiBNb2NrUHJvamVjdCwKICApID0+IFByb21pc2U8dm9pZD4gPSB1c2VDYWxsYmFjaygKICAgIGFzeW5jIChwcm9qZWN0KSA9PiB7CiAgICAgIC8vIFRyeSB0byBpbXBsZW1lbnQgdGhpcyB3aXRoIHRoZSBPbnRvbG9neSBTREshCiAgICAgIGF3YWl0IE1vY2tzLnVwZGF0ZVByb2plY3REZXNjcmlwdGlvbihwcm9qZWN0KTsKICAgICAgYXdhaXQgbXV0YXRlKCk7CiAgICB9LAogICAgW211dGF0ZV0sCiAgKTsKCiAgY29uc3QgZGVsZXRlUHJvamVjdDogKHByb2plY3Q6IE1vY2tQcm9qZWN0KSA9PiBQcm9taXNlPHZvaWQ+ID0gdXNlQ2FsbGJhY2soCiAgICBhc3luYyAocHJvamVjdCkgPT4gewogICAgICAvLyBUcnkgdG8gaW1wbGVtZW50IHRoaXMgd2l0aCB0aGUgT250b2xvZ3kgU0RLIQogICAgICBhd2FpdCBNb2Nrcy5kZWxldGVQcm9qZWN0KHByb2plY3QuJHByaW1hcnlLZXkpOwogICAgICBhd2FpdCBtdXRhdGUoKTsKICAgIH0sCiAgICBbbXV0YXRlXSwKICApOwoKICByZXR1cm4gewogICAgcHJvamVjdHM6IGRhdGEsCiAgICBpc0xvYWRpbmcsCiAgICBpc1ZhbGlkYXRpbmcsCiAgICBpc0Vycm9yOiBlcnJvciwKICAgIGNyZWF0ZVByb2plY3QsCiAgICBkZWxldGVQcm9qZWN0LAogICAgdXBkYXRlUHJvamVjdERlc2NyaXB0aW9uLAogIH07Cn0KCmV4cG9ydCBkZWZhdWx0IHVzZVByb2plY3RzOwo="
1137
+ }], ["src/vite-env.d.ts", {
1138
+ "type": "base64",
1139
+ "body": "Ly8vIDxyZWZlcmVuY2UgdHlwZXM9InZpdGUvY2xpZW50IiAvPgo="
1140
+ }], ["tsconfig.json", {
1141
+ "type": "base64",
1142
+ "body": "ewogICJjb21waWxlck9wdGlvbnMiOiB7CiAgICAidGFyZ2V0IjogIkVTMjAyMCIsCiAgICAidXNlRGVmaW5lRm9yQ2xhc3NGaWVsZHMiOiB0cnVlLAogICAgImxpYiI6IFsiRVMyMDIwIiwgIkRPTSIsICJET00uSXRlcmFibGUiXSwKICAgICJtb2R1bGUiOiAiRVNOZXh0IiwKICAgICJza2lwTGliQ2hlY2siOiB0cnVlLAoKICAgIC8qIEJ1bmRsZXIgbW9kZSAqLwogICAgIm1vZHVsZVJlc29sdXRpb24iOiAiYnVuZGxlciIsCiAgICAiYWxsb3dJbXBvcnRpbmdUc0V4dGVuc2lvbnMiOiB0cnVlLAogICAgInJlc29sdmVKc29uTW9kdWxlIjogdHJ1ZSwKICAgICJpc29sYXRlZE1vZHVsZXMiOiB0cnVlLAogICAgIm5vRW1pdCI6IHRydWUsCiAgICAianN4IjogInJlYWN0LWpzeCIsCgogICAgLyogTGludGluZyAqLwogICAgInN0cmljdCI6IHRydWUsCiAgICAibm9VbnVzZWRMb2NhbHMiOiB0cnVlLAogICAgIm5vVW51c2VkUGFyYW1ldGVycyI6IHRydWUsCiAgICAibm9GYWxsdGhyb3VnaENhc2VzSW5Td2l0Y2giOiB0cnVlCiAgfSwKICAiaW5jbHVkZSI6IFsic3JjIl0sCiAgInJlZmVyZW5jZXMiOiBbeyAicGF0aCI6ICIuL3RzY29uZmlnLm5vZGUuanNvbiIgfV0KfQo="
1143
+ }], ["tsconfig.node.json", {
1144
+ "type": "base64",
1145
+ "body": "ewogICJjb21waWxlck9wdGlvbnMiOiB7CiAgICAiY29tcG9zaXRlIjogdHJ1ZSwKICAgICJza2lwTGliQ2hlY2siOiB0cnVlLAogICAgIm1vZHVsZSI6ICJFU05leHQiLAogICAgIm1vZHVsZVJlc29sdXRpb24iOiAiYnVuZGxlciIsCiAgICAiYWxsb3dTeW50aGV0aWNEZWZhdWx0SW1wb3J0cyI6IHRydWUKICB9LAogICJpbmNsdWRlIjogWyJ2aXRlLmNvbmZpZy50cyJdCn0K"
1146
+ }], ["vite.config.ts.hbs", {
1147
+ type: "raw",
1148
+ body: `import react from "@vitejs/plugin-react";
1149
+ import { defineConfig } from "vite";
1150
+
1151
+ // https://vitejs.dev/config/
1152
+ export default defineConfig({
1153
+ plugins: [react()],
1154
+ server: {
1155
+ port: 8080,
1156
+ {{#if corsProxy}}
1157
+ proxy: {
1158
+ "^(/multipass/api|/api)": {
1159
+ target: "{{foundryUrl}}",
1160
+ changeOrigin: true,
1161
+ secure: true,
1162
+ },
1163
+ },
1164
+ {{/if}}
1165
+ },
1166
+ });
1167
+ `
1168
+ }]]);
1169
+
1170
+ exports.files = files;
1171
+ //# sourceMappingURL=esm-RRFVZF4X.cjs.map
1172
+ //# sourceMappingURL=esm-RRFVZF4X.cjs.map