canvaslms-cli 1.6.2 → 1.6.4-fix

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 (80) hide show
  1. package/CHANGELOG.md +64 -31
  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/calendar.d.ts +7 -0
  16. package/dist/commands/calendar.d.ts.map +1 -0
  17. package/dist/commands/calendar.js +150 -0
  18. package/dist/commands/calendar.js.map +1 -0
  19. package/dist/commands/config.d.ts.map +1 -1
  20. package/dist/commands/config.js +102 -85
  21. package/dist/commands/config.js.map +1 -1
  22. package/dist/commands/grades.d.ts +2 -2
  23. package/dist/commands/grades.d.ts.map +1 -1
  24. package/dist/commands/grades.js +296 -176
  25. package/dist/commands/grades.js.map +1 -1
  26. package/dist/commands/list.d.ts +1 -1
  27. package/dist/commands/list.d.ts.map +1 -1
  28. package/dist/commands/list.js +21 -19
  29. package/dist/commands/list.js.map +1 -1
  30. package/dist/commands/modules.d.ts +5 -0
  31. package/dist/commands/modules.d.ts.map +1 -0
  32. package/dist/commands/modules.js +263 -0
  33. package/dist/commands/modules.js.map +1 -0
  34. package/dist/commands/profile.d.ts.map +1 -1
  35. package/dist/commands/profile.js +57 -32
  36. package/dist/commands/profile.js.map +1 -1
  37. package/dist/commands/submit.d.ts +1 -2
  38. package/dist/commands/submit.d.ts.map +1 -1
  39. package/dist/commands/submit.js +88 -79
  40. package/dist/commands/submit.js.map +1 -1
  41. package/dist/index.d.ts +16 -14
  42. package/dist/index.d.ts.map +1 -1
  43. package/dist/index.js +16 -14
  44. package/dist/index.js.map +1 -1
  45. package/dist/lib/api-client.d.ts +3 -0
  46. package/dist/lib/api-client.d.ts.map +1 -1
  47. package/dist/lib/api-client.js +31 -16
  48. package/dist/lib/api-client.js.map +1 -1
  49. package/dist/lib/config-validator.d.ts.map +1 -1
  50. package/dist/lib/config-validator.js +12 -12
  51. package/dist/lib/config-validator.js.map +1 -1
  52. package/dist/lib/config.d.ts +1 -1
  53. package/dist/lib/config.d.ts.map +1 -1
  54. package/dist/lib/config.js +16 -14
  55. package/dist/lib/config.js.map +1 -1
  56. package/dist/lib/display.d.ts +10 -4
  57. package/dist/lib/display.d.ts.map +1 -1
  58. package/dist/lib/display.js +263 -167
  59. package/dist/lib/display.js.map +1 -1
  60. package/dist/lib/file-upload.d.ts.map +1 -1
  61. package/dist/lib/file-upload.js +17 -17
  62. package/dist/lib/file-upload.js.map +1 -1
  63. package/dist/lib/interactive.d.ts +1 -1
  64. package/dist/lib/interactive.d.ts.map +1 -1
  65. package/dist/lib/interactive.js +196 -144
  66. package/dist/lib/interactive.js.map +1 -1
  67. package/dist/src/index.d.ts +0 -1
  68. package/dist/src/index.js +83 -63
  69. package/dist/src/index.js.map +1 -1
  70. package/dist/types/index.d.ts +34 -1
  71. package/dist/types/index.d.ts.map +1 -1
  72. package/package.json +10 -3
  73. package/dist/commands/coursenames.d.ts +0 -15
  74. package/dist/commands/coursenames.d.ts.map +0 -1
  75. package/dist/commands/coursenames.js +0 -150
  76. package/dist/commands/coursenames.js.map +0 -1
  77. package/dist/lib/course-utils.d.ts +0 -6
  78. package/dist/lib/course-utils.d.ts.map +0 -1
  79. package/dist/lib/course-utils.js +0 -17
  80. 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,56 +330,64 @@ 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
+ {
351
+ key: "name",
352
+ header: "Assignment Name",
353
+ flex: 1,
354
+ minWidth: 15,
355
+ maxWidth: 35,
356
+ },
269
357
  ];
