@@ -11,10 +11,12 @@ Example:
1111Card 1 Question
1212{{blank}}
1313tags: tagA, tagB
14+ elo: 1500
1415---
1516---
1617Card 2 Question
1718Another {{blank}}
19+ elo: 1200
1820tags: tagC"
1921 rows =" 15"
2022 varient =" outlined"
@@ -75,18 +77,7 @@ import { BlanksCardDataShapes } from '@vue-skuilder/courses';
7577import { getCurrentUser } from ' @vue-skuilder/common-ui' ;
7678import { getDataLayer , CourseDBInterface } from ' @vue-skuilder/db' ;
7779import { alertUser } from ' @vue-skuilder/common-ui' ; // For user feedback
78-
79- interface ImportResult {
80- originalText: string ;
81- status: ' success' | ' error' ;
82- message: string ;
83- cardId? : string ;
84- }
85-
86- interface ParsedCard {
87- markdown: string ;
88- tags: string [];
89- }
80+ import { ImportResult , processBulkCards , validateProcessorConfig , isValidBulkFormat } from ' @/utils/bulkImport' ;
9081
9182export default defineComponent ({
9283 name: ' BulkImportView' ,
@@ -125,36 +116,6 @@ export default defineComponent({
125116 }
126117 },
127118 methods: {
128- parseCard(cardString : string ): ParsedCard | null {
129- const trimmedCardString = cardString .trim ();
130- if (! trimmedCardString ) {
131- return null ;
132- }
133-
134- const lines = trimmedCardString .split (' \n ' );
135- let tags: string [] = [];
136- const markdownLines = [... lines ];
137-
138- if (lines .length > 0 ) {
139- const lastLine = lines [lines .length - 1 ].trim ();
140- if (lastLine .toLowerCase ().startsWith (' tags:' )) {
141- tags = lastLine
142- .substring (5 )
143- .split (' ,' )
144- .map ((tag ) => tag .trim ())
145- .filter ((tag ) => tag );
146- markdownLines .pop (); // Remove the tags line
147- }
148- }
149-
150- const markdown = markdownLines .join (' \n ' ).trim ();
151- if (! markdown ) {
152- // Card must have some markdown content
153- return null ;
154- }
155- return { markdown , tags };
156- },
157-
158119 async processCards() {
159120 if (! this .courseDB ) {
160121 alertUser ({
@@ -164,7 +125,11 @@ export default defineComponent({
164125 this .processing = false ;
165126 return ;
166127 }
167- if (! this .bulkText .trim ()) return ;
128+
129+ if (! isValidBulkFormat (this .bulkText )) {
130+ this .processing = false ;
131+ return ;
132+ }
168133
169134 // Validate that we have datashapes in the course config
170135 if (! this .courseCfg ?.dataShapes || this .courseCfg .dataShapes .length === 0 ) {
@@ -179,8 +144,6 @@ export default defineComponent({
179144 this .processing = true ;
180145 this .results = [];
181146
182- const cardDelimiter = ' \n ---\n ---\n ' ;
183- const cardStrings = this .bulkText .split (cardDelimiter );
184147 const currentUser = await getCurrentUser ();
185148 const userName = currentUser .getUsername ();
186149
@@ -205,80 +168,49 @@ export default defineComponent({
205168 dataShapeToUse: dataShapeToUse .name ,
206169 });
207170
208- for (const cardString of cardStrings ) {
209- const originalText = cardString .trim ();
210- if (! originalText ) continue ;
211-
212- const parsed = this .parseCard (originalText );
213-
214- if (! parsed ) {
215- this .results .push ({
216- originalText ,
217- status: ' error' ,
218- message: ' Failed to parse card: Empty content after tag removal or invalid format.' ,
219- });
220- continue ;
221- }
222-
223- const { markdown, tags } = parsed ;
224-
225- // The BlanksCardDataShapes expects an 'Input' field for markdown
226- // and an 'Uploads' field for media.
227- const cardData = {
228- Input: markdown ,
229- Uploads: [], // As per requirement, no uploads for bulk import
230- };
231-
232- try {
233- // Extract course code from first dataShape in course config
234- const configDataShape = this .courseCfg ?.dataShapes ?.[0 ];
235- if (! configDataShape ) {
236- throw new Error (' No data shapes found in course configuration' );
237- }
171+ // Extract course code from first dataShape in course config
172+ const configDataShape = this .courseCfg ?.dataShapes ?.[0 ];
173+ if (! configDataShape ) {
174+ this .results .push ({
175+ originalText: ' N/A - Configuration Error' ,
176+ status: ' error' ,
177+ message: ' No data shapes found in course configuration' ,
178+ });
179+ this .processing = false ;
180+ return ;
181+ }
238182
239- const codeCourse = NameSpacer .getDataShapeDescriptor (configDataShape .name ).course ;
240- console .log (` [BulkImportView] Using codeCourse: ${codeCourse } for note addition ` );
183+ const codeCourse = NameSpacer .getDataShapeDescriptor (configDataShape .name ).course ;
184+ console .log (` [BulkImportView] Using codeCourse: ${codeCourse } for note addition ` );
241185
242- const result = await this .courseDB .addNote (
243- codeCourse ,
244- dataShapeToUse ,
245- cardData ,
246- userName ,
247- tags ,
248- undefined , // deck
249- undefined // elo
250- );
186+ // Prepare processor configuration
187+ const config = {
188+ dataShape: dataShapeToUse ,
189+ courseCode: codeCourse ,
190+ userName: userName ,
191+ };
251192
252- if (result .status === Status .ok ) {
253- this .results .push ({
254- originalText ,
255- status: ' success' ,
256- message: ' Card added successfully.' ,
257- cardId: result .id ? result .id : ' (unknown)' ,
258- });
259- } else {
260- this .results .push ({
261- originalText ,
262- status: ' error' ,
263- message: result .message || ' Failed to add card to database. Unknown error.' ,
264- });
265- }
266- } catch (error ) {
267- console .error (' Error adding note:' , error );
268- this .results .push ({
269- originalText ,
270- status: ' error' ,
271- message: ` Error adding card: ${error instanceof Error ? error .message : ' Unknown error' } ` ,
272- });
273- }
193+ // Validate processor configuration
194+ const validation = validateProcessorConfig (config );
195+ if (! validation .isValid ) {
196+ this .results .push ({
197+ originalText: ' N/A - Configuration Error' ,
198+ status: ' error' ,
199+ message: validation .errorMessage || ' Invalid processor configuration' ,
200+ });
201+ this .processing = false ;
202+ return ;
274203 }
275204
276- if (this .results .length === 0 && cardStrings .length > 0 && cardStrings .every ((s ) => ! s .trim ())) {
277- // This case handles if bulkText only contained delimiters or whitespace
205+ // Process the cards
206+ try {
207+ this .results = await processBulkCards (this .bulkText , this .courseDB , config );
208+ } catch (error ) {
209+ console .error (' [BulkImportView] Error processing cards:' , error );
278210 this .results .push ({
279211 originalText: this .bulkText ,
280212 status: ' error' ,
281- message: ' No valid card data found. Please check your input and delimiters. ' ,
213+ message: ` Error processing cards: ${ error instanceof Error ? error . message : ' Unknown error ' } ` ,
282214 });
283215 }
284216
0 commit comments