canvaslms-cli 1.6.2 → 1.6.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/CHANGELOG.md +221 -195
  2. package/README.md +131 -129
  3. package/dist/commands/announcements.d.ts +2 -2
  4. package/dist/commands/announcements.d.ts.map +1 -1
  5. package/dist/commands/announcements.js +29 -20
  6. package/dist/commands/announcements.js.map +1 -1
  7. package/dist/commands/api.d.ts +1 -1
  8. package/dist/commands/api.d.ts.map +1 -1
  9. package/dist/commands/api.js +1 -1
  10. package/dist/commands/api.js.map +1 -1
  11. package/dist/commands/assignments.d.ts +2 -2
  12. package/dist/commands/assignments.d.ts.map +1 -1
  13. package/dist/commands/assignments.js +24 -19
  14. package/dist/commands/assignments.js.map +1 -1
  15. package/dist/commands/config.d.ts.map +1 -1
  16. package/dist/commands/config.js +102 -85
  17. package/dist/commands/config.js.map +1 -1
  18. package/dist/commands/grades.d.ts +2 -2
  19. package/dist/commands/grades.d.ts.map +1 -1
  20. package/dist/commands/grades.js +183 -228
  21. package/dist/commands/grades.js.map +1 -1
  22. package/dist/commands/list.d.ts +1 -1
  23. package/dist/commands/list.d.ts.map +1 -1
  24. package/dist/commands/list.js +22 -20
  25. package/dist/commands/list.js.map +1 -1
  26. package/dist/commands/profile.d.ts.map +1 -1
  27. package/dist/commands/profile.js +57 -32
  28. package/dist/commands/profile.js.map +1 -1
  29. package/dist/commands/submit.d.ts +1 -2
  30. package/dist/commands/submit.d.ts.map +1 -1
  31. package/dist/commands/submit.js +88 -79
  32. package/dist/commands/submit.js.map +1 -1
  33. package/dist/index.d.ts +14 -14
  34. package/dist/index.js +14 -14
  35. package/dist/lib/api-client.d.ts +3 -0
  36. package/dist/lib/api-client.d.ts.map +1 -1
  37. package/dist/lib/api-client.js +31 -16
  38. package/dist/lib/api-client.js.map +1 -1
  39. package/dist/lib/config-validator.d.ts.map +1 -1
  40. package/dist/lib/config-validator.js +12 -12
  41. package/dist/lib/config-validator.js.map +1 -1
  42. package/dist/lib/config.d.ts +1 -1
  43. package/dist/lib/config.d.ts.map +1 -1
  44. package/dist/lib/config.js +16 -14
  45. package/dist/lib/config.js.map +1 -1
  46. package/dist/lib/display.d.ts +11 -5
  47. package/dist/lib/display.d.ts.map +1 -1
  48. package/dist/lib/display.js +261 -169
  49. package/dist/lib/display.js.map +1 -1
  50. package/dist/lib/file-upload.d.ts.map +1 -1
  51. package/dist/lib/file-upload.js +17 -17
  52. package/dist/lib/file-upload.js.map +1 -1
  53. package/dist/lib/interactive.d.ts +1 -1
  54. package/dist/lib/interactive.d.ts.map +1 -1
  55. package/dist/lib/interactive.js +194 -144
  56. package/dist/lib/interactive.js.map +1 -1
  57. package/dist/src/index.d.ts +0 -1
  58. package/dist/src/index.js +62 -63
  59. package/dist/src/index.js.map +1 -1
  60. package/dist/types/index.d.ts +1 -1
  61. package/package.json +10 -3
  62. package/dist/commands/coursenames.d.ts +0 -15
  63. package/dist/commands/coursenames.d.ts.map +0 -1
  64. package/dist/commands/coursenames.js +0 -150
  65. package/dist/commands/coursenames.js.map +0 -1
  66. package/dist/lib/course-utils.d.ts +0 -6
  67. package/dist/lib/course-utils.d.ts.map +0 -1
  68. package/dist/lib/course-utils.js +0 -17
  69. package/dist/lib/course-utils.js.map +0 -1
@@ -1,53 +1,60 @@
1
- import chalk from 'chalk';
2
- import { makeCanvasRequest } from './api-client.js';
3
- import { createReadlineInterface, askQuestion } from './interactive.js';
4
- export function pad(str, len, align = 'left') {
1
+ import chalk from "chalk";
2
+ import { makeCanvasRequest } from "./api-client.js";
3
+ import { createReadlineInterface, askQuestion } from "./interactive.js";
4
+ export function pad(str, len, align = "left") {
5
5
  const strLen = stripAnsi(str).length;
6
6
  const padding = Math.max(0, len - strLen);
7
- if (align === 'right') {
8
- return ' '.repeat(padding) + str;
7
+ if (align === "right") {
8
+ return " ".repeat(padding) + str;
9
9
  }
10
- else if (align === 'center') {
10
+ else if (align === "center") {
11
11
  const leftPad = Math.floor(padding / 2);
12
12
  const rightPad = padding - leftPad;
13
- return ' '.repeat(leftPad) + str + ' '.repeat(rightPad);
13
+ return " ".repeat(leftPad) + str + " ".repeat(rightPad);
14
14
  }
15
- return str + ' '.repeat(padding);
15
+ return str + " ".repeat(padding);
16
16
  }
17
17
  function stripAnsi(str) {
18
- return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, '');
18
+ return str.replace(/\x1B\[[0-9;]*[a-zA-Z]/g, "");
19
19
  }
20
20
  export function truncate(str, maxLen) {
21
- if (str.length <= maxLen)
21
+ const visible = stripAnsi(str);
22
+ if (visible.length <= maxLen)
22
23
  return str;
23
- return str.substring(0, maxLen - 3) + '...';
24
+ if (maxLen <= 3)
25
+ return visible.substring(0, maxLen);
26
+ const truncatedVisible = visible.substring(0, Math.max(0, maxLen - 3)) + "...";
27
+ return truncatedVisible;
24
28
  }
25
29
  function calculateColumnWidths(columns, data, terminalWidth, showRowNumbers) {
26
- const borderOverhead = 2 + (columns.length * 3) + 1;
27
- const rowNumWidth = showRowNumbers ? Math.max(3, String(data.length).length + 1) : 0;
28
- const rowNumOverhead = showRowNumbers ? 3 : 0;
29
- const effectiveTermWidth = Math.max(60, Math.min(terminalWidth, 200));
30
- const availableWidth = effectiveTermWidth - borderOverhead - rowNumOverhead - rowNumWidth;
31
- const widths = [];
30
+ const numCols = columns.length;
31
+ const borderOverhead = 2 * numCols + 1;
32
+ const rowNumWidth = showRowNumbers
33
+ ? Math.max(3, String(data.length).length + 1)
34
+ : 0;
35
+ const rowNumOverhead = showRowNumbers ? 2 + rowNumWidth : 0;
36
+ const effectiveTermWidth = Math.min(terminalWidth, 240);
37
+ const availableWidth = Math.max(numCols * 4, effectiveTermWidth - borderOverhead - rowNumOverhead);
38
+ let widths = [];
32
39
  const contentWidths = [];
33
40
  let fixedWidthTotal = 0;
34
41
  let totalFlex = 0;
35
42
  columns.forEach((col, i) => {
36
- const headerLen = col.header.length;
37
- const maxContentLen = Math.max(headerLen, ...data.map(row => String(row[col.key] || '').length));
43
+ const headerLen = stripAnsi(col.header).length;
44
+ const maxContentLen = Math.max(headerLen, ...data.map((row) => stripAnsi(String(row[col.key] ?? "")).length));
38
45
  contentWidths[i] = maxContentLen;
39
46
  if (col.width) {
40
47
  widths[i] = col.width;
41
48
  fixedWidthTotal += col.width;
42
49
  }
43
50
  else if (col.flex) {
44
- const minW = col.minWidth || Math.min(headerLen, 8);
51
+ const minW = col.minWidth || 4;
45
52
  widths[i] = minW;
46
53
  fixedWidthTotal += minW;
47
54
  totalFlex += col.flex;
48
55
  }
49
56
  else {
50
- const minW = col.minWidth || Math.min(headerLen, 8);
57
+ const minW = col.minWidth || 4;
51
58
  const maxW = col.maxWidth || maxContentLen;
52
59
  widths[i] = Math.min(maxW, Math.max(minW, maxContentLen));
53
60
  fixedWidthTotal += widths[i];
@@ -58,18 +65,25 @@ function calculateColumnWidths(columns, data, terminalWidth, showRowNumbers) {
58
65
  columns.forEach((col, i) => {
59
66
  if (col.flex) {
60
67
  const extraWidth = Math.floor((remainingWidth * col.flex) / totalFlex);
61
- const maxW = col.maxWidth || contentWidths[i] || 50;
68
+ const maxW = col.maxWidth || 999;
62
69
  widths[i] = Math.min((widths[i] ?? 0) + extraWidth, maxW);
63
70
  }
64
71
  });
65
72
  }
66
73
  let totalWidth = widths.reduce((sum, w) => sum + (w ?? 0), 0);
67
- if (totalWidth > availableWidth) {
68
- const scale = availableWidth / totalWidth;
69
- columns.forEach((col, i) => {
70
- const minW = col.minWidth || 8;
71
- widths[i] = Math.max(minW, Math.floor((widths[i] ?? 0) * scale));
72
- });
74
+ while (totalWidth > availableWidth && totalWidth > numCols * 4) {
75
+ let maxIdx = 0;
76
+ let maxW = widths[0] ?? 0;
77
+ for (let i = 1; i < widths.length; i++) {
78
+ if ((widths[i] ?? 0) > maxW) {
79
+ maxW = widths[i] ?? 0;
80
+ maxIdx = i;
81
+ }
82
+ }
83
+ if (maxW <= 4)
84
+ break;
85
+ widths[maxIdx] = Math.max(4, maxW - 1);
86
+ totalWidth--;
73
87
  }
74
88
  return widths;
75
89
  }
@@ -78,13 +92,17 @@ export class Table {
78
92
  data;
79
93
  options;
80
94
  rowNumWidth = 0;
95
+ lastLineCount = 0;
96
+ lastTableWidth = 0;
97
+ resizeHandler = null;
98
+ isWatching = false;
81
99
  constructor(columns, options = {}) {
82
100
  this.columns = columns;
83
101
  this.data = [];
84
102
  this.options = {
85
103
  showRowNumbers: true,
86
- rowNumberHeader: '#',
87
- ...options
104
+ rowNumberHeader: "#",
105
+ ...options,
88
106
  };
89
107
  }
90
108
  addRow(row) {
@@ -100,8 +118,38 @@ export class Table {
100
118
  }
101
119
  renderWithResize() {
102
120
  this.renderTable();
121
+ this.startWatching();
122
+ }
123
+ startWatching() {
124
+ if (this.isWatching || !process.stdout.isTTY)
125
+ return;
126
+ this.resizeHandler = () => {
127
+ this.clearTable();
128
+ this.renderTable();
129
+ };
130
+ process.stdout.on("resize", this.resizeHandler);
131
+ this.isWatching = true;
103
132
  }
104
133
  stopWatching() {
134
+ if (!this.isWatching || !this.resizeHandler)
135
+ return;
136
+ process.stdout.removeListener("resize", this.resizeHandler);
137
+ this.resizeHandler = null;
138
+ this.isWatching = false;
139
+ }
140
+ clearTable() {
141
+ if (this.lastLineCount <= 0)
142
+ return;
143
+ const maxPossibleWraps = Math.ceil(this.lastTableWidth / 20);
144
+ const worstCaseLines = this.lastLineCount * Math.max(maxPossibleWraps, 3);
145
+ const linesToClear = Math.max(worstCaseLines, 60);
146
+ process.stdout.write("\x1b[2K");
147
+ for (let i = 0; i < linesToClear; i++) {
148
+ process.stdout.write("\x1b[1A");
149
+ process.stdout.write("\x1b[2K");
150
+ }
151
+ process.stdout.write("\x1b[G");
152
+ process.stdout.write("\x1b[0J");
105
153
  }
106
154
  renderTable() {
107
155
  const terminalWidth = process.stdout.columns || 100;
@@ -109,50 +157,78 @@ export class Table {
109
157
  if (this.options.showRowNumbers) {
110
158
  this.rowNumWidth = Math.max(3, String(this.data.length).length + 1);
111
159
  }
160
+ const numCols = this.columns.length;
161
+ const borderWidth = 2 * numCols + 1;
162
+ const rowNumExtra = this.options.showRowNumbers ? 2 + this.rowNumWidth : 0;
163
+ const tableWidth = widths.reduce((a, b) => a + b, 0) + borderWidth + rowNumExtra;
164
+ this.lastTableWidth = tableWidth;
165
+ const linesPerRow = Math.max(1, Math.ceil(tableWidth / terminalWidth));
166
+ let lineCount = 0;
112
167
  if (this.options.title) {
113
168
  console.log(chalk.cyan.bold(`\n${this.options.title}`));
169
+ lineCount += 2;
114
170
  }
115
171
  this.renderTopBorder(widths);
172
+ lineCount += linesPerRow;
116
173
  this.renderHeader(widths);
174
+ lineCount += linesPerRow;
117
175
  this.renderHeaderSeparator(widths);
118
- this.data.forEach((row, index) => this.renderRow(row, index, widths));
176
+ lineCount += linesPerRow;
177
+ this.data.forEach((row, index) => {
178
+ this.renderRow(row, index, widths);
179
+ lineCount += linesPerRow;
180
+ });
119
181
  this.renderBottomBorder(widths);
182
+ lineCount += linesPerRow;
183
+ this.lastLineCount = lineCount;
120
184
  }
121
185
  renderTopBorder(widths) {
122
- let border = chalk.gray('╭─');
186
+ let border = chalk.gray("╭─");
123
187
  if (this.options.showRowNumbers) {
124
- border += chalk.gray(''.repeat(this.rowNumWidth)) + chalk.gray('┬─');
188
+ border += chalk.gray("".repeat(this.rowNumWidth)) + chalk.gray("┬─");
125
189
  }
126
- border += widths.map(w => chalk.gray('─'.repeat(w))).join(chalk.gray('┬─'));
127
- border += chalk.gray('╮');
190
+ border += widths
191
+ .map((w) => chalk.gray("─".repeat(w)))
192
+ .join(chalk.gray("┬─"));
193
+ border += chalk.gray("╮");
128
194
  console.log(border);
129
195
  }
130
196
  renderHeader(widths) {
131
- let header = chalk.gray('');
197
+ let header = chalk.gray("");
132
198
  if (this.options.showRowNumbers) {
133
- header += chalk.cyan.bold(pad(this.options.rowNumberHeader, this.rowNumWidth)) + chalk.gray('│ ');
199
+ header +=
200
+ chalk.cyan.bold(pad(truncate(this.options.rowNumberHeader, this.rowNumWidth), this.rowNumWidth)) + chalk.gray("│ ");
134
201
  }
135
- header += this.columns.map((col, i) => chalk.cyan.bold(pad(col.header, widths[i] || 10, col.align))).join(chalk.gray('│ '));
136
- header += chalk.gray('│');
202
+ header += this.columns
203
+ .map((col, i) => {
204
+ const colWidth = widths[i] || 10;
205
+ return chalk.cyan.bold(pad(truncate(col.header, colWidth), colWidth, col.align));
206
+ })
207
+ .join(chalk.gray("│ "));
208
+ header += chalk.gray("│");
137
209
  console.log(header);
138
210
  }
139
211
  renderHeaderSeparator(widths) {
140
- let separator = chalk.gray('├─');
212
+ let separator = chalk.gray("├─");
141
213
  if (this.options.showRowNumbers) {
142
- separator += chalk.gray(''.repeat(this.rowNumWidth)) + chalk.gray('┼─');
214
+ separator += chalk.gray("".repeat(this.rowNumWidth)) + chalk.gray("┼─");
143
215
  }
144
- separator += widths.map(w => chalk.gray('─'.repeat(w))).join(chalk.gray('┼─'));
145
- separator += chalk.gray('┤');
216
+ separator += widths
217
+ .map((w) => chalk.gray("─".repeat(w)))
218
+ .join(chalk.gray("┼─"));
219
+ separator += chalk.gray("┤");
146
220
  console.log(separator);
147
221
  }
148
222
  renderRow(row, index, widths) {
149
- let rowStr = chalk.gray('');
223
+ let rowStr = chalk.gray("");
150
224
  if (this.options.showRowNumbers) {
151
- rowStr += chalk.white(pad(`${index + 1}.`, this.rowNumWidth)) + chalk.gray('│ ');
225
+ rowStr +=
226
+ chalk.white(pad(`${index + 1}.`, this.rowNumWidth)) + chalk.gray("│ ");
152
227
  }
153
- rowStr += this.columns.map((col, i) => {
228
+ rowStr += this.columns
229
+ .map((col, i) => {
154
230
  const colWidth = widths[i] || 10;
155
- let value = String(row[col.key] ?? '');
231
+ let value = String(row[col.key] ?? "");
156
232
  value = truncate(value, colWidth);
157
233
  value = pad(value, colWidth, col.align);
158
234
  if (col.color) {
@@ -162,70 +238,72 @@ export class Table {
162
238
  value = chalk.white(value);
163
239
  }
164
240
  return value;
165
- }).join(chalk.gray('│ '));
166
- rowStr += chalk.gray('');
241
+ })
242
+ .join(chalk.gray(" "));
243
+ rowStr += chalk.gray("│");
167
244
  console.log(rowStr);
168
245
  }
169
246
  renderBottomBorder(widths) {
170
- let border = chalk.gray('╰─');
247
+ let border = chalk.gray("╰─");
171
248
  if (this.options.showRowNumbers) {
172
- border += chalk.gray(''.repeat(this.rowNumWidth)) + chalk.gray('┴─');
249
+ border += chalk.gray("".repeat(this.rowNumWidth)) + chalk.gray("┴─");
173
250
  }
174
- border += widths.map(w => chalk.gray('─'.repeat(w))).join(chalk.gray('┴─'));
175
- border += chalk.gray('╯');
251
+ border += widths
252
+ .map((w) => chalk.gray("─".repeat(w)))
253
+ .join(chalk.gray("┴─"));
254
+ border += chalk.gray("╯");
176
255
  console.log(border);
177
256
  }
178
257
  }
179
258
  export function displayCourses(courses, options = {}) {
180
259
  const columns = [
181
- { key: 'name', header: 'Course Name', flex: 1, minWidth: 15 }
260
+ { key: "name", header: "Course Name", flex: 1, minWidth: 15 },
182
261
  ];
183
262
  if (options.showId) {
184
- columns.push({ key: 'id', header: 'ID', minWidth: 5, maxWidth: 10 });
263
+ columns.push({ key: "id", header: "ID", minWidth: 5, maxWidth: 10 });
185
264
  }
186
265
  const table = new Table(columns);
187
- courses.forEach(course => {
266
+ courses.forEach((course) => {
188
267
  table.addRow({ name: course.name, id: course.id });
189
268
  });
190
269
  table.render();
191
270
  }
192
271
  export async function pickCourse(options = {}) {
193
272
  const rl = createReadlineInterface();
194
- console.log(chalk.cyan.bold(options.title || '\nLoading your courses, please wait...'));
195
- const queryParams = [
196
- 'enrollment_state=active',
197
- 'include[]=favorites'
198
- ];
199
- const courses = await makeCanvasRequest('get', 'courses', queryParams);
273
+ console.log(chalk.cyan.bold(options.title || "\nLoading your courses, please wait..."));
274
+ const queryParams = ["enrollment_state=active", "include[]=favorites"];
275
+ const courses = await makeCanvasRequest("get", "courses", queryParams);
200
276
  if (!courses || courses.length === 0) {
201
- console.log(chalk.red('Error: No courses found.'));
277
+ console.log(chalk.red("Error: No courses found."));
202
278
  rl.close();
203
279
  return null;
204
280
  }
205
281
  let displayCourses = courses;
206
282
  if (!options.showAll) {
207
- const starred = courses.filter(c => c.is_favorite);
283
+ const starred = courses.filter((c) => c.is_favorite);
208
284
  if (starred.length > 0) {
209
285
  displayCourses = starred;
210
286
  }
211
287
  }
212
288
  console.log(chalk.green(`✓ Found ${displayCourses.length} course(s).`));
213
289
  const table = new Table([
214
- { key: 'name', header: 'Course Name', flex: 1, minWidth: 15 }
290
+ { key: "name", header: "Course Name", flex: 1, minWidth: 15 },
215
291
  ]);
216
- displayCourses.forEach(course => table.addRow({ name: course.name }));
292
+ displayCourses.forEach((course) => table.addRow({ name: course.name }));
217
293
  table.renderWithResize();
218
- const prompt = options.prompt || chalk.bold.cyan('\nEnter course number: ');
294
+ const prompt = options.prompt || chalk.bold.cyan("\nEnter course number: ");
219
295
  const courseChoice = await askQuestion(rl, prompt);
220
296
  table.stopWatching();
221
- if (!courseChoice.trim() || courseChoice === '..' || courseChoice.toLowerCase() === 'back') {
222
- console.log(chalk.red('No course selected. Exiting...'));
297
+ if (!courseChoice.trim() ||
298
+ courseChoice === ".." ||
299
+ courseChoice.toLowerCase() === "back") {
300
+ console.log(chalk.red("No course selected. Exiting..."));
223
301
  rl.close();
224
302
  return null;
225
303
  }
226
304
  const courseIndex = parseInt(courseChoice) - 1;
227
305
  if (courseIndex < 0 || courseIndex >= displayCourses.length) {
228
- console.log(chalk.red('Invalid course selection.'));
306
+ console.log(chalk.red("Invalid course selection."));
229
307
  rl.close();
230
308
  return null;
231
309
  }
@@ -234,8 +312,12 @@ export async function pickCourse(options = {}) {
234
312
  return { course: selectedCourse, rl };
235
313
  }
236
314
  export function formatGrade(submission, pointsPossible) {
237
- if (submission && submission.score !== null && submission.score !== undefined) {
238
- const score = submission.score % 1 === 0 ? Math.round(submission.score) : submission.score;
315
+ if (submission &&
316
+ submission.score !== null &&
317
+ submission.score !== undefined) {
318
+ const score = submission.score % 1 === 0
319
+ ? Math.round(submission.score)
320
+ : submission.score;
239
321
  const text = `${score}/${pointsPossible}`;
240
322
  const percentage = pointsPossible > 0 ? (score / pointsPossible) * 100 : 0;
241
323
  let color = chalk.white;
@@ -248,133 +330,141 @@ export function formatGrade(submission, pointsPossible) {
248
330
  return { text, color };
249
331
  }
250
332
  else if (submission && submission.excused) {
251
- return { text: 'Excused', color: chalk.blue };
333
+ return { text: "Excused", color: chalk.blue };
252
334
  }
253
335
  else if (submission && submission.missing) {
254
- return { text: 'Missing', color: chalk.red };
336
+ return { text: "Missing", color: chalk.red };
255
337
  }
256
338
  else if (pointsPossible) {
257
339
  return { text: `–/${pointsPossible}`, color: chalk.gray };
258
340
  }
259
- return { text: 'N/A', color: chalk.gray };
341
+ return { text: "N/A", color: chalk.gray };
260
342
  }
261
343
  export function formatDueDate(dueAt) {
262
344
  if (!dueAt)
263
- return 'No due date';
345
+ return "No due date";
264
346
  return new Date(dueAt).toLocaleString();
265
347
  }
266
348
  export function displayAssignments(assignments, options = {}) {
267
349
  const columns = [
268
- { key: 'name', header: 'Assignment Name', flex: 1, minWidth: 15 }
350
+ { key: "name", header: "Assignment Name", flex: 1, minWidth: 15 },
269
351
  ];
270
352
  if (options.showId) {
271
- columns.push({ key: 'id', header: 'ID', minWidth: 7, maxWidth: 10 });
353
+ columns.push({ key: "id", header: "ID", width: 7 });
272
354
  }
273
355
  if (options.showGrade) {
274
356
  columns.push({
275
- key: 'grade',
276
- header: 'Grade',
277
- minWidth: 8,
278
- maxWidth: 12,
357
+ key: "grade",
358
+ header: "Grade",
359
+ width: 10,
279
360
  color: (value, row) => {
280
361
  const gradeInfo = formatGrade(row._submission, row._pointsPossible);
281
362
  return gradeInfo.color(value);
282
- }
363
+ },
283
364
  });
284
365
  }
285
366
  if (options.showDueDate) {
286
- columns.push({ key: 'dueDate', header: 'Due Date', minWidth: 14, maxWidth: 22 });
367
+ columns.push({ key: "dueDate", header: "Due", width: 10 });
287
368
  }
288
369
  if (options.showStatus) {
289
370
  columns.push({
290
- key: 'status',
291
- header: 'Status',
292
- minWidth: 10,
293
- maxWidth: 14,
371
+ key: "status",
372
+ header: "Status",
373
+ width: 10,
294
374
  color: (value, row) => {
295
375
  return row._isSubmitted ? chalk.green(value) : chalk.yellow(value);
296
- }
376
+ },
297
377
  });
298
378
  }
299
379
  const table = new Table(columns);
300
- assignments.forEach(assignment => {
380
+ assignments.forEach((assignment) => {
301
381
  const submission = assignment.submission;
302
382
  const gradeInfo = formatGrade(submission, assignment.points_possible || 0);
303
383
  const isSubmitted = !!(submission && submission.submitted_at);
384
+ let dueDate = "No due";
385
+ if (assignment.due_at) {
386
+ const d = new Date(assignment.due_at);
387
+ dueDate = `${(d.getMonth() + 1).toString().padStart(2, "0")}/${d.getDate().toString().padStart(2, "0")}/${d.getFullYear()}`;
388
+ }
304
389
  table.addRow({
305
390
  name: assignment.name,
306
391
  id: assignment.id,
307
392
  grade: gradeInfo.text,
308
- dueDate: formatDueDate(assignment.due_at),
309
- status: isSubmitted ? '✓ Submitted' : 'Not submitted',
393
+ dueDate: dueDate,
394
+ status: isSubmitted ? "✓ Submitted" : "Not submit",
310
395
  _submission: submission,
311
396
  _pointsPossible: assignment.points_possible || 0,
312
- _isSubmitted: isSubmitted
397
+ _isSubmitted: isSubmitted,
313
398
  });
314
399
  });
315
- table.render();
400
+ table.renderWithResize();
401
+ return table;
316
402
  }
317
403
  function getAssignmentType(assignment) {
318
- if (!assignment.submission_types || assignment.submission_types.length === 0) {
319
- return 'Unknown';
404
+ if (!assignment.submission_types ||
405
+ assignment.submission_types.length === 0) {
406
+ return "Unknown";
320
407
  }
321
408
  const types = assignment.submission_types;
322
- if (types.includes('online_quiz')) {
323
- return 'Quiz';
409
+ if (types.includes("online_quiz")) {
410
+ return "Quiz";
324
411
  }
325
- else if (types.includes('online_upload')) {
326
- if (assignment.allowed_extensions && assignment.allowed_extensions.length > 0) {
412
+ else if (types.includes("online_upload")) {
413
+ if (assignment.allowed_extensions &&
414
+ assignment.allowed_extensions.length > 0) {
327
415
  const exts = assignment.allowed_extensions.slice(0, 3);
328
- const extList = exts.join(', ');
329
- const suffix = assignment.allowed_extensions.length > 3 ? '...' : '';
416
+ const extList = exts.join(", ");
417
+ const suffix = assignment.allowed_extensions.length > 3 ? "..." : "";
330
418
  return `${extList}${suffix}`;
331
419
  }
332
- return 'Any file';
420
+ return "Any file";
333
421
  }
334
- else if (types.includes('online_text_entry')) {
335
- return 'Text Entry';
422
+ else if (types.includes("online_text_entry")) {
423
+ return "Text Entry";
336
424
  }
337
- else if (types.includes('online_url')) {
338
- return 'URL';
425
+ else if (types.includes("online_url")) {
426
+ return "URL";
339
427
  }
340
- else if (types.includes('external_tool')) {
341
- return 'External Tool';
428
+ else if (types.includes("external_tool")) {
429
+ return "External Tool";
342
430
  }
343
- else if (types.includes('media_recording')) {
344
- return 'Media';
431
+ else if (types.includes("media_recording")) {
432
+ return "Media";
345
433
  }
346
434
  else if (types[0]) {
347
- return types[0].replace(/_/g, ' ');
435
+ return types[0].replace(/_/g, " ");
348
436
  }
349
- return 'Unknown';
437
+ return "Unknown";
350
438
  }
351
439
  export function displaySubmitAssignments(assignments) {
352
440
  const columns = [
353
- { key: 'name', header: 'Assignment Name', flex: 1, minWidth: 20 },
354
- { key: 'type', header: 'Type', minWidth: 8, maxWidth: 18 },
355
- { key: 'dueDate', header: 'Due Date', minWidth: 16, maxWidth: 22 },
441
+ { key: "name", header: "Assignment Name", flex: 1, minWidth: 15 },
442
+ { key: "type", header: "Type", width: 8 },
443
+ { key: "dueDate", header: "Due", width: 10 },
356
444
  {
357
- key: 'status',
358
- header: 'Status',
359
- minWidth: 10,
360
- maxWidth: 14,
445
+ key: "status",
446
+ header: "Status",
447
+ width: 10,
361
448
  color: (value, row) => {
362
449
  return row._isSubmitted ? chalk.green(value) : chalk.yellow(value);
363
- }
364
- }
450
+ },
451
+ },
365
452
  ];
366
453
  const table = new Table(columns);
367
- assignments.forEach(assignment => {
454
+ assignments.forEach((assignment) => {
368
455
  const submission = assignment.submission;
369
456
  const isSubmitted = !!(submission && submission.submitted_at);
457
+ let dueDate = "No due date";
458
+ if (assignment.due_at) {
459
+ const d = new Date(assignment.due_at);
460
+ dueDate = `${(d.getMonth() + 1).toString().padStart(2, "0")}/${d.getDate().toString().padStart(2, "0")}/${d.getFullYear()}`;
461
+ }
370
462
  table.addRow({
371
463
  name: assignment.name,
372
464
  type: getAssignmentType(assignment),
373
- dueDate: assignment.due_at
374
- ? new Date(assignment.due_at).toLocaleString()
375
- : 'No due date',
376
- status: isSubmitted ? '✓ Submitted' : 'Not submitted',
377
- _isSubmitted: isSubmitted
465
+ dueDate: dueDate,
466
+ status: isSubmitted ? "✓ Submitted" : "Not submit",
467
+ _isSubmitted: isSubmitted,
378
468
  });
379
469
  });
380
470
  table.renderWithResize();
@@ -382,30 +472,30 @@ export function displaySubmitAssignments(assignments) {
382
472
  }
383
473
  export function displayAnnouncements(announcements) {
384
474
  const columns = [
385
- { key: 'title', header: 'Title', flex: 1, minWidth: 15 },
386
- { key: 'posted', header: 'Posted', width: 10 }
475
+ { key: "title", header: "Title", flex: 1, minWidth: 15 },
476
+ { key: "posted", header: "Posted", width: 10 },
387
477
  ];
388
478
  const table = new Table(columns);
389
- announcements.forEach(announcement => {
479
+ announcements.forEach((announcement) => {
390
480
  const date = announcement.posted_at
391
481
  ? new Date(announcement.posted_at).toLocaleDateString()
392
- : 'N/A';
482
+ : "N/A";
393
483
  table.addRow({
394
- title: announcement.title || 'Untitled',
395
- posted: date
484
+ title: announcement.title || "Untitled",
485
+ posted: date,
396
486
  });
397
487
  });
398
488
  table.renderWithResize();
399
489
  return table;
400
490
  }
401
- export function printSeparator(char = '', length) {
402
- const width = length || (process.stdout.columns || 60);
491
+ export function printSeparator(char = "", length) {
492
+ const width = length || process.stdout.columns || 60;
403
493
  console.log(chalk.cyan.bold(char.repeat(width)));
404
494
  }
405
495
  export function printHeader(title) {
406
- console.log(chalk.cyan.bold('\n' + ''.repeat(60)));
496
+ console.log(chalk.cyan.bold("\n" + "".repeat(60)));
407
497
  console.log(chalk.cyan.bold(title));
408
- console.log(chalk.cyan.bold(''.repeat(60)));
498
+ console.log(chalk.cyan.bold("".repeat(60)));
409
499
  }
410
500
  export function printSuccess(message) {
411
501
  console.log(chalk.green(`✓ ${message}`));
@@ -420,40 +510,40 @@ export function printWarning(message) {
420
510
  console.log(chalk.yellow(message));
421
511
  }
422
512
  function cleanHtmlContent(html) {
423
- return html
424
- .replace(/&nbsp;/g, ' ')
425
- .replace(/&amp;/g, '&')
426
- .replace(/&lt;/g, '<')
427
- .replace(/&gt;/g, '>')
513
+ return (html
514
+ .replace(/&nbsp;/g, " ")
515
+ .replace(/&amp;/g, "&")
516
+ .replace(/&lt;/g, "<")
517
+ .replace(/&gt;/g, ">")
428
518
  .replace(/&quot;/g, '"')
429
519
  .replace(/&#39;/g, "'")
430
520
  .replace(/&apos;/g, "'")
431
- .replace(/<br\s*\/?>/gi, '\n')
432
- .replace(/<\/(p|div|li|h[1-6])>/gi, '\n')
433
- .replace(/<li[^>]*>/gi, '')
434
- .replace(/<[^>]+>/g, '')
435
- .replace(/\n{3,}/g, '\n\n')
436
- .replace(/[ \t]+/g, ' ')
437
- .split('\n')
438
- .map(line => line.trim())
439
- .join('\n')
440
- .trim();
521
+ .replace(/<br\s*\/?>/gi, "\n")
522
+ .replace(/<\/(p|div|li|h[1-6])>/gi, "\n")
523
+ .replace(/<li[^>]*>/gi, "")
524
+ .replace(/<[^>]+>/g, "")
525
+ .replace(/\n{3,}/g, "\n\n")
526
+ .replace(/[ \t]+/g, " ")
527
+ .split("\n")
528
+ .map((line) => line.trim())
529
+ .join("\n")
530
+ .trim());
441
531
  }
442
532
  function wordWrap(text, maxWidth) {
443
533
  const lines = [];
444
- const paragraphs = text.split('\n');
534
+ const paragraphs = text.split("\n");
445
535
  for (const paragraph of paragraphs) {
446
- if (paragraph.trim() === '') {
447
- lines.push('');
536
+ if (paragraph.trim() === "") {
537
+ lines.push("");
448
538
  continue;
449
539
  }
450
- const words = paragraph.split(' ').filter(w => w.length > 0);
451
- let currentLine = '';
540
+ const words = paragraph.split(" ").filter((w) => w.length > 0);
541
+ let currentLine = "";
452
542
  for (const word of words) {
453
543
  if (word.length > maxWidth) {
454
544
  if (currentLine) {
455
545
  lines.push(currentLine);
456
- currentLine = '';
546
+ currentLine = "";
457
547
  }
458
548
  for (let i = 0; i < word.length; i += maxWidth) {
459
549
  lines.push(word.substring(i, i + maxWidth));
@@ -481,27 +571,29 @@ export function displayAnnouncementDetail(announcement) {
481
571
  const terminalWidth = process.stdout.columns || 80;
482
572
  const boxWidth = Math.max(50, terminalWidth - 4);
483
573
  const contentWidth = boxWidth - 4;
484
- const title = announcement.title || 'Untitled';
485
- const date = announcement.postedAt ? new Date(announcement.postedAt).toLocaleString() : 'N/A';
486
- const author = announcement.author || 'Unknown';
487
- const cleanedMessage = cleanHtmlContent(announcement.message || 'No content');
574
+ const title = announcement.title || "Untitled";
575
+ const date = announcement.postedAt
576
+ ? new Date(announcement.postedAt).toLocaleString()
577
+ : "N/A";
578
+ const author = announcement.author || "Unknown";
579
+ const cleanedMessage = cleanHtmlContent(announcement.message || "No content");
488
580
  const titleLines = wordWrap(title, contentWidth);
489
581
  const messageLines = wordWrap(cleanedMessage, contentWidth);
490
582
  const printLine = (content, style = chalk.white) => {
491
583
  const paddedContent = content.padEnd(contentWidth);
492
- console.log(chalk.gray('') + style(paddedContent) + chalk.gray(''));
584
+ console.log(chalk.gray("") + style(paddedContent) + chalk.gray(""));
493
585
  };
494
- console.log('\n' + chalk.gray('' + ''.repeat(boxWidth - 2) + ''));
586
+ console.log("\n" + chalk.gray("" + "".repeat(boxWidth - 2) + ""));
495
587
  for (const line of titleLines) {
496
588
  printLine(line, chalk.bold.white);
497
589
  }
498
- console.log(chalk.gray('' + ''.repeat(boxWidth - 2) + ''));
590
+ console.log(chalk.gray("" + "".repeat(boxWidth - 2) + ""));
499
591
  printLine(`Posted: ${date}`, chalk.gray);
500
592
  printLine(`Author: ${author}`, chalk.gray);
501
- console.log(chalk.gray('' + ''.repeat(boxWidth - 2) + ''));
593
+ console.log(chalk.gray("" + "".repeat(boxWidth - 2) + ""));
502
594
  for (const line of messageLines) {
503
595
  printLine(line, chalk.white);
504
596
  }
505
- console.log(chalk.gray('' + ''.repeat(boxWidth - 2) + '') + '\n');
597
+ console.log(chalk.gray("" + "".repeat(boxWidth - 2) + "") + "\n");
506
598
  }
507
599
  //# sourceMappingURL=display.js.map