270
358
  if (options.showId) {
271
- columns.push({ key: 'id', header: 'ID', minWidth: 7, maxWidth: 10 });
359
+ columns.push({ key: "id", header: "ID", width: 8 });
272
360
  }
273
361
  if (options.showGrade) {
274
362
  columns.push({
275
- key: 'grade',
276
- header: 'Grade',
277
- minWidth: 8,
278
- maxWidth: 12,
363
+ key: "grade",
364
+ header: "Grade",
365
+ width: 10,
279
366
  color: (value, row) => {
280
367
  const gradeInfo = formatGrade(row._submission, row._pointsPossible);
281
368
  return gradeInfo.color(value);
282
- }
369
+ },
283
370
  });
284
371
  }
285
372
  if (options.showDueDate) {
286
- columns.push({ key: 'dueDate', header: 'Due Date', minWidth: 14, maxWidth: 22 });
373
+ columns.push({
374
+ key: "dueDate",
375
+ header: "Due Date",
376
+ width: 16,
377
+ });
287
378
  }
288
379
  if (options.showStatus) {
289
380
  columns.push({
290
- key: 'status',
291
- header: 'Status',
292
- minWidth: 10,
293
- maxWidth: 14,
381
+ key: "status",
382
+ header: "Status",
383
+ width: 12,
294
384
  color: (value, row) => {
295
385
  return row._isSubmitted ? chalk.green(value) : chalk.yellow(value);
296
- }
386
+ },
297
387
  });
298
388
  }
299
389
  const table = new Table(columns);
300
- assignments.forEach(assignment => {
390
+ assignments.forEach((assignment) => {
301
391
  const submission = assignment.submission;
302
392
  const gradeInfo = formatGrade(submission, assignment.points_possible || 0);
303
393
  const isSubmitted = !!(submission && submission.submitted_at);
@@ -306,75 +396,79 @@ export function displayAssignments(assignments, options = {}) {
306
396
  id: assignment.id,
307
397
  grade: gradeInfo.text,
308
398
  dueDate: formatDueDate(assignment.due_at),
309
- status: isSubmitted ? '✓ Submitted' : 'Not submitted',
399
+ status: isSubmitted ? "✓ Submitted" : "Not submit",
310
400
  _submission: submission,
311
401
  _pointsPossible: assignment.points_possible || 0,
312
- _isSubmitted: isSubmitted
402
+ _isSubmitted: isSubmitted,
313
403
  });
314
404
  });
315
405
  table.render();
316
406
  }
