@vue-skuilder/cli 0.1.7 → 0.1.8-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/README.md +122 -8
- package/dist/cli.d.ts +1 -1
- package/dist/cli.d.ts.map +1 -1
- package/dist/cli.js +2 -1
- package/dist/cli.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +34 -3
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/pack.d.ts +10 -0
- package/dist/commands/pack.d.ts.map +1 -1
- package/dist/commands/pack.js +1 -1
- package/dist/commands/pack.js.map +1 -1
- package/dist/commands/studio.d.ts.map +1 -1
- package/dist/commands/studio.js +641 -106
- package/dist/commands/studio.js.map +1 -1
- package/dist/commands/unpack.d.ts +12 -0
- package/dist/commands/unpack.d.ts.map +1 -1
- package/dist/commands/unpack.js +1 -1
- package/dist/commands/unpack.js.map +1 -1
- package/dist/express-assets/app.d.ts +6 -0
- package/dist/express-assets/app.d.ts.map +1 -0
- package/dist/express-assets/app.js +209 -0
- package/dist/express-assets/app.js.map +1 -0
- package/dist/express-assets/assets/classroomDesignDoc.js +24 -0
- package/dist/express-assets/assets/courseValidateDocUpdate.js +56 -0
- package/dist/express-assets/assets/get-tagsDesignDoc.json +9 -0
- package/dist/express-assets/attachment-preprocessing/index.d.ts +11 -0
- package/dist/express-assets/attachment-preprocessing/index.d.ts.map +1 -0
- package/dist/express-assets/attachment-preprocessing/index.js +204 -0
- package/dist/express-assets/attachment-preprocessing/index.js.map +1 -0
- package/dist/express-assets/attachment-preprocessing/normalize.d.ts +7 -0
- package/dist/express-assets/attachment-preprocessing/normalize.d.ts.map +1 -0
- package/dist/express-assets/attachment-preprocessing/normalize.js +90 -0
- package/dist/express-assets/attachment-preprocessing/normalize.js.map +1 -0
- package/dist/express-assets/client-requests/classroom-requests.d.ts +26 -0
- package/dist/express-assets/client-requests/classroom-requests.d.ts.map +1 -0
- package/dist/express-assets/client-requests/classroom-requests.js +171 -0
- package/dist/express-assets/client-requests/classroom-requests.js.map +1 -0
- package/dist/express-assets/client-requests/course-requests.d.ts +10 -0
- package/dist/express-assets/client-requests/course-requests.d.ts.map +1 -0
- package/dist/express-assets/client-requests/course-requests.js +135 -0
- package/dist/express-assets/client-requests/course-requests.js.map +1 -0
- package/dist/express-assets/client-requests/pack-requests.d.ts +19 -0
- package/dist/express-assets/client-requests/pack-requests.d.ts.map +1 -0
- package/dist/express-assets/client-requests/pack-requests.js +130 -0
- package/dist/express-assets/client-requests/pack-requests.js.map +1 -0
- package/dist/express-assets/client.d.ts +31 -0
- package/dist/express-assets/client.d.ts.map +1 -0
- package/dist/express-assets/client.js +70 -0
- package/dist/express-assets/client.js.map +1 -0
- package/dist/express-assets/couchdb/authentication.d.ts +4 -0
- package/dist/express-assets/couchdb/authentication.d.ts.map +1 -0
- package/dist/express-assets/couchdb/authentication.js +69 -0
- package/dist/express-assets/couchdb/authentication.js.map +1 -0
- package/dist/express-assets/couchdb/index.d.ts +18 -0
- package/dist/express-assets/couchdb/index.d.ts.map +1 -0
- package/dist/express-assets/couchdb/index.js +52 -0
- package/dist/express-assets/couchdb/index.js.map +1 -0
- package/dist/express-assets/design-docs.d.ts +63 -0
- package/dist/express-assets/design-docs.d.ts.map +1 -0
- package/dist/express-assets/design-docs.js +90 -0
- package/dist/express-assets/design-docs.js.map +1 -0
- package/dist/express-assets/logger.d.ts +3 -0
- package/dist/express-assets/logger.d.ts.map +1 -0
- package/dist/express-assets/logger.js +62 -0
- package/dist/express-assets/logger.js.map +1 -0
- package/dist/express-assets/routes/logs.d.ts +3 -0
- package/dist/express-assets/routes/logs.d.ts.map +1 -0
- package/dist/express-assets/routes/logs.js +274 -0
- package/dist/express-assets/routes/logs.js.map +1 -0
- package/dist/express-assets/utils/env.d.ts +11 -0
- package/dist/express-assets/utils/env.d.ts.map +1 -0
- package/dist/express-assets/utils/env.js +39 -0
- package/dist/express-assets/utils/env.js.map +1 -0
- package/dist/express-assets/utils/processQueue.d.ts +39 -0
- package/dist/express-assets/utils/processQueue.d.ts.map +1 -0
- package/dist/express-assets/utils/processQueue.js +175 -0
- package/dist/express-assets/utils/processQueue.js.map +1 -0
- package/dist/studio-ui-src/App.vue +132 -0
- package/dist/studio-ui-src/api/index.ts +30 -0
- package/dist/studio-ui-src/components/StudioFlush.vue +108 -0
- package/dist/studio-ui-src/config/development.ts +98 -0
- package/dist/studio-ui-src/index.html +13 -0
- package/dist/studio-ui-src/main.ts +186 -0
- package/dist/studio-ui-src/package.json +35 -0
- package/dist/studio-ui-src/router/index.ts +32 -0
- package/dist/studio-ui-src/stores/useAuthStore.ts +3 -0
- package/dist/studio-ui-src/tsconfig.json +28 -0
- package/dist/studio-ui-src/utils/courseConfigRegistration.ts +297 -0
- package/dist/studio-ui-src/views/BrowseView.vue +82 -0
- package/dist/studio-ui-src/views/BulkImportView.vue +89 -0
- package/dist/studio-ui-src/views/CourseEditorView.vue +62 -0
- package/dist/studio-ui-src/views/CreateCardView.vue +144 -0
- package/dist/studio-ui-src/vite.config.base.js +103 -0
- package/dist/studio-ui-src/vite.config.ts +26 -0
- package/dist/templates/.skuilder/README.md +29 -0
- package/dist/types.d.ts +5 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/dist/utils/ExpressManager.d.ts +28 -0
- package/dist/utils/ExpressManager.d.ts.map +1 -0
- package/dist/utils/ExpressManager.js +166 -0
- package/dist/utils/ExpressManager.js.map +1 -0
- package/dist/utils/NodeFileSystemAdapter.d.ts +6 -0
- package/dist/utils/NodeFileSystemAdapter.d.ts.map +1 -1
- package/dist/utils/NodeFileSystemAdapter.js +29 -1
- package/dist/utils/NodeFileSystemAdapter.js.map +1 -1
- package/dist/utils/error-reporting.d.ts +54 -0
- package/dist/utils/error-reporting.d.ts.map +1 -0
- package/dist/utils/error-reporting.js +143 -0
- package/dist/utils/error-reporting.js.map +1 -0
- package/dist/utils/pack-courses.d.ts.map +1 -1
- package/dist/utils/pack-courses.js +10 -27
- package/dist/utils/pack-courses.js.map +1 -1
- package/dist/utils/prompts.d.ts.map +1 -1
- package/dist/utils/prompts.js +24 -0
- package/dist/utils/prompts.js.map +1 -1
- package/dist/utils/questions-hash.d.ts +22 -0
- package/dist/utils/questions-hash.d.ts.map +1 -0
- package/dist/utils/questions-hash.js +96 -0
- package/dist/utils/questions-hash.js.map +1 -0
- package/dist/utils/template.d.ts +1 -1
- package/dist/utils/template.d.ts.map +1 -1
- package/dist/utils/template.js +209 -27
- package/dist/utils/template.js.map +1 -1
- package/eslint.config.mjs +1 -1
- package/package.json +30 -11
- package/src/cli.ts +3 -1
- package/src/commands/init.ts +48 -3
- package/src/commands/pack.ts +1 -1
- package/src/commands/studio.ts +851 -122
- package/src/commands/unpack.ts +1 -1
- package/src/types.ts +5 -0
- package/src/utils/ExpressManager.ts +210 -0
- package/src/utils/NodeFileSystemAdapter.ts +46 -2
- package/src/utils/error-reporting.ts +192 -0
- package/src/utils/pack-courses.ts +11 -36
- package/src/utils/prompts.ts +34 -0
- package/src/utils/questions-hash.ts +109 -0
- package/src/utils/template.ts +243 -29
- package/templates/.skuilder/README.md +29 -0
- package/dist/studio-ui-assets/assets/BrowseView-BJbixGOU.js +0 -2
- package/dist/studio-ui-assets/assets/BrowseView-BJbixGOU.js.map +0 -1
- package/dist/studio-ui-assets/assets/BrowseView-CM4HBO4j.css +0 -1
- package/dist/studio-ui-assets/assets/BulkImportView-DB6DYDJU.js +0 -2
- package/dist/studio-ui-assets/assets/BulkImportView-DB6DYDJU.js.map +0 -1
- package/dist/studio-ui-assets/assets/BulkImportView-g4wQUfPA.css +0 -1
- package/dist/studio-ui-assets/assets/CourseEditorView-BIlhlhw1.js +0 -2
- package/dist/studio-ui-assets/assets/CourseEditorView-BIlhlhw1.js.map +0 -1
- package/dist/studio-ui-assets/assets/CourseEditorView-WuPNLVKp.css +0 -1
- package/dist/studio-ui-assets/assets/CreateCardView-CyNOKCkm.css +0 -1
- package/dist/studio-ui-assets/assets/CreateCardView-DPjPvzzt.js +0 -2
- package/dist/studio-ui-assets/assets/CreateCardView-DPjPvzzt.js.map +0 -1
- package/dist/studio-ui-assets/assets/edit-ui.es-DiUxqbgF.js +0 -330
- package/dist/studio-ui-assets/assets/edit-ui.es-DiUxqbgF.js.map +0 -1
- package/dist/studio-ui-assets/assets/index--zY88pg6.css +0 -14
- package/dist/studio-ui-assets/assets/index-BnAv1C72.js +0 -287
- package/dist/studio-ui-assets/assets/index-BnAv1C72.js.map +0 -1
- package/dist/studio-ui-assets/assets/index-DHMXQY3-.js +0 -192
- package/dist/studio-ui-assets/assets/index-DHMXQY3-.js.map +0 -1
- package/dist/studio-ui-assets/assets/materialdesignicons-webfont-B7mPwVP_.ttf +0 -0
- package/dist/studio-ui-assets/assets/materialdesignicons-webfont-CSr8KVlo.eot +0 -0
- package/dist/studio-ui-assets/assets/materialdesignicons-webfont-Dp5v-WZN.woff2 +0 -0
- package/dist/studio-ui-assets/assets/materialdesignicons-webfont-PXm3-2wK.woff +0 -0
- package/dist/studio-ui-assets/assets/vue-DZcMATiC.js +0 -28
- package/dist/studio-ui-assets/assets/vue-DZcMATiC.js.map +0 -1
- package/dist/studio-ui-assets/assets/vuetify-qg7mRxy_.js +0 -6
- package/dist/studio-ui-assets/assets/vuetify-qg7mRxy_.js.map +0 -1
- package/dist/studio-ui-assets/index.html +0 -16
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { createHash } from 'crypto';
|
|
2
|
+
import { promises as fs, existsSync } from 'fs';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Calculate hash of src/questions/ directory contents
|
|
7
|
+
* Returns consistent hash based on file names, content, and modification times
|
|
8
|
+
*/
|
|
9
|
+
export async function hashQuestionsDirectory(coursePath: string): Promise<string> {
|
|
10
|
+
const questionsPath = path.join(coursePath, 'src', 'questions');
|
|
11
|
+
|
|
12
|
+
// If questions directory doesn't exist, return special "no-questions" hash
|
|
13
|
+
if (!existsSync(questionsPath)) {
|
|
14
|
+
return 'no-questions';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const hash = createHash('sha256');
|
|
18
|
+
|
|
19
|
+
try {
|
|
20
|
+
// Get all files recursively, sort for consistent ordering
|
|
21
|
+
const files = await getAllFiles(questionsPath);
|
|
22
|
+
files.sort();
|
|
23
|
+
|
|
24
|
+
// If no files, return "empty-questions" hash
|
|
25
|
+
if (files.length === 0) {
|
|
26
|
+
return 'empty-questions';
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Hash each file's relative path, content, and mtime
|
|
30
|
+
for (const file of files) {
|
|
31
|
+
const relativePath = path.relative(questionsPath, file);
|
|
32
|
+
const stat = await fs.stat(file);
|
|
33
|
+
const content = await fs.readFile(file);
|
|
34
|
+
|
|
35
|
+
// Include relative path, modification time, and content in hash
|
|
36
|
+
hash.update(relativePath);
|
|
37
|
+
hash.update(stat.mtime.toISOString());
|
|
38
|
+
hash.update(content);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
return hash.digest('hex').substring(0, 12); // First 12 chars for readability
|
|
42
|
+
} catch (error) {
|
|
43
|
+
console.warn(`Warning: Failed to hash questions directory: ${error}`);
|
|
44
|
+
return 'hash-error';
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Recursively get all files in a directory
|
|
50
|
+
*/
|
|
51
|
+
async function getAllFiles(dirPath: string): Promise<string[]> {
|
|
52
|
+
const files: string[] = [];
|
|
53
|
+
|
|
54
|
+
try {
|
|
55
|
+
const entries = await fs.readdir(dirPath, { withFileTypes: true });
|
|
56
|
+
|
|
57
|
+
for (const entry of entries) {
|
|
58
|
+
const fullPath = path.join(dirPath, entry.name);
|
|
59
|
+
|
|
60
|
+
if (entry.isDirectory()) {
|
|
61
|
+
// Recursively get files from subdirectories
|
|
62
|
+
const subFiles = await getAllFiles(fullPath);
|
|
63
|
+
files.push(...subFiles);
|
|
64
|
+
} else if (entry.isFile()) {
|
|
65
|
+
// Only include source files (TypeScript, Vue, JavaScript)
|
|
66
|
+
if (/\.(ts|vue|js|tsx|jsx)$/.test(entry.name)) {
|
|
67
|
+
files.push(fullPath);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} catch (error) {
|
|
72
|
+
// If directory can't be read, return empty array
|
|
73
|
+
console.warn(`Warning: Could not read directory ${dirPath}: ${error}`);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
return files;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get the studio build directory path for a given questions hash
|
|
81
|
+
*/
|
|
82
|
+
export function getStudioBuildPath(coursePath: string, questionsHash: string): string {
|
|
83
|
+
return path.join(coursePath, '.skuilder', 'studio-builds', questionsHash);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Check if a studio build exists for the given questions hash
|
|
88
|
+
*/
|
|
89
|
+
export function studioBuildExists(coursePath: string, questionsHash: string): boolean {
|
|
90
|
+
const buildPath = getStudioBuildPath(coursePath, questionsHash);
|
|
91
|
+
return existsSync(path.join(buildPath, 'index.html'));
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Ensure the cache directory structure exists
|
|
96
|
+
*/
|
|
97
|
+
export async function ensureCacheDirectory(coursePath: string): Promise<void> {
|
|
98
|
+
const cacheDir = path.join(coursePath, '.skuilder', 'studio-builds');
|
|
99
|
+
await fs.mkdir(cacheDir, { recursive: true });
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Ensure a specific build directory exists
|
|
104
|
+
*/
|
|
105
|
+
export async function ensureBuildDirectory(coursePath: string, questionsHash: string): Promise<string> {
|
|
106
|
+
const buildPath = getStudioBuildPath(coursePath, questionsHash);
|
|
107
|
+
await fs.mkdir(buildPath, { recursive: true });
|
|
108
|
+
return buildPath;
|
|
109
|
+
}
|
package/src/utils/template.ts
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { promises as fs, existsSync } from 'fs';
|
|
2
2
|
import path from 'path';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
|
+
import { randomUUID } from 'crypto';
|
|
4
5
|
import chalk from 'chalk';
|
|
5
6
|
import { ProjectConfig, SkuilderConfig } from '../types.js';
|
|
7
|
+
import { CourseConfig } from '@vue-skuilder/common';
|
|
6
8
|
|
|
7
9
|
const __filename = fileURLToPath(import.meta.url);
|
|
8
10
|
const __dirname = path.dirname(__filename);
|
|
@@ -73,20 +75,26 @@ export async function transformPackageJson(
|
|
|
73
75
|
packageJson.description = `Skuilder course application: ${projectName}`;
|
|
74
76
|
packageJson.version = '1.0.0';
|
|
75
77
|
|
|
76
|
-
// Transform workspace dependencies to published versions
|
|
78
|
+
// Transform workspace and file dependencies to published versions
|
|
77
79
|
if (packageJson.dependencies) {
|
|
78
80
|
for (const [depName, version] of Object.entries(packageJson.dependencies)) {
|
|
79
|
-
if (
|
|
80
|
-
|
|
81
|
+
if (
|
|
82
|
+
typeof version === 'string' &&
|
|
83
|
+
(version.startsWith('workspace:') || version.startsWith('file:'))
|
|
84
|
+
) {
|
|
85
|
+
// Replace workspace and file references with CLI's version
|
|
81
86
|
packageJson.dependencies[depName] = `^${cliVersion}`;
|
|
82
87
|
}
|
|
83
88
|
}
|
|
84
89
|
}
|
|
85
90
|
|
|
86
|
-
// Add missing
|
|
91
|
+
// Add missing devDependencies for build system
|
|
87
92
|
if (packageJson.devDependencies && !packageJson.devDependencies['terser']) {
|
|
88
93
|
packageJson.devDependencies['terser'] = '^5.39.0';
|
|
89
94
|
}
|
|
95
|
+
if (packageJson.devDependencies && !packageJson.devDependencies['vite-plugin-dts']) {
|
|
96
|
+
packageJson.devDependencies['vite-plugin-dts'] = '^4.3.0';
|
|
97
|
+
}
|
|
90
98
|
|
|
91
99
|
// Add CLI as devDependency for all projects
|
|
92
100
|
if (!packageJson.devDependencies) {
|
|
@@ -114,19 +122,34 @@ export async function transformPackageJson(
|
|
|
114
122
|
* // [ ] This should be revised so that it works from the existing vite.config.ts in standalone-ui. As is, it recreates 95% of the same config.
|
|
115
123
|
*/
|
|
116
124
|
export async function createViteConfig(viteConfigPath: string): Promise<void> {
|
|
117
|
-
// Create
|
|
118
|
-
const transformedContent =
|
|
119
|
-
import { defineConfig } from 'vite';
|
|
125
|
+
// Create dual build config similar to standalone-ui but without workspace dependencies
|
|
126
|
+
const transformedContent = `import { defineConfig } from 'vite';
|
|
120
127
|
import vue from '@vitejs/plugin-vue';
|
|
128
|
+
import dts from 'vite-plugin-dts';
|
|
129
|
+
import { resolve } from 'path';
|
|
121
130
|
import { fileURLToPath, URL } from 'node:url';
|
|
122
131
|
|
|
132
|
+
// Determine build mode from environment variable
|
|
133
|
+
const buildMode = process.env.BUILD_MODE || 'webapp';
|
|
134
|
+
|
|
123
135
|
export default defineConfig({
|
|
124
|
-
plugins: [
|
|
136
|
+
plugins: [
|
|
137
|
+
vue(),
|
|
138
|
+
// Only include dts plugin for library builds
|
|
139
|
+
...(buildMode === 'library'
|
|
140
|
+
? [dts({
|
|
141
|
+
insertTypesEntry: true,
|
|
142
|
+
include: ['src/questions/**/*.ts', 'src/questions/**/*.vue'],
|
|
143
|
+
exclude: ['**/*.spec.ts', '**/*.test.ts'],
|
|
144
|
+
outDir: 'dist-lib',
|
|
145
|
+
})]
|
|
146
|
+
: []
|
|
147
|
+
)
|
|
148
|
+
],
|
|
125
149
|
resolve: {
|
|
126
150
|
alias: {
|
|
127
151
|
// Alias for internal src paths
|
|
128
152
|
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
|
129
|
-
|
|
130
153
|
// Add events alias if needed (often required by dependencies)
|
|
131
154
|
events: 'events',
|
|
132
155
|
},
|
|
@@ -140,30 +163,81 @@ export default defineConfig({
|
|
|
140
163
|
'@vue-skuilder/db',
|
|
141
164
|
'@vue-skuilder/common',
|
|
142
165
|
'@vue-skuilder/common-ui',
|
|
143
|
-
'@vue-skuilder/
|
|
166
|
+
'@vue-skuilder/courseware',
|
|
144
167
|
],
|
|
145
168
|
},
|
|
146
169
|
// --- Dependencies optimization ---
|
|
147
170
|
optimizeDeps: {
|
|
148
|
-
// Help Vite pre-bundle dependencies from published packages
|
|
149
171
|
include: [
|
|
172
|
+
'events',
|
|
150
173
|
'@vue-skuilder/common-ui',
|
|
151
174
|
'@vue-skuilder/db',
|
|
152
175
|
'@vue-skuilder/common',
|
|
153
|
-
'@vue-skuilder/
|
|
176
|
+
'@vue-skuilder/courseware',
|
|
154
177
|
],
|
|
155
178
|
},
|
|
156
179
|
server: {
|
|
157
180
|
port: 5173, // Use standard Vite port for standalone projects
|
|
158
181
|
},
|
|
159
|
-
build:
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
182
|
+
build: buildMode === 'library'
|
|
183
|
+
? {
|
|
184
|
+
// Library build configuration
|
|
185
|
+
sourcemap: true,
|
|
186
|
+
target: 'es2020',
|
|
187
|
+
minify: 'terser',
|
|
188
|
+
terserOptions: {
|
|
189
|
+
keep_classnames: true,
|
|
190
|
+
},
|
|
191
|
+
lib: {
|
|
192
|
+
entry: resolve(__dirname, 'src/questions/index.ts'),
|
|
193
|
+
name: 'VueSkuilderStandaloneQuestions',
|
|
194
|
+
fileName: (format) => \`questions.\${format === 'es' ? 'mjs' : 'cjs.js'}\`,
|
|
195
|
+
},
|
|
196
|
+
rollupOptions: {
|
|
197
|
+
// External packages that shouldn't be bundled in library mode
|
|
198
|
+
external: [
|
|
199
|
+
'vue',
|
|
200
|
+
'vue-router',
|
|
201
|
+
'vuetify',
|
|
202
|
+
'pinia',
|
|
203
|
+
'@vue-skuilder/common',
|
|
204
|
+
'@vue-skuilder/common-ui',
|
|
205
|
+
'@vue-skuilder/courseware',
|
|
206
|
+
'@vue-skuilder/db',
|
|
207
|
+
],
|
|
208
|
+
output: {
|
|
209
|
+
// Global variables for UMD build
|
|
210
|
+
globals: {
|
|
211
|
+
'vue': 'Vue',
|
|
212
|
+
'vue-router': 'VueRouter',
|
|
213
|
+
'vuetify': 'Vuetify',
|
|
214
|
+
'pinia': 'Pinia',
|
|
215
|
+
'@vue-skuilder/common': 'VueSkuilderCommon',
|
|
216
|
+
'@vue-skuilder/common-ui': 'VueSkuilderCommonUI',
|
|
217
|
+
'@vue-skuilder/courseware': 'VueSkuilderCourseWare',
|
|
218
|
+
'@vue-skuilder/db': 'VueSkuilderDB',
|
|
219
|
+
},
|
|
220
|
+
exports: 'named',
|
|
221
|
+
// Preserve CSS in the output bundle
|
|
222
|
+
assetFileNames: 'assets/[name].[ext]',
|
|
223
|
+
},
|
|
224
|
+
},
|
|
225
|
+
// Output to separate directory for library build
|
|
226
|
+
outDir: 'dist-lib',
|
|
227
|
+
// Allow CSS code splitting for component libraries
|
|
228
|
+
cssCodeSplit: true,
|
|
229
|
+
}
|
|
230
|
+
: {
|
|
231
|
+
// Webapp build configuration (existing)
|
|
232
|
+
sourcemap: true,
|
|
233
|
+
target: 'es2020',
|
|
234
|
+
minify: 'terser',
|
|
235
|
+
terserOptions: {
|
|
236
|
+
keep_classnames: true,
|
|
237
|
+
},
|
|
238
|
+
// Standard webapp output directory
|
|
239
|
+
outDir: 'dist',
|
|
240
|
+
},
|
|
167
241
|
// Add define block for process polyfills
|
|
168
242
|
define: {
|
|
169
243
|
global: 'window',
|
|
@@ -182,7 +256,8 @@ export default defineConfig({
|
|
|
182
256
|
*/
|
|
183
257
|
export async function generateSkuilderConfig(
|
|
184
258
|
configPath: string,
|
|
185
|
-
config: ProjectConfig
|
|
259
|
+
config: ProjectConfig,
|
|
260
|
+
outputPath?: string
|
|
186
261
|
): Promise<void> {
|
|
187
262
|
const skuilderConfig: SkuilderConfig = {
|
|
188
263
|
title: config.title,
|
|
@@ -194,13 +269,14 @@ export async function generateSkuilderConfig(
|
|
|
194
269
|
skuilderConfig.course = config.course;
|
|
195
270
|
}
|
|
196
271
|
|
|
197
|
-
// For static data layer
|
|
198
|
-
if (
|
|
199
|
-
config.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
272
|
+
// For static data layer, use imported course ID or generate new one
|
|
273
|
+
if (config.dataLayerType === 'static') {
|
|
274
|
+
if (config.importCourseIds && config.importCourseIds.length > 0) {
|
|
275
|
+
skuilderConfig.course = config.importCourseIds[0];
|
|
276
|
+
} else {
|
|
277
|
+
// Generate UUID for new static courses without imports
|
|
278
|
+
skuilderConfig.course = randomUUID();
|
|
279
|
+
}
|
|
204
280
|
}
|
|
205
281
|
|
|
206
282
|
if (config.couchdbUrl) {
|
|
@@ -212,6 +288,15 @@ export async function generateSkuilderConfig(
|
|
|
212
288
|
}
|
|
213
289
|
|
|
214
290
|
await fs.writeFile(configPath, JSON.stringify(skuilderConfig, null, 2));
|
|
291
|
+
|
|
292
|
+
// For static data layer without imports, create empty course structure
|
|
293
|
+
if (
|
|
294
|
+
config.dataLayerType === 'static' &&
|
|
295
|
+
(!config.importCourseIds || config.importCourseIds.length === 0) &&
|
|
296
|
+
outputPath
|
|
297
|
+
) {
|
|
298
|
+
await createEmptyCourseStructure(outputPath, skuilderConfig.course!, config.title);
|
|
299
|
+
}
|
|
215
300
|
}
|
|
216
301
|
|
|
217
302
|
/**
|
|
@@ -250,6 +335,75 @@ export async function transformTsConfig(tsconfigPath: string): Promise<void> {
|
|
|
250
335
|
await fs.writeFile(tsconfigPath, JSON.stringify(tsconfig, null, 2));
|
|
251
336
|
}
|
|
252
337
|
|
|
338
|
+
/**
|
|
339
|
+
* Create empty course structure for new static courses
|
|
340
|
+
*/
|
|
341
|
+
async function createEmptyCourseStructure(
|
|
342
|
+
projectPath: string,
|
|
343
|
+
courseId: string,
|
|
344
|
+
title: string
|
|
345
|
+
): Promise<void> {
|
|
346
|
+
const staticCoursesPath = path.join(projectPath, 'public', 'static-courses');
|
|
347
|
+
const coursePath = path.join(staticCoursesPath, courseId);
|
|
348
|
+
|
|
349
|
+
// Create directory structure
|
|
350
|
+
await fs.mkdir(coursePath, { recursive: true });
|
|
351
|
+
await fs.mkdir(path.join(coursePath, 'chunks'), { recursive: true });
|
|
352
|
+
await fs.mkdir(path.join(coursePath, 'indices'), { recursive: true });
|
|
353
|
+
|
|
354
|
+
// Create minimal CourseConfig
|
|
355
|
+
const courseConfig: CourseConfig = {
|
|
356
|
+
courseID: courseId,
|
|
357
|
+
name: title,
|
|
358
|
+
description: '',
|
|
359
|
+
public: false,
|
|
360
|
+
deleted: false,
|
|
361
|
+
creator: 'system',
|
|
362
|
+
admins: [],
|
|
363
|
+
moderators: [],
|
|
364
|
+
dataShapes: [],
|
|
365
|
+
questionTypes: [],
|
|
366
|
+
};
|
|
367
|
+
|
|
368
|
+
// Create manifest.json with proper structure
|
|
369
|
+
const manifest = {
|
|
370
|
+
version: '1.0.0',
|
|
371
|
+
courseId,
|
|
372
|
+
courseName: title,
|
|
373
|
+
courseConfig,
|
|
374
|
+
lastUpdated: new Date().toISOString(),
|
|
375
|
+
documentCount: 0,
|
|
376
|
+
chunks: [],
|
|
377
|
+
indices: [],
|
|
378
|
+
designDocs: [],
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
await fs.writeFile(path.join(coursePath, 'manifest.json'), JSON.stringify(manifest, null, 2));
|
|
382
|
+
|
|
383
|
+
// Create empty tags index
|
|
384
|
+
await fs.writeFile(
|
|
385
|
+
path.join(coursePath, 'indices', 'tags.json'),
|
|
386
|
+
JSON.stringify({ tags: [] }, null, 2)
|
|
387
|
+
);
|
|
388
|
+
|
|
389
|
+
// Create CourseConfig chunk
|
|
390
|
+
await fs.writeFile(
|
|
391
|
+
path.join(coursePath, 'chunks', 'CourseConfig.json'),
|
|
392
|
+
JSON.stringify(
|
|
393
|
+
[
|
|
394
|
+
{
|
|
395
|
+
_id: 'CourseConfig',
|
|
396
|
+
...courseConfig,
|
|
397
|
+
},
|
|
398
|
+
],
|
|
399
|
+
null,
|
|
400
|
+
2
|
|
401
|
+
)
|
|
402
|
+
);
|
|
403
|
+
|
|
404
|
+
console.log(chalk.green(`✅ Created empty course structure for ${courseId}`));
|
|
405
|
+
}
|
|
406
|
+
|
|
253
407
|
/**
|
|
254
408
|
* Generate .gitignore file for the project
|
|
255
409
|
*/
|
|
@@ -368,6 +522,7 @@ Thumbs.db
|
|
|
368
522
|
|
|
369
523
|
# Skuilder specific
|
|
370
524
|
/src/data/local-*.json
|
|
525
|
+
.skuilder/
|
|
371
526
|
`;
|
|
372
527
|
|
|
373
528
|
await fs.writeFile(gitignorePath, gitignoreContent);
|
|
@@ -413,8 +568,34 @@ npm run dev
|
|
|
413
568
|
Build for production:
|
|
414
569
|
\`\`\`bash
|
|
415
570
|
npm run build
|
|
571
|
+
\`\`\`${
|
|
572
|
+
config.dataLayerType === 'static'
|
|
573
|
+
? `
|
|
574
|
+
|
|
575
|
+
## Studio Mode (Content Editing)
|
|
576
|
+
|
|
577
|
+
This project supports **Studio Mode** - a content editing web interface for modifying course data:
|
|
578
|
+
|
|
579
|
+
\`\`\`bash
|
|
580
|
+
npm run studio
|
|
416
581
|
\`\`\`
|
|
417
582
|
|
|
583
|
+
Studio mode provides:
|
|
584
|
+
- **Visual Course Editor**: Interactive interface for editing course content
|
|
585
|
+
- **Live Preview**: See changes immediately in the browser
|
|
586
|
+
- **Hot Reload**: Changes are saved automatically to your course files
|
|
587
|
+
- **No Setup Required**: Built into the Skuilder CLI - just run the command
|
|
588
|
+
|
|
589
|
+
When you run \`npm run studio\`, it will:
|
|
590
|
+
1. Start a local CouchDB instance for temporary editing
|
|
591
|
+
2. Load your course data from \`public/static-courses/\`
|
|
592
|
+
3. Launch the studio interface at http://localhost:7174
|
|
593
|
+
4. Save changes back to your static course files when you flush
|
|
594
|
+
|
|
595
|
+
**Important**: Studio mode **overwrites** existing static data source files in \`public/static-courses/\`. Make sure to commit or backup your course data before making major edits.`
|
|
596
|
+
: ''
|
|
597
|
+
}
|
|
598
|
+
|
|
418
599
|
## Configuration
|
|
419
600
|
|
|
420
601
|
Course configuration is managed in \`skuilder.config.json\`. You can modify:
|
|
@@ -482,6 +663,36 @@ Visit the [Skuilder documentation](https://github.com/NiloCK/vue-skuilder) for m
|
|
|
482
663
|
await fs.writeFile(readmePath, readme);
|
|
483
664
|
}
|
|
484
665
|
|
|
666
|
+
/**
|
|
667
|
+
* Create .skuilder directory structure for studio builds cache
|
|
668
|
+
*/
|
|
669
|
+
async function createSkuilderDirectory(projectPath: string): Promise<void> {
|
|
670
|
+
const skuilderPath = path.join(projectPath, '.skuilder');
|
|
671
|
+
const templatesPath = path.join(__dirname, '..', '..', 'templates', '.skuilder');
|
|
672
|
+
|
|
673
|
+
// Create .skuilder directory
|
|
674
|
+
await fs.mkdir(skuilderPath, { recursive: true });
|
|
675
|
+
|
|
676
|
+
// Create studio-builds subdirectory
|
|
677
|
+
await fs.mkdir(path.join(skuilderPath, 'studio-builds'), { recursive: true });
|
|
678
|
+
|
|
679
|
+
// Copy README template if it exists
|
|
680
|
+
if (existsSync(templatesPath)) {
|
|
681
|
+
await copyDirectory(templatesPath, skuilderPath);
|
|
682
|
+
} else {
|
|
683
|
+
// Fallback: create basic README
|
|
684
|
+
const readmeContent = `# .skuilder Directory
|
|
685
|
+
|
|
686
|
+
**⚠️ WARNING: GENERATED CONTENT - DO NOT EDIT MANUALLY ⚠️**
|
|
687
|
+
|
|
688
|
+
This directory contains files generated by the Skuilder CLI tools.
|
|
689
|
+
|
|
690
|
+
Generated by @vue-skuilder/cli
|
|
691
|
+
`;
|
|
692
|
+
await fs.writeFile(path.join(skuilderPath, 'README.md'), readmeContent);
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
|
|
485
696
|
/**
|
|
486
697
|
* Copy and transform the standalone-ui template to create a new project
|
|
487
698
|
*/
|
|
@@ -514,7 +725,7 @@ export async function processTemplate(
|
|
|
514
725
|
|
|
515
726
|
console.log(chalk.blue('🔧 Generating configuration...'));
|
|
516
727
|
const configPath = path.join(projectPath, 'skuilder.config.json');
|
|
517
|
-
await generateSkuilderConfig(configPath, config);
|
|
728
|
+
await generateSkuilderConfig(configPath, config, projectPath);
|
|
518
729
|
|
|
519
730
|
console.log(chalk.blue('📝 Creating README...'));
|
|
520
731
|
const readmePath = path.join(projectPath, 'README.md');
|
|
@@ -524,5 +735,8 @@ export async function processTemplate(
|
|
|
524
735
|
const gitignorePath = path.join(projectPath, '.gitignore');
|
|
525
736
|
await generateGitignore(gitignorePath);
|
|
526
737
|
|
|
738
|
+
console.log(chalk.blue('📁 Creating .skuilder directory structure...'));
|
|
739
|
+
await createSkuilderDirectory(projectPath);
|
|
740
|
+
|
|
527
741
|
console.log(chalk.green('✅ Template processing complete!'));
|
|
528
742
|
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# .skuilder Directory
|
|
2
|
+
|
|
3
|
+
**⚠️ WARNING: GENERATED CONTENT - DO NOT EDIT MANUALLY ⚠️**
|
|
4
|
+
|
|
5
|
+
This directory contains files generated by the Skuilder CLI tools and is **NOT** intended for manual editing except under experimental circumstances.
|
|
6
|
+
|
|
7
|
+
## Contents
|
|
8
|
+
|
|
9
|
+
- `studio-builds/` - Cached builds of studio-ui with local question types
|
|
10
|
+
- Each subdirectory represents a different build based on your `src/questions/` content
|
|
11
|
+
- Builds are automatically managed by `skuilder studio` command
|
|
12
|
+
- Safe to delete - will be regenerated as needed
|
|
13
|
+
|
|
14
|
+
## Purpose
|
|
15
|
+
|
|
16
|
+
The Skuilder CLI uses this directory to cache studio-ui builds that include your local question types. This enables:
|
|
17
|
+
|
|
18
|
+
- Fast startup of `skuilder studio` when your questions haven't changed
|
|
19
|
+
- Isolation between different question type configurations
|
|
20
|
+
- Automatic rebuild when your local questions are modified
|
|
21
|
+
|
|
22
|
+
## Maintenance
|
|
23
|
+
|
|
24
|
+
- **Safe to delete**: The entire `.skuilder` directory can be deleted safely
|
|
25
|
+
- **Automatic cleanup**: Old builds may be cleaned up automatically
|
|
26
|
+
- **Version control**: This directory should be ignored by git (check your .gitignore)
|
|
27
|
+
|
|
28
|
+
---
|
|
29
|
+
Generated by @vue-skuilder/cli
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{g as _,a as w,C as g,_ as k}from"./index-DHMXQY3-.js";import{a as C}from"./index-BnAv1C72.js";import{h as x,d as u,x as y,X as m,ai as s,aj as r,m as a,ak as t,ao as d,Q as c,V as B,u as v}from"./vue-DZcMATiC.js";import"./vuetify-qg7mRxy_.js";const V={class:"browse-view"},E={key:0,class:"text-center pa-4"},N={key:1,class:"text-center pa-4"},b={key:2},z={key:3,class:"text-center pa-4"},I=x({__name:"BrowseView",setup(L){const n=u(!0),i=u(null),l=u(null);return y(async()=>{try{const o=_();if(!o)throw new Error(w());l.value=o.database.name,n.value=!1}catch(o){console.error("Browse view initialization error:",o),i.value=o instanceof Error?o.message:"Unknown error",n.value=!1}}),(o,e)=>{const f=m("v-progress-circular"),p=m("v-icon");return r(),s("div",V,[n.value?(r(),s("div",E,[a(f,{indeterminate:""}),e[0]||(e[0]=t("p",{class:"mt-2"},"Loading course...",-1))])):i.value?(r(),s("div",N,[a(p,{color:"error",size:"48"},{default:d(()=>e[1]||(e[1]=[c("mdi-alert-circle")])),_:1}),e[2]||(e[2]=t("h2",{class:"mt-2"},"Browse Error",-1)),t("p",null,B(i.value),1)])):l.value?(r(),s("div",b,[a(v(g),{"course-id":l.value,"view-lookup-function":v(C).getView,"edit-mode":"full"},{actions:d(()=>e[3]||(e[3]=[c(" ")])),_:1},8,["course-id","view-lookup-function"])])):(r(),s("div",z,[a(p,{size:"48"},{default:d(()=>e[4]||(e[4]=[c("mdi-school")])),_:1}),e[5]||(e[5]=t("h2",{class:"mt-2"},"No Course Loaded",-1)),e[6]||(e[6]=t("p",null,"Please load a course to start browsing.",-1))]))])}}}),P=k(I,[["__scopeId","data-v-2c3c618e"]]);export{P as default};
|
|
2
|
-
//# sourceMappingURL=BrowseView-BJbixGOU.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BrowseView-BJbixGOU.js","sources":["../../src/views/BrowseView.vue"],"sourcesContent":["<template>\n <div class=\"browse-view\">\n <div v-if=\"loading\" class=\"text-center pa-4\">\n <v-progress-circular indeterminate />\n <p class=\"mt-2\">Loading course...</p>\n </div>\n\n <div v-else-if=\"error\" class=\"text-center pa-4\">\n <v-icon color=\"error\" size=\"48\">mdi-alert-circle</v-icon>\n <h2 class=\"mt-2\">Browse Error</h2>\n <p>{{ error }}</p>\n </div>\n\n <div v-else-if=\"courseId\">\n <course-information :course-id=\"courseId\" :view-lookup-function=\"allCourses.getView\" :edit-mode=\"'full'\">\n <template #actions> </template>\n </course-information>\n </div>\n\n <div v-else class=\"text-center pa-4\">\n <v-icon size=\"48\">mdi-school</v-icon>\n <h2 class=\"mt-2\">No Course Loaded</h2>\n <p>Please load a course to start browsing.</p>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted } from 'vue';\nimport { CourseInformation } from '@vue-skuilder/common-ui';\nimport { allCourses } from '@vue-skuilder/courses';\nimport { getStudioConfig, getConfigErrorMessage } from '../config/development';\n\n// Browse view state\nconst loading = ref(true);\nconst error = ref<string | null>(null);\nconst courseId = ref<string | null>(null);\n\n// Initialize browse view\nonMounted(async () => {\n try {\n // Get studio configuration (CLI-injected or environment variables)\n const studioConfig = getStudioConfig();\n\n if (!studioConfig) {\n throw new Error(getConfigErrorMessage());\n }\n\n courseId.value = studioConfig.database.name;\n loading.value = false;\n } catch (err) {\n console.error('Browse view initialization error:', err);\n error.value = err instanceof Error ? err.message : 'Unknown error';\n loading.value = false;\n }\n});\n</script>\n\n<style scoped>\n.browse-view {\n height: 100%;\n}\n\n.studio-header {\n padding: 16px 0;\n}\n\n.studio-header h1 {\n color: rgb(var(--v-theme-primary));\n font-weight: 500;\n}\n\n.studio-header p {\n color: rgb(var(--v-theme-on-surface-variant));\n margin: 0;\n}\n</style>\n"],"names":["loading","ref","error","courseId","onMounted","studioConfig","getStudioConfig","getConfigErrorMessage","err"],"mappings":"6aAkCM,MAAAA,EAAUC,EAAI,EAAI,EAClBC,EAAQD,EAAmB,IAAI,EAC/BE,EAAWF,EAAmB,IAAI,EAGxC,OAAAG,EAAU,SAAY,CAChB,GAAA,CAEF,MAAMC,EAAeC,EAAgB,EAErC,GAAI,CAACD,EACG,MAAA,IAAI,MAAME,GAAuB,EAGhCJ,EAAA,MAAQE,EAAa,SAAS,KACvCL,EAAQ,MAAQ,SACTQ,EAAK,CACJ,QAAA,MAAM,oCAAqCA,CAAG,EACtDN,EAAM,MAAQM,aAAe,MAAQA,EAAI,QAAU,gBACnDR,EAAQ,MAAQ,EAAA,CAClB,CACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.browse-view[data-v-2c3c618e]{height:100%}.studio-header[data-v-2c3c618e]{padding:16px 0}.studio-header h1[data-v-2c3c618e]{color:rgb(var(--v-theme-primary));font-weight:500}.studio-header p[data-v-2c3c618e]{color:rgb(var(--v-theme-on-surface-variant));margin:0}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{B as x}from"./edit-ui.es-DiUxqbgF.js";import{a as B}from"./index-BnAv1C72.js";import{g as y,a as I,b as V,_ as b}from"./index-DHMXQY3-.js";import{h as D,d as i,x as E,X as r,ai as s,aj as a,m as t,ao as n,Q as m,ak as _,V as L,u as v}from"./vue-DZcMATiC.js";import"./vuetify-qg7mRxy_.js";const N={class:"bulk-import-view"},z={key:0,class:"text-center pa-4"},M={key:1,class:"text-center pa-4"},S={class:"mt-2 text-error"},h={key:2},j={key:3},Q=D({__name:"BulkImportView",setup(T){const c=i(!0),u=i(null),d=i(null),p=i(null);E(async()=>{try{const o=y();if(!o)throw new Error(I());d.value=o.database.name;const l=V().getCourseDB(d.value);p.value=await l.getCourseConfig(),c.value=!1}catch(o){console.error("Bulk import initialization error:",o),u.value=o instanceof Error?o.message:"Unknown error",c.value=!1}});const f=o=>{console.log("Import completed:",o)};return(o,e)=>{const l=r("v-icon"),g=r("v-card-title"),k=r("v-progress-circular"),C=r("v-card-text"),w=r("v-card");return a(),s("div",N,[t(w,null,{default:n(()=>[t(g,null,{default:n(()=>[t(l,{left:""},{default:n(()=>e[0]||(e[0]=[m("mdi-file-import")])),_:1}),e[1]||(e[1]=m(" Bulk Import Cards "))]),_:1}),t(C,null,{default:n(()=>[c.value?(a(),s("div",z,[t(k,{indeterminate:""}),e[2]||(e[2]=_("p",{class:"mt-2"},"Loading bulk import tool...",-1))])):u.value?(a(),s("div",M,[t(l,{color:"error",size:"24"},{default:n(()=>e[3]||(e[3]=[m("mdi-alert-circle")])),_:1}),_("p",S,L(u.value),1)])):d.value&&p.value?(a(),s("div",h,[t(v(x),{"course-cfg":p.value,"view-lookup-function":v(B).getView,onImportCompleted:f},null,8,["course-cfg","view-lookup-function"])])):(a(),s("div",j,e[4]||(e[4]=[_("p",{class:"text-center"},"No course loaded",-1)])))]),_:1})]),_:1})])}}}),F=b(Q,[["__scopeId","data-v-ba3b5194"]]);export{F as default};
|
|
2
|
-
//# sourceMappingURL=BulkImportView-DB6DYDJU.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"BulkImportView-DB6DYDJU.js","sources":["../../src/views/BulkImportView.vue"],"sourcesContent":["<template>\n <div class=\"bulk-import-view\">\n <v-card>\n <v-card-title>\n <v-icon left>mdi-file-import</v-icon>\n Bulk Import Cards\n </v-card-title>\n \n <v-card-text>\n <div v-if=\"loading\" class=\"text-center pa-4\">\n <v-progress-circular indeterminate />\n <p class=\"mt-2\">Loading bulk import tool...</p>\n </div>\n\n <div v-else-if=\"error\" class=\"text-center pa-4\">\n <v-icon color=\"error\" size=\"24\">mdi-alert-circle</v-icon>\n <p class=\"mt-2 text-error\">{{ error }}</p>\n </div>\n\n <div v-else-if=\"courseId && courseConfig\">\n <!-- Bulk Import View from edit-ui package -->\n <bulk-import-view \n :course-cfg=\"courseConfig\"\n :view-lookup-function=\"allCourses.getView\"\n @import-completed=\"onImportCompleted\"\n />\n </div>\n\n <div v-else>\n <p class=\"text-center\">No course loaded</p>\n </div>\n </v-card-text>\n </v-card>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted } from 'vue';\nimport { BulkImportView } from '@vue-skuilder/edit-ui';\nimport { allCourses } from '@vue-skuilder/courses';\nimport { getStudioConfig, getConfigErrorMessage } from '../config/development';\nimport { getDataLayer } from '@vue-skuilder/db';\nimport type { CourseConfig } from '@vue-skuilder/common';\n\n// Bulk import state\nconst loading = ref(true);\nconst error = ref<string | null>(null);\nconst courseId = ref<string | null>(null);\nconst courseConfig = ref<CourseConfig | null>(null);\n\n// Initialize bulk import view\nonMounted(async () => {\n try {\n // Get studio configuration (CLI-injected or environment variables)\n const studioConfig = getStudioConfig();\n\n if (!studioConfig) {\n throw new Error(getConfigErrorMessage());\n }\n\n courseId.value = studioConfig.database.name;\n\n // Load course configuration\n const dataLayer = getDataLayer();\n const courseDB = dataLayer.getCourseDB(courseId.value);\n courseConfig.value = await courseDB.getCourseConfig();\n\n loading.value = false;\n } catch (err) {\n console.error('Bulk import initialization error:', err);\n error.value = err instanceof Error ? err.message : 'Unknown error';\n loading.value = false;\n }\n});\n\n// Handle import completion\nconst onImportCompleted = (result: any) => {\n console.log('Import completed:', result);\n // Could add success notification here\n};\n</script>\n\n<style scoped>\n.bulk-import-view {\n max-width: 1200px;\n margin: 0 auto;\n padding: 16px;\n}\n</style>"],"names":["loading","ref","error","courseId","courseConfig","onMounted","studioConfig","getStudioConfig","getConfigErrorMessage","courseDB","getDataLayer","err","onImportCompleted","result"],"mappings":"seA6CM,MAAAA,EAAUC,EAAI,EAAI,EAClBC,EAAQD,EAAmB,IAAI,EAC/BE,EAAWF,EAAmB,IAAI,EAClCG,EAAeH,EAAyB,IAAI,EAGlDI,EAAU,SAAY,CAChB,GAAA,CAEF,MAAMC,EAAeC,EAAgB,EAErC,GAAI,CAACD,EACG,MAAA,IAAI,MAAME,GAAuB,EAGhCL,EAAA,MAAQG,EAAa,SAAS,KAIvC,MAAMG,EADYC,EAAa,EACJ,YAAYP,EAAS,KAAK,EACxCC,EAAA,MAAQ,MAAMK,EAAS,gBAAgB,EAEpDT,EAAQ,MAAQ,SACTW,EAAK,CACJ,QAAA,MAAM,oCAAqCA,CAAG,EACtDT,EAAM,MAAQS,aAAe,MAAQA,EAAI,QAAU,gBACnDX,EAAQ,MAAQ,EAAA,CAClB,CACD,EAGK,MAAAY,EAAqBC,GAAgB,CACjC,QAAA,IAAI,oBAAqBA,CAAM,CAEzC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.bulk-import-view[data-v-ba3b5194]{max-width:1200px;margin:0 auto;padding:16px}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{C as _}from"./edit-ui.es-DiUxqbgF.js";import{a as g}from"./index-BnAv1C72.js";import{g as C,a as k,_ as w}from"./index-DHMXQY3-.js";import{h as x,d as u,x as E,X as c,ai as r,aj as s,m as a,ak as t,ao as p,Q as m,V as y,u as v}from"./vue-DZcMATiC.js";import"./vuetify-qg7mRxy_.js";const V={class:"course-editor-view"},N={key:0,class:"text-center pa-4"},z={key:1,class:"text-center pa-4"},B={key:2},I={key:3,class:"text-center pa-4"},L=x({__name:"CourseEditorView",setup(M){const n=u(!0),i=u(null),l=u(null);return E(async()=>{try{const o=C();if(!o)throw new Error(k());l.value=o.database.name,n.value=!1}catch(o){console.error("Course editor initialization error:",o),i.value=o instanceof Error?o.message:"Unknown error",n.value=!1}}),(o,e)=>{const f=c("v-progress-circular"),d=c("v-icon");return s(),r("div",V,[n.value?(s(),r("div",N,[a(f,{indeterminate:""}),e[0]||(e[0]=t("p",{class:"mt-2"},"Loading course editor...",-1))])):i.value?(s(),r("div",z,[a(d,{color:"error",size:"48"},{default:p(()=>e[1]||(e[1]=[m("mdi-alert-circle")])),_:1}),e[2]||(e[2]=t("h2",{class:"mt-2"},"Editor Error",-1)),t("p",null,y(i.value),1)])):l.value?(s(),r("div",B,[a(v(_),{course:l.value,"view-lookup-function":v(g).getView},null,8,["course","view-lookup-function"])])):(s(),r("div",I,[a(d,{size:"48"},{default:p(()=>e[3]||(e[3]=[m("mdi-school")])),_:1}),e[4]||(e[4]=t("h2",{class:"mt-2"},"No Course Loaded",-1)),e[5]||(e[5]=t("p",null,"Please load a course to start editing.",-1))]))])}}}),P=w(L,[["__scopeId","data-v-c575e95c"]]);export{P as default};
|
|
2
|
-
//# sourceMappingURL=CourseEditorView-BIlhlhw1.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CourseEditorView-BIlhlhw1.js","sources":["../../src/views/CourseEditorView.vue"],"sourcesContent":["<template>\n <div class=\"course-editor-view\">\n <div v-if=\"loading\" class=\"text-center pa-4\">\n <v-progress-circular indeterminate />\n <p class=\"mt-2\">Loading course editor...</p>\n </div>\n\n <div v-else-if=\"error\" class=\"text-center pa-4\">\n <v-icon color=\"error\" size=\"48\">mdi-alert-circle</v-icon>\n <h2 class=\"mt-2\">Editor Error</h2>\n <p>{{ error }}</p>\n </div>\n\n <div v-else-if=\"courseId\">\n <!-- Course Editor from edit-ui package -->\n <course-editor :course=\"courseId\" :view-lookup-function=\"allCourses.getView\" />\n </div>\n\n <div v-else class=\"text-center pa-4\">\n <v-icon size=\"48\">mdi-school</v-icon>\n <h2 class=\"mt-2\">No Course Loaded</h2>\n <p>Please load a course to start editing.</p>\n </div>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted } from 'vue';\nimport { CourseEditor } from '@vue-skuilder/edit-ui';\nimport { allCourses } from '@vue-skuilder/courses';\nimport { getStudioConfig, getConfigErrorMessage } from '../config/development';\n\n// Course editor state\nconst loading = ref(true);\nconst error = ref<string | null>(null);\nconst courseId = ref<string | null>(null);\n\n// Initialize course editor\nonMounted(async () => {\n try {\n // Get studio configuration (CLI-injected or environment variables)\n const studioConfig = getStudioConfig();\n\n if (!studioConfig) {\n throw new Error(getConfigErrorMessage());\n }\n\n courseId.value = studioConfig.database.name;\n loading.value = false;\n } catch (err) {\n console.error('Course editor initialization error:', err);\n error.value = err instanceof Error ? err.message : 'Unknown error';\n loading.value = false;\n }\n});\n</script>\n\n<style scoped>\n.course-editor-view {\n height: 100%;\n}\n</style>\n"],"names":["loading","ref","error","courseId","onMounted","studioConfig","getStudioConfig","getConfigErrorMessage","err"],"mappings":"geAiCM,MAAAA,EAAUC,EAAI,EAAI,EAClBC,EAAQD,EAAmB,IAAI,EAC/BE,EAAWF,EAAmB,IAAI,EAGxC,OAAAG,EAAU,SAAY,CAChB,GAAA,CAEF,MAAMC,EAAeC,EAAgB,EAErC,GAAI,CAACD,EACG,MAAA,IAAI,MAAME,GAAuB,EAGhCJ,EAAA,MAAQE,EAAa,SAAS,KACvCL,EAAQ,MAAQ,SACTQ,EAAK,CACJ,QAAA,MAAM,sCAAuCA,CAAG,EACxDN,EAAM,MAAQM,aAAe,MAAQA,EAAI,QAAU,gBACnDR,EAAQ,MAAQ,EAAA,CAClB,CACD"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.course-editor-view[data-v-c575e95c]{height:100%}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
.create-card-view[data-v-6c9210e9]{max-width:1200px;margin:0 auto;padding:16px}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{D as I}from"./edit-ui.es-DiUxqbgF.js";import{a as x}from"./index-BnAv1C72.js";import{g as L,a as z,b as q,_ as M}from"./index-DHMXQY3-.js";import{h as T,d as c,c as w,x as U,X as r,ai as n,aj as t,m as s,ao as l,Q as v,ak as m,V as j,an as h,am as V,u as D}from"./vue-DZcMATiC.js";import"./vuetify-qg7mRxy_.js";const F={class:"create-card-view"},Q={key:0,class:"text-center pa-4"},X={key:1,class:"text-center pa-4"},A={class:"mt-2 text-error"},G={key:2},H={key:2,class:"text-center pa-4"},J={key:3},K=T({__name:"CreateCardView",setup(O){const f=c(!0),_=c(null),i=c(null),u=c(null),g=c(0),d=w(()=>u.value?.dataShapes?u.value.dataShapes:[]),k=w(()=>{const a=d.value;if(a.length===0)return null;const e=a[g.value]?.name;if(!e)return null;for(const o of x.courses)for(const C of o.questions)for(const p of C.dataShapes)if(p.name===e.split(".").pop())return p;return null});U(async()=>{try{const a=L();if(!a)throw new Error(z());i.value=a.database.name;const o=q().getCourseDB(i.value);u.value=await o.getCourseConfig(),f.value=!1}catch(a){console.error("Create card initialization error:",a),_.value=a instanceof Error?a.message:"Unknown error",f.value=!1}});const S=a=>{console.log("Card created:",a)};return(a,e)=>{const o=r("v-icon"),C=r("v-card-title"),p=r("v-progress-circular"),N=r("v-select"),b=r("v-card-text"),B=r("v-card");return t(),n("div",F,[s(B,null,{default:l(()=>[s(C,null,{default:l(()=>[s(o,{left:""},{default:l(()=>e[1]||(e[1]=[v("mdi-card-plus")])),_:1}),e[2]||(e[2]=v(" Create New Card "))]),_:1}),s(b,null,{default:l(()=>[f.value?(t(),n("div",Q,[s(p,{indeterminate:""}),e[3]||(e[3]=m("p",{class:"mt-2"},"Loading card creation form...",-1))])):_.value?(t(),n("div",X,[s(o,{color:"error",size:"24"},{default:l(()=>e[4]||(e[4]=[v("mdi-alert-circle")])),_:1}),m("p",A,j(_.value),1)])):i.value&&u.value?(t(),n("div",G,[d.value.length>1?(t(),h(N,{key:0,modelValue:g.value,"onUpdate:modelValue":e[0]||(e[0]=y=>g.value=y),items:d.value.map((y,E)=>({title:y.name.replace(/^.*\./,""),value:E})),label:"Card Type",class:"mb-4"},null,8,["modelValue","items"])):V("",!0),k.value?(t(),h(D(I),{key:1,"course-id":i.value,"course-cfg":u.value,"data-shape":k.value,"view-lookup-function":D(x).getView,onCardCreated:S},null,8,["course-id","course-cfg","data-shape","view-lookup-function"])):d.value.length===0?(t(),n("div",H,[s(o,{color:"warning",size:"24"},{default:l(()=>e[5]||(e[5]=[v("mdi-alert")])),_:1}),e[6]||(e[6]=m("p",{class:"mt-2"},"No card types available in this course",-1))])):V("",!0)])):(t(),n("div",J,e[7]||(e[7]=[m("p",{class:"text-center"},"No course loaded",-1)])))]),_:1})]),_:1})])}}}),$=M(K,[["__scopeId","data-v-6c9210e9"]]);export{$ as default};
|
|
2
|
-
//# sourceMappingURL=CreateCardView-DPjPvzzt.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"CreateCardView-DPjPvzzt.js","sources":["../../src/views/CreateCardView.vue"],"sourcesContent":["<template>\n <div class=\"create-card-view\">\n <v-card>\n <v-card-title>\n <v-icon left>mdi-card-plus</v-icon>\n Create New Card\n </v-card-title>\n\n <v-card-text>\n <div v-if=\"loading\" class=\"text-center pa-4\">\n <v-progress-circular indeterminate />\n <p class=\"mt-2\">Loading card creation form...</p>\n </div>\n\n <div v-else-if=\"error\" class=\"text-center pa-4\">\n <v-icon color=\"error\" size=\"24\">mdi-alert-circle</v-icon>\n <p class=\"mt-2 text-error\">{{ error }}</p>\n </div>\n\n <div v-else-if=\"courseId && courseConfig\">\n <!-- Card type selector -->\n <v-select\n v-if=\"availableDataShapes.length > 1\"\n v-model=\"selectedDataShapeIndex\"\n :items=\"\n availableDataShapes.map((shape, index) => ({\n title: shape.name.replace(/^.*\\./, ''),\n value: index,\n }))\n \"\n label=\"Card Type\"\n class=\"mb-4\"\n />\n\n <!-- Data Input Form from edit-ui package -->\n <data-input-form\n v-if=\"selectedDataShape\"\n :course-id=\"courseId\"\n :course-cfg=\"courseConfig\"\n :data-shape=\"selectedDataShape\"\n :view-lookup-function=\"allCourses.getView\"\n @card-created=\"onCardCreated\"\n />\n\n <div v-else-if=\"availableDataShapes.length === 0\" class=\"text-center pa-4\">\n <v-icon color=\"warning\" size=\"24\">mdi-alert</v-icon>\n <p class=\"mt-2\">No card types available in this course</p>\n </div>\n </div>\n\n <div v-else>\n <p class=\"text-center\">No course loaded</p>\n </div>\n </v-card-text>\n </v-card>\n </div>\n</template>\n\n<script setup lang=\"ts\">\nimport { ref, onMounted, computed } from 'vue';\nimport { DataInputForm } from '@vue-skuilder/edit-ui';\nimport { allCourses } from '@vue-skuilder/courses';\nimport { getStudioConfig, getConfigErrorMessage } from '../config/development';\nimport { getDataLayer } from '@vue-skuilder/db';\nimport type { CourseConfig, DataShape } from '@vue-skuilder/common';\n\n// Create card state\nconst loading = ref(true);\nconst error = ref<string | null>(null);\nconst courseId = ref<string | null>(null);\nconst courseConfig = ref<CourseConfig | null>(null);\nconst selectedDataShapeIndex = ref<number>(0);\n\n// Get available data shapes\nconst availableDataShapes = computed(() => {\n if (!courseConfig.value?.dataShapes) return [];\n return courseConfig.value.dataShapes;\n});\n\n// Get currently selected data shape\nconst selectedDataShape = computed((): DataShape | null => {\n const shapes = availableDataShapes.value;\n if (shapes.length === 0) return null;\n\n // Find the corresponding DataShape from allCourses\n const shapeName = shapes[selectedDataShapeIndex.value]?.name;\n if (!shapeName) return null;\n\n // Search through all courses to find the DataShape\n for (const course of allCourses.courses) {\n for (const question of course.questions) {\n for (const dataShape of question.dataShapes) {\n if (dataShape.name === shapeName.split('.').pop()) {\n return dataShape;\n }\n }\n }\n }\n return null;\n});\n\n// Initialize create card view\nonMounted(async () => {\n try {\n // Get studio configuration (CLI-injected or environment variables)\n const studioConfig = getStudioConfig();\n\n if (!studioConfig) {\n throw new Error(getConfigErrorMessage());\n }\n\n courseId.value = studioConfig.database.name;\n\n // Load course configuration\n const dataLayer = getDataLayer();\n const courseDB = dataLayer.getCourseDB(courseId.value);\n courseConfig.value = await courseDB.getCourseConfig();\n\n loading.value = false;\n } catch (err) {\n console.error('Create card initialization error:', err);\n error.value = err instanceof Error ? err.message : 'Unknown error';\n loading.value = false;\n }\n});\n\n// Handle card creation\nconst onCardCreated = (cardData: any) => {\n console.log('Card created:', cardData);\n // Could add success notification or redirect here\n};\n</script>\n\n<style scoped>\n.create-card-view {\n max-width: 1200px;\n margin: 0 auto;\n padding: 16px;\n}\n</style>\n"],"names":["loading","ref","error","courseId","courseConfig","selectedDataShapeIndex","availableDataShapes","computed","selectedDataShape","shapes","shapeName","course","allCourses","question","dataShape","onMounted","studioConfig","getStudioConfig","getConfigErrorMessage","courseDB","getDataLayer","err","onCardCreated","cardData"],"mappings":"giBAmEM,MAAAA,EAAUC,EAAI,EAAI,EAClBC,EAAQD,EAAmB,IAAI,EAC/BE,EAAWF,EAAmB,IAAI,EAClCG,EAAeH,EAAyB,IAAI,EAC5CI,EAAyBJ,EAAY,CAAC,EAGtCK,EAAsBC,EAAS,IAC9BH,EAAa,OAAO,WAClBA,EAAa,MAAM,WADkB,CAAC,CAE9C,EAGKI,EAAoBD,EAAS,IAAwB,CACzD,MAAME,EAASH,EAAoB,MAC/B,GAAAG,EAAO,SAAW,EAAU,OAAA,KAGhC,MAAMC,EAAYD,EAAOJ,EAAuB,KAAK,GAAG,KACpD,GAAA,CAACK,EAAkB,OAAA,KAGZ,UAAAC,KAAUC,EAAW,QACnB,UAAAC,KAAYF,EAAO,UACjB,UAAAG,KAAaD,EAAS,WAC/B,GAAIC,EAAU,OAASJ,EAAU,MAAM,GAAG,EAAE,MACnC,OAAAI,EAKR,OAAA,IAAA,CACR,EAGDC,EAAU,SAAY,CAChB,GAAA,CAEF,MAAMC,EAAeC,EAAgB,EAErC,GAAI,CAACD,EACG,MAAA,IAAI,MAAME,GAAuB,EAGhCf,EAAA,MAAQa,EAAa,SAAS,KAIvC,MAAMG,EADYC,EAAa,EACJ,YAAYjB,EAAS,KAAK,EACxCC,EAAA,MAAQ,MAAMe,EAAS,gBAAgB,EAEpDnB,EAAQ,MAAQ,SACTqB,EAAK,CACJ,QAAA,MAAM,oCAAqCA,CAAG,EACtDnB,EAAM,MAAQmB,aAAe,MAAQA,EAAI,QAAU,gBACnDrB,EAAQ,MAAQ,EAAA,CAClB,CACD,EAGK,MAAAsB,EAAiBC,GAAkB,CAC/B,QAAA,IAAI,gBAAiBA,CAAQ,CAEvC"}
|