@vue-skuilder/cli 0.1.7 → 0.1.8-0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +640 -105
- 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 +148 -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/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 +140 -0
- package/dist/studio-ui-src/vite.config.base.js +100 -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 +202 -25
- 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 +850 -121
- 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 +231 -27
- 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,23 @@ 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 (typeof version === 'string' && version.startsWith('workspace:')) {
|
|
80
|
-
// Replace workspace references with CLI's version
|
|
81
|
+
if (typeof version === 'string' && (version.startsWith('workspace:') || version.startsWith('file:'))) {
|
|
82
|
+
// Replace workspace and file references with CLI's version
|
|
81
83
|
packageJson.dependencies[depName] = `^${cliVersion}`;
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
86
|
}
|
|
85
87
|
|
|
86
|
-
// Add missing
|
|
88
|
+
// Add missing devDependencies for build system
|
|
87
89
|
if (packageJson.devDependencies && !packageJson.devDependencies['terser']) {
|
|
88
90
|
packageJson.devDependencies['terser'] = '^5.39.0';
|
|
89
91
|
}
|
|
92
|
+
if (packageJson.devDependencies && !packageJson.devDependencies['vite-plugin-dts']) {
|
|
93
|
+
packageJson.devDependencies['vite-plugin-dts'] = '^4.3.0';
|
|
94
|
+
}
|
|
90
95
|
|
|
91
96
|
// Add CLI as devDependency for all projects
|
|
92
97
|
if (!packageJson.devDependencies) {
|
|
@@ -114,19 +119,34 @@ export async function transformPackageJson(
|
|
|
114
119
|
* // [ ] 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
120
|
*/
|
|
116
121
|
export async function createViteConfig(viteConfigPath: string): Promise<void> {
|
|
117
|
-
// Create
|
|
118
|
-
const transformedContent =
|
|
119
|
-
import { defineConfig } from 'vite';
|
|
122
|
+
// Create dual build config similar to standalone-ui but without workspace dependencies
|
|
123
|
+
const transformedContent = `import { defineConfig } from 'vite';
|
|
120
124
|
import vue from '@vitejs/plugin-vue';
|
|
125
|
+
import dts from 'vite-plugin-dts';
|
|
126
|
+
import { resolve } from 'path';
|
|
121
127
|
import { fileURLToPath, URL } from 'node:url';
|
|
122
128
|
|
|
129
|
+
// Determine build mode from environment variable
|
|
130
|
+
const buildMode = process.env.BUILD_MODE || 'webapp';
|
|
131
|
+
|
|
123
132
|
export default defineConfig({
|
|
124
|
-
plugins: [
|
|
133
|
+
plugins: [
|
|
134
|
+
vue(),
|
|
135
|
+
// Only include dts plugin for library builds
|
|
136
|
+
...(buildMode === 'library'
|
|
137
|
+
? [dts({
|
|
138
|
+
insertTypesEntry: true,
|
|
139
|
+
include: ['src/questions/**/*.ts', 'src/questions/**/*.vue'],
|
|
140
|
+
exclude: ['**/*.spec.ts', '**/*.test.ts'],
|
|
141
|
+
outDir: 'dist-lib',
|
|
142
|
+
})]
|
|
143
|
+
: []
|
|
144
|
+
)
|
|
145
|
+
],
|
|
125
146
|
resolve: {
|
|
126
147
|
alias: {
|
|
127
148
|
// Alias for internal src paths
|
|
128
149
|
'@': fileURLToPath(new URL('./src', import.meta.url)),
|
|
129
|
-
|
|
130
150
|
// Add events alias if needed (often required by dependencies)
|
|
131
151
|
events: 'events',
|
|
132
152
|
},
|
|
@@ -145,8 +165,8 @@ export default defineConfig({
|
|
|
145
165
|
},
|
|
146
166
|
// --- Dependencies optimization ---
|
|
147
167
|
optimizeDeps: {
|
|
148
|
-
// Help Vite pre-bundle dependencies from published packages
|
|
149
168
|
include: [
|
|
169
|
+
'events',
|
|
150
170
|
'@vue-skuilder/common-ui',
|
|
151
171
|
'@vue-skuilder/db',
|
|
152
172
|
'@vue-skuilder/common',
|
|
@@ -156,14 +176,65 @@ export default defineConfig({
|
|
|
156
176
|
server: {
|
|
157
177
|
port: 5173, // Use standard Vite port for standalone projects
|
|
158
178
|
},
|
|
159
|
-
build:
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
179
|
+
build: buildMode === 'library'
|
|
180
|
+
? {
|
|
181
|
+
// Library build configuration
|
|
182
|
+
sourcemap: true,
|
|
183
|
+
target: 'es2020',
|
|
184
|
+
minify: 'terser',
|
|
185
|
+
terserOptions: {
|
|
186
|
+
keep_classnames: true,
|
|
187
|
+
},
|
|
188
|
+
lib: {
|
|
189
|
+
entry: resolve(__dirname, 'src/questions/index.ts'),
|
|
190
|
+
name: 'VueSkuilderStandaloneQuestions',
|
|
191
|
+
fileName: (format) => \`questions.\${format === 'es' ? 'mjs' : 'cjs.js'}\`,
|
|
192
|
+
},
|
|
193
|
+
rollupOptions: {
|
|
194
|
+
// External packages that shouldn't be bundled in library mode
|
|
195
|
+
external: [
|
|
196
|
+
'vue',
|
|
197
|
+
'vue-router',
|
|
198
|
+
'vuetify',
|
|
199
|
+
'pinia',
|
|
200
|
+
'@vue-skuilder/common',
|
|
201
|
+
'@vue-skuilder/common-ui',
|
|
202
|
+
'@vue-skuilder/courses',
|
|
203
|
+
'@vue-skuilder/db',
|
|
204
|
+
],
|
|
205
|
+
output: {
|
|
206
|
+
// Global variables for UMD build
|
|
207
|
+
globals: {
|
|
208
|
+
'vue': 'Vue',
|
|
209
|
+
'vue-router': 'VueRouter',
|
|
210
|
+
'vuetify': 'Vuetify',
|
|
211
|
+
'pinia': 'Pinia',
|
|
212
|
+
'@vue-skuilder/common': 'VueSkuilderCommon',
|
|
213
|
+
'@vue-skuilder/common-ui': 'VueSkuilderCommonUI',
|
|
214
|
+
'@vue-skuilder/courses': 'VueSkuilderCourses',
|
|
215
|
+
'@vue-skuilder/db': 'VueSkuilderDB',
|
|
216
|
+
},
|
|
217
|
+
exports: 'named',
|
|
218
|
+
// Preserve CSS in the output bundle
|
|
219
|
+
assetFileNames: 'assets/[name].[ext]',
|
|
220
|
+
},
|
|
221
|
+
},
|
|
222
|
+
// Output to separate directory for library build
|
|
223
|
+
outDir: 'dist-lib',
|
|
224
|
+
// Allow CSS code splitting for component libraries
|
|
225
|
+
cssCodeSplit: true,
|
|
226
|
+
}
|
|
227
|
+
: {
|
|
228
|
+
// Webapp build configuration (existing)
|
|
229
|
+
sourcemap: true,
|
|
230
|
+
target: 'es2020',
|
|
231
|
+
minify: 'terser',
|
|
232
|
+
terserOptions: {
|
|
233
|
+
keep_classnames: true,
|
|
234
|
+
},
|
|
235
|
+
// Standard webapp output directory
|
|
236
|
+
outDir: 'dist',
|
|
237
|
+
},
|
|
167
238
|
// Add define block for process polyfills
|
|
168
239
|
define: {
|
|
169
240
|
global: 'window',
|
|
@@ -182,7 +253,8 @@ export default defineConfig({
|
|
|
182
253
|
*/
|
|
183
254
|
export async function generateSkuilderConfig(
|
|
184
255
|
configPath: string,
|
|
185
|
-
config: ProjectConfig
|
|
256
|
+
config: ProjectConfig,
|
|
257
|
+
outputPath?: string
|
|
186
258
|
): Promise<void> {
|
|
187
259
|
const skuilderConfig: SkuilderConfig = {
|
|
188
260
|
title: config.title,
|
|
@@ -194,13 +266,14 @@ export async function generateSkuilderConfig(
|
|
|
194
266
|
skuilderConfig.course = config.course;
|
|
195
267
|
}
|
|
196
268
|
|
|
197
|
-
// For static data layer
|
|
198
|
-
if (
|
|
199
|
-
config.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
269
|
+
// For static data layer, use imported course ID or generate new one
|
|
270
|
+
if (config.dataLayerType === 'static') {
|
|
271
|
+
if (config.importCourseIds && config.importCourseIds.length > 0) {
|
|
272
|
+
skuilderConfig.course = config.importCourseIds[0];
|
|
273
|
+
} else {
|
|
274
|
+
// Generate UUID for new static courses without imports
|
|
275
|
+
skuilderConfig.course = randomUUID();
|
|
276
|
+
}
|
|
204
277
|
}
|
|
205
278
|
|
|
206
279
|
if (config.couchdbUrl) {
|
|
@@ -212,6 +285,11 @@ export async function generateSkuilderConfig(
|
|
|
212
285
|
}
|
|
213
286
|
|
|
214
287
|
await fs.writeFile(configPath, JSON.stringify(skuilderConfig, null, 2));
|
|
288
|
+
|
|
289
|
+
// For static data layer without imports, create empty course structure
|
|
290
|
+
if (config.dataLayerType === 'static' && (!config.importCourseIds || config.importCourseIds.length === 0) && outputPath) {
|
|
291
|
+
await createEmptyCourseStructure(outputPath, skuilderConfig.course!, config.title);
|
|
292
|
+
}
|
|
215
293
|
}
|
|
216
294
|
|
|
217
295
|
/**
|
|
@@ -250,6 +328,72 @@ export async function transformTsConfig(tsconfigPath: string): Promise<void> {
|
|
|
250
328
|
await fs.writeFile(tsconfigPath, JSON.stringify(tsconfig, null, 2));
|
|
251
329
|
}
|
|
252
330
|
|
|
331
|
+
/**
|
|
332
|
+
* Create empty course structure for new static courses
|
|
333
|
+
*/
|
|
334
|
+
async function createEmptyCourseStructure(
|
|
335
|
+
projectPath: string,
|
|
336
|
+
courseId: string,
|
|
337
|
+
title: string
|
|
338
|
+
): Promise<void> {
|
|
339
|
+
const staticCoursesPath = path.join(projectPath, 'public', 'static-courses');
|
|
340
|
+
const coursePath = path.join(staticCoursesPath, courseId);
|
|
341
|
+
|
|
342
|
+
// Create directory structure
|
|
343
|
+
await fs.mkdir(coursePath, { recursive: true });
|
|
344
|
+
await fs.mkdir(path.join(coursePath, 'chunks'), { recursive: true });
|
|
345
|
+
await fs.mkdir(path.join(coursePath, 'indices'), { recursive: true });
|
|
346
|
+
|
|
347
|
+
// Create minimal CourseConfig
|
|
348
|
+
const courseConfig: CourseConfig = {
|
|
349
|
+
courseID: courseId,
|
|
350
|
+
name: title,
|
|
351
|
+
description: '',
|
|
352
|
+
public: false,
|
|
353
|
+
deleted: false,
|
|
354
|
+
creator: 'system',
|
|
355
|
+
admins: [],
|
|
356
|
+
moderators: [],
|
|
357
|
+
dataShapes: [],
|
|
358
|
+
questionTypes: []
|
|
359
|
+
};
|
|
360
|
+
|
|
361
|
+
// Create manifest.json with proper structure
|
|
362
|
+
const manifest = {
|
|
363
|
+
version: '1.0.0',
|
|
364
|
+
courseId,
|
|
365
|
+
courseName: title,
|
|
366
|
+
courseConfig,
|
|
367
|
+
lastUpdated: new Date().toISOString(),
|
|
368
|
+
documentCount: 0,
|
|
369
|
+
chunks: [],
|
|
370
|
+
indices: [],
|
|
371
|
+
designDocs: []
|
|
372
|
+
};
|
|
373
|
+
|
|
374
|
+
await fs.writeFile(
|
|
375
|
+
path.join(coursePath, 'manifest.json'),
|
|
376
|
+
JSON.stringify(manifest, null, 2)
|
|
377
|
+
);
|
|
378
|
+
|
|
379
|
+
// Create empty tags index
|
|
380
|
+
await fs.writeFile(
|
|
381
|
+
path.join(coursePath, 'indices', 'tags.json'),
|
|
382
|
+
JSON.stringify({ tags: [] }, null, 2)
|
|
383
|
+
);
|
|
384
|
+
|
|
385
|
+
// Create CourseConfig chunk
|
|
386
|
+
await fs.writeFile(
|
|
387
|
+
path.join(coursePath, 'chunks', 'CourseConfig.json'),
|
|
388
|
+
JSON.stringify([{
|
|
389
|
+
_id: 'CourseConfig',
|
|
390
|
+
...courseConfig
|
|
391
|
+
}], null, 2)
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
console.log(chalk.green(`✅ Created empty course structure for ${courseId}`));
|
|
395
|
+
}
|
|
396
|
+
|
|
253
397
|
/**
|
|
254
398
|
* Generate .gitignore file for the project
|
|
255
399
|
*/
|
|
@@ -368,6 +512,7 @@ Thumbs.db
|
|
|
368
512
|
|
|
369
513
|
# Skuilder specific
|
|
370
514
|
/src/data/local-*.json
|
|
515
|
+
.skuilder/
|
|
371
516
|
`;
|
|
372
517
|
|
|
373
518
|
await fs.writeFile(gitignorePath, gitignoreContent);
|
|
@@ -413,8 +558,34 @@ npm run dev
|
|
|
413
558
|
Build for production:
|
|
414
559
|
\`\`\`bash
|
|
415
560
|
npm run build
|
|
561
|
+
\`\`\`${
|
|
562
|
+
config.dataLayerType === 'static'
|
|
563
|
+
? `
|
|
564
|
+
|
|
565
|
+
## Studio Mode (Content Editing)
|
|
566
|
+
|
|
567
|
+
This project supports **Studio Mode** - a content editing web interface for modifying course data:
|
|
568
|
+
|
|
569
|
+
\`\`\`bash
|
|
570
|
+
npm run studio
|
|
416
571
|
\`\`\`
|
|
417
572
|
|
|
573
|
+
Studio mode provides:
|
|
574
|
+
- **Visual Course Editor**: Interactive interface for editing course content
|
|
575
|
+
- **Live Preview**: See changes immediately in the browser
|
|
576
|
+
- **Hot Reload**: Changes are saved automatically to your course files
|
|
577
|
+
- **No Setup Required**: Built into the Skuilder CLI - just run the command
|
|
578
|
+
|
|
579
|
+
When you run \`npm run studio\`, it will:
|
|
580
|
+
1. Start a local CouchDB instance for temporary editing
|
|
581
|
+
2. Load your course data from \`public/static-courses/\`
|
|
582
|
+
3. Launch the studio interface at http://localhost:7174
|
|
583
|
+
4. Save changes back to your static course files when you flush
|
|
584
|
+
|
|
585
|
+
**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.`
|
|
586
|
+
: ''
|
|
587
|
+
}
|
|
588
|
+
|
|
418
589
|
## Configuration
|
|
419
590
|
|
|
420
591
|
Course configuration is managed in \`skuilder.config.json\`. You can modify:
|
|
@@ -482,6 +653,36 @@ Visit the [Skuilder documentation](https://github.com/NiloCK/vue-skuilder) for m
|
|
|
482
653
|
await fs.writeFile(readmePath, readme);
|
|
483
654
|
}
|
|
484
655
|
|
|
656
|
+
/**
|
|
657
|
+
* Create .skuilder directory structure for studio builds cache
|
|
658
|
+
*/
|
|
659
|
+
async function createSkuilderDirectory(projectPath: string): Promise<void> {
|
|
660
|
+
const skuilderPath = path.join(projectPath, '.skuilder');
|
|
661
|
+
const templatesPath = path.join(__dirname, '..', '..', 'templates', '.skuilder');
|
|
662
|
+
|
|
663
|
+
// Create .skuilder directory
|
|
664
|
+
await fs.mkdir(skuilderPath, { recursive: true });
|
|
665
|
+
|
|
666
|
+
// Create studio-builds subdirectory
|
|
667
|
+
await fs.mkdir(path.join(skuilderPath, 'studio-builds'), { recursive: true });
|
|
668
|
+
|
|
669
|
+
// Copy README template if it exists
|
|
670
|
+
if (existsSync(templatesPath)) {
|
|
671
|
+
await copyDirectory(templatesPath, skuilderPath);
|
|
672
|
+
} else {
|
|
673
|
+
// Fallback: create basic README
|
|
674
|
+
const readmeContent = `# .skuilder Directory
|
|
675
|
+
|
|
676
|
+
**⚠️ WARNING: GENERATED CONTENT - DO NOT EDIT MANUALLY ⚠️**
|
|
677
|
+
|
|
678
|
+
This directory contains files generated by the Skuilder CLI tools.
|
|
679
|
+
|
|
680
|
+
Generated by @vue-skuilder/cli
|
|
681
|
+
`;
|
|
682
|
+
await fs.writeFile(path.join(skuilderPath, 'README.md'), readmeContent);
|
|
683
|
+
}
|
|
684
|
+
}
|
|
685
|
+
|
|
485
686
|
/**
|
|
486
687
|
* Copy and transform the standalone-ui template to create a new project
|
|
487
688
|
*/
|
|
@@ -514,7 +715,7 @@ export async function processTemplate(
|
|
|
514
715
|
|
|
515
716
|
console.log(chalk.blue('🔧 Generating configuration...'));
|
|
516
717
|
const configPath = path.join(projectPath, 'skuilder.config.json');
|
|
517
|
-
await generateSkuilderConfig(configPath, config);
|
|
718
|
+
await generateSkuilderConfig(configPath, config, projectPath);
|
|
518
719
|
|
|
519
720
|
console.log(chalk.blue('📝 Creating README...'));
|
|
520
721
|
const readmePath = path.join(projectPath, 'README.md');
|
|
@@ -524,5 +725,8 @@ export async function processTemplate(
|
|
|
524
725
|
const gitignorePath = path.join(projectPath, '.gitignore');
|
|
525
726
|
await generateGitignore(gitignorePath);
|
|
526
727
|
|
|
728
|
+
console.log(chalk.blue('📁 Creating .skuilder directory structure...'));
|
|
729
|
+
await createSkuilderDirectory(projectPath);
|
|
730
|
+
|
|
527
731
|
console.log(chalk.green('✅ Template processing complete!'));
|
|
528
732
|
}
|
|
@@ -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"}
|