317
407
  function getAssignmentType(assignment) {
318
- if (!assignment.submission_types || assignment.submission_types.length === 0) {
319
- return 'Unknown';
408
+ if (!assignment.submission_types ||
409
+ assignment.submission_types.length === 0) {
410
+ return "Unknown";
320
411
  }
321
412
  const types = assignment.submission_types;
322
- if (types.includes('online_quiz')) {
323
- return 'Quiz';
413
+ if (types.includes("online_quiz")) {
414
+ return "Quiz";
324
415
  }
325
- else if (types.includes('online_upload')) {
326
- if (assignment.allowed_extensions && assignment.allowed_extensions.length > 0) {
416
+ else if (types.includes("online_upload")) {
417
+ if (assignment.allowed_extensions &&
418
+ assignment.allowed_extensions.length > 0) {
327
419
  const exts = assignment.allowed_extensions.slice(0, 3);
328
- const extList = exts.join(', ');
329
- const suffix = assignment.allowed_extensions.length > 3 ? '...' : '';
420
+ const extList = exts.join(", ");
421
+ const suffix = assignment.allowed_extensions.length > 3 ? "..." : "";
330
422
  return `${extList}${suffix}`;
331
423
  }
332
- return 'Any file';
424
+ return "Any file";
333
425
  }
334
- else if (types.includes('online_text_entry')) {
335
- return 'Text Entry';
426
+ else if (types.includes("online_text_entry")) {
427
+ return "Text Entry";
336
428
  }
337
- else if (types.includes('online_url')) {
338
- return 'URL';
429
+ else if (types.includes("online_url")) {
430
+ return "URL";
339
431
  }
340
- else if (types.includes('external_tool')) {
341
- return 'External Tool';
432
+ else if (types.includes("external_tool")) {
433
+ return "External Tool";
342
434
  }
343
- else if (types.includes('media_recording')) {
344
- return 'Media';
435
+ else if (types.includes("media_recording")) {
436
+ return "Media";
345
437
  }
346
438
  else if (types[0]) {
347
- return types[0].replace(/_/g, ' ');
439
+ return types[0].replace(/_/g, " ");
348
440
  }
349
- return 'Unknown';
441
+ return "Unknown";
350
442
  }
351
443
  export function displaySubmitAssignments(assignments) {
352
444
  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 },
445
+ { key: "name", header: "Assignment Name", flex: 1, minWidth: 15 },
446
+ { key: "type", header: "Type", width: 8 },
447
+ { key: "dueDate", header: "Due", width: 10 },
356
448
  {
357
- key: 'status',
358
- header: 'Status',
359
- minWidth: 10,
360
- maxWidth: 14,
449
+ key: "status",
450
+ header: "Status",
451
+ width: 10,
361
452
  color: (value, row) => {
362
453
  return row._isSubmitted ? chalk.green(value) : chalk.yellow(value);
363
- }
364
- }
454
+ },
455
+ },
365
456
  ];
366
457
  const table = new Table(columns);
367
- assignments.forEach(assignment => {
458
+ assignments.forEach((assignment) => {
368
459
  const submission = assignment.submission;
369
460
  const isSubmitted = !!(submission && submission.submitted_at);
461
+ let dueDate = "No due date";
462
+ if (assignment.due_at) {
463
+ const d = new Date(assignment.due_at);
464
+ dueDate = `${(d.getMonth() + 1).toString().padStart(2, "0")}/${d.getDate().toString().padStart(2, "0")}/${d.getFullYear()}`;
465
+ }
370
466
  table.addRow({
371
467
  name: assignment.name,
372
468
  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
469
+ dueDate: dueDate,
470
+ status: isSubmitted ? "✓ Submitted" : "Not submit",
471
+ _isSubmitted: isSubmitted,
378
472
  });
379
473
  });
380
474
  table.renderWithResize();
@@ -382,30 +476,30 @@ export function displaySubmitAssignments(assignments) {
382
476
  }
383
477
  export function displayAnnouncements(announcements) {
384
478
  const columns = [
385
- { key: 'title', header: 'Title', flex: 1, minWidth: 15 },
386
- { key: 'posted', header: 'Posted', width: 10 }
479
+ { key: "title", header: "Title", flex: 1, minWidth: 15 },
480
+ { key: "posted", header: "Posted", width: 10 },
387
481
  ];
388
482
  const table = new Table(columns);
389
- announcements.forEach(announcement => {
483
+ announcements.forEach((announcement) => {
390
484
  const date = announcement.posted_at
391
485
  ? new Date(announcement.posted_at).toLocaleDateString()
392
- : 'N/A';
486
+ : "N/A";
393
487
  table.addRow({
394
- title: announcement.title || 'Untitled',
395
- posted: date
488
+ title: announcement.title || "Untitled",
489
+ posted: date,
396
490
  });
397
491
  });
398
492
  table.renderWithResize();
399
493
  return table;
400
494
  }
401
- export function printSeparator(char = '', length) {
402
- const width = length || (process.stdout.columns || 60);
495
+ export function printSeparator(char = "", length) {
496
+ const width = length || process.stdout.columns || 60;
403
497
  console.log(chalk.cyan.bold(char.repeat(width)));
404
498
  }
405
499
  export function printHeader(title) {
406
- console.log(chalk.cyan.bold('\n' + ''.repeat(60)));
500
+ console.log(chalk.cyan.bold("\n" + "".repeat(60)));
407
501
  console.log(chalk.cyan.bold(title));
408
- console.log(chalk.cyan.bold(''.repeat(60)));
502
+ console.log(chalk.cyan.bold("".repeat(60)));
409
503
  }
410
504
  export function printSuccess(message) {
411
505
  console.log(chalk.green(`✓ ${message}`));
@@ -420,40 +514,40 @@ export function printWarning(message) {
420
514
  console.log(chalk.yellow(message));
421
515
  }
422
516
  function cleanHtmlContent(html) {
423
- return html
424
- .replace(/&nbsp;/g, ' ')
425
- .replace(/&amp;/g, '&')
426
- .replace(/&lt;/g, '<')
427
- .replace(/&gt;/g, '>')
517
+ return (html
518
+ .replace(/&nbsp;/g, " ")
519
+ .replace(/&amp;/g, "&")
520
+ .replace(/&lt;/g, "<")
521
+ .replace(/&gt;/g, ">")
428
522
  .replace(/&quot;/g, '"')
429
523
  .replace(/&#39;/g, "'")
430
524
  .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();
525
+ .replace(/<br\s*\/?>/gi, "\n")
526
+ .replace(/<\/(p|div|li|h[1-6])>/gi, "\n")
527
+ .replace(/<li[^>]*>/gi, "")
528
+ .replace(/<[^>]+>/g, "")
529
+ .replace(/\n{3,}/g, "\n\n")
530
+ .replace(/[ \t]+/g, " ")
531
+ .split("\n")
532
+ .map((line) => line.trim())
533
+ .join("\n")
534
+ .trim());
441
535
  }
442
536
  function wordWrap(text, maxWidth) {
443
537
  const lines = [];
444
- const paragraphs = text.split('\n');
538
+ const paragraphs = text.split("\n");
445
539
  for (const paragraph of paragraphs) {
446
- if (paragraph.trim() === '') {
447
- lines.push('');
540
+ if (paragraph.trim() === "") {
541
+ lines.push("");
448
542
  continue;
449
543
  }
450
- const words = paragraph.split(' ').filter(w => w.length > 0);
451
- let currentLine = '';
544
+ const words = paragraph.split(" ").filter((w) => w.length > 0);
545
+ let currentLine = "";
452
546
  for (const word of words) {
453
547
  if (word.length > maxWidth) {
454
548
  if (currentLine) {
455
549
  lines.push(currentLine);
456
- currentLine = '';
550
+ currentLine = "";
457
551
  }
458
552
  for (let i = 0; i < word.length; i += maxWidth) {
459
553
  lines.push(word.substring(i, i + maxWidth));
@@ -481,27 +575,29 @@ export function displayAnnouncementDetail(announcement) {
481
575
  const terminalWidth = process.stdout.columns || 80;
482
576
  const boxWidth = Math.max(50, terminalWidth - 4);
483
577
  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');
578
+ const title = announcement.title || "Untitled";
579
+ const date = announcement.postedAt
580
+ ? new Date(announcement.postedAt).toLocaleString()
581
+ : "N/A";
582
+ const author = announcement.author || "Unknown";
583
+ const cleanedMessage = cleanHtmlContent(announcement.message || "No content");
488
584
  const titleLines = wordWrap(title, contentWidth);
489
585
  const messageLines = wordWrap(cleanedMessage, contentWidth);
490
586
  const printLine = (content, style = chalk.white) => {
491
587
  const paddedContent = content.padEnd(contentWidth);
492
- console.log(chalk.gray('') + style(paddedContent) + chalk.gray(''));
588
+ console.log(chalk.gray("") + style(paddedContent) + chalk.gray(""));
493
589
  };
494
- console.log('\n' + chalk.gray('' + ''.repeat(boxWidth - 2) + ''));
590
+ console.log("\n" + chalk.gray("" + "".repeat(boxWidth - 2) + ""));
495
591
  for (const line of titleLines) {
496
592
  printLine(line, chalk.bold.white);
497
593
  }
498
- console.log(chalk.gray('' + ''.repeat(boxWidth - 2) + ''));
594
+ console.log(chalk.gray("" + "".repeat(boxWidth - 2) + ""));
499
595
  printLine(`Posted: ${date}`, chalk.gray);
500
596
  printLine(`Author: ${author}`, chalk.gray);
501
- console.log(chalk.gray('' + ''.repeat(boxWidth - 2) + ''));
597
+ console.log(chalk.gray("" + "".repeat(boxWidth - 2) + ""));
502
598
  for (const line of messageLines) {
503
599
  printLine(line, chalk.white);
504
600
  }
505
- console.log(chalk.gray('' + ''.repeat(boxWidth - 2) + '') + '\n');
601
+ console.log(chalk.gray("" + "".repeat(boxWidth - 2) + "") + "\n");
506
602
  }
507
603
  //# sourceMappingURL=display.js.map