From 246011e2924fafd3fb67da6446b89735b8e871df Mon Sep 17 00:00:00 2001 From: Leo Luong Date: Sun, 7 Aug 2022 13:16:15 +1000 Subject: [PATCH 0001/1280] new: create initial files for migration of unauthorized --- .../states/unauthorised/unauthorised.component.html | 0 .../states/unauthorised/unauthorised.component.scss | 0 .../states/unauthorised/unauthorised.component.ts | 10 ++++++++++ 3 files changed, 10 insertions(+) create mode 100644 src/app/errors/states/unauthorised/unauthorised.component.html create mode 100644 src/app/errors/states/unauthorised/unauthorised.component.scss create mode 100644 src/app/errors/states/unauthorised/unauthorised.component.ts diff --git a/src/app/errors/states/unauthorised/unauthorised.component.html b/src/app/errors/states/unauthorised/unauthorised.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/errors/states/unauthorised/unauthorised.component.scss b/src/app/errors/states/unauthorised/unauthorised.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/errors/states/unauthorised/unauthorised.component.ts b/src/app/errors/states/unauthorised/unauthorised.component.ts new file mode 100644 index 0000000000..60254f6f70 --- /dev/null +++ b/src/app/errors/states/unauthorised/unauthorised.component.ts @@ -0,0 +1,10 @@ +import { Component} from '@angular/core'; + +@Component({ + selector: 'unauthorised', + templateUrl: 'unauthorised.component.html', + styleUrls: ['unauthorised.component.scss'], +}) +export class UnauthorisedComponent { + constructor(){} +} \ No newline at end of file From 22611c632131b59b27374b11ace21c5ad4e0b7c3 Mon Sep 17 00:00:00 2001 From: Leo Luong Date: Sun, 7 Aug 2022 13:26:47 +1000 Subject: [PATCH 0002/1280] migrate:unlink old components --- src/app/doubtfire-angular.module.ts | 2 ++ src/app/doubtfire-angularjs.module.ts | 4 +++- src/app/doubtfire.states.ts | 24 ++++++++++++++++++- .../unauthorised/unauthorised.component.ts | 4 ++-- 4 files changed, 30 insertions(+), 4 deletions(-) diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index febb3b8164..33d494bb99 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -164,6 +164,7 @@ import { HeaderComponent } from './common/header/header.component'; import { UnitDropdownComponent } from './common/header/unit-dropdown/unit-dropdown.component'; import { TaskDropdownComponent } from './common/header/task-dropdown/task-dropdown.component'; import { SplashScreenComponent } from './home/splash-screen/splash-screen.component'; +import { UnauthorisedComponent } from './errors/states/unauthorised/unauthorised.component'; @NgModule({ // Components we declare @@ -221,6 +222,7 @@ import { SplashScreenComponent } from './home/splash-screen/splash-screen.compon UnitDropdownComponent, TaskDropdownComponent, SplashScreenComponent, + UnauthorisedComponent, ], // Module Imports imports: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index c8ec2ba1d8..8cc5001dfb 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -236,7 +236,6 @@ import 'build/src/app/api/models/unit.js'; import 'build/src/app/api/api.js'; import 'build/src/app/api/resource-plus.js'; import 'build/src/app/errors/errors.js'; -import 'build/src/app/errors/states/unauthorised/unauthorised.js'; import 'build/src/app/errors/states/not-found/not-found.js'; import 'build/src/app/errors/states/timeout/timeout.js'; import 'build/src/app/errors/states/states.js'; @@ -289,6 +288,7 @@ import { TaskAssessmentModalService } from './common/modals/task-assessment-moda import { TaskSubmissionHistoryComponent } from './tasks/task-submission-history/task-submission-history.component'; import { HeaderComponent } from './common/header/header.component'; import { GlobalStateService } from './projects/states/index/global-state.service'; +import { UnauthorisedComponent } from './errors/states/unauthorised/unauthorised.component'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -396,6 +396,8 @@ DoubtfireAngularJSModule.directive( downgradeComponent({ component: TaskPlagiarismCardComponent }) ); +DoubtfireAngularJSModule.directive('unauthorised', downgradeComponent({ component: UnauthorisedComponent })); + // Global configuration // If the user enters a URL that doesn't match any known URL (state), send them to `/home` diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index cb9b495500..b4859fac58 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -2,6 +2,7 @@ import { NgHybridStateDeclaration } from '@uirouter/angular-hybrid'; import { Ng2ViewDeclaration } from '@uirouter/angular'; import { InstitutionSettingsComponent } from './admin/institution-settings/institution-settings.component'; import { HomeComponent } from './home/states/home/home.component'; +import { UnauthorisedComponent } from './errors/states/unauthorised/unauthorised.component'; /* @@ -50,7 +51,28 @@ const institutionSettingsState: NgHybridStateDeclaration = { } }; +const UnauthoriedState: NgHybridStateDeclaration = { + name: 'unauthorised', + url: '/unauthorised', // You get here with this url + views: { + // These are the 2 views - the header and main from the body of DF + header: { + // Header is still angularjs + controller: 'BasicHeaderCtrl', // This is the angularjs controller + templateUrl: 'common/header/header.tpl.html', // and the related template html + } as unknown as Ng2ViewDeclaration, // Need dodgy cast to get compiler to ignore type data + main: { + // Main body links to angular component + component: UnauthorisedComponent, + }, + }, + data: { + // Add data used by header + pageTitle: 'Unauthorised', + roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin'], + }, +}; /** * Export the list of states we have created in angular */ -export const doubtfireStates = [institutionSettingsState, HomeState]; +export const doubtfireStates = [institutionSettingsState, HomeState, UnauthoriedState]; diff --git a/src/app/errors/states/unauthorised/unauthorised.component.ts b/src/app/errors/states/unauthorised/unauthorised.component.ts index 60254f6f70..a41aebb8cf 100644 --- a/src/app/errors/states/unauthorised/unauthorised.component.ts +++ b/src/app/errors/states/unauthorised/unauthorised.component.ts @@ -1,4 +1,4 @@ -import { Component} from '@angular/core'; +import { Component } from '@angular/core'; @Component({ selector: 'unauthorised', @@ -7,4 +7,4 @@ import { Component} from '@angular/core'; }) export class UnauthorisedComponent { constructor(){} -} \ No newline at end of file +} From a94db3d8838355dfa763c544fdbe978bc258b066 Mon Sep 17 00:00:00 2001 From: Leo Luong Date: Sun, 7 Aug 2022 13:27:32 +1000 Subject: [PATCH 0003/1280] migrate:unlink old components --- .../errors/states/unauthorised/unauthorised.component.html | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/errors/states/unauthorised/unauthorised.component.html b/src/app/errors/states/unauthorised/unauthorised.component.html index e69de29bb2..4f92fedc18 100644 --- a/src/app/errors/states/unauthorised/unauthorised.component.html +++ b/src/app/errors/states/unauthorised/unauthorised.component.html @@ -0,0 +1,7 @@ +
+
+ +

Unauthorised

+

You do not have sufficient permissions to access this resource, or your session has expired.

+
+
\ No newline at end of file From c269b04a3a1694cb2056313a0335f1d4f3e7f3be Mon Sep 17 00:00:00 2001 From: Leo Luong Date: Sun, 7 Aug 2022 13:30:22 +1000 Subject: [PATCH 0004/1280] migrate:unlink old components --- src/app/errors/states/states.coffee | 1 - 1 file changed, 1 deletion(-) diff --git a/src/app/errors/states/states.coffee b/src/app/errors/states/states.coffee index 84cdc11e25..ffcf5c77f7 100644 --- a/src/app/errors/states/states.coffee +++ b/src/app/errors/states/states.coffee @@ -1,5 +1,4 @@ angular.module("doubtfire.errors.states", [ "doubtfire.errors.states.not-found" "doubtfire.errors.states.timeout" - "doubtfire.errors.states.unauthorised" ]) From 275f4c01b255060acf2c4c76803133c7615b1b6a Mon Sep 17 00:00:00 2001 From: Leo Luong Date: Sun, 7 Aug 2022 13:31:57 +1000 Subject: [PATCH 0005/1280] migrate: adjust style --- .../errors/states/unauthorised/unauthorised.component.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/errors/states/unauthorised/unauthorised.component.html b/src/app/errors/states/unauthorised/unauthorised.component.html index 4f92fedc18..e5566606d5 100644 --- a/src/app/errors/states/unauthorised/unauthorised.component.html +++ b/src/app/errors/states/unauthorised/unauthorised.component.html @@ -1,6 +1,6 @@ -
-
- +
+
+

Unauthorised

You do not have sufficient permissions to access this resource, or your session has expired.

From 917a36b69fd3f90e9173a9fef6852507dea419bb Mon Sep 17 00:00:00 2001 From: Leo Luong Date: Sun, 7 Aug 2022 13:34:44 +1000 Subject: [PATCH 0006/1280] migrate: update unit test for unauthorised component --- .../unauthorised.component.spec.ts | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/app/errors/states/unauthorised/unauthorised.component.spec.ts diff --git a/src/app/errors/states/unauthorised/unauthorised.component.spec.ts b/src/app/errors/states/unauthorised/unauthorised.component.spec.ts new file mode 100644 index 0000000000..dcd275e0fd --- /dev/null +++ b/src/app/errors/states/unauthorised/unauthorised.component.spec.ts @@ -0,0 +1,24 @@ +import { ComponentFixture, TestBed } from '@angular/core/testing'; + +import { UnauthorisedComponent } from './unauthorised.component'; + +describe('UnauthorisedComponent', () => { + let component: UnauthorisedComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [UnauthorisedComponent], + }).compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(UnauthorisedComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); \ No newline at end of file From 427ec6e20d597307a7643bd3e70c922b088d2bde Mon Sep 17 00:00:00 2001 From: Anthony Papoutsis Date: Fri, 19 Aug 2022 19:00:45 +1000 Subject: [PATCH 0007/1280] build: create initial files for migration of unit-student-enrollment-modal --- ...it-student-enrollment-modal.component.html | 26 +++++++++++++++++++ ...it-student-enrollment-modal.component.scss | 0 ...unit-student-enrollment-modal.component.ts | 10 +++++++ .../unit-student-enrollment-modal.service.ts | 0 .../unit-student-enrollment-modal.spec.ts | 0 5 files changed, 36 insertions(+) create mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.html create mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.scss create mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.ts create mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.service.ts create mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.spec.ts diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.html b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.html new file mode 100644 index 0000000000..428daca3dd --- /dev/null +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.html @@ -0,0 +1,26 @@ +
+ + + +
diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.scss b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.ts new file mode 100644 index 0000000000..4b84e82634 --- /dev/null +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.ts @@ -0,0 +1,10 @@ +import { Component, Input, Inject } from '@angular/core'; + +@Component({ + selector: 'unit-student-enrollment-modal', + templateUrl: 'unit-student-enrollment-modal.component.html', + styleUrls: ['unit-student-enrollment-modal.component.scss'], +}) +export class UnitStudentEnrollmentModalComponent { + constructor() {} +} diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.service.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.service.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.spec.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.spec.ts new file mode 100644 index 0000000000..e69de29bb2 From 45fc26c8ec5d11b2e86304113c486aa9e9e19503 Mon Sep 17 00:00:00 2001 From: Anthony Papoutsis Date: Sat, 27 Aug 2022 11:56:28 +1000 Subject: [PATCH 0008/1280] build: material ui and functioanlity --- package-lock.json | 73 +++++++++++++++++++ src/app/ajs-upgraded-providers.ts | 7 ++ src/app/doubtfire-angular.module.ts | 4 + src/app/doubtfire-angularjs.module.ts | 23 +++--- src/app/units/modals/modals.coffee | 1 - ...nit-student-enrolment-modal.component.html | 34 +++++++++ ...nit-student-enrolment-modal.component.scss | 27 +++++++ .../unit-student-enrolment-modal.component.ts | 55 ++++++++++++++ .../unit-student-enrolment-modal.service.ts | 20 +++++ .../unit-student-enrolment-modal.spec.ts | 0 .../unit-student-enrolment-modal.tpl.html | 2 +- 11 files changed, 233 insertions(+), 13 deletions(-) create mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.html create mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.scss create mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts create mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service.ts create mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.spec.ts diff --git a/package-lock.json b/package-lock.json index ab253c8d86..80bef8d980 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44085,6 +44085,79 @@ "escape-html": "~1.0.3", "parseurl": "~1.3.3", "send": "0.18.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha1-i1VoC7S+KDoLW/TqLjhYC+HZMg0=", + "dev": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "dev": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "send": { + "version": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "dev": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "dev": true + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "dev": true + } } }, "server-destroy": { diff --git a/src/app/ajs-upgraded-providers.ts b/src/app/ajs-upgraded-providers.ts index cb3e586088..c4aef6e1e2 100644 --- a/src/app/ajs-upgraded-providers.ts +++ b/src/app/ajs-upgraded-providers.ts @@ -30,6 +30,13 @@ export const calendarModal = new InjectionToken('CalendarModal'); export const aboutDoubtfireModal = new InjectionToken('AboutDoubtfireModal'); export const groupService = new InjectionToken('groupService'); export const plagiarismReportModal = new InjectionToken('PlagiarismReportModal'); +export const CampusService = new InjectionToken('campusService'); + +export const campusServiceProvider = { + provide: CampusService, + useFactory: (i: any) => i.get('campusService'), + deps: ['$injector'], +}; // Define a provider for the above injection token... // It will get the service from AngularJS via the factory diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index febb3b8164..4a7de72f49 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -76,6 +76,7 @@ import { aboutDoubtfireModalProvider, calendarModalProvider, userNotificationSettingsModalProvider, + campusServiceProvider, } from './ajs-upgraded-providers'; import { TaskCommentComposerComponent, @@ -164,6 +165,7 @@ import { HeaderComponent } from './common/header/header.component'; import { UnitDropdownComponent } from './common/header/unit-dropdown/unit-dropdown.component'; import { TaskDropdownComponent } from './common/header/task-dropdown/task-dropdown.component'; import { SplashScreenComponent } from './home/splash-screen/splash-screen.component'; +import { UnitStudentEnrolmentModalComponent } from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component'; @NgModule({ // Components we declare @@ -221,6 +223,7 @@ import { SplashScreenComponent } from './home/splash-screen/splash-screen.compon UnitDropdownComponent, TaskDropdownComponent, SplashScreenComponent, + UnitStudentEnrolmentModalComponent, ], // Module Imports imports: [ @@ -332,6 +335,7 @@ import { SplashScreenComponent } from './home/splash-screen/splash-screen.compon TasksInTutorialsPipe, TasksForInboxSearchPipe, IsActiveUnitRole, + campusServiceProvider, ], }) // There is no longer any requirement for an EntryComponents section diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index c8ec2ba1d8..d3ce823e71 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -128,7 +128,6 @@ import 'build/src/app/groups/group-member-list/group-member-list.js'; import 'build/src/app/groups/group-set-selector/group-set-selector.js'; import 'build/src/app/groups/tutor-group-manager/tutor-group-manager.js'; import 'build/src/app/groups/student-group-manager/student-group-manager.js'; -import 'build/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.js'; import 'build/src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.js'; import 'build/src/app/units/modals/modals.js'; import 'build/src/app/units/units.js'; @@ -289,6 +288,7 @@ import { TaskAssessmentModalService } from './common/modals/task-assessment-moda import { TaskSubmissionHistoryComponent } from './tasks/task-submission-history/task-submission-history.component'; import { HeaderComponent } from './common/header/header.component'; import { GlobalStateService } from './projects/states/index/global-state.service'; +import { UnitStudentEnrolmentModalService } from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -322,16 +322,14 @@ DoubtfireAngularJSModule.factory('checkForUpdateService', downgradeInjectable(Ch DoubtfireAngularJSModule.factory('TaskAssessmentModal', downgradeInjectable(TaskAssessmentModalService)); DoubtfireAngularJSModule.factory('TaskSubmission', downgradeInjectable(TaskSubmissionService)); DoubtfireAngularJSModule.factory('GlobalStateService', downgradeInjectable(GlobalStateService)); +DoubtfireAngularJSModule.factory('UnitStudentEnrolmentModal', downgradeInjectable(UnitStudentEnrolmentModalService)); // directive -> component DoubtfireAngularJSModule.directive( 'taskCommentComposer', downgradeComponent({ component: TaskCommentComposerComponent }) ); -DoubtfireAngularJSModule.directive( - 'appHeader', - downgradeComponent({ component: HeaderComponent }) -); +DoubtfireAngularJSModule.directive('appHeader', downgradeComponent({ component: HeaderComponent })); DoubtfireAngularJSModule.directive( 'intelligentDiscussionPlayer', downgradeComponent({ component: IntelligentDiscussionPlayerComponent }) @@ -374,12 +372,15 @@ DoubtfireAngularJSModule.directive( downgradeComponent({ component: TaskDescriptionCardComponent }) ); -DoubtfireAngularJSModule.directive('taskAssessor', - downgradeComponent({ component: TaskAssessorComponent })); -DoubtfireAngularJSModule.directive('taskAssessmentComment', - downgradeComponent({ component: TaskAssessmentCommentComponent })); -DoubtfireAngularJSModule.directive('taskSubmissionHistory', - downgradeComponent({ component: TaskSubmissionHistoryComponent })); +DoubtfireAngularJSModule.directive('taskAssessor', downgradeComponent({ component: TaskAssessorComponent })); +DoubtfireAngularJSModule.directive( + 'taskAssessmentComment', + downgradeComponent({ component: TaskAssessmentCommentComponent }) +); +DoubtfireAngularJSModule.directive( + 'taskSubmissionHistory', + downgradeComponent({ component: TaskSubmissionHistoryComponent }) +); // Global configuration DoubtfireAngularJSModule.directive( diff --git a/src/app/units/modals/modals.coffee b/src/app/units/modals/modals.coffee index fb091e725e..9b2b2c391f 100644 --- a/src/app/units/modals/modals.coffee +++ b/src/app/units/modals/modals.coffee @@ -1,4 +1,3 @@ angular.module('doubtfire.units.modals', [ 'doubtfire.units.modals.unit-ilo-edit-modal' - 'doubtfire.units.modals.unit-student-enrolment-modal' ]) diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.html b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.html new file mode 100644 index 0000000000..7b25032b56 --- /dev/null +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.html @@ -0,0 +1,34 @@ + diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.scss b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.scss new file mode 100644 index 0000000000..4ffc18b0ce --- /dev/null +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.scss @@ -0,0 +1,27 @@ +.modal-complete { + width: 500px; +} + +.modal-heading-container { + margin-bottom: 16px; +} + +.modal-heading { + font-size: 24px; +} + +.modal-content-container { + margin-top: 16px; +} + +.modal-container { + display: flex; + justify-content: space-around; + align-items: center; +} + +.card-actions { + margin-top: 8px; + display: flex; + justify-content: flex-end; +} diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts new file mode 100644 index 0000000000..328b04ae9a --- /dev/null +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts @@ -0,0 +1,55 @@ +import { Component, Input, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { alertService, CampusService } from 'src/app/ajs-upgraded-providers'; + +@Component({ + selector: 'unit-student-enrolment-modal', + templateUrl: 'unit-student-enrolment-modal.component.html', + styleUrls: ['unit-student-enrolment-modal.component.scss'], +}) +export class UnitStudentEnrolmentModalComponent { + unit: any; + campuses: any = []; + projects: any; + student_id: string; + campus_id: any; + this; + + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: any, + @Inject(alertService) public alert: any, + @Inject(CampusService) public campusService: any + ) {} + + ngOnInit() { + this.unit = this.data.unit; + this.projects = this.data.unit.students; + this.campusService.query().subscribe((campuses: any) => { + this.campuses = campuses; + }); + console.log(this.unit); + console.log(this.projects); + } + + enrolStudent(student_id, campus_id) { + console.log(this.unit.id, student_id, campus_id); + if (campus_id == null) { + this.alert.add('danger', 'Campus missing. Please indicate student campus', 5000); + return; + } + + return this.unit.$create( + { unit_id: this.unit.id, student_num: student_id, campus_id: campus_id }, + (project: { project_id }) => { + if (!this.unit.studentEnrolled(project.project_id)) { + this.alert.add('success', 'Student enrolled', 2000); + } else { + this.alert.add('danger', 'Student is already enrolled', 2000); + } + }, + (response: { data: { error } }) => + this.alert.add('danger', `Error enrolling student: ${response.data.error}`, 6000) + ); + } +} diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service.ts new file mode 100644 index 0000000000..6d99509ab7 --- /dev/null +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@angular/core'; +import { MatDialogRef, MatDialog } from '@angular/material/dialog'; +import { UnitStudentEnrolmentModalComponent } from './unit-student-enrolment-modal.component'; + +@Injectable({ + providedIn: 'root', +}) +export class UnitStudentEnrolmentModalService { + constructor(public dialog: MatDialog) {} + + public show(unit: any, project: any) { + let dialogRef: MatDialogRef; + dialogRef = this.dialog.open(UnitStudentEnrolmentModalComponent, { + data: { + unit, + project, + }, + }); + } +} diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.spec.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.spec.ts new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.tpl.html b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.tpl.html index 3605bbfe53..53bfe9afd0 100644 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.tpl.html +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.tpl.html @@ -7,7 +7,7 @@

Enrol Student

- +
From da51e8e0cc9518a2a76447a48079b42f144064fc Mon Sep 17 00:00:00 2001 From: Anthony Papoutsis Date: Sat, 27 Aug 2022 11:59:30 +1000 Subject: [PATCH 0009/1280] fix: duplicate files --- ...it-student-enrollment-modal.component.html | 26 ------------------- ...it-student-enrollment-modal.component.scss | 0 ...unit-student-enrollment-modal.component.ts | 10 ------- .../unit-student-enrollment-modal.service.ts | 0 .../unit-student-enrollment-modal.spec.ts | 0 5 files changed, 36 deletions(-) delete mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.html delete mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.scss delete mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.ts delete mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.service.ts delete mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.spec.ts diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.html b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.html deleted file mode 100644 index 428daca3dd..0000000000 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.html +++ /dev/null @@ -1,26 +0,0 @@ -
- - - -
diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.scss b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.ts deleted file mode 100644 index 4b84e82634..0000000000 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.component.ts +++ /dev/null @@ -1,10 +0,0 @@ -import { Component, Input, Inject } from '@angular/core'; - -@Component({ - selector: 'unit-student-enrollment-modal', - templateUrl: 'unit-student-enrollment-modal.component.html', - styleUrls: ['unit-student-enrollment-modal.component.scss'], -}) -export class UnitStudentEnrollmentModalComponent { - constructor() {} -} diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.service.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.service.ts deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.spec.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrollment-modal.spec.ts deleted file mode 100644 index e69de29bb2..0000000000 From 070ed11f520dcbcfa470063185a1d53036bbd3ce Mon Sep 17 00:00:00 2001 From: Anthony Papoutsis Date: Wed, 31 Aug 2022 14:01:37 +1000 Subject: [PATCH 0010/1280] build: complete --- src/app/ajs-upgraded-providers.ts | 7 +++ src/app/doubtfire-angular.module.ts | 2 + .../unit-student-enrolment-modal.coffee | 45 ------------------- .../unit-student-enrolment-modal.component.ts | 15 ++++--- .../unit-student-enrolment-modal.service.ts | 3 +- .../unit-student-enrolment-modal.spec.ts | 27 +++++++++++ .../unit-student-enrolment-modal.tpl.html | 26 ----------- 7 files changed, 45 insertions(+), 80 deletions(-) delete mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.coffee delete mode 100644 src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.tpl.html diff --git a/src/app/ajs-upgraded-providers.ts b/src/app/ajs-upgraded-providers.ts index c4aef6e1e2..554a5e4e3d 100644 --- a/src/app/ajs-upgraded-providers.ts +++ b/src/app/ajs-upgraded-providers.ts @@ -31,6 +31,13 @@ export const aboutDoubtfireModal = new InjectionToken('AboutDoubtfireModal'); export const groupService = new InjectionToken('groupService'); export const plagiarismReportModal = new InjectionToken('PlagiarismReportModal'); export const CampusService = new InjectionToken('campusService'); +export const Project = new InjectionToken('Project'); + +export const projectProvider = { + provide: Project, + useFactory: (i: any) => i.get('Project'), + deps: ['$injector'], +}; export const campusServiceProvider = { provide: CampusService, diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 4a7de72f49..679f643767 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -77,6 +77,7 @@ import { calendarModalProvider, userNotificationSettingsModalProvider, campusServiceProvider, + projectProvider, } from './ajs-upgraded-providers'; import { TaskCommentComposerComponent, @@ -336,6 +337,7 @@ import { UnitStudentEnrolmentModalComponent } from './units/modals/unit-student- TasksForInboxSearchPipe, IsActiveUnitRole, campusServiceProvider, + projectProvider, ], }) // There is no longer any requirement for an EntryComponents section diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.coffee b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.coffee deleted file mode 100644 index 4c3f117660..0000000000 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.coffee +++ /dev/null @@ -1,45 +0,0 @@ -angular.module('doubtfire.units.modals.unit-student-enrolment-modal', []) -# -# Modal to enrol a student in the given tutorial -# -.factory('UnitStudentEnrolmentModal', ($modal) -> - UnitStudentEnrolmentModal = {} - - # Must provide unit - UnitStudentEnrolmentModal.show = (unit) -> - $modal.open - controller: 'UnitStudentEnrolmentModalCtrl' - templateUrl: 'units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.tpl.html' - resolve: { - unit: -> unit - } - - UnitStudentEnrolmentModal -) -.controller('UnitStudentEnrolmentModalCtrl', ($scope, $modalInstance, Project, unit, alertService, campusService) -> - $scope.unit = unit - $scope.projects = unit.students - $scope.campuses = [] - $scope.data = { campus_id: 1 } # need in object for observing - - campusService.query().subscribe( (campuses) -> - $scope.campuses = campuses - $scope.data.campus_id = campuses[0].id - ) - - $scope.enrolStudent = (student_id, campus_id) -> - if ! campus_id? - alertService.add('danger', 'Campus missing. Please indicate student campus', 5000) - return - Project.create {unit_id: unit.id, student_num: student_id, campus_id: campus_id }, - (project) -> - if ! unit.studentEnrolled project.project_id - unit.addStudent project - alertService.add("success", "Student enrolled", 2000) - $modalInstance.close() - else - alertService.add("danger", "Student is already enrolled", 2000) - $modalInstance.close() - (response) -> - alertService.add("danger", "Error enrolling student: #{response.data.error}", 6000) -) diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts index 328b04ae9a..c58d56df74 100644 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts @@ -1,6 +1,6 @@ -import { Component, Input, Inject } from '@angular/core'; +import { Component, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { alertService, CampusService } from 'src/app/ajs-upgraded-providers'; +import { alertService, CampusService, Project } from 'src/app/ajs-upgraded-providers'; @Component({ selector: 'unit-student-enrolment-modal', @@ -13,13 +13,13 @@ export class UnitStudentEnrolmentModalComponent { projects: any; student_id: string; campus_id: any; - this; constructor( public dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: any, @Inject(alertService) public alert: any, - @Inject(CampusService) public campusService: any + @Inject(CampusService) public campusService: any, + @Inject(Project) private project: any ) {} ngOnInit() { @@ -38,12 +38,13 @@ export class UnitStudentEnrolmentModalComponent { this.alert.add('danger', 'Campus missing. Please indicate student campus', 5000); return; } - - return this.unit.$create( + this.project.create( { unit_id: this.unit.id, student_num: student_id, campus_id: campus_id }, - (project: { project_id }) => { + (project) => { if (!this.unit.studentEnrolled(project.project_id)) { + this.unit.addStudent(project); this.alert.add('success', 'Student enrolled', 2000); + this.dialogRef.close(); } else { this.alert.add('danger', 'Student is already enrolled', 2000); } diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service.ts index 6d99509ab7..5ecec93bc9 100644 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service.ts +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service.ts @@ -8,12 +8,11 @@ import { UnitStudentEnrolmentModalComponent } from './unit-student-enrolment-mod export class UnitStudentEnrolmentModalService { constructor(public dialog: MatDialog) {} - public show(unit: any, project: any) { + public show(unit: any) { let dialogRef: MatDialogRef; dialogRef = this.dialog.open(UnitStudentEnrolmentModalComponent, { data: { unit, - project, }, }); } diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.spec.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.spec.ts index e69de29bb2..7331956e18 100644 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.spec.ts +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.spec.ts @@ -0,0 +1,27 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; +import { UnitStudentEnrolmentModalComponent } from './unit-student-enrolment-modal.component'; + +describe('RolloverTeachingPeriodModalComponent', () => { + let component: UnitStudentEnrolmentModalComponent; + let fixture: ComponentFixture; + + beforeEach( + waitForAsync(() => { + TestBed.configureTestingModule({ + declarations: [UnitStudentEnrolmentModalComponent], + providers: [{ provide: DoubtfireConstants }], + }).compileComponents(); + }) + ); + + beforeEach(() => { + fixture = TestBed.createComponent(UnitStudentEnrolmentModalComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.tpl.html b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.tpl.html deleted file mode 100644 index 53bfe9afd0..0000000000 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.tpl.html +++ /dev/null @@ -1,26 +0,0 @@ -
- - - -
From 97686fcad49cd1fd4af9aef266af26064fdfb186 Mon Sep 17 00:00:00 2001 From: Leo Luong Date: Fri, 9 Sep 2022 16:35:28 +1000 Subject: [PATCH 0011/1280] chore: update html template --- .../unauthorised/unauthorised.component.html | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app/errors/states/unauthorised/unauthorised.component.html b/src/app/errors/states/unauthorised/unauthorised.component.html index e5566606d5..a0f26d25c2 100644 --- a/src/app/errors/states/unauthorised/unauthorised.component.html +++ b/src/app/errors/states/unauthorised/unauthorised.component.html @@ -1,7 +1,7 @@ -
-
- -

Unauthorised

-

You do not have sufficient permissions to access this resource, or your session has expired.

-
-
\ No newline at end of file +
+
+ +

Unauthorised

+

You do not have sufficient permissions to access this resource, or your session has expired.

+
+
\ No newline at end of file From a31cc1bfb9a03a60a0c087cb84ae559fb515b404 Mon Sep 17 00:00:00 2001 From: Leo Luong Date: Mon, 12 Sep 2022 11:15:40 +1000 Subject: [PATCH 0012/1280] chore: delete old files --- .../states/unauthorised/unauthorised.coffee | 19 ------------------- .../states/unauthorised/unauthorised.tpl.html | 7 ------- 2 files changed, 26 deletions(-) delete mode 100644 src/app/errors/states/unauthorised/unauthorised.coffee delete mode 100644 src/app/errors/states/unauthorised/unauthorised.tpl.html diff --git a/src/app/errors/states/unauthorised/unauthorised.coffee b/src/app/errors/states/unauthorised/unauthorised.coffee deleted file mode 100644 index 1c16b98025..0000000000 --- a/src/app/errors/states/unauthorised/unauthorised.coffee +++ /dev/null @@ -1,19 +0,0 @@ -angular.module("doubtfire.errors.states.unauthorised", []) - -# -# Define the unauthorised state -# -.config((headerServiceProvider) -> - stateData = - url: "/unauthorised" - views: - main: - controller: "UnauthorisedCtrl" - templateUrl: "errors/states/unauthorised/unauthorised.tpl.html" - data: - pageTitle: "_Unauthorised_" - - headerServiceProvider.state "unauthorised", stateData -) - -.controller("UnauthorisedCtrl", ($scope) ->) diff --git a/src/app/errors/states/unauthorised/unauthorised.tpl.html b/src/app/errors/states/unauthorised/unauthorised.tpl.html deleted file mode 100644 index a0f26d25c2..0000000000 --- a/src/app/errors/states/unauthorised/unauthorised.tpl.html +++ /dev/null @@ -1,7 +0,0 @@ -
-
- -

Unauthorised

-

You do not have sufficient permissions to access this resource, or your session has expired.

-
-
\ No newline at end of file From 164659e66a352612ce9e66c1b37e0eec6107e004 Mon Sep 17 00:00:00 2001 From: Leo Luong Date: Tue, 13 Sep 2022 12:51:18 +1000 Subject: [PATCH 0013/1280] chore: upload icon --- src/app/errors/errors.scss | 10 +--------- .../unauthorised/unauthorised.component.html | 12 ++++++------ .../unauthorised/unauthorised.component.scss | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 15 deletions(-) diff --git a/src/app/errors/errors.scss b/src/app/errors/errors.scss index bb20204bca..8b13789179 100644 --- a/src/app/errors/errors.scss +++ b/src/app/errors/errors.scss @@ -1,9 +1 @@ -.error-container { - h1 + p { - margin-top: 20px; - } - i { - margin-top: 30px; - font-size: 100px; - } -} + diff --git a/src/app/errors/states/unauthorised/unauthorised.component.html b/src/app/errors/states/unauthorised/unauthorised.component.html index a0f26d25c2..6954101277 100644 --- a/src/app/errors/states/unauthorised/unauthorised.component.html +++ b/src/app/errors/states/unauthorised/unauthorised.component.html @@ -1,7 +1,7 @@ -
-
- -

Unauthorised

-

You do not have sufficient permissions to access this resource, or your session has expired.

+ +
+ warning
-
\ No newline at end of file +

Unauthorised

+

You do not have sufficient permissions to access this resource, or your session has expired.

+ diff --git a/src/app/errors/states/unauthorised/unauthorised.component.scss b/src/app/errors/states/unauthorised/unauthorised.component.scss index e69de29bb2..52cb7522ff 100644 --- a/src/app/errors/states/unauthorised/unauthorised.component.scss +++ b/src/app/errors/states/unauthorised/unauthorised.component.scss @@ -0,0 +1,14 @@ +.icon-display { + font-size: 15rem; + padding-top: 10px; + padding-bottom: 10px; + +} + +.icon-container{ + padding-right: 12rem; +} + +.text-centre{ + text-align: center; +} \ No newline at end of file From ae20c0371389573c11bd2efe4da4da1fb1f10ec4 Mon Sep 17 00:00:00 2001 From: Chanputhi Date: Sun, 18 Dec 2022 00:29:56 +1100 Subject: [PATCH 0014/1280] build: create initial file for privacy-policy.ts migration --- .../config/privacy-policy/privacy-policy.ts | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 src/app/config/privacy-policy/privacy-policy.ts diff --git a/src/app/config/privacy-policy/privacy-policy.ts b/src/app/config/privacy-policy/privacy-policy.ts new file mode 100644 index 0000000000..8142d8b08c --- /dev/null +++ b/src/app/config/privacy-policy/privacy-policy.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@angular/core'; +import { HttpClient } from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiURL'; + +interface Response { + privacy: string; + plagiarism: string; +} + +@Injectable({ + providedIn: 'root' +}) + +export class PrivacyPolicy { + privacy = ''; + plagiarism = ''; + loaded = false; + + public API_URL: string = API_URL; + + constructor(private http: HttpClient) { + + const url: string = `${this.API_URL}/settings/privacy`; + + this.http + .get(url) + .subscribe(response => { + this.privacy = response.privacy; + this.plagiarism = response.plagiarism; + this.loaded = true; + }); + } +} \ No newline at end of file From 36ed3ba44126d9a29b366999e49b07631a93e308 Mon Sep 17 00:00:00 2001 From: Chanputhi Date: Sun, 18 Dec 2022 00:35:51 +1100 Subject: [PATCH 0015/1280] test: create privacy-policy.spec.ts for testing the privacy-policy service --- .../config/privacy-policy/privacy-policy.spec.ts | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) create mode 100644 src/app/config/privacy-policy/privacy-policy.spec.ts diff --git a/src/app/config/privacy-policy/privacy-policy.spec.ts b/src/app/config/privacy-policy/privacy-policy.spec.ts new file mode 100644 index 0000000000..23982f5ecd --- /dev/null +++ b/src/app/config/privacy-policy/privacy-policy.spec.ts @@ -0,0 +1,16 @@ +import { TestBed } from '@angular/core/testing'; + +import {PrivacyPolicy } from './privacy-policy'; + +describe('PrivacyPolicy', () => { + let service: PrivacyPolicy; + + beforeEach(() => { + TestBed.configureTestingModule({}); + service = TestBed.inject(PrivacyPolicy); + }); + + it('should be created', () => { + expect(service).toBeTruthy(); + }); +}); \ No newline at end of file From c3f860cdbc10a38505bfbf6b14e381042bdc58f2 Mon Sep 17 00:00:00 2001 From: Chanputhi Date: Sun, 18 Dec 2022 00:45:07 +1100 Subject: [PATCH 0016/1280] migrate: linking new and unlink old module from doubtfire-angularjs and doubtfire-angular --- src/app/config/config.coffee | 1 - src/app/doubtfire-angular.module.ts | 2 ++ src/app/doubtfire-angularjs.module.ts | 4 +++- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/app/config/config.coffee b/src/app/config/config.coffee index 853d046373..a97f457d3b 100644 --- a/src/app/config/config.coffee +++ b/src/app/config/config.coffee @@ -13,5 +13,4 @@ angular.module('doubtfire.config', [ 'doubtfire.config.runtime' 'doubtfire.config.root-controller' 'doubtfire.config.debug' - 'doubtfire.config.privacy-policy' ]) diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 6087e7228d..d6ecea7f5f 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -175,6 +175,7 @@ import { EditProfileFormComponent } from './common/edit-profile-form/edit-profil import { TransitionHooksService } from './sessions/transition-hooks.service'; import { EditProfileComponent } from './account/edit-profile/edit-profile.component'; import { UserBadgeComponent } from './common/user-badge/user-badge.component'; +import { PrivacyPolicy } from './config/privacy-policy/privacy-policy'; @NgModule({ // Components we declare @@ -358,6 +359,7 @@ import { UserBadgeComponent } from './common/user-badge/user-badge.component'; TasksInTutorialsPipe, TasksForInboxSearchPipe, IsActiveUnitRole, + PrivacyPolicy ], }) // There is no longer any requirement for an EntryComponents section diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 6cab1797bc..3152b71ec4 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -60,7 +60,7 @@ import 'build/src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/t import 'build/src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.js'; import 'build/src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.js'; import 'build/src/app/tasks/task-definition-editor/task-definition-editor.js'; -import 'build/src/app/config/privacy-policy/privacy-policy.js'; + import 'build/src/app/config/runtime/runtime.js'; import 'build/src/app/config/config.js'; import 'build/src/app/config/root-controller/root-controller.js'; @@ -265,6 +265,7 @@ import { TaskDefinitionService } from './api/services/task-definition.service'; import { EditProfileDialogService } from './common/modals/edit-profile-dialog/edit-profile-dialog.service'; import { GroupService } from './api/services/group.service'; import { UserBadgeComponent } from './common/user-badge/user-badge.component'; +import { PrivacyPolicy } from './config/privacy-policy/privacy-policy'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -311,6 +312,7 @@ DoubtfireAngularJSModule.factory('TaskSubmission', downgradeInjectable(TaskSubmi DoubtfireAngularJSModule.factory('GlobalStateService', downgradeInjectable(GlobalStateService)); DoubtfireAngularJSModule.factory('TransitionHooksService', downgradeInjectable(TransitionHooksService)); DoubtfireAngularJSModule.factory('EditProfileService', downgradeInjectable(EditProfileDialogService)); +DoubtfireAngularJSModule.factory('PrivacyPolicy', downgradeInjectable(PrivacyPolicy)); // directive -> component DoubtfireAngularJSModule.directive( From 940c25acd27c5cfe9ffaa9c4fddd4f5a183e0ecc Mon Sep 17 00:00:00 2001 From: Chanputhi Date: Sun, 18 Dec 2022 00:47:25 +1100 Subject: [PATCH 0017/1280] remove: delete the old privacy-policy.coffescript from the file --- .../config/privacy-policy/privacy-policy.coffee | 17 ----------------- 1 file changed, 17 deletions(-) delete mode 100644 src/app/config/privacy-policy/privacy-policy.coffee diff --git a/src/app/config/privacy-policy/privacy-policy.coffee b/src/app/config/privacy-policy/privacy-policy.coffee deleted file mode 100644 index a7a1a84efa..0000000000 --- a/src/app/config/privacy-policy/privacy-policy.coffee +++ /dev/null @@ -1,17 +0,0 @@ -angular.module("doubtfire.config.privacy-policy", []) - -.factory('PrivacyPolicy', ($http, DoubtfireConstants) -> - privacyPolicy = { - privacy: '', - plagiarism: '', - loaded: false, - } - - $http.get("#{DoubtfireConstants.API_URL}/settings/privacy").then ((response) -> - privacyPolicy.privacy = response.data.privacy - privacyPolicy.plagiarism = response.data.plagiarism - privacyPolicy.loaded = true - ) - - privacyPolicy -) From f1cc39e59dd224c55ee0e8b5f1d50855263d147e Mon Sep 17 00:00:00 2001 From: brandonsmith301 Date: Fri, 16 Feb 2024 13:16:31 +1100 Subject: [PATCH 0018/1280] feat: visualisations Updated Both Progress Burndown Chart And Pie Chart Change by Brandon --- package-lock.json | 19336 ++++++++++------ package.json | 2 + src/app/doubtfire-angular.module.ts | 7 + src/app/doubtfire-angularjs.module.ts | 13 + .../progress-dashboard.tpl.html | 10 +- .../progressburndownchart.component.html | 19 + .../progressburndownchart.component.scss | 0 .../progressburndownchart.component.ts | 132 + .../taskvisualisation.component.html | 7 + .../taskvisualisation.component.scss | 0 .../taskvisualisation.component.ts | 99 + 11 files changed, 12256 insertions(+), 7369 deletions(-) create mode 100644 src/app/visualisations/progress-burndown-chart/progressburndownchart.component.html create mode 100644 src/app/visualisations/progress-burndown-chart/progressburndownchart.component.scss create mode 100644 src/app/visualisations/progress-burndown-chart/progressburndownchart.component.ts create mode 100644 src/app/visualisations/task-visualisation/taskvisualisation.component.html create mode 100644 src/app/visualisations/task-visualisation/taskvisualisation.component.scss create mode 100644 src/app/visualisations/task-visualisation/taskvisualisation.component.ts diff --git a/package-lock.json b/package-lock.json index 09d112c716..5732ac6a28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,7 @@ "@angular/service-worker": "^17.0.3", "@angular/upgrade": "^17.0.3", "@ctrl/ngx-emoji-mart": "^9.2.0", + "@swimlane/ngx-charts": "^20.5.0", "@uirouter/angular": "^12.0", "@uirouter/angular-hybrid": "^16.0", "@uirouter/angularjs": "^1.0.30", @@ -66,6 +67,7 @@ "ngx-bootstrap": "^6.1.0", "ngx-entity-service": "^0.0.37", "ngx-lottie": "^10.0.0", + "npm": "^10.4.0", "nvd3": "1.8.6", "rxjs": "~7.4.0", "showdown": "1.3.0", @@ -5710,6 +5712,38 @@ "dev": true, "license": "MIT" }, + "node_modules/@swimlane/ngx-charts": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@swimlane/ngx-charts/-/ngx-charts-20.5.0.tgz", + "integrity": "sha512-PNBIHdu/R3ceD7jnw1uCBVOj4k3T6IxfdW6xsDsglGkZyoWMEEq4tLoEurjLEKzmDtRv9c35kVNOXy0lkOuXeA==", + "dependencies": { + "d3-array": "^3.1.1", + "d3-brush": "^3.0.0", + "d3-color": "^3.1.0", + "d3-ease": "^3.0.1", + "d3-format": "^3.1.0", + "d3-hierarchy": "^3.1.0", + "d3-interpolate": "^3.0.1", + "d3-sankey": "^0.12.3", + "d3-scale": "^4.0.2", + "d3-selection": "^3.0.0", + "d3-shape": "^3.2.0", + "d3-time-format": "^3.0.0", + "d3-transition": "^3.0.1", + "rfdc": "^1.3.0", + "tslib": "^2.0.0" + }, + "peerDependencies": { + "@angular/animations": ">=12.0.0", + "@angular/cdk": ">=12.0.0", + "@angular/common": ">=12.0.0", + "@angular/core": ">=12.0.0", + "@angular/forms": ">=12.0.0", + "@angular/platform-browser": ">=12.0.0", + "@angular/platform-browser-dynamic": ">=12.0.0", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "dev": true, @@ -7387,7 +7421,7 @@ }, "node_modules/anymatch": { "version": "3.1.3", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "normalize-path": "^3.0.0", @@ -8073,7 +8107,7 @@ }, "node_modules/binary-extensions": { "version": "2.2.0", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -8280,7 +8314,7 @@ }, "node_modules/braces": { "version": "3.0.2", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "fill-range": "^7.0.1" @@ -9024,7 +9058,7 @@ }, "node_modules/chokidar": { "version": "3.5.3", - "devOptional": true, + "dev": true, "funding": [ { "type": "individual", @@ -10060,6 +10094,238 @@ "version": "3.5.17", "license": "BSD-3-Clause" }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "dependencies": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "dependencies": { + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "dependencies": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-sankey/node_modules/d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "node_modules/d3-sankey/node_modules/d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "dependencies": { + "d3-path": "1" + } + }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" + }, + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "dependencies": { + "d3-path": "^3.1.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "dependencies": { + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-time-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", + "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", + "dependencies": { + "d3-time": "1 - 2" + } + }, + "node_modules/d3-time-format/node_modules/d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "dependencies": { + "internmap": "^1.0.0" + } + }, + "node_modules/d3-time-format/node_modules/d3-time": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", + "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", + "dependencies": { + "d3-array": "2" + } + }, + "node_modules/d3-time-format/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" + }, + "node_modules/d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "dependencies": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + }, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "d3-selection": "2 - 3" + } + }, "node_modules/dargs": { "version": "7.0.0", "dev": true, @@ -12221,7 +12487,7 @@ }, "node_modules/fill-range": { "version": "7.0.1", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "to-regex-range": "^5.0.1" @@ -12723,7 +12989,7 @@ }, "node_modules/glob-parent": { "version": "5.1.2", - "devOptional": true, + "dev": true, "license": "ISC", "dependencies": { "is-glob": "^4.0.1" @@ -14995,6 +15261,14 @@ "node": ">= 0.4" } }, + "node_modules/internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "engines": { + "node": ">=12" + } + }, "node_modules/interpret": { "version": "1.1.0", "dev": true, @@ -15086,7 +15360,7 @@ }, "node_modules/is-binary-path": { "version": "2.1.0", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "binary-extensions": "^2.0.0" @@ -15240,7 +15514,7 @@ }, "node_modules/is-extglob": { "version": "2.1.1", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -15255,7 +15529,7 @@ }, "node_modules/is-glob": { "version": "4.0.3", - "devOptional": true, + "dev": true, "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -15322,7 +15596,7 @@ }, "node_modules/is-number": { "version": "7.0.0", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.12.0" @@ -18331,7 +18605,7 @@ }, "node_modules/normalize-path": { "version": "3.0.0", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -18345,6 +18619,162 @@ "node": ">=0.10.0" } }, + "node_modules/npm": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.4.0.tgz", + "integrity": "sha512-RS7Mx0OVfXlOcQLRePuDIYdFCVBPCNapWHplDK+mh7GDdP/Tvor4ocuybRRPSvfcRb2vjRJt1fHCqw3cr8qACQ==", + "bundleDependencies": [ + "@isaacs/string-locale-compare", + "@npmcli/arborist", + "@npmcli/config", + "@npmcli/fs", + "@npmcli/map-workspaces", + "@npmcli/package-json", + "@npmcli/promise-spawn", + "@npmcli/run-script", + "@sigstore/tuf", + "abbrev", + "archy", + "cacache", + "chalk", + "ci-info", + "cli-columns", + "cli-table3", + "columnify", + "fastest-levenshtein", + "fs-minipass", + "glob", + "graceful-fs", + "hosted-git-info", + "ini", + "init-package-json", + "is-cidr", + "json-parse-even-better-errors", + "libnpmaccess", + "libnpmdiff", + "libnpmexec", + "libnpmfund", + "libnpmhook", + "libnpmorg", + "libnpmpack", + "libnpmpublish", + "libnpmsearch", + "libnpmteam", + "libnpmversion", + "make-fetch-happen", + "minimatch", + "minipass", + "minipass-pipeline", + "ms", + "node-gyp", + "nopt", + "normalize-package-data", + "npm-audit-report", + "npm-install-checks", + "npm-package-arg", + "npm-pick-manifest", + "npm-profile", + "npm-registry-fetch", + "npm-user-validate", + "npmlog", + "p-map", + "pacote", + "parse-conflict-json", + "proc-log", + "qrcode-terminal", + "read", + "semver", + "spdx-expression-parse", + "ssri", + "supports-color", + "tar", + "text-table", + "tiny-relative-date", + "treeverse", + "validate-npm-package-name", + "which", + "write-file-atomic" + ], + "dependencies": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^7.2.1", + "@npmcli/config": "^8.0.2", + "@npmcli/fs": "^3.1.0", + "@npmcli/map-workspaces": "^3.0.4", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.1", + "@npmcli/run-script": "^7.0.4", + "@sigstore/tuf": "^2.3.0", + "abbrev": "^2.0.0", + "archy": "~1.0.0", + "cacache": "^18.0.2", + "chalk": "^5.3.0", + "ci-info": "^4.0.0", + "cli-columns": "^4.0.0", + "cli-table3": "^0.6.3", + "columnify": "^1.6.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.3", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^7.0.1", + "ini": "^4.1.1", + "init-package-json": "^6.0.0", + "is-cidr": "^5.0.3", + "json-parse-even-better-errors": "^3.0.1", + "libnpmaccess": "^8.0.1", + "libnpmdiff": "^6.0.3", + "libnpmexec": "^7.0.4", + "libnpmfund": "^5.0.1", + "libnpmhook": "^10.0.0", + "libnpmorg": "^6.0.1", + "libnpmpack": "^6.0.3", + "libnpmpublish": "^9.0.2", + "libnpmsearch": "^7.0.0", + "libnpmteam": "^6.0.0", + "libnpmversion": "^5.0.1", + "make-fetch-happen": "^13.0.0", + "minimatch": "^9.0.3", + "minipass": "^7.0.4", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^10.0.1", + "nopt": "^7.2.0", + "normalize-package-data": "^6.0.0", + "npm-audit-report": "^5.0.0", + "npm-install-checks": "^6.3.0", + "npm-package-arg": "^11.0.1", + "npm-pick-manifest": "^9.0.0", + "npm-profile": "^9.0.0", + "npm-registry-fetch": "^16.1.0", + "npm-user-validate": "^2.0.0", + "npmlog": "^7.0.1", + "p-map": "^4.0.0", + "pacote": "^17.0.6", + "parse-conflict-json": "^3.0.1", + "proc-log": "^3.0.0", + "qrcode-terminal": "^0.12.0", + "read": "^2.1.0", + "semver": "^7.5.4", + "spdx-expression-parse": "^3.0.1", + "ssri": "^10.0.5", + "supports-color": "^9.4.0", + "tar": "^6.2.0", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^5.0.0", + "which": "^4.0.0", + "write-file-atomic": "^5.0.1" + }, + "bin": { + "npm": "bin/npm-cli.js", + "npx": "bin/npx-cli.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0" + } + }, "node_modules/npm-bundled": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", @@ -18547,631 +18977,653 @@ "node": ">=8" } }, - "node_modules/nth-check": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", - "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", - "dev": true, + "node_modules/npm/node_modules/@colors/colors": { + "version": "1.5.0", + "inBundle": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/npm/node_modules/@isaacs/cliui": { + "version": "8.0.2", + "inBundle": true, + "license": "ISC", "dependencies": { - "boolbase": "^1.0.0" + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" }, - "funding": { - "url": "https://github.com/fb55/nth-check?sponsor=1" + "engines": { + "node": ">=12" } }, - "node_modules/num2fraction": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", - "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==", - "dev": true - }, - "node_modules/number-is-nan": { - "version": "1.0.1", + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "inBundle": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/nvd3": { - "version": "1.8.6", - "license": "Apache-2.0", - "peerDependencies": { - "d3": "^3.4.4" - } + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "inBundle": true, + "license": "MIT" }, - "node_modules/nx": { - "version": "17.0.3", - "resolved": "https://registry.npmjs.org/nx/-/nx-17.0.3.tgz", - "integrity": "sha512-VShJISKCYt3iVJoMUPZiv67+0tiItxWMnfVmTmPZPio2Fu+wGc9U4ijjPxcmp2RJmLRaxkB9cn5rlrAvkIrNMA==", - "dev": true, - "hasInstallScript": true, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT", "dependencies": { - "@nrwl/tao": "17.0.3", - "@yarnpkg/lockfile": "^1.1.0", - "@yarnpkg/parsers": "3.0.0-rc.46", - "@zkochan/js-yaml": "0.0.6", - "axios": "^1.5.1", - "chalk": "^4.1.0", - "cli-cursor": "3.1.0", - "cli-spinners": "2.6.1", - "cliui": "^8.0.1", - "dotenv": "~16.3.1", - "dotenv-expand": "~10.0.0", - "enquirer": "~2.3.6", - "figures": "3.2.0", - "flat": "^5.0.2", - "fs-extra": "^11.1.0", - "glob": "7.1.4", - "ignore": "^5.0.4", - "jest-diff": "^29.4.1", - "js-yaml": "4.1.0", - "jsonc-parser": "3.2.0", - "lines-and-columns": "~2.0.3", - "minimatch": "3.0.5", - "node-machine-id": "1.1.12", - "npm-run-path": "^4.0.1", - "open": "^8.4.0", - "semver": "7.5.3", - "string-width": "^4.2.3", - "strong-log-transformer": "^2.1.0", - "tar-stream": "~2.2.0", - "tmp": "~0.2.1", - "tsconfig-paths": "^4.1.2", - "tslib": "^2.3.0", - "v8-compile-cache": "2.3.0", - "yargs": "^17.6.2", - "yargs-parser": "21.1.1" - }, - "bin": { - "nx": "bin/nx.js", - "nx-cloud": "bin/nx-cloud.js" - }, - "optionalDependencies": { - "@nx/nx-darwin-arm64": "17.0.3", - "@nx/nx-darwin-x64": "17.0.3", - "@nx/nx-freebsd-x64": "17.0.3", - "@nx/nx-linux-arm-gnueabihf": "17.0.3", - "@nx/nx-linux-arm64-gnu": "17.0.3", - "@nx/nx-linux-arm64-musl": "17.0.3", - "@nx/nx-linux-x64-gnu": "17.0.3", - "@nx/nx-linux-x64-musl": "17.0.3", - "@nx/nx-win32-arm64-msvc": "17.0.3", - "@nx/nx-win32-x64-msvc": "17.0.3" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" }, - "peerDependencies": { - "@swc-node/register": "^1.6.7", - "@swc/core": "^1.3.85" + "engines": { + "node": ">=12" }, - "peerDependenciesMeta": { - "@swc-node/register": { - "optional": true - }, - "@swc/core": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/nx/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, + "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "inBundle": true, + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "ansi-regex": "^6.0.1" }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/nx/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "node_modules/npm/node_modules/@isaacs/string-locale-compare": { + "version": "1.1.0", + "inBundle": true, + "license": "ISC" }, - "node_modules/nx/node_modules/axios": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz", - "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==", - "dev": true, + "node_modules/npm/node_modules/@npmcli/agent": { + "version": "2.2.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "follow-redirects": "^1.15.0", - "form-data": "^4.0.0", - "proxy-from-env": "^1.1.0" + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, + "node_modules/npm/node_modules/@npmcli/arborist": { + "version": "7.3.1", + "inBundle": true, + "license": "ISC", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^3.1.0", + "@npmcli/installed-package-contents": "^2.0.2", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/metavuln-calculator": "^7.0.0", + "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/query": "^3.0.1", + "@npmcli/run-script": "^7.0.2", + "bin-links": "^4.0.1", + "cacache": "^18.0.0", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^7.0.1", + "json-parse-even-better-errors": "^3.0.0", + "json-stringify-nice": "^1.1.4", + "minimatch": "^9.0.0", + "nopt": "^7.0.0", + "npm-install-checks": "^6.2.0", + "npm-package-arg": "^11.0.1", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "npmlog": "^7.0.1", + "pacote": "^17.0.4", + "parse-conflict-json": "^3.0.0", + "proc-log": "^3.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^3.0.1", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^10.0.5", + "treeverse": "^3.0.0", + "walk-up-path": "^3.0.1" }, - "engines": { - "node": ">=10" + "bin": { + "arborist": "bin/index.js" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/cli-spinners": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", - "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", - "dev": true, - "engines": { - "node": ">=6" + "node_modules/npm/node_modules/@npmcli/config": { + "version": "8.1.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/map-workspaces": "^3.0.2", + "ci-info": "^4.0.0", + "ini": "^4.1.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.5", + "walk-up-path": "^3.0.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/npm/node_modules/@npmcli/disparity-colors": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "color-name": "~1.1.4" + "ansi-styles": "^4.3.0" }, "engines": { - "node": ">=7.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/nx/node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, + "node_modules/npm/node_modules/@npmcli/disparity-colors/node_modules/ansi-styles": { + "version": "4.3.0", + "inBundle": true, + "license": "MIT", "dependencies": { - "escape-string-regexp": "^1.0.5" + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/nx/node_modules/form-data": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", - "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, + "node_modules/npm/node_modules/@npmcli/fs": { + "version": "3.1.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "mime-types": "^2.1.12" + "semver": "^7.3.5" }, "engines": { - "node": ">= 6" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/fs-extra": { - "version": "11.1.1", - "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", - "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", - "dev": true, + "node_modules/npm/node_modules/@npmcli/git": { + "version": "5.0.4", + "inBundle": true, + "license": "ISC", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" }, "engines": { - "node": ">=14.14" - } - }, - "node_modules/nx/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, + "node_modules/npm/node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "inBundle": true, + "license": "ISC", "dependencies": { - "argparse": "^2.0.1" + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" }, "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/nx/node_modules/lines-and-columns": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", - "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", - "dev": true, + "installed-package-contents": "lib/index.js" + }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/minimatch": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", - "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", - "dev": true, + "node_modules/npm/node_modules/@npmcli/map-workspaces": { + "version": "3.0.4", + "inBundle": true, + "license": "ISC", "dependencies": { - "brace-expansion": "^1.1.7" + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0", + "read-package-json-fast": "^3.0.0" }, "engines": { - "node": "*" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { + "version": "7.0.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "has-flag": "^4.0.0" + "cacache": "^18.0.0", + "json-parse-even-better-errors": "^3.0.0", + "pacote": "^17.0.0", + "semver": "^7.3.5" }, "engines": { - "node": ">=8" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, + "node_modules/npm/node_modules/@npmcli/name-from-folder": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", "engines": { - "node": ">=6" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/nx/node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", - "dev": true, - "engines": { - "node": ">=12" + "node_modules/npm/node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "dev": true, - "license": "Apache-2.0", + "node_modules/npm/node_modules/@npmcli/package-json": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + }, "engines": { - "node": "*" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/@npmcli/promise-spawn": { + "version": "7.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "which": "^4.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/object-copy": { - "version": "0.1.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/@npmcli/query": { + "version": "3.0.1", + "inBundle": true, + "license": "ISC", "dependencies": { - "copy-descriptor": "^0.1.0", - "define-property": "^0.2.5", - "kind-of": "^3.0.3" + "postcss-selector-parser": "^6.0.10" }, "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/object-copy/node_modules/kind-of": { - "version": "3.2.2", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/@npmcli/run-script": { + "version": "7.0.4", + "inBundle": true, + "license": "ISC", "dependencies": { - "is-buffer": "^1.1.5" + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "which": "^4.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/object-hash": { - "version": "3.0.0", - "dev": true, + "node_modules/npm/node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "inBundle": true, "license": "MIT", + "optional": true, "engines": { - "node": ">= 6" + "node": ">=14" } }, - "node_modules/object-inspect": { - "version": "1.12.3", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node_modules/npm/node_modules/@sigstore/bundle": { + "version": "2.1.1", + "inBundle": true, + "license": "Apache-2.0", + "dependencies": { + "@sigstore/protobuf-specs": "^0.2.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/@sigstore/core": { + "version": "0.2.0", + "inBundle": true, + "license": "Apache-2.0", "engines": { - "node": ">= 0.4" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/object-visit": { - "version": "1.0.1", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/@sigstore/protobuf-specs": { + "version": "0.2.1", + "inBundle": true, + "license": "Apache-2.0", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@sigstore/sign": { + "version": "2.2.1", + "inBundle": true, + "license": "Apache-2.0", "dependencies": { - "isobject": "^3.0.0" + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", + "@sigstore/protobuf-specs": "^0.2.1", + "make-fetch-happen": "^13.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/object.assign": { - "version": "4.1.4", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/@sigstore/tuf": { + "version": "2.3.0", + "inBundle": true, + "license": "Apache-2.0", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "has-symbols": "^1.0.3", - "object-keys": "^1.1.1" + "@sigstore/protobuf-specs": "^0.2.1", + "tuf-js": "^2.2.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/object.defaults": { - "version": "1.1.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/@sigstore/verify": { + "version": "0.1.0", + "inBundle": true, + "license": "Apache-2.0", "dependencies": { - "array-each": "^1.0.1", - "array-slice": "^1.0.0", - "for-own": "^1.0.0", - "isobject": "^3.0.0" + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", + "@sigstore/protobuf-specs": "^0.2.1" }, "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/object.map": { - "version": "1.0.1", - "dev": true, + "node_modules/npm/node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/@tufjs/models": { + "version": "2.0.0", + "inBundle": true, "license": "MIT", "dependencies": { - "for-own": "^1.0.0", - "make-iterator": "^1.0.0" + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.3" }, "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/object.pick": { - "version": "1.3.0", - "dev": true, + "node_modules/npm/node_modules/abbrev": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/agent-base": { + "version": "7.1.0", + "inBundle": true, "license": "MIT", "dependencies": { - "isobject": "^3.0.1" + "debug": "^4.3.4" }, "engines": { - "node": ">=0.10.0" + "node": ">= 14" } }, - "node_modules/object.values": { - "version": "1.1.6", - "dev": true, + "node_modules/npm/node_modules/aggregate-error": { + "version": "3.1.0", + "inBundle": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ansi-regex": { + "version": "5.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/ansi-styles": { + "version": "6.2.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/obuf": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", - "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", - "dev": true + "node_modules/npm/node_modules/aproba": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" }, - "node_modules/on-finished": { - "version": "2.3.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/archy": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/are-we-there-yet": { + "version": "4.0.2", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/balanced-match": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/bin-links": { + "version": "4.0.3", + "inBundle": true, + "license": "ISC", "dependencies": { - "ee-first": "1.1.1" + "cmd-shim": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "read-cmd-shim": "^4.0.0", + "write-file-atomic": "^5.0.0" }, "engines": { - "node": ">= 0.8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/on-headers": { - "version": "1.0.2", - "dev": true, + "node_modules/npm/node_modules/binary-extensions": { + "version": "2.2.0", + "inBundle": true, "license": "MIT", "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/once": { - "version": "1.4.0", - "dev": true, - "license": "ISC", + "node_modules/npm/node_modules/brace-expansion": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", "dependencies": { - "wrappy": "1" + "balanced-match": "^1.0.0" } }, - "node_modules/onetime": { - "version": "5.1.2", + "node_modules/npm/node_modules/builtins": { + "version": "5.0.1", + "inBundle": true, "license": "MIT", "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "semver": "^7.0.0" } }, - "node_modules/open": { - "version": "8.4.2", - "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", - "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "node_modules/npm/node_modules/cacache": { + "version": "18.0.2", + "inBundle": true, + "license": "ISC", "dependencies": { - "define-lazy-prop": "^2.0.0", - "is-docker": "^2.1.1", - "is-wsl": "^2.2.0" + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/openurl": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz", - "integrity": "sha512-d/gTkTb1i1GKz5k3XE3XFV/PxQ1k45zDqGP2OA7YhgsaLoqm6qRvARAZOFer1fcXritWlGBRCu/UgeS4HAnXAA==", - "dev": true - }, - "node_modules/opn": { + "node_modules/npm/node_modules/chalk": { "version": "5.3.0", - "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", - "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", - "dev": true, - "dependencies": { - "is-wsl": "^1.1.0" + "inBundle": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/npm/node_modules/chownr": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC", "engines": { - "node": ">=4" + "node": ">=10" } }, - "node_modules/opn/node_modules/is-wsl": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", - "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", - "dev": true, + "node_modules/npm/node_modules/ci-info": { + "version": "4.0.0", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "inBundle": true, + "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/optimist": { - "version": "0.6.1", - "dev": true, - "license": "MIT/X11", + "node_modules/npm/node_modules/cidr-regex": { + "version": "4.0.3", + "inBundle": true, + "license": "BSD-2-Clause", "dependencies": { - "minimist": "~0.0.1", - "wordwrap": "~0.0.2" + "ip-regex": "^5.0.0" + }, + "engines": { + "node": ">=14" } }, - "node_modules/optimist/node_modules/minimist": { - "version": "0.0.10", - "dev": true, - "license": "MIT" - }, - "node_modules/optimist/node_modules/wordwrap": { - "version": "0.0.3", - "dev": true, + "node_modules/npm/node_modules/clean-stack": { + "version": "2.2.0", + "inBundle": true, "license": "MIT", "engines": { - "node": ">=0.4.0" + "node": ">=6" } }, - "node_modules/optionator": { - "version": "0.9.3", - "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", - "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", - "dev": true, + "node_modules/npm/node_modules/cli-columns": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", "dependencies": { - "@aashutoshrathi/word-wrap": "^1.2.3", - "deep-is": "^0.1.3", - "fast-levenshtein": "^2.0.6", - "levn": "^0.4.1", - "prelude-ls": "^1.2.1", - "type-check": "^0.4.0" + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">= 0.8.0" + "node": ">= 10" } }, - "node_modules/ora": { - "version": "5.4.1", + "node_modules/npm/node_modules/cli-table3": { + "version": "0.6.3", + "inBundle": true, "license": "MIT", "dependencies": { - "bl": "^4.1.0", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-spinners": "^2.5.0", - "is-interactive": "^1.0.0", - "is-unicode-supported": "^0.1.0", - "log-symbols": "^4.1.0", - "strip-ansi": "^6.0.0", - "wcwidth": "^1.0.1" + "string-width": "^4.2.0" }, "engines": { - "node": ">=10" + "node": "10.* || >= 12.*" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "optionalDependencies": { + "@colors/colors": "1.5.0" } }, - "node_modules/ora/node_modules/ansi-styles": { - "version": "4.3.0", + "node_modules/npm/node_modules/clone": { + "version": "1.0.4", + "inBundle": true, "license": "MIT", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=0.8" } }, - "node_modules/ora/node_modules/chalk": { - "version": "4.1.2", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "node_modules/npm/node_modules/cmd-shim": { + "version": "6.0.2", + "inBundle": true, + "license": "ISC", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/ora/node_modules/color-convert": { + "node_modules/npm/node_modules/color-convert": { "version": "2.0.1", + "inBundle": true, "license": "MIT", "dependencies": { "color-name": "~1.1.4" @@ -19180,1149 +19632,1150 @@ "node": ">=7.0.0" } }, - "node_modules/ora/node_modules/color-name": { + "node_modules/npm/node_modules/color-name": { "version": "1.1.4", + "inBundle": true, "license": "MIT" }, - "node_modules/ora/node_modules/has-flag": { - "version": "4.0.0", - "license": "MIT", - "engines": { - "node": ">=8" + "node_modules/npm/node_modules/color-support": { + "version": "1.1.3", + "inBundle": true, + "license": "ISC", + "bin": { + "color-support": "bin.js" } }, - "node_modules/ora/node_modules/supports-color": { - "version": "7.2.0", + "node_modules/npm/node_modules/columnify": { + "version": "1.6.0", + "inBundle": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=8.0.0" } }, - "node_modules/ordered-ast-traverse": { - "version": "1.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "ordered-esprima-props": "~1.1.0" - } + "node_modules/npm/node_modules/common-ancestor-path": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC" }, - "node_modules/ordered-esprima-props": { + "node_modules/npm/node_modules/console-control-strings": { "version": "1.1.0", - "dev": true, - "license": "MIT" + "inBundle": true, + "license": "ISC" }, - "node_modules/os-homedir": { - "version": "1.0.2", - "dev": true, + "node_modules/npm/node_modules/cross-spawn": { + "version": "7.0.3", + "inBundle": true, "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/os-locale": { - "version": "1.4.0", - "license": "MIT", + "node_modules/npm/node_modules/cross-spawn/node_modules/which": { + "version": "2.0.2", + "inBundle": true, + "license": "ISC", "dependencies": { - "lcid": "^1.0.0" + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" }, "engines": { - "node": ">=0.10.0" + "node": ">= 8" } }, - "node_modules/os-tmpdir": { - "version": "1.0.2", + "node_modules/npm/node_modules/cssesc": { + "version": "3.0.0", + "inBundle": true, "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/osenv": { - "version": "0.1.5", - "dev": true, - "license": "ISC", - "dependencies": { - "os-homedir": "^1.0.0", - "os-tmpdir": "^1.0.0" + "node": ">=4" } }, - "node_modules/p-limit": { - "version": "3.1.0", - "dev": true, + "node_modules/npm/node_modules/debug": { + "version": "4.3.4", + "inBundle": true, "license": "MIT", "dependencies": { - "yocto-queue": "^0.1.0" + "ms": "2.1.2" }, "engines": { - "node": ">=10" + "node": ">=6.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } } }, - "node_modules/p-locate": { - "version": "5.0.0", - "dev": true, + "node_modules/npm/node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/defaults": { + "version": "1.0.4", + "inBundle": true, "license": "MIT", "dependencies": { - "p-limit": "^3.0.2" - }, - "engines": { - "node": ">=10" + "clone": "^1.0.2" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/p-map": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", - "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", - "dependencies": { - "aggregate-error": "^3.0.0" - }, + "node_modules/npm/node_modules/diff": { + "version": "5.1.0", + "inBundle": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.3.1" } }, - "node_modules/p-retry": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", - "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", - "dev": true, + "node_modules/npm/node_modules/eastasianwidth": { + "version": "0.2.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/emoji-regex": { + "version": "8.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/encoding": { + "version": "0.1.13", + "inBundle": true, + "license": "MIT", + "optional": true, "dependencies": { - "@types/retry": "0.12.0", - "retry": "^0.13.1" - }, - "engines": { - "node": ">=8" + "iconv-lite": "^0.6.2" } }, - "node_modules/p-retry/node_modules/retry": { - "version": "0.13.1", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", - "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", - "dev": true, + "node_modules/npm/node_modules/env-paths": { + "version": "2.2.1", + "inBundle": true, + "license": "MIT", "engines": { - "node": ">= 4" + "node": ">=6" } }, - "node_modules/p-try": { - "version": "2.2.0", - "dev": true, + "node_modules/npm/node_modules/err-code": { + "version": "2.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/exponential-backoff": { + "version": "3.1.1", + "inBundle": true, + "license": "Apache-2.0" + }, + "node_modules/npm/node_modules/fastest-levenshtein": { + "version": "1.0.16", + "inBundle": true, "license": "MIT", "engines": { - "node": ">=6" + "node": ">= 4.9.1" } }, - "node_modules/pacote": { - "version": "17.0.4", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.4.tgz", - "integrity": "sha512-eGdLHrV/g5b5MtD5cTPyss+JxOlaOloSMG3UwPMAvL8ywaLJ6beONPF40K4KKl/UI6q5hTKCJq5rCu8tkF+7Dg==", + "node_modules/npm/node_modules/foreground-child": { + "version": "3.1.1", + "inBundle": true, + "license": "ISC", "dependencies": { - "@npmcli/git": "^5.0.0", - "@npmcli/installed-package-contents": "^2.0.1", - "@npmcli/promise-spawn": "^7.0.0", - "@npmcli/run-script": "^7.0.0", - "cacache": "^18.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^7.0.2", - "npm-package-arg": "^11.0.0", - "npm-packlist": "^8.0.0", - "npm-pick-manifest": "^9.0.0", - "npm-registry-fetch": "^16.0.0", - "proc-log": "^3.0.0", - "promise-retry": "^2.0.1", - "read-package-json": "^7.0.0", - "read-package-json-fast": "^3.0.0", - "sigstore": "^2.0.0", - "ssri": "^10.0.0", - "tar": "^6.1.11" - }, - "bin": { - "pacote": "lib/bin.js" + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" }, "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true - }, - "node_modules/param-case": { - "version": "2.1.1", - "dev": true, - "license": "MIT", - "dependencies": { - "no-case": "^2.2.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/fs-minipass": { + "version": "3.0.3", + "inBundle": true, + "license": "ISC", "dependencies": { - "callsites": "^3.0.0" + "minipass": "^7.0.3" }, "engines": { - "node": ">=6" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/parse-filepath": { - "version": "1.0.2", - "dev": true, + "node_modules/npm/node_modules/function-bind": { + "version": "1.1.2", + "inBundle": true, "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/npm/node_modules/gauge": { + "version": "5.0.1", + "inBundle": true, + "license": "ISC", "dependencies": { - "is-absolute": "^1.0.0", - "map-cache": "^0.2.0", - "path-root": "^0.1.1" + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^4.0.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" }, "engines": { - "node": ">=0.8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/parse-json": { - "version": "5.2.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/glob": { + "version": "10.3.10", + "inBundle": true, + "license": "ISC", "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=8" + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/parse-node-version": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.10" - } + "node_modules/npm/node_modules/graceful-fs": { + "version": "4.2.11", + "inBundle": true, + "license": "ISC" }, - "node_modules/parse-passwd": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "node_modules/npm/node_modules/has-unicode": { + "version": "2.0.1", + "inBundle": true, + "license": "ISC" }, - "node_modules/parse5": { - "version": "7.1.2", - "devOptional": true, + "node_modules/npm/node_modules/hasown": { + "version": "2.0.0", + "inBundle": true, "license": "MIT", "dependencies": { - "entities": "^4.4.0" + "function-bind": "^1.1.2" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "engines": { + "node": ">= 0.4" } }, - "node_modules/parse5-html-rewriting-stream": { - "version": "7.0.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/hosted-git-info": { + "version": "7.0.1", + "inBundle": true, + "license": "ISC", "dependencies": { - "entities": "^4.3.0", - "parse5": "^7.0.0", - "parse5-sax-parser": "^7.0.0" + "lru-cache": "^10.0.1" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/parse5-sax-parser": { + "node_modules/npm/node_modules/http-cache-semantics": { + "version": "4.1.1", + "inBundle": true, + "license": "BSD-2-Clause" + }, + "node_modules/npm/node_modules/http-proxy-agent": { "version": "7.0.0", - "dev": true, + "inBundle": true, "license": "MIT", "dependencies": { - "parse5": "^7.0.0" + "agent-base": "^7.1.0", + "debug": "^4.3.4" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" + "engines": { + "node": ">= 14" } }, - "node_modules/parseurl": { - "version": "1.3.3", - "dev": true, + "node_modules/npm/node_modules/https-proxy-agent": { + "version": "7.0.2", + "inBundle": true, "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, "engines": { - "node": ">= 0.8" + "node": ">= 14" } }, - "node_modules/pascalcase": { - "version": "0.1.1", - "dev": true, + "node_modules/npm/node_modules/iconv-lite": { + "version": "0.6.3", + "inBundle": true, "license": "MIT", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/path-dirname": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/path-exists": { - "version": "4.0.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/ignore-walk": { + "version": "6.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minimatch": "^9.0.0" + }, "engines": { - "node": ">=8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "dev": true, + "node_modules/npm/node_modules/imurmurhash": { + "version": "0.1.4", + "inBundle": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=0.8.19" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "dev": true, - "license": "(WTFPL OR MIT)" - }, - "node_modules/path-key": { - "version": "3.1.1", + "node_modules/npm/node_modules/indent-string": { + "version": "4.0.0", + "inBundle": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "license": "MIT" + "node_modules/npm/node_modules/ini": { + "version": "4.1.1", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } }, - "node_modules/path-root": { - "version": "0.1.1", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/init-package-json": { + "version": "6.0.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "path-root-regex": "^0.1.0" + "npm-package-arg": "^11.0.0", + "promzard": "^1.0.0", + "read": "^2.0.0", + "read-package-json": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/path-root-regex": { - "version": "0.1.2", - "dev": true, + "node_modules/npm/node_modules/ip": { + "version": "2.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/ip-regex": { + "version": "5.0.0", + "inBundle": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/path-scurry": { - "version": "1.10.1", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", - "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "node_modules/npm/node_modules/is-cidr": { + "version": "5.0.3", + "inBundle": true, + "license": "BSD-2-Clause", "dependencies": { - "lru-cache": "^9.1.1 || ^10.0.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + "cidr-regex": "4.0.3" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=14" } }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", - "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", - "engines": { - "node": "14 || >=16.14" + "node_modules/npm/node_modules/is-core-module": { + "version": "2.13.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", - "dev": true - }, - "node_modules/path-type": { - "version": "4.0.0", - "dev": true, + "node_modules/npm/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "inBundle": true, "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/pdfjs-dist": { - "version": "2.16.105", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.16.105.tgz", - "integrity": "sha512-J4dn41spsAwUxCpEoVf6GVoz908IAA3mYiLmNxg8J9kfRXc2jxpbUepcP0ocp0alVNLFthTAM8DZ1RaHh8sU0A==", - "dependencies": { - "dommatrix": "^1.0.3", - "web-streams-polyfill": "^3.2.1" - }, - "peerDependencies": { - "worker-loader": "^3.0.8" - }, - "peerDependenciesMeta": { - "worker-loader": { - "optional": true - } - } - }, - "node_modules/performance-now": { - "version": "2.1.0", - "dev": true, + "node_modules/npm/node_modules/is-lambda": { + "version": "1.0.1", + "inBundle": true, "license": "MIT" }, - "node_modules/picocolors": { - "version": "1.0.0", - "dev": true, + "node_modules/npm/node_modules/isexe": { + "version": "2.0.0", + "inBundle": true, "license": "ISC" }, - "node_modules/picomatch": { - "version": "2.3.1", - "devOptional": true, - "license": "MIT", + "node_modules/npm/node_modules/jackspeak": { + "version": "2.3.6", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, "engines": { - "node": ">=8.6" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/pidtree": { - "version": "0.3.1", - "dev": true, - "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" + "url": "https://github.com/sponsors/isaacs" }, - "engines": { - "node": ">=0.10" + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" } }, - "node_modules/pify": { - "version": "2.3.0", - "dev": true, + "node_modules/npm/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "inBundle": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/pinkie": { - "version": "2.0.4", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" + "node_modules/npm/node_modules/json-stringify-nice": { + "version": "1.1.4", + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "pinkie": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } + "node_modules/npm/node_modules/jsonparse": { + "version": "1.3.1", + "engines": [ + "node >= 0.2.0" + ], + "inBundle": true, + "license": "MIT" }, - "node_modules/pirates": { - "version": "4.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } + "node_modules/npm/node_modules/just-diff": { + "version": "6.0.2", + "inBundle": true, + "license": "MIT" }, - "node_modules/piscina": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.1.0.tgz", - "integrity": "sha512-sjbLMi3sokkie+qmtZpkfMCUJTpbxJm/wvaPzU28vmYSsTSW8xk9JcFUsbqGJdtPpIQ9tuj+iDcTtgZjwnOSig==", - "dev": true, + "node_modules/npm/node_modules/just-diff-apply": { + "version": "5.5.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/libnpmaccess": { + "version": "8.0.2", + "inBundle": true, + "license": "ISC", "dependencies": { - "eventemitter-asyncresource": "^1.0.0", - "hdr-histogram-js": "^2.0.1", - "hdr-histogram-percentiles-obj": "^3.0.0" + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0" }, - "optionalDependencies": { - "nice-napi": "^1.0.2" + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pkg-dir": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", - "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", - "dev": true, + "node_modules/npm/node_modules/libnpmdiff": { + "version": "6.0.6", + "inBundle": true, + "license": "ISC", "dependencies": { - "find-up": "^6.3.0" + "@npmcli/arborist": "^7.2.1", + "@npmcli/disparity-colors": "^3.0.0", + "@npmcli/installed-package-contents": "^2.0.2", + "binary-extensions": "^2.2.0", + "diff": "^5.1.0", + "minimatch": "^9.0.0", + "npm-package-arg": "^11.0.1", + "pacote": "^17.0.4", + "tar": "^6.2.0" }, "engines": { - "node": ">=14.16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pkg-dir/node_modules/find-up": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", - "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", - "dev": true, + "node_modules/npm/node_modules/libnpmexec": { + "version": "7.0.7", + "inBundle": true, + "license": "ISC", "dependencies": { - "locate-path": "^7.1.0", - "path-exists": "^5.0.0" + "@npmcli/arborist": "^7.2.1", + "@npmcli/run-script": "^7.0.2", + "ci-info": "^4.0.0", + "npm-package-arg": "^11.0.1", + "npmlog": "^7.0.1", + "pacote": "^17.0.4", + "proc-log": "^3.0.0", + "read": "^2.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "walk-up-path": "^3.0.1" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pkg-dir/node_modules/locate-path": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", - "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", - "dev": true, + "node_modules/npm/node_modules/libnpmfund": { + "version": "5.0.4", + "inBundle": true, + "license": "ISC", "dependencies": { - "p-locate": "^6.0.0" + "@npmcli/arborist": "^7.2.1" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pkg-dir/node_modules/p-limit": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", - "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", - "dev": true, + "node_modules/npm/node_modules/libnpmhook": { + "version": "10.0.1", + "inBundle": true, + "license": "ISC", "dependencies": { - "yocto-queue": "^1.0.0" + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pkg-dir/node_modules/p-locate": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", - "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", - "dev": true, + "node_modules/npm/node_modules/libnpmorg": { + "version": "6.0.2", + "inBundle": true, + "license": "ISC", "dependencies": { - "p-limit": "^4.0.0" + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pkg-dir/node_modules/path-exists": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", - "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", - "dev": true, + "node_modules/npm/node_modules/libnpmpack": { + "version": "6.0.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/run-script": "^7.0.2", + "npm-package-arg": "^11.0.1", + "pacote": "^17.0.4" + }, "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pkg-dir/node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", - "dev": true, - "engines": { - "node": ">=12.20" + "node_modules/npm/node_modules/libnpmpublish": { + "version": "9.0.4", + "inBundle": true, + "license": "ISC", + "dependencies": { + "ci-info": "^4.0.0", + "normalize-package-data": "^6.0.0", + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7", + "sigstore": "^2.2.0", + "ssri": "^10.0.5" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pkg-up": { - "version": "3.1.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/libnpmsearch": { + "version": "7.0.1", + "inBundle": true, + "license": "ISC", "dependencies": { - "find-up": "^3.0.0" + "npm-registry-fetch": "^16.0.0" }, "engines": { - "node": ">=8" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pkg-up/node_modules/find-up": { - "version": "3.0.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/libnpmteam": { + "version": "6.0.1", + "inBundle": true, + "license": "ISC", "dependencies": { - "locate-path": "^3.0.0" + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" }, "engines": { - "node": ">=6" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pkg-up/node_modules/locate-path": { - "version": "3.0.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/libnpmversion": { + "version": "5.0.2", + "inBundle": true, + "license": "ISC", "dependencies": { - "p-locate": "^3.0.0", - "path-exists": "^3.0.0" + "@npmcli/git": "^5.0.3", + "@npmcli/run-script": "^7.0.2", + "json-parse-even-better-errors": "^3.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7" }, "engines": { - "node": ">=6" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pkg-up/node_modules/p-limit": { - "version": "2.3.0", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, + "node_modules/npm/node_modules/lru-cache": { + "version": "10.1.0", + "inBundle": true, + "license": "ISC", "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "14 || >=16.14" } }, - "node_modules/pkg-up/node_modules/p-locate": { - "version": "3.0.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/make-fetch-happen": { + "version": "13.0.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "p-limit": "^2.0.0" + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" }, "engines": { - "node": ">=6" - } - }, - "node_modules/pkg-up/node_modules/path-exists": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/portscanner": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.2.0.tgz", - "integrity": "sha512-IFroCz/59Lqa2uBvzK3bKDbDDIEaAY8XJ1jFxcLWTqosrsc32//P4VuSB2vZXoHiHqOmx8B5L5hnKOxL/7FlPw==", - "dev": true, + "node_modules/npm/node_modules/minimatch": { + "version": "9.0.3", + "inBundle": true, + "license": "ISC", "dependencies": { - "async": "^2.6.0", - "is-number-like": "^1.0.3" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=0.4", - "npm": ">=1.0.0" - } - }, - "node_modules/portscanner/node_modules/async": { - "version": "2.6.4", - "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", - "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", - "dev": true, - "dependencies": { - "lodash": "^4.17.14" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/posix-character-classes": { - "version": "0.1.1", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/minipass": { + "version": "7.0.4", + "inBundle": true, + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/postcss": { - "version": "8.4.31", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", - "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/npm/node_modules/minipass-collect": { + "version": "2.0.1", + "inBundle": true, + "license": "ISC", "dependencies": { - "nanoid": "^3.3.6", - "picocolors": "^1.0.0", - "source-map-js": "^1.0.2" + "minipass": "^7.0.3" }, "engines": { - "node": "^10 || ^12 || >=14" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/postcss-import": { - "version": "15.1.0", - "dev": true, + "node_modules/npm/node_modules/minipass-fetch": { + "version": "3.0.4", + "inBundle": true, "license": "MIT", "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" }, "engines": { - "node": ">=14.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" }, - "peerDependencies": { - "postcss": "^8.0.0" + "optionalDependencies": { + "encoding": "^0.1.13" } }, - "node_modules/postcss-js": { - "version": "4.0.1", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/minipass-flush": { + "version": "1.0.5", + "inBundle": true, + "license": "ISC", "dependencies": { - "camelcase-css": "^2.0.1" + "minipass": "^3.0.0" }, "engines": { - "node": "^12 || ^14 || >= 16" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.4.21" + "node": ">= 8" } }, - "node_modules/postcss-load-config": { - "version": "4.0.1", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "inBundle": true, + "license": "ISC", "dependencies": { - "lilconfig": "^2.0.5", - "yaml": "^2.1.1" + "yallist": "^4.0.0" }, "engines": { - "node": ">= 14" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": ">=8.0.9", - "ts-node": ">=9.0.0" - }, - "peerDependenciesMeta": { - "postcss": { - "optional": true - }, - "ts-node": { - "optional": true - } + "node": ">=8" } }, - "node_modules/postcss-load-config/node_modules/yaml": { - "version": "2.2.2", - "dev": true, - "license": "ISC", - "engines": { - "node": ">= 14" + "node_modules/npm/node_modules/minipass-json-stream": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" } }, - "node_modules/postcss-loader": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", - "integrity": "sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==", - "dev": true, + "node_modules/npm/node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "inBundle": true, + "license": "ISC", "dependencies": { - "cosmiconfig": "^8.2.0", - "jiti": "^1.18.2", - "semver": "^7.3.8" + "yallist": "^4.0.0" }, "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "postcss": "^7.0.0 || ^8.0.1", - "webpack": "^5.0.0" + "node": ">=8" } }, - "node_modules/postcss-loader/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, - "node_modules/postcss-loader/node_modules/cosmiconfig": { - "version": "8.2.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", - "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", - "dev": true, + "node_modules/npm/node_modules/minipass-pipeline": { + "version": "1.2.4", + "inBundle": true, + "license": "ISC", "dependencies": { - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "parse-json": "^5.0.0", - "path-type": "^4.0.0" + "minipass": "^3.0.0" }, "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/d-fischer" + "node": ">=8" } }, - "node_modules/postcss-loader/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, + "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "inBundle": true, + "license": "ISC", "dependencies": { - "argparse": "^2.0.1" + "yallist": "^4.0.0" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=8" } }, - "node_modules/postcss-modules-extract-imports": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", - "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "engines": { - "node": "^10 || ^12 || >= 14" + "node_modules/npm/node_modules/minipass-sized": { + "version": "1.0.3", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^3.0.0" }, - "peerDependencies": { - "postcss": "^8.1.0" + "engines": { + "node": ">=8" } }, - "node_modules/postcss-modules-local-by-default": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", - "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", - "dev": true, + "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "inBundle": true, + "license": "ISC", "dependencies": { - "icss-utils": "^5.0.0", - "postcss-selector-parser": "^6.0.2", - "postcss-value-parser": "^4.1.0" + "yallist": "^4.0.0" }, "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=8" } }, - "node_modules/postcss-modules-scope": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", - "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", - "dev": true, + "node_modules/npm/node_modules/minizlib": { + "version": "2.1.2", + "inBundle": true, + "license": "MIT", "dependencies": { - "postcss-selector-parser": "^6.0.4" + "minipass": "^3.0.0", + "yallist": "^4.0.0" }, "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">= 8" } }, - "node_modules/postcss-modules-values": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", - "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", - "dev": true, + "node_modules/npm/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "inBundle": true, + "license": "ISC", "dependencies": { - "icss-utils": "^5.0.0" + "yallist": "^4.0.0" }, "engines": { - "node": "^10 || ^12 || >= 14" - }, - "peerDependencies": { - "postcss": "^8.1.0" + "node": ">=8" } }, - "node_modules/postcss-nested": { - "version": "6.0.1", - "dev": true, + "node_modules/npm/node_modules/mkdirp": { + "version": "1.0.4", + "inBundle": true, "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.0.11" + "bin": { + "mkdirp": "bin/cmd.js" }, "engines": { - "node": ">=12.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - "peerDependencies": { - "postcss": "^8.2.14" + "node": ">=10" } }, - "node_modules/postcss-scss": { - "version": "0.1.9", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss": "^5.1.0" + "node_modules/npm/node_modules/ms": { + "version": "2.1.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/mute-stream": { + "version": "1.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/postcss-scss/node_modules/ansi-regex": { - "version": "2.1.1", - "dev": true, + "node_modules/npm/node_modules/negotiator": { + "version": "0.6.3", + "inBundle": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/postcss-scss/node_modules/ansi-styles": { - "version": "2.2.1", - "dev": true, + "node_modules/npm/node_modules/node-gyp": { + "version": "10.0.1", + "inBundle": true, "license": "MIT", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/postcss-scss/node_modules/chalk": { - "version": "1.1.3", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/nopt": { + "version": "7.2.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" }, "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/postcss-scss/node_modules/chalk/node_modules/supports-color": { - "version": "2.0.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/normalize-package-data": { + "version": "6.0.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, "engines": { - "node": ">=0.8.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/postcss-scss/node_modules/has-flag": { - "version": "1.0.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/npm-audit-report": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/postcss-scss/node_modules/postcss": { - "version": "5.2.18", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/npm-bundled": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "chalk": "^1.1.3", - "js-base64": "^2.1.9", - "source-map": "^0.5.6", - "supports-color": "^3.2.3" + "npm-normalize-package-bin": "^3.0.0" }, "engines": { - "node": ">=0.12" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/postcss-scss/node_modules/source-map": { - "version": "0.5.7", - "dev": true, - "license": "BSD-3-Clause", + "node_modules/npm/node_modules/npm-install-checks": { + "version": "6.3.0", + "inBundle": true, + "license": "BSD-2-Clause", + "dependencies": { + "semver": "^7.1.1" + }, "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/postcss-scss/node_modules/strip-ansi": { + "node_modules/npm/node_modules/npm-normalize-package-bin": { "version": "3.0.1", - "dev": true, - "license": "MIT", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/npm-package-arg": { + "version": "11.0.1", + "inBundle": true, + "license": "ISC", "dependencies": { - "ansi-regex": "^2.0.0" + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/postcss-scss/node_modules/supports-color": { - "version": "3.2.3", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/npm-packlist": { + "version": "8.0.2", + "inBundle": true, + "license": "ISC", "dependencies": { - "has-flag": "^1.0.0" + "ignore-walk": "^6.0.4" }, "engines": { - "node": ">=0.8.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/postcss-selector-parser": { - "version": "6.0.11", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/npm-pick-manifest": { + "version": "9.0.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" }, "engines": { - "node": ">=4" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", - "dev": true - }, - "node_modules/prelude-ls": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", - "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, + "node_modules/npm/node_modules/npm-profile": { + "version": "9.0.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0" + }, "engines": { - "node": ">= 0.8.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/preprocess": { - "version": "3.2.0", - "dev": true, + "node_modules/npm/node_modules/npm-registry-fetch": { + "version": "16.1.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "xregexp": "3.1.0" + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" }, "engines": { - "node": ">= 0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/prettier": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", - "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", - "dev": true, - "bin": { - "prettier": "bin/prettier.cjs" - }, + "node_modules/npm/node_modules/npm-user-validate": { + "version": "2.0.0", + "inBundle": true, + "license": "BSD-2-Clause", "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/npmlog": { + "version": "7.0.1", + "inBundle": true, + "license": "ISC", "dependencies": { - "fast-diff": "^1.1.2" + "are-we-there-yet": "^4.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^5.0.0", + "set-blocking": "^2.0.0" }, "engines": { - "node": ">=6.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/pretty-bytes": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", - "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", - "dev": true, + "node_modules/npm/node_modules/p-map": { + "version": "4.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "aggregate-error": "^3.0.0" + }, "engines": { - "node": ">=6" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, + "node_modules/npm/node_modules/pacote": { + "version": "17.0.6", + "inBundle": true, + "license": "ISC", "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" }, "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, + "node_modules/npm/node_modules/parse-conflict-json": { + "version": "3.0.1", + "inBundle": true, + "license": "ISC", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" + }, "engines": { - "node": ">=10" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/path-key": { + "version": "3.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/path-scurry": { + "version": "1.10.1", + "inBundle": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/proc-log": { + "node_modules/npm/node_modules/postcss-selector-parser": { + "version": "6.0.15", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/npm/node_modules/proc-log": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", - "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "inBundle": true, + "license": "ISC", "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/process-nextick-args": { - "version": "2.0.1", - "dev": true, - "license": "MIT" + "node_modules/npm/node_modules/promise-all-reject-late": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" + } }, - "node_modules/promise": { - "version": "7.3.1", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "asap": "~2.0.3" + "node_modules/npm/node_modules/promise-call-limit": { + "version": "3.0.1", + "inBundle": true, + "license": "ISC", + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/promise-inflight": { + "node_modules/npm/node_modules/promise-inflight": { "version": "1.0.1", - "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", - "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" + "inBundle": true, + "license": "ISC" }, - "node_modules/promise-retry": { + "node_modules/npm/node_modules/promise-retry": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "inBundle": true, + "license": "MIT", "dependencies": { "err-code": "^2.0.2", "retry": "^0.12.0" @@ -20331,260 +20784,275 @@ "node": ">=10" } }, - "node_modules/protractor": { - "version": "7.0.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/promzard": { + "version": "1.0.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "@types/q": "^0.0.32", - "@types/selenium-webdriver": "^3.0.0", - "blocking-proxy": "^1.0.0", - "browserstack": "^1.5.1", - "chalk": "^1.1.3", - "glob": "^7.0.3", - "jasmine": "2.8.0", - "jasminewd2": "^2.1.0", - "q": "1.4.1", - "saucelabs": "^1.5.0", - "selenium-webdriver": "3.6.0", - "source-map-support": "~0.4.0", - "webdriver-js-extender": "2.1.0", - "webdriver-manager": "^12.1.7", - "yargs": "^15.3.1" - }, - "bin": { - "protractor": "bin/protractor", - "webdriver-manager": "bin/webdriver-manager" + "read": "^2.0.0" }, "engines": { - "node": ">=10.13.x" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/protractor/node_modules/ansi-regex": { - "version": "2.1.1", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/qrcode-terminal": { + "version": "0.12.0", + "inBundle": true, + "bin": { + "qrcode-terminal": "bin/qrcode-terminal.js" + } + }, + "node_modules/npm/node_modules/read": { + "version": "2.1.0", + "inBundle": true, + "license": "ISC", + "dependencies": { + "mute-stream": "~1.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/protractor/node_modules/ansi-styles": { - "version": "2.2.1", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/read-cmd-shim": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/protractor/node_modules/chalk": { - "version": "1.1.3", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/read-package-json": { + "version": "7.0.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/protractor/node_modules/cliui": { - "version": "6.0.0", - "dev": true, + "node_modules/npm/node_modules/read-package-json-fast": { + "version": "3.0.2", + "inBundle": true, "license": "ISC", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, + "node_modules/npm/node_modules/retry": { + "version": "0.12.0", + "inBundle": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 4" } }, - "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "dev": true, + "node_modules/npm/node_modules/safer-buffer": { + "version": "2.1.2", + "inBundle": true, "license": "MIT", + "optional": true + }, + "node_modules/npm/node_modules/semver": { + "version": "7.5.4", + "inBundle": true, + "license": "ISC", "dependencies": { - "ansi-regex": "^5.0.1" + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/protractor/node_modules/color-convert": { - "version": "2.0.1", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "color-name": "~1.1.4" + "yallist": "^4.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=10" } }, - "node_modules/protractor/node_modules/color-name": { - "version": "1.1.4", - "dev": true, - "license": "MIT" + "node_modules/npm/node_modules/set-blocking": { + "version": "2.0.0", + "inBundle": true, + "license": "ISC" }, - "node_modules/protractor/node_modules/find-up": { - "version": "4.1.0", - "dev": true, + "node_modules/npm/node_modules/shebang-command": { + "version": "2.0.0", + "inBundle": true, "license": "MIT", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "shebang-regex": "^3.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/protractor/node_modules/glob": { - "version": "7.2.3", - "dev": true, + "node_modules/npm/node_modules/shebang-regex": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/npm/node_modules/signal-exit": { + "version": "4.1.0", + "inBundle": true, "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, "engines": { - "node": "*" + "node": ">=14" }, "funding": { "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/protractor/node_modules/locate-path": { - "version": "5.0.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/sigstore": { + "version": "2.2.0", + "inBundle": true, + "license": "Apache-2.0", "dependencies": { - "p-locate": "^4.1.0" + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", + "@sigstore/protobuf-specs": "^0.2.1", + "@sigstore/sign": "^2.2.1", + "@sigstore/tuf": "^2.3.0", + "@sigstore/verify": "^0.1.0" }, "engines": { - "node": ">=8" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/protractor/node_modules/p-limit": { - "version": "2.3.0", - "dev": true, + "node_modules/npm/node_modules/smart-buffer": { + "version": "4.2.0", + "inBundle": true, "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 6.0.0", + "npm": ">= 3.0.0" } }, - "node_modules/protractor/node_modules/p-locate": { - "version": "4.1.0", - "dev": true, + "node_modules/npm/node_modules/socks": { + "version": "2.7.1", + "inBundle": true, "license": "MIT", "dependencies": { - "p-limit": "^2.2.0" + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" }, "engines": { - "node": ">=8" + "node": ">= 10.13.0", + "npm": ">= 3.0.0" } }, - "node_modules/protractor/node_modules/q": { - "version": "1.4.1", - "dev": true, + "node_modules/npm/node_modules/socks-proxy-agent": { + "version": "8.0.2", + "inBundle": true, "license": "MIT", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } - }, - "node_modules/protractor/node_modules/source-map": { - "version": "0.5.7", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" + "node": ">= 14" } }, - "node_modules/protractor/node_modules/source-map-support": { - "version": "0.4.18", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/spdx-correct": { + "version": "3.2.0", + "inBundle": true, + "license": "Apache-2.0", "dependencies": { - "source-map": "^0.5.6" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/protractor/node_modules/strip-ansi": { + "node_modules/npm/node_modules/spdx-exceptions": { + "version": "2.3.0", + "inBundle": true, + "license": "CC-BY-3.0" + }, + "node_modules/npm/node_modules/spdx-expression-parse": { "version": "3.0.1", - "dev": true, + "inBundle": true, "license": "MIT", "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "node_modules/protractor/node_modules/supports-color": { - "version": "2.0.0", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/spdx-license-ids": { + "version": "3.0.16", + "inBundle": true, + "license": "CC0-1.0" + }, + "node_modules/npm/node_modules/ssri": { + "version": "10.0.5", + "inBundle": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.3" + }, "engines": { - "node": ">=0.8.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/protractor/node_modules/wrap-ansi": { - "version": "6.2.0", - "dev": true, + "node_modules/npm/node_modules/string-width": { + "version": "4.2.3", + "inBundle": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { "node": ">=8" } }, - "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "5.0.1", - "dev": true, + "node_modules/npm/node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "inBundle": true, "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, "engines": { "node": ">=8" } }, - "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "dev": true, + "node_modules/npm/node_modules/strip-ansi": { + "version": "6.0.1", + "inBundle": true, "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "ansi-regex": "^5.0.1" }, "engines": { "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/protractor/node_modules/wrap-ansi/node_modules/strip-ansi": { + "node_modules/npm/node_modules/strip-ansi-cjs": { + "name": "strip-ansi", "version": "6.0.1", - "dev": true, + "inBundle": true, "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" @@ -20593,2403 +21061,2160 @@ "node": ">=8" } }, - "node_modules/protractor/node_modules/y18n": { - "version": "4.0.3", - "dev": true, - "license": "ISC" - }, - "node_modules/protractor/node_modules/yargs": { - "version": "15.4.1", - "dev": true, + "node_modules/npm/node_modules/supports-color": { + "version": "9.4.0", + "inBundle": true, "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/npm/node_modules/tar": { + "version": "6.2.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/protractor/node_modules/yargs-parser": { - "version": "18.1.3", - "dev": true, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "inBundle": true, "license": "ISC", "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" + "minipass": "^3.0.0" }, "engines": { - "node": ">=6" + "node": ">= 8" } }, - "node_modules/proxy-addr": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", - "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", - "dev": true, + "node_modules/npm/node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "inBundle": true, + "license": "ISC", "dependencies": { - "forwarded": "0.2.0", - "ipaddr.js": "1.9.1" + "yallist": "^4.0.0" }, "engines": { - "node": ">= 0.10" + "node": ">=8" } }, - "node_modules/proxy-addr/node_modules/ipaddr.js": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", - "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", - "dev": true, + "node_modules/npm/node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", "engines": { - "node": ">= 0.10" + "node": ">=8" } }, - "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true - }, - "node_modules/prr": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "optional": true + "node_modules/npm/node_modules/text-table": { + "version": "0.2.0", + "inBundle": true, + "license": "MIT" }, - "node_modules/psl": { - "version": "1.9.0", - "dev": true, + "node_modules/npm/node_modules/tiny-relative-date": { + "version": "1.3.0", + "inBundle": true, "license": "MIT" }, - "node_modules/pug": { - "version": "2.0.4", - "dev": true, + "node_modules/npm/node_modules/treeverse": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm/node_modules/tuf-js": { + "version": "2.2.0", + "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { - "pug-code-gen": "^2.0.2", - "pug-filters": "^3.1.1", - "pug-lexer": "^4.1.0", - "pug-linker": "^3.0.6", - "pug-load": "^2.0.12", - "pug-parser": "^5.0.1", - "pug-runtime": "^2.0.5", - "pug-strip-comments": "^1.0.4" + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/pug-attrs": { - "version": "2.0.4", - "dev": true, - "license": "MIT", - "optional": true, + "node_modules/npm/node_modules/unique-filename": { + "version": "3.0.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "constantinople": "^3.0.1", - "js-stringify": "^1.0.1", - "pug-runtime": "^2.0.5" + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/pug-code-gen": { - "version": "2.0.3", - "dev": true, - "license": "MIT", - "optional": true, + "node_modules/npm/node_modules/unique-slug": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "constantinople": "^3.1.2", - "doctypes": "^1.1.0", - "js-stringify": "^1.0.1", - "pug-attrs": "^2.0.4", - "pug-error": "^1.3.3", - "pug-runtime": "^2.0.5", - "void-elements": "^2.0.1", - "with": "^5.0.0" + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/pug-error": { - "version": "1.3.3", - "dev": true, - "license": "MIT", - "optional": true + "node_modules/npm/node_modules/util-deprecate": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" }, - "node_modules/pug-filters": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "optional": true, + "node_modules/npm/node_modules/validate-npm-package-license": { + "version": "3.0.4", + "inBundle": true, + "license": "Apache-2.0", "dependencies": { - "clean-css": "^4.1.11", - "constantinople": "^3.0.1", - "jstransformer": "1.0.0", - "pug-error": "^1.3.3", - "pug-walk": "^1.1.8", - "resolve": "^1.1.6", - "uglify-js": "^2.6.1" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, - "node_modules/pug-lexer": { - "version": "4.1.0", - "dev": true, - "license": "MIT", - "optional": true, + "node_modules/npm/node_modules/validate-npm-package-name": { + "version": "5.0.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "character-parser": "^2.1.1", - "is-expression": "^3.0.0", - "pug-error": "^1.3.3" + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/pug-linker": { - "version": "3.0.6", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "pug-error": "^1.3.3", - "pug-walk": "^1.1.8" - } + "node_modules/npm/node_modules/walk-up-path": { + "version": "3.0.1", + "inBundle": true, + "license": "ISC" }, - "node_modules/pug-load": { - "version": "2.0.12", - "dev": true, + "node_modules/npm/node_modules/wcwidth": { + "version": "1.0.1", + "inBundle": true, "license": "MIT", - "optional": true, "dependencies": { - "object-assign": "^4.1.0", - "pug-walk": "^1.1.8" + "defaults": "^1.0.3" } }, - "node_modules/pug-parser": { - "version": "5.0.1", - "dev": true, - "license": "MIT", - "optional": true, + "node_modules/npm/node_modules/which": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC", "dependencies": { - "pug-error": "^1.3.3", - "token-stream": "0.0.1" + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" } }, - "node_modules/pug-runtime": { - "version": "2.0.5", - "dev": true, - "license": "MIT", - "optional": true + "node_modules/npm/node_modules/which/node_modules/isexe": { + "version": "3.1.1", + "inBundle": true, + "license": "ISC", + "engines": { + "node": ">=16" + } }, - "node_modules/pug-strip-comments": { - "version": "1.0.4", - "dev": true, - "license": "MIT", - "optional": true, + "node_modules/npm/node_modules/wide-align": { + "version": "1.1.5", + "inBundle": true, + "license": "ISC", "dependencies": { - "pug-error": "^1.3.3" + "string-width": "^1.0.2 || 2 || 3 || 4" } }, - "node_modules/pug-walk": { - "version": "1.1.8", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/punycode": { - "version": "2.3.0", + "node_modules/npm/node_modules/wrap-ansi": { + "version": "8.1.0", + "inBundle": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, "engines": { - "node": ">=6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/q": { - "version": "1.5.1", - "dev": true, + "node_modules/npm/node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "inBundle": true, "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/qjobs": { - "version": "1.2.0", - "dev": true, + "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "inBundle": true, "license": "MIT", - "engines": { - "node": ">=0.9" - } - }, - "node_modules/qs": { - "version": "6.11.1", - "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "side-channel": "^1.0.4" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=0.6" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/queue-microtask": { - "version": "1.2.3", - "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT" - }, - "node_modules/quick-lru": { - "version": "4.0.1", - "dev": true, + "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "inBundle": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/randombytes": { - "version": "2.1.0", - "dev": true, + "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "inBundle": true, "license": "MIT", "dependencies": { - "safe-buffer": "^5.1.0" + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/range-parser": { - "version": "1.2.1", - "dev": true, + "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "inBundle": true, "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, "engines": { - "node": ">= 0.6" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/raw-body": { - "version": "2.5.2", - "dev": true, - "license": "MIT", + "node_modules/npm/node_modules/write-file-atomic": { + "version": "5.0.1", + "inBundle": true, + "license": "ISC", "dependencies": { - "bytes": "3.1.2", - "http-errors": "2.0.0", - "iconv-lite": "0.4.24", - "unpipe": "1.0.0" + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">= 0.8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.4.24", + "node_modules/npm/node_modules/yallist": { + "version": "4.0.0", + "inBundle": true, + "license": "ISC" + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", "dev": true, - "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" + "boolbase": "^1.0.0" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/react-is": { - "version": "18.2.0", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", - "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "node_modules/num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==", "dev": true }, - "node_modules/read-cache": { - "version": "1.0.0", - "dev": true, + "node_modules/number-is-nan": { + "version": "1.0.1", "license": "MIT", - "dependencies": { - "pify": "^2.3.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/read-package-json": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz", - "integrity": "sha512-uL4Z10OKV4p6vbdvIXB+OzhInYtIozl/VxUBPgNkBuUi2DeRonnuspmaVAMcrkmfjKGNmRndyQAbE7/AmzGwFg==", - "dependencies": { - "glob": "^10.2.2", - "json-parse-even-better-errors": "^3.0.0", - "normalize-package-data": "^6.0.0", - "npm-normalize-package-bin": "^3.0.0" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" + "node_modules/nvd3": { + "version": "1.8.6", + "license": "Apache-2.0", + "peerDependencies": { + "d3": "^3.4.4" } }, - "node_modules/read-package-json-fast": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", - "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "node_modules/nx": { + "version": "17.0.3", + "resolved": "https://registry.npmjs.org/nx/-/nx-17.0.3.tgz", + "integrity": "sha512-VShJISKCYt3iVJoMUPZiv67+0tiItxWMnfVmTmPZPio2Fu+wGc9U4ijjPxcmp2RJmLRaxkB9cn5rlrAvkIrNMA==", + "dev": true, + "hasInstallScript": true, "dependencies": { - "json-parse-even-better-errors": "^3.0.0", - "npm-normalize-package-bin": "^3.0.0" + "@nrwl/tao": "17.0.3", + "@yarnpkg/lockfile": "^1.1.0", + "@yarnpkg/parsers": "3.0.0-rc.46", + "@zkochan/js-yaml": "0.0.6", + "axios": "^1.5.1", + "chalk": "^4.1.0", + "cli-cursor": "3.1.0", + "cli-spinners": "2.6.1", + "cliui": "^8.0.1", + "dotenv": "~16.3.1", + "dotenv-expand": "~10.0.0", + "enquirer": "~2.3.6", + "figures": "3.2.0", + "flat": "^5.0.2", + "fs-extra": "^11.1.0", + "glob": "7.1.4", + "ignore": "^5.0.4", + "jest-diff": "^29.4.1", + "js-yaml": "4.1.0", + "jsonc-parser": "3.2.0", + "lines-and-columns": "~2.0.3", + "minimatch": "3.0.5", + "node-machine-id": "1.1.12", + "npm-run-path": "^4.0.1", + "open": "^8.4.0", + "semver": "7.5.3", + "string-width": "^4.2.3", + "strong-log-transformer": "^2.1.0", + "tar-stream": "~2.2.0", + "tmp": "~0.2.1", + "tsconfig-paths": "^4.1.2", + "tslib": "^2.3.0", + "v8-compile-cache": "2.3.0", + "yargs": "^17.6.2", + "yargs-parser": "21.1.1" }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "bin": { + "nx": "bin/nx.js", + "nx-cloud": "bin/nx-cloud.js" + }, + "optionalDependencies": { + "@nx/nx-darwin-arm64": "17.0.3", + "@nx/nx-darwin-x64": "17.0.3", + "@nx/nx-freebsd-x64": "17.0.3", + "@nx/nx-linux-arm-gnueabihf": "17.0.3", + "@nx/nx-linux-arm64-gnu": "17.0.3", + "@nx/nx-linux-arm64-musl": "17.0.3", + "@nx/nx-linux-x64-gnu": "17.0.3", + "@nx/nx-linux-x64-musl": "17.0.3", + "@nx/nx-win32-arm64-msvc": "17.0.3", + "@nx/nx-win32-x64-msvc": "17.0.3" + }, + "peerDependencies": { + "@swc-node/register": "^1.6.7", + "@swc/core": "^1.3.85" + }, + "peerDependenciesMeta": { + "@swc-node/register": { + "optional": true + }, + "@swc/core": { + "optional": true + } } }, - "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", - "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "node_modules/nx/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/read-package-json/node_modules/brace-expansion": { + "node_modules/nx/node_modules/argparse": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/nx/node_modules/axios": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.1.tgz", + "integrity": "sha512-vfBmhDpKafglh0EldBEbVuoe7DyAavGSLWhuSm5ZSEKQnHhBf0xAAwybbNH1IkrJNGnS/VG4I5yxig1pCEXE4g==", + "dev": true, "dependencies": { - "balanced-match": "^1.0.0" + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" } }, - "node_modules/read-package-json/node_modules/glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "node_modules/nx/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/read-package-json/node_modules/hosted-git-info": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", - "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", - "dependencies": { - "lru-cache": "^10.0.1" - }, + "node_modules/nx/node_modules/cli-spinners": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.1.tgz", + "integrity": "sha512-x/5fWmGMnbKQAaNwN+UZlV79qBLM9JFnJuJ03gIi5whrob0xV0ofNVHy9DhwGdsMJQc2OKv0oGmLzvaqvAVv+g==", + "dev": true, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-package-json/node_modules/json-parse-even-better-errors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", - "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "node_modules/nx/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=7.0.0" } }, - "node_modules/read-package-json/node_modules/lru-cache": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", - "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", - "engines": { - "node": "14 || >=16.14" - } + "node_modules/nx/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, - "node_modules/read-package-json/node_modules/minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "node_modules/nx/node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dev": true, "dependencies": { - "brace-expansion": "^2.0.1" + "escape-string-regexp": "^1.0.5" }, "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=8" }, "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/read-package-json/node_modules/normalize-package-data": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", - "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", - "dependencies": { - "hosted-git-info": "^7.0.0", - "is-core-module": "^2.8.1", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^16.14.0 || >=18.0.0" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/read-pkg": { - "version": "3.0.0", + "node_modules/nx/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", "dev": true, - "license": "MIT", "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" }, "engines": { - "node": ">=4" + "node": ">= 6" } }, - "node_modules/read-pkg/node_modules/path-type": { - "version": "3.0.0", + "node_modules/nx/node_modules/fs-extra": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.1.1.tgz", + "integrity": "sha512-MGIE4HOvQCeUCzmlHs0vXpih4ysz4wg9qiSAu6cd42lVwPbTM1TjV7RusoyQqMmk/95gdQZX72u+YW+c3eEpFQ==", "dev": true, - "license": "MIT", "dependencies": { - "pify": "^3.0.0" + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" }, "engines": { - "node": ">=4" + "node": ">=14.14" } }, - "node_modules/read-pkg/node_modules/pify": { - "version": "3.0.0", + "node_modules/nx/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/readable-stream": { - "version": "2.3.8", + "node_modules/nx/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, - "license": "MIT", "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/readable-stream/node_modules/isarray": { - "version": "1.0.0", + "node_modules/nx/node_modules/lines-and-columns": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", + "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", "dev": true, - "license": "MIT" - }, - "node_modules/readdirp": { - "version": "3.6.0", - "devOptional": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, "engines": { - "node": ">=8.10.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/rechoir": { - "version": "0.7.1", + "node_modules/nx/node_modules/minimatch": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.5.tgz", + "integrity": "sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==", "dev": true, - "license": "MIT", "dependencies": { - "resolve": "^1.9.0" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">= 0.10" + "node": "*" } }, - "node_modules/redent": { - "version": "3.0.0", + "node_modules/nx/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", "dev": true, - "license": "MIT", "dependencies": { - "indent-string": "^4.0.0", - "strip-indent": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/reflect-metadata": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", - "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", - "dev": true - }, - "node_modules/regenerate": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", - "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", - "dev": true - }, - "node_modules/regenerate-unicode-properties": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", - "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "node_modules/nx/node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", "dev": true, "dependencies": { - "regenerate": "^1.4.2" + "json5": "^2.2.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" }, "engines": { - "node": ">=4" + "node": ">=6" } }, - "node_modules/regenerator-runtime": { - "version": "0.14.0", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", - "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", - "dev": true - }, - "node_modules/regenerator-transform": { - "version": "0.15.2", - "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", - "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "node_modules/nx/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "dependencies": { - "@babel/runtime": "^7.8.4" + "engines": { + "node": ">=12" } }, - "node_modules/regex-not": { - "version": "1.0.2", + "node_modules/oauth-sign": { + "version": "0.9.0", "dev": true, - "license": "MIT", - "dependencies": { - "extend-shallow": "^3.0.2", - "safe-regex": "^1.1.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=0.10.0" + "node": "*" } }, - "node_modules/regex-not/node_modules/extend-shallow": { - "version": "3.0.2", + "node_modules/object-assign": { + "version": "4.1.1", "dev": true, "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/regex-not/node_modules/is-extendable": { - "version": "1.0.1", + "node_modules/object-copy": { + "version": "0.1.0", "dev": true, "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4" + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/regex-parser": { - "version": "2.2.11", - "dev": true, - "license": "MIT" - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.0", + "node_modules/object-copy/node_modules/kind-of": { + "version": "3.2.2", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "functions-have-names": "^1.2.3" + "is-buffer": "^1.1.5" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/regexpu-core": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", - "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "node_modules/object-hash": { + "version": "3.0.0", "dev": true, - "dependencies": { - "@babel/regjsgen": "^0.8.0", - "regenerate": "^1.4.2", - "regenerate-unicode-properties": "^10.1.0", - "regjsparser": "^0.9.1", - "unicode-match-property-ecmascript": "^2.0.0", - "unicode-match-property-value-ecmascript": "^2.1.0" - }, + "license": "MIT", "engines": { - "node": ">=4" - } - }, - "node_modules/regjsparser": { - "version": "0.9.1", - "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", - "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", - "dev": true, - "dependencies": { - "jsesc": "~0.5.0" - }, - "bin": { - "regjsparser": "bin/parser" + "node": ">= 6" } }, - "node_modules/regjsparser/node_modules/jsesc": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", - "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "node_modules/object-inspect": { + "version": "1.12.3", "dev": true, - "bin": { - "jsesc": "bin/jsesc" + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/relateurl": { - "version": "0.2.7", + "node_modules/object-keys": { + "version": "1.1.1", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.10" + "node": ">= 0.4" } }, - "node_modules/remove-trailing-separator": { - "version": "1.1.0", - "dev": true, - "license": "ISC" - }, - "node_modules/repeat-element": { - "version": "1.1.4", + "node_modules/object-visit": { + "version": "1.0.1", "dev": true, "license": "MIT", + "dependencies": { + "isobject": "^3.0.0" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/repeat-string": { - "version": "1.6.1", + "node_modules/object.assign": { + "version": "4.1.4", "dev": true, "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, "engines": { - "node": ">=0.10" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/request": { - "version": "2.88.2", + "node_modules/object.defaults": { + "version": "1.1.0", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" }, "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/request/node_modules/qs": { - "version": "6.5.3", + "node_modules/object.map": { + "version": "1.0.1", "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.6" - } - }, - "node_modules/require-directory": { - "version": "2.1.1", "license": "MIT", + "dependencies": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/require-from-string": { - "version": "2.0.2", + "node_modules/object.pick": { + "version": "1.3.0", + "dev": true, "license": "MIT", + "dependencies": { + "isobject": "^3.0.1" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/requires-port": { - "version": "1.0.0", + "node_modules/object.values": { + "version": "1.1.6", "dev": true, - "license": "MIT" - }, - "node_modules/resolve": { - "version": "1.22.8", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", - "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "license": "MIT", "dependencies": { - "is-core-module": "^2.13.0", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" }, - "bin": { - "resolve": "bin/resolve" + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-dir": { - "version": "1.0.1", + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==", + "dev": true + }, + "node_modules/on-finished": { + "version": "2.3.0", "dev": true, "license": "MIT", "dependencies": { - "expand-tilde": "^2.0.0", - "global-modules": "^1.0.0" + "ee-first": "1.1.1" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/resolve-from": { - "version": "5.0.0", + "node_modules/on-headers": { + "version": "1.0.2", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">= 0.8" } }, - "node_modules/resolve-global": { - "version": "1.0.0", + "node_modules/once": { + "version": "1.4.0", "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", "license": "MIT", "dependencies": { - "global-dirs": "^0.1.1" + "mimic-fn": "^2.1.0" }, "engines": { - "node": ">=8" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/resolve-pkg": { - "version": "2.0.0", - "dev": true, - "license": "MIT", + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", "dependencies": { - "resolve-from": "^5.0.0" + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/resolve-url": { - "version": "0.2.1", - "dev": true, - "license": "MIT" + "node_modules/openurl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/openurl/-/openurl-1.1.1.tgz", + "integrity": "sha512-d/gTkTb1i1GKz5k3XE3XFV/PxQ1k45zDqGP2OA7YhgsaLoqm6qRvARAZOFer1fcXritWlGBRCu/UgeS4HAnXAA==", + "dev": true }, - "node_modules/resolve-url-loader": { - "version": "5.0.0", + "node_modules/opn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", + "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", "dev": true, - "license": "MIT", "dependencies": { - "adjust-sourcemap-loader": "^4.0.0", - "convert-source-map": "^1.7.0", - "loader-utils": "^2.0.0", - "postcss": "^8.2.14", - "source-map": "0.6.1" + "is-wsl": "^1.1.0" }, "engines": { - "node": ">=12" + "node": ">=4" } }, - "node_modules/resolve-url-loader/node_modules/loader-utils": { - "version": "2.0.4", + "node_modules/opn/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", "dev": true, - "license": "MIT", - "dependencies": { - "big.js": "^5.2.2", - "emojis-list": "^3.0.0", - "json5": "^2.1.2" - }, "engines": { - "node": ">=8.9.0" + "node": ">=4" } }, - "node_modules/resolve-url-loader/node_modules/source-map": { + "node_modules/optimist": { "version": "0.6.1", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT/X11", + "dependencies": { + "minimist": "~0.0.1", + "wordwrap": "~0.0.2" + } + }, + "node_modules/optimist/node_modules/minimist": { + "version": "0.0.10", + "dev": true, + "license": "MIT" + }, + "node_modules/optimist/node_modules/wordwrap": { + "version": "0.0.3", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=0.4.0" } }, - "node_modules/resp-modifier": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz", - "integrity": "sha512-U1+0kWC/+4ncRFYqQWTx/3qkfE6a4B/h3XXgmXypfa0SPZ3t7cbbaFk297PjQS/yov24R18h6OZe6iZwj3NSLw==", + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", "dev": true, "dependencies": { - "debug": "^2.2.0", - "minimatch": "^3.0.2" + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" }, "engines": { "node": ">= 0.8.0" } }, - "node_modules/resp-modifier/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, + "node_modules/ora": { + "version": "5.4.1", + "license": "MIT", "dependencies": { - "ms": "2.0.0" + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/resp-modifier/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/restore-cursor": { - "version": "3.1.0", + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", "license": "MIT", "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" + "color-convert": "^2.0.1" }, "engines": { "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/ret": { - "version": "0.1.15", - "dev": true, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.2", "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, "engines": { - "node": ">=0.12" - } - }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "engines": { - "node": ">= 4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/reusify": { - "version": "1.0.4", - "dev": true, + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" + "node": ">=7.0.0" } }, - "node_modules/rfdc": { - "version": "1.3.0", - "dev": true, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", "license": "MIT" }, - "node_modules/right-align": { - "version": "0.1.3", - "dev": true, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", "license": "MIT", - "optional": true, - "dependencies": { - "align-text": "^0.1.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/rimraf": { - "version": "3.0.2", - "dev": true, - "license": "ISC", + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "license": "MIT", "dependencies": { - "glob": "^7.1.3" + "has-flag": "^4.0.0" }, - "bin": { - "rimraf": "bin.js" + "engines": { + "node": ">=8" + } + }, + "node_modules/ordered-ast-traverse": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ordered-esprima-props": "~1.1.0" + } + }, + "node_modules/ordered-esprima-props": { + "version": "1.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/os-homedir": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/os-locale": { + "version": "1.4.0", + "license": "MIT", + "dependencies": { + "lcid": "^1.0.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/rimraf/node_modules/glob": { - "version": "7.2.3", + "node_modules/os-tmpdir": { + "version": "1.0.2", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/osenv": { + "version": "0.1.5", "dev": true, "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" }, "engines": { - "node": "*" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "node_modules/p-locate": { + "version": "5.0.0", "dev": true, - "bin": { - "rollup": "dist/bin/rollup" + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" }, "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" + "node": ">=10" }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-applescript": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", - "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", - "dev": true, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", "dependencies": { - "execa": "^5.0.0" + "aggregate-error": "^3.0.0" }, "engines": { - "node": ">=12" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/run-async": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", - "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dev": true, + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, "engines": { - "node": ">=0.12.0" + "node": ">=8" } }, - "node_modules/run-parallel": { - "version": "1.2.0", + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "dependencies": { - "queue-microtask": "^1.2.2" + "engines": { + "node": ">= 4" } }, - "node_modules/rx": { - "version": "2.3.24", - "dev": true + "node_modules/p-try": { + "version": "2.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } }, - "node_modules/rxjs": { - "version": "7.4.0", - "license": "Apache-2.0", + "node_modules/pacote": { + "version": "17.0.4", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.4.tgz", + "integrity": "sha512-eGdLHrV/g5b5MtD5cTPyss+JxOlaOloSMG3UwPMAvL8ywaLJ6beONPF40K4KKl/UI6q5hTKCJq5rCu8tkF+7Dg==", "dependencies": { - "tslib": "~2.1.0" + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/rxjs/node_modules/tslib": { - "version": "2.1.0", - "license": "0BSD" - }, - "node_modules/safe-buffer": { - "version": "5.1.2", - "license": "MIT" - }, - "node_modules/safe-json-parse": { - "version": "1.0.1", + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "dev": true }, - "node_modules/safe-regex": { - "version": "1.1.0", + "node_modules/param-case": { + "version": "2.1.1", "dev": true, "license": "MIT", "dependencies": { - "ret": "~0.1.10" + "no-case": "^2.2.0" } }, - "node_modules/safe-regex-test": { - "version": "1.0.0", + "node_modules/parent-module": { + "version": "1.0.1", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.3", - "is-regex": "^1.1.4" + "callsites": "^3.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=6" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "license": "MIT" - }, - "node_modules/safevalues": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/safevalues/-/safevalues-0.3.4.tgz", - "integrity": "sha512-LRneZZRXNgjzwG4bDQdOTSbze3fHm1EAKN/8bePxnlEZiBmkYEDggaHbuvHI9/hoqHbGfsEA7tWS9GhYHZBBsw==" - }, - "node_modules/sass": { - "version": "1.69.5", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.5.tgz", - "integrity": "sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==", + "node_modules/parse-filepath": { + "version": "1.0.2", "dev": true, + "license": "MIT", "dependencies": { - "chokidar": ">=3.0.0 <4.0.0", - "immutable": "^4.0.0", - "source-map-js": ">=0.6.2 <2.0.0" - }, - "bin": { - "sass": "sass.js" + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" }, "engines": { - "node": ">=14.0.0" + "node": ">=0.8" } }, - "node_modules/sass-loader": { - "version": "13.3.2", - "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz", - "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==", + "node_modules/parse-json": { + "version": "5.2.0", "dev": true, + "license": "MIT", "dependencies": { - "neo-async": "^2.6.2" + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" }, "engines": { - "node": ">= 14.15.0" + "node": ">=8" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "fibers": ">= 3.1.0", - "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", - "sass": "^1.3.0", - "sass-embedded": "*", - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "fibers": { - "optional": true - }, - "node-sass": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/sass/node_modules/immutable": { - "version": "4.3.0", + "node_modules/parse-node-version": { + "version": "1.0.1", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">= 0.10" + } }, - "node_modules/saucelabs": { - "version": "1.5.0", + "node_modules/parse-passwd": { + "version": "1.0.0", "dev": true, - "dependencies": { - "https-proxy-agent": "^2.2.1" - }, + "license": "MIT", "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/saucelabs/node_modules/agent-base": { - "version": "4.3.0", - "dev": true, + "node_modules/parse5": { + "version": "7.1.2", + "devOptional": true, "license": "MIT", "dependencies": { - "es6-promisify": "^5.0.0" + "entities": "^4.4.0" }, - "engines": { - "node": ">= 4.0.0" + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/saucelabs/node_modules/debug": { - "version": "3.2.7", + "node_modules/parse5-html-rewriting-stream": { + "version": "7.0.0", "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/saucelabs/node_modules/https-proxy-agent": { - "version": "2.2.4", + "node_modules/parse5-sax-parser": { + "version": "7.0.0", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" + "parse5": "^7.0.0" }, - "engines": { - "node": ">= 4.5.0" + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/sax": { - "version": "1.2.4", + "node_modules/parseurl": { + "version": "1.3.3", "dev": true, - "license": "ISC" + "license": "MIT", + "engines": { + "node": ">= 0.8" + } }, - "node_modules/schema-utils": { - "version": "4.0.1", + "node_modules/pascalcase": { + "version": "0.1.1", "dev": true, "license": "MIT", - "dependencies": { - "@types/json-schema": "^7.0.9", - "ajv": "^8.9.0", - "ajv-formats": "^2.1.1", - "ajv-keywords": "^5.1.0" - }, "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">=0.10.0" } }, - "node_modules/select-hose": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", - "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", - "dev": true + "node_modules/path-dirname": { + "version": "1.0.2", + "dev": true, + "license": "MIT" }, - "node_modules/selenium-webdriver": { - "version": "3.6.0", + "node_modules/path-exists": { + "version": "4.0.0", "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jszip": "^3.1.3", - "rimraf": "^2.5.4", - "tmp": "0.0.30", - "xml2js": "^0.4.17" - }, + "license": "MIT", "engines": { - "node": ">= 6.9.0" + "node": ">=8" } }, - "node_modules/selenium-webdriver/node_modules/glob": { - "version": "7.2.3", + "node_modules/path-is-absolute": { + "version": "1.0.1", "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, + "license": "MIT", "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=0.10.0" } }, - "node_modules/selenium-webdriver/node_modules/rimraf": { - "version": "2.7.1", + "node_modules/path-is-inside": { + "version": "1.0.2", "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" + "license": "(WTFPL OR MIT)" + }, + "node_modules/path-key": { + "version": "3.1.1", + "license": "MIT", + "engines": { + "node": ">=8" } }, - "node_modules/selenium-webdriver/node_modules/tmp": { - "version": "0.0.30", + "node_modules/path-parse": { + "version": "1.0.7", + "license": "MIT" + }, + "node_modules/path-root": { + "version": "0.1.1", "dev": true, "license": "MIT", "dependencies": { - "os-tmpdir": "~1.0.1" + "path-root-regex": "^0.1.0" }, "engines": { - "node": ">=0.4.0" + "node": ">=0.10.0" } }, - "node_modules/selfsigned": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", - "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "node_modules/path-root-regex": { + "version": "0.1.2", "dev": true, - "dependencies": { - "@types/node-forge": "^1.3.0", - "node-forge": "^1" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/semver": { - "version": "7.5.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", - "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", "dependencies": { - "lru-cache": "^6.0.0" - }, - "bin": { - "semver": "bin/semver.js" + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" }, "engines": { - "node": ">=10" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", "engines": { - "node": ">=10" + "node": "14 || >=16.14" } }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "license": "ISC" + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==", + "dev": true }, - "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "node_modules/path-type": { + "version": "4.0.0", "dev": true, - "dependencies": { - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "1.2.0", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "etag": "~1.8.1", - "fresh": "0.5.2", - "http-errors": "2.0.0", - "mime": "1.6.0", - "ms": "2.1.3", - "on-finished": "2.4.1", - "range-parser": "~1.2.1", - "statuses": "2.0.1" - }, + "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/send/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, + "node_modules/pdfjs-dist": { + "version": "2.16.105", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.16.105.tgz", + "integrity": "sha512-J4dn41spsAwUxCpEoVf6GVoz908IAA3mYiLmNxg8J9kfRXc2jxpbUepcP0ocp0alVNLFthTAM8DZ1RaHh8sU0A==", "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/send/node_modules/debug/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/send/node_modules/mime": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", - "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", - "dev": true, - "bin": { - "mime": "cli.js" + "dommatrix": "^1.0.3", + "web-streams-polyfill": "^3.2.1" }, - "engines": { - "node": ">=4" + "peerDependencies": { + "worker-loader": "^3.0.8" + }, + "peerDependenciesMeta": { + "worker-loader": { + "optional": true + } } }, - "node_modules/send/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true - }, - "node_modules/send/node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "node_modules/performance-now": { + "version": "2.1.0", "dev": true, - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } + "license": "MIT" }, - "node_modules/send/node_modules/statuses": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", - "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "node_modules/picocolors": { + "version": "1.0.0", "dev": true, - "engines": { - "node": ">= 0.8" - } + "license": "ISC" }, - "node_modules/serialize-javascript": { - "version": "6.0.1", + "node_modules/picomatch": { + "version": "2.3.1", "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "randombytes": "^2.1.0" + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/serve-index": { - "version": "1.9.1", + "node_modules/pidtree": { + "version": "0.3.1", "dev": true, "license": "MIT", - "dependencies": { - "accepts": "~1.3.4", - "batch": "0.6.1", - "debug": "2.6.9", - "escape-html": "~1.0.3", - "http-errors": "~1.6.2", - "mime-types": "~2.1.17", - "parseurl": "~1.3.2" + "bin": { + "pidtree": "bin/pidtree.js" }, "engines": { - "node": ">= 0.8.0" + "node": ">=0.10" } }, - "node_modules/serve-index/node_modules/debug": { - "version": "2.6.9", + "node_modules/pify": { + "version": "2.3.0", "dev": true, "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/serve-index/node_modules/depd": { - "version": "1.1.2", + "node_modules/pinkie": { + "version": "2.0.4", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/serve-index/node_modules/http-errors": { - "version": "1.6.3", + "node_modules/pinkie-promise": { + "version": "2.0.1", "dev": true, "license": "MIT", "dependencies": { - "depd": "~1.1.2", - "inherits": "2.0.3", - "setprototypeof": "1.1.0", - "statuses": ">= 1.4.0 < 2" + "pinkie": "^2.0.0" }, "engines": { - "node": ">= 0.6" + "node": ">=0.10.0" } }, - "node_modules/serve-index/node_modules/inherits": { - "version": "2.0.3", - "dev": true, - "license": "ISC" - }, - "node_modules/serve-index/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/serve-index/node_modules/setprototypeof": { - "version": "1.1.0", - "dev": true, - "license": "ISC" - }, - "node_modules/serve-index/node_modules/statuses": { - "version": "1.5.0", + "node_modules/pirates": { + "version": "4.0.5", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 6" } }, - "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "node_modules/piscina": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.1.0.tgz", + "integrity": "sha512-sjbLMi3sokkie+qmtZpkfMCUJTpbxJm/wvaPzU28vmYSsTSW8xk9JcFUsbqGJdtPpIQ9tuj+iDcTtgZjwnOSig==", "dev": true, "dependencies": { - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "parseurl": "~1.3.3", - "send": "0.18.0" + "eventemitter-asyncresource": "^1.0.0", + "hdr-histogram-js": "^2.0.1", + "hdr-histogram-percentiles-obj": "^3.0.0" }, - "engines": { - "node": ">= 0.8.0" + "optionalDependencies": { + "nice-napi": "^1.0.2" } }, - "node_modules/server-destroy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", - "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", - "dev": true - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "dev": true, - "license": "ISC" - }, - "node_modules/set-value": { - "version": "2.0.1", + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", "dev": true, - "license": "MIT", "dependencies": { - "extend-shallow": "^2.0.1", - "is-extendable": "^0.1.1", - "is-plain-object": "^2.0.3", - "split-string": "^3.0.1" + "find-up": "^6.3.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/setimmediate": { - "version": "1.0.5", - "dev": true, - "license": "MIT" - }, - "node_modules/setprototypeof": { - "version": "1.2.0", - "dev": true, - "license": "ISC" - }, - "node_modules/shallow-clone": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", - "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", "dev": true, "dependencies": { - "kind-of": "^6.0.2" + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" }, "engines": { - "node": ">=8" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "license": "MIT", + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dev": true, "dependencies": { - "shebang-regex": "^3.0.0" + "p-locate": "^6.0.0" }, "engines": { - "node": ">=8" - } - }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/shell-quote": { - "version": "1.8.1", - "dev": true, - "license": "MIT", + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/shelljs": { - "version": "0.3.0", + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, - "license": "BSD*", - "bin": { - "shjs": "bin/shjs" + "dependencies": { + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">=0.8.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/showdown": { - "version": "1.3.0", - "license": "BSD-2-Clause", + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dev": true, "dependencies": { - "yargs": "^3.15.0" + "p-limit": "^4.0.0" }, - "bin": { - "showdown": "bin/showdown.js" - } - }, - "node_modules/showdown/node_modules/ansi-regex": { - "version": "2.1.1", - "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/showdown/node_modules/camelcase": { - "version": "2.1.1", - "license": "MIT", + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "dev": true, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/showdown/node_modules/cliui": { - "version": "3.2.0", - "license": "ISC", - "dependencies": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1", - "wrap-ansi": "^2.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/showdown/node_modules/is-fullwidth-code-point": { + "node_modules/pkg-dir/node_modules/yocto-queue": { "version": "1.0.0", - "license": "MIT", - "dependencies": { - "number-is-nan": "^1.0.0" - }, + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "dev": true, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/showdown/node_modules/string-width": { - "version": "1.0.2", - "license": "MIT", - "dependencies": { - "code-point-at": "^1.0.0", - "is-fullwidth-code-point": "^1.0.0", - "strip-ansi": "^3.0.0" + "node": ">=12.20" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/showdown/node_modules/strip-ansi": { - "version": "3.0.1", + "node_modules/pkg-up": { + "version": "3.1.0", + "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^2.0.0" + "find-up": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=8" } }, - "node_modules/showdown/node_modules/window-size": { - "version": "0.1.4", + "node_modules/pkg-up/node_modules/find-up": { + "version": "3.0.0", + "dev": true, "license": "MIT", - "bin": { - "window-size": "cli.js" + "dependencies": { + "locate-path": "^3.0.0" }, "engines": { - "node": ">= 0.10.0" + "node": ">=6" } }, - "node_modules/showdown/node_modules/wrap-ansi": { - "version": "2.1.0", + "node_modules/pkg-up/node_modules/locate-path": { + "version": "3.0.0", + "dev": true, "license": "MIT", "dependencies": { - "string-width": "^1.0.1", - "strip-ansi": "^3.0.1" + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/showdown/node_modules/y18n": { - "version": "3.2.2", - "license": "ISC" - }, - "node_modules/showdown/node_modules/yargs": { - "version": "3.32.0", - "license": "MIT", - "dependencies": { - "camelcase": "^2.0.1", - "cliui": "^3.0.3", - "decamelize": "^1.1.1", - "os-locale": "^1.4.0", - "string-width": "^1.0.1", - "window-size": "^0.1.4", - "y18n": "^3.2.0" + "node": ">=6" } }, - "node_modules/side-channel": { - "version": "1.0.4", + "node_modules/pkg-up/node_modules/p-limit": { + "version": "2.3.0", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.0", - "get-intrinsic": "^1.0.2", - "object-inspect": "^1.9.0" + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/sigmund": { - "version": "1.0.1", - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "license": "ISC" - }, - "node_modules/sigstore": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.1.0.tgz", - "integrity": "sha512-kPIj+ZLkyI3QaM0qX8V/nSsweYND3W448pwkDgS6CQ74MfhEkIR8ToK5Iyx46KJYRjseVcD3Rp9zAmUAj6ZjPw==", + "node_modules/pkg-up/node_modules/p-locate": { + "version": "3.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "@sigstore/bundle": "^2.1.0", - "@sigstore/protobuf-specs": "^0.2.1", - "@sigstore/sign": "^2.1.0", - "@sigstore/tuf": "^2.1.0" + "p-limit": "^2.0.0" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=6" } }, - "node_modules/simple-fmt": { - "version": "0.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/simple-is": { - "version": "0.2.0", - "dev": true, - "license": "MIT" - }, - "node_modules/slash": { + "node_modules/pkg-up/node_modules/path-exists": { "version": "3.0.0", "dev": true, "license": "MIT", "engines": { - "node": ">=8" - } - }, - "node_modules/smart-buffer": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", - "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" + "node": ">=4" } }, - "node_modules/snapdragon": { - "version": "0.8.2", + "node_modules/portscanner": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.2.0.tgz", + "integrity": "sha512-IFroCz/59Lqa2uBvzK3bKDbDDIEaAY8XJ1jFxcLWTqosrsc32//P4VuSB2vZXoHiHqOmx8B5L5hnKOxL/7FlPw==", "dev": true, - "license": "MIT", "dependencies": { - "base": "^0.11.1", - "debug": "^2.2.0", - "define-property": "^0.2.5", - "extend-shallow": "^2.0.1", - "map-cache": "^0.2.2", - "source-map": "^0.5.6", - "source-map-resolve": "^0.5.0", - "use": "^3.1.0" + "async": "^2.6.0", + "is-number-like": "^1.0.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.4", + "npm": ">=1.0.0" } }, - "node_modules/snapdragon-node": { - "version": "2.1.1", + "node_modules/portscanner/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", "dev": true, - "license": "MIT", "dependencies": { - "define-property": "^1.0.0", - "isobject": "^3.0.0", - "snapdragon-util": "^3.0.1" - }, - "engines": { - "node": ">=0.10.0" + "lodash": "^4.17.14" } }, - "node_modules/snapdragon-node/node_modules/define-property": { - "version": "1.0.0", + "node_modules/posix-character-classes": { + "version": "0.1.1", "dev": true, "license": "MIT", - "dependencies": { - "is-descriptor": "^1.0.0" - }, "engines": { "node": ">=0.10.0" } }, - "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { - "version": "1.0.0", + "node_modules/postcss": { + "version": "8.4.31", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz", + "integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==", "dev": true, - "license": "MIT", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "dependencies": { - "kind-of": "^6.0.0" + "nanoid": "^3.3.6", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" }, "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || >=14" } }, - "node_modules/snapdragon-node/node_modules/is-data-descriptor": { - "version": "1.0.0", + "node_modules/postcss-import": { + "version": "15.1.0", "dev": true, "license": "MIT", "dependencies": { - "kind-of": "^6.0.0" + "postcss-value-parser": "^4.0.0", + "read-cache": "^1.0.0", + "resolve": "^1.1.7" }, "engines": { - "node": ">=0.10.0" + "node": ">=14.0.0" + }, + "peerDependencies": { + "postcss": "^8.0.0" } }, - "node_modules/snapdragon-node/node_modules/is-descriptor": { - "version": "1.0.2", + "node_modules/postcss-js": { + "version": "4.0.1", "dev": true, "license": "MIT", "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "camelcase-css": "^2.0.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon-util": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "kind-of": "^3.2.0" + "node": "^12 || ^14 || >= 16" }, - "engines": { - "node": ">=0.10.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": "^8.4.21" } }, - "node_modules/snapdragon-util/node_modules/kind-of": { - "version": "3.2.2", + "node_modules/postcss-load-config": { + "version": "4.0.1", "dev": true, "license": "MIT", "dependencies": { - "is-buffer": "^1.1.5" + "lilconfig": "^2.0.5", + "yaml": "^2.1.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/snapdragon/node_modules/debug": { - "version": "2.6.9", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "node": ">= 14" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } } }, - "node_modules/snapdragon/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/snapdragon/node_modules/source-map": { - "version": "0.5.7", + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "2.2.2", "dev": true, - "license": "BSD-3-Clause", + "license": "ISC", "engines": { - "node": ">=0.10.0" + "node": ">= 14" } }, - "node_modules/socket.io": { - "version": "4.6.1", + "node_modules/postcss-loader": { + "version": "7.3.3", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-7.3.3.tgz", + "integrity": "sha512-YgO/yhtevGO/vJePCQmTxiaEwER94LABZN0ZMT4A0vsak9TpO+RvKRs7EmJ8peIlB9xfXCsS7M8LjqncsUZ5HA==", "dev": true, - "license": "MIT", "dependencies": { - "accepts": "~1.3.4", - "base64id": "~2.0.0", - "debug": "~4.3.2", - "engine.io": "~6.4.1", - "socket.io-adapter": "~2.5.2", - "socket.io-parser": "~4.2.1" + "cosmiconfig": "^8.2.0", + "jiti": "^1.18.2", + "semver": "^7.3.8" }, "engines": { - "node": ">=10.0.0" + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" } }, - "node_modules/socket.io-adapter": { - "version": "2.5.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ws": "~8.11.0" - } + "node_modules/postcss-loader/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true }, - "node_modules/socket.io-client": { - "version": "4.7.2", - "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", - "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "node_modules/postcss-loader/node_modules/cosmiconfig": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-8.2.0.tgz", + "integrity": "sha512-3rTMnFJA1tCOPwRxtgF4wd7Ab2qvDbL8jX+3smjIbS4HlZBagTlpERbdN7iAbWlrfxE3M8c27kTwTawQ7st+OQ==", "dev": true, "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.2", - "engine.io-client": "~6.5.2", - "socket.io-parser": "~4.2.4" + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "parse-json": "^5.0.0", + "path-type": "^4.0.0" }, "engines": { - "node": ">=10.0.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" } }, - "node_modules/socket.io-parser": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", - "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "node_modules/postcss-loader/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "dev": true, "dependencies": { - "@socket.io/component-emitter": "~3.1.0", - "debug": "~4.3.1" + "argparse": "^2.0.1" }, - "engines": { - "node": ">=10.0.0" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/sockjs": { - "version": "0.3.24", - "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", - "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", "dev": true, - "dependencies": { - "faye-websocket": "^0.11.3", - "uuid": "^8.3.2", - "websocket-driver": "^0.7.4" + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/sockjs/node_modules/faye-websocket": { - "version": "0.11.4", - "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", - "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.3.tgz", + "integrity": "sha512-2/u2zraspoACtrbFRnTijMiQtb4GW4BvatjaG/bCjYQo8kLTdevCUlwuBHx2sCnSyrI3x3qj4ZK1j5LQBgzmwA==", "dev": true, "dependencies": { - "websocket-driver": ">=0.5.1" + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" }, "engines": { - "node": ">=0.8.0" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/sockjs/node_modules/uuid": { - "version": "8.3.2", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", - "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "node_modules/postcss-modules-scope": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz", + "integrity": "sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg==", "dev": true, - "bin": { - "uuid": "dist/bin/uuid" - } - }, - "node_modules/socks": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", - "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", "dependencies": { - "ip": "^2.0.0", - "smart-buffer": "^4.2.0" + "postcss-selector-parser": "^6.0.4" }, "engines": { - "node": ">= 10.13.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/socks-proxy-agent": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", - "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", - "dependencies": { - "agent-base": "^7.0.2", - "debug": "^4.3.4", - "socks": "^2.7.1" + "node": "^10 || ^12 || >= 14" }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/socks/node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" - }, - "node_modules/source-map": { - "version": "0.7.4", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", - "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", - "engines": { - "node": ">= 8" + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/source-map-js": { - "version": "1.0.2", + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", "dev": true, - "license": "BSD-3-Clause", + "dependencies": { + "icss-utils": "^5.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" } }, - "node_modules/source-map-loader": { - "version": "4.0.1", + "node_modules/postcss-nested": { + "version": "6.0.1", "dev": true, "license": "MIT", "dependencies": { - "abab": "^2.0.6", - "iconv-lite": "^0.6.3", - "source-map-js": "^1.0.2" + "postcss-selector-parser": "^6.0.11" }, "engines": { - "node": ">= 14.15.0" + "node": ">=12.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://opencollective.com/postcss/" }, "peerDependencies": { - "webpack": "^5.72.1" + "postcss": "^8.2.14" } }, - "node_modules/source-map-resolve": { - "version": "0.5.3", + "node_modules/postcss-scss": { + "version": "0.1.9", "dev": true, "license": "MIT", "dependencies": { - "atob": "^2.1.2", - "decode-uri-component": "^0.2.0", - "resolve-url": "^0.2.1", - "source-map-url": "^0.4.0", - "urix": "^0.1.0" + "postcss": "^5.1.0" } }, - "node_modules/source-map-support": { - "version": "0.5.21", + "node_modules/postcss-scss/node_modules/ansi-regex": { + "version": "2.1.1", "dev": true, "license": "MIT", - "dependencies": { - "buffer-from": "^1.0.0", - "source-map": "^0.6.0" - } - }, - "node_modules/source-map-support/node_modules/source-map": { - "version": "0.6.1", - "dev": true, - "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/source-map-url": { - "version": "0.4.1", - "dev": true, - "license": "MIT" - }, - "node_modules/spawn-command": { - "version": "0.0.2-1", + "node_modules/postcss-scss/node_modules/ansi-styles": { + "version": "2.2.1", "dev": true, - "license": "MIT" - }, - "node_modules/spdx-correct": { - "version": "3.2.0", - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.3.0", - "license": "CC-BY-3.0" - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.1", "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/spdx-license-ids": { - "version": "3.0.13", - "license": "CC0-1.0" - }, - "node_modules/spdy": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", - "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "node_modules/postcss-scss/node_modules/chalk": { + "version": "1.1.3", "dev": true, + "license": "MIT", "dependencies": { - "debug": "^4.1.0", - "handle-thing": "^2.0.0", - "http-deceiver": "^1.2.7", - "select-hose": "^2.0.0", - "spdy-transport": "^3.0.0" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=0.10.0" } }, - "node_modules/spdy-transport": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", - "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "node_modules/postcss-scss/node_modules/chalk/node_modules/supports-color": { + "version": "2.0.0", "dev": true, - "dependencies": { - "debug": "^4.1.0", - "detect-node": "^2.0.4", - "hpack.js": "^2.1.6", - "obuf": "^1.1.2", - "readable-stream": "^3.0.6", - "wbuf": "^1.7.3" + "license": "MIT", + "engines": { + "node": ">=0.8.0" } }, - "node_modules/spdy-transport/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/postcss-scss/node_modules/has-flag": { + "version": "1.0.0", "dev": true, - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, + "license": "MIT", "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/split-string": { - "version": "3.1.0", + "node_modules/postcss-scss/node_modules/postcss": { + "version": "5.2.18", "dev": true, "license": "MIT", "dependencies": { - "extend-shallow": "^3.0.0" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.12" } }, - "node_modules/split-string/node_modules/extend-shallow": { - "version": "3.0.2", + "node_modules/postcss-scss/node_modules/source-map": { + "version": "0.5.7", "dev": true, - "license": "MIT", - "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - }, + "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" } }, - "node_modules/split-string/node_modules/is-extendable": { - "version": "1.0.1", + "node_modules/postcss-scss/node_modules/strip-ansi": { + "version": "3.0.1", "dev": true, "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4" + "ansi-regex": "^2.0.0" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/split2": { - "version": "3.2.2", + "node_modules/postcss-scss/node_modules/supports-color": { + "version": "3.2.3", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "readable-stream": "^3.0.0" + "has-flag": "^1.0.0" + }, + "engines": { + "node": ">=0.8.0" } }, - "node_modules/split2/node_modules/readable-stream": { - "version": "3.6.2", + "node_modules/postcss-selector-parser": { + "version": "6.0.11", "dev": true, "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" }, "engines": { - "node": ">= 6" + "node": ">=4" } }, - "node_modules/sprintf-js": { - "version": "1.0.3", - "dev": true, - "license": "BSD-3-Clause" + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "dev": true }, - "node_modules/sshpk": { - "version": "1.17.0", + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "dev": true, - "license": "MIT", - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/ssri": { - "version": "10.0.5", - "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", - "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "node_modules/preprocess": { + "version": "3.2.0", + "dev": true, "dependencies": { - "minipass": "^7.0.3" + "xregexp": "3.1.0" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">= 0.10.0" } }, - "node_modules/stable": { - "version": "0.1.8", + "node_modules/prettier": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.1.0.tgz", + "integrity": "sha512-TQLvXjq5IAibjh8EpBIkNKxO749UEWABoiIZehEPiY4GNpVdhaFKqSTu+QrlU6D2dPAfubRmtJTi4K4YkQ5eXw==", "dev": true, - "license": "MIT" + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } }, - "node_modules/static-extend": { - "version": "0.1.2", + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", "dev": true, "license": "MIT", "dependencies": { - "define-property": "^0.2.5", - "object-copy": "^0.1.0" + "fast-diff": "^1.1.2" }, "engines": { - "node": ">=0.10.0" + "node": ">=6.0.0" } }, - "node_modules/statuses": { - "version": "1.3.1", + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", "dev": true, - "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/stream-throttle": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz", - "integrity": "sha512-889+B9vN9dq7/vLbGyuHeZ6/ctf5sNuGWsDy89uNxkFTAgzy0eK7+w5fL3KLNRTkLle7EgZGvHUphZW0Q26MnQ==", + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", "dev": true, "dependencies": { - "commander": "^2.2.0", - "limiter": "^1.0.5" - }, - "bin": { - "throttleproxy": "bin/throttleproxy.js" + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" }, "engines": { - "node": ">= 0.10.0" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/streamroller": { - "version": "3.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, "engines": { - "node": ">=8.0" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/streamroller/node_modules/fs-extra": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", "engines": { - "node": ">=6 <7 || >=8" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/streamroller/node_modules/jsonfile": { - "version": "4.0.0", + "node_modules/process-nextick-args": { + "version": "2.0.1", "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } + "license": "MIT" }, - "node_modules/streamroller/node_modules/universalify": { - "version": "0.1.2", + "node_modules/promise": { + "version": "7.3.1", "dev": true, "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/string_decoder": { - "version": "1.1.1", - "license": "MIT", + "optional": true, "dependencies": { - "safe-buffer": "~5.1.0" + "asap": "~2.0.3" } }, - "node_modules/string-template": { - "version": "0.2.1", - "dev": true + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" }, - "node_modules/string-width": { - "version": "4.2.3", - "license": "MIT", + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "err-code": "^2.0.2", + "retry": "^0.12.0" }, "engines": { - "node": ">=8" + "node": ">=10" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "node_modules/protractor": { + "version": "7.0.0", + "dev": true, + "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "@types/q": "^0.0.32", + "@types/selenium-webdriver": "^3.0.0", + "blocking-proxy": "^1.0.0", + "browserstack": "^1.5.1", + "chalk": "^1.1.3", + "glob": "^7.0.3", + "jasmine": "2.8.0", + "jasminewd2": "^2.1.0", + "q": "1.4.1", + "saucelabs": "^1.5.0", + "selenium-webdriver": "3.6.0", + "source-map-support": "~0.4.0", + "webdriver-js-extender": "2.1.0", + "webdriver-manager": "^12.1.7", + "yargs": "^15.3.1" + }, + "bin": { + "protractor": "bin/protractor", + "webdriver-manager": "bin/webdriver-manager" }, "engines": { - "node": ">=8" + "node": ">=10.13.x" } }, - "node_modules/string.prototype.padend": { - "version": "3.1.4", + "node_modules/protractor/node_modules/ansi-regex": { + "version": "2.1.1", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/string.prototype.trim": { - "version": "1.2.7", + "node_modules/protractor/node_modules/ansi-styles": { + "version": "2.2.1", "dev": true, "license": "MIT", - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/string.prototype.trimend": { - "version": "1.0.6", + "node_modules/protractor/node_modules/chalk": { + "version": "1.1.3", "dev": true, "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.6", + "node_modules/protractor/node_modules/cliui": { + "version": "6.0.0", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.1.4", - "es-abstract": "^1.20.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" } }, - "node_modules/stringmap": { - "version": "0.2.2", - "dev": true, - "license": "MIT" - }, - "node_modules/stringset": { - "version": "0.2.1", + "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { + "version": "5.0.1", "dev": true, - "license": "MIT" - }, - "node_modules/strip-ansi": { - "version": "6.0.1", "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, "engines": { "node": ">=8" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", + "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", "dependencies": { "ansi-regex": "^5.0.1" }, @@ -22997,1540 +23222,1399 @@ "node": ">=8" } }, - "node_modules/strip-bom": { - "version": "3.0.0", + "node_modules/protractor/node_modules/color-convert": { + "version": "2.0.1", "dev": true, "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=4" + "node": ">=7.0.0" } }, - "node_modules/strip-final-newline": { - "version": "2.0.0", + "node_modules/protractor/node_modules/color-name": { + "version": "1.1.4", "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } + "license": "MIT" }, - "node_modules/strip-indent": { - "version": "3.0.0", + "node_modules/protractor/node_modules/find-up": { + "version": "4.1.0", "dev": true, "license": "MIT", "dependencies": { - "min-indent": "^1.0.0" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" }, "engines": { "node": ">=8" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/strong-log-transformer": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", - "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", + "node_modules/protractor/node_modules/glob": { + "version": "7.2.3", "dev": true, + "license": "ISC", "dependencies": { - "duplexer": "^0.1.1", - "minimist": "^1.2.0", - "through": "^2.3.4" - }, - "bin": { - "sl-log-transformer": "bin/sl-log-transformer.js" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" }, "engines": { - "node": ">=4" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/sucrase": { - "version": "3.32.0", + "node_modules/protractor/node_modules/locate-path": { + "version": "5.0.0", "dev": true, "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "glob": "7.1.6", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" + "p-locate": "^4.1.0" }, "engines": { "node": ">=8" } }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", + "node_modules/protractor/node_modules/p-limit": { + "version": "2.3.0", "dev": true, "license": "MIT", - "engines": { - "node": ">= 6" - } - }, - "node_modules/sucrase/node_modules/glob": { - "version": "7.1.6", - "dev": true, - "license": "ISC", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "p-try": "^2.0.0" }, "engines": { - "node": "*" + "node": ">=6" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/supports-color": { - "version": "5.5.0", + "node_modules/protractor/node_modules/p-locate": { + "version": "4.1.0", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "p-limit": "^2.2.0" }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", + "node_modules/protractor/node_modules/q": { + "version": "1.4.1", + "dev": true, "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.6.0", + "teleport": ">=0.2.0" } }, - "node_modules/symbol-observable": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", - "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "node_modules/protractor/node_modules/source-map": { + "version": "0.5.7", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=0.10" + "node": ">=0.10.0" } }, - "node_modules/synckit": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", - "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "node_modules/protractor/node_modules/source-map-support": { + "version": "0.4.18", "dev": true, + "license": "MIT", "dependencies": { - "@pkgr/utils": "^2.3.1", - "tslib": "^2.5.0" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" + "source-map": "^0.5.6" } }, - "node_modules/tailwindcss": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz", - "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==", + "node_modules/protractor/node_modules/strip-ansi": { + "version": "3.0.1", "dev": true, + "license": "MIT", "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.5.3", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.2.12", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.18.2", - "lilconfig": "^2.1.0", - "micromatch": "^4.0.5", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.0.0", - "postcss": "^8.4.23", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.1", - "postcss-nested": "^6.0.1", - "postcss-selector-parser": "^6.0.11", - "resolve": "^1.22.2", - "sucrase": "^3.32.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" + "ansi-regex": "^2.0.0" }, "engines": { - "node": ">=14.0.0" + "node": ">=0.10.0" } }, - "node_modules/tailwindcss/node_modules/arg": { - "version": "5.0.2", + "node_modules/protractor/node_modules/supports-color": { + "version": "2.0.0", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } }, - "node_modules/tailwindcss/node_modules/glob-parent": { - "version": "6.0.2", + "node_modules/protractor/node_modules/wrap-ansi": { + "version": "6.2.0", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "is-glob": "^4.0.3" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=10.13.0" + "node": ">=8" } }, - "node_modules/tapable": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", - "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", "dev": true, + "license": "MIT", "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/tar": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", - "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "node_modules/protractor/node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "dev": true, + "license": "MIT", "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/tar-stream": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", - "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "node_modules/protractor/node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", "dev": true, + "license": "MIT", "dependencies": { - "bl": "^4.0.3", - "end-of-stream": "^1.4.1", - "fs-constants": "^1.0.0", - "inherits": "^2.0.3", - "readable-stream": "^3.1.1" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=6" + "node": ">=8" } }, - "node_modules/tar-stream/node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "node_modules/protractor/node_modules/y18n": { + "version": "4.0.3", + "dev": true, + "license": "ISC" + }, + "node_modules/protractor/node_modules/yargs": { + "version": "15.4.1", "dev": true, + "license": "MIT", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" }, "engines": { - "node": ">= 6" + "node": ">=8" } }, - "node_modules/tar/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "node_modules/protractor/node_modules/yargs-parser": { + "version": "18.1.3", + "dev": true, + "license": "ISC", "dependencies": { - "minipass": "^3.0.0" + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" }, "engines": { - "node": ">= 8" + "node": ">=6" } }, - "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dev": true, "dependencies": { - "yallist": "^4.0.0" + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" }, "engines": { - "node": ">=8" - } - }, - "node_modules/tar/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "engines": { - "node": ">=8" + "node": ">= 0.10" } }, - "node_modules/tar/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "dev": true, "engines": { - "node": ">=10" + "node": ">= 0.10" } }, - "node_modules/tar/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "dev": true }, - "node_modules/terser": { - "version": "5.24.0", - "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", - "integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==", + "node_modules/prr": { + "version": "1.0.1", "dev": true, - "dependencies": { - "@jridgewell/source-map": "^0.3.3", - "acorn": "^8.8.2", - "commander": "^2.20.0", - "source-map-support": "~0.5.20" - }, - "bin": { - "terser": "bin/terser" - }, - "engines": { - "node": ">=10" - } + "license": "MIT", + "optional": true }, - "node_modules/terser-webpack-plugin": { - "version": "5.3.7", + "node_modules/psl": { + "version": "1.9.0", + "dev": true, + "license": "MIT" + }, + "node_modules/pug": { + "version": "2.0.4", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@jridgewell/trace-mapping": "^0.3.17", - "jest-worker": "^27.4.5", - "schema-utils": "^3.1.1", - "serialize-javascript": "^6.0.1", - "terser": "^5.16.5" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.1.0" - }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "uglify-js": { - "optional": true - } + "pug-code-gen": "^2.0.2", + "pug-filters": "^3.1.1", + "pug-lexer": "^4.1.0", + "pug-linker": "^3.0.6", + "pug-load": "^2.0.12", + "pug-parser": "^5.0.1", + "pug-runtime": "^2.0.5", + "pug-strip-comments": "^1.0.4" } }, - "node_modules/terser-webpack-plugin/node_modules/ajv": { - "version": "6.12.6", + "node_modules/pug-attrs": { + "version": "2.0.4", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "constantinople": "^3.0.1", + "js-stringify": "^1.0.1", + "pug-runtime": "^2.0.5" } }, - "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { - "version": "3.5.2", + "node_modules/pug-code-gen": { + "version": "2.0.3", "dev": true, "license": "MIT", - "peerDependencies": { - "ajv": "^6.9.1" + "optional": true, + "dependencies": { + "constantinople": "^3.1.2", + "doctypes": "^1.1.0", + "js-stringify": "^1.0.1", + "pug-attrs": "^2.0.4", + "pug-error": "^1.3.3", + "pug-runtime": "^2.0.5", + "void-elements": "^2.0.1", + "with": "^5.0.0" } }, - "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { - "version": "0.4.1", + "node_modules/pug-error": { + "version": "1.3.3", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, - "node_modules/terser-webpack-plugin/node_modules/schema-utils": { - "version": "3.1.2", + "node_modules/pug-filters": { + "version": "3.1.1", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, - "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "clean-css": "^4.1.11", + "constantinople": "^3.0.1", + "jstransformer": "1.0.0", + "pug-error": "^1.3.3", + "pug-walk": "^1.1.8", + "resolve": "^1.1.6", + "uglify-js": "^2.6.1" } }, - "node_modules/terser/node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", - "dev": true + "node_modules/pug-lexer": { + "version": "4.1.0", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "character-parser": "^2.1.1", + "is-expression": "^3.0.0", + "pug-error": "^1.3.3" + } }, - "node_modules/test-exclude": { - "version": "6.0.0", + "node_modules/pug-linker": { + "version": "3.0.6", "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, "dependencies": { - "@istanbuljs/schema": "^0.1.2", - "glob": "^7.1.4", - "minimatch": "^3.0.4" - }, - "engines": { - "node": ">=8" + "pug-error": "^1.3.3", + "pug-walk": "^1.1.8" } }, - "node_modules/test-exclude/node_modules/glob": { - "version": "7.2.3", + "node_modules/pug-load": { + "version": "2.0.12", "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "object-assign": "^4.1.0", + "pug-walk": "^1.1.8" } }, - "node_modules/text-extensions": { - "version": "1.9.0", + "node_modules/pug-parser": { + "version": "5.0.1", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10" + "optional": true, + "dependencies": { + "pug-error": "^1.3.3", + "token-stream": "0.0.1" } }, - "node_modules/text-table": { - "version": "0.2.0", + "node_modules/pug-runtime": { + "version": "2.0.5", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true }, - "node_modules/thenify": { - "version": "3.3.1", + "node_modules/pug-strip-comments": { + "version": "1.0.4", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "any-promise": "^1.0.0" + "pug-error": "^1.3.3" } }, - "node_modules/thenify-all": { - "version": "1.6.0", + "node_modules/pug-walk": { + "version": "1.1.8", "dev": true, "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, + "optional": true + }, + "node_modules/punycode": { + "version": "2.3.0", + "license": "MIT", "engines": { - "node": ">=0.8" + "node": ">=6" } }, - "node_modules/through": { - "version": "2.3.8", + "node_modules/q": { + "version": "1.5.1", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=0.6.0", + "teleport": ">=0.2.0" + } }, - "node_modules/through2": { - "version": "4.0.2", + "node_modules/qjobs": { + "version": "1.2.0", "dev": true, "license": "MIT", - "dependencies": { - "readable-stream": "3" + "engines": { + "node": ">=0.9" } }, - "node_modules/through2/node_modules/readable-stream": { - "version": "3.6.2", + "node_modules/qs": { + "version": "6.11.1", "dev": true, - "license": "MIT", + "license": "BSD-3-Clause", "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" + "side-channel": "^1.0.4" }, "engines": { - "node": ">= 6" + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/thunky": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", - "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", - "dev": true + "node_modules/queue-microtask": { + "version": "1.2.3", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" }, - "node_modules/tiny-lr": { - "version": "1.1.1", + "node_modules/quick-lru": { + "version": "4.0.1", "dev": true, "license": "MIT", - "dependencies": { - "body": "^5.1.0", - "debug": "^3.1.0", - "faye-websocket": "~0.10.0", - "livereload-js": "^2.3.0", - "object-assign": "^4.1.0", - "qs": "^6.4.0" + "engines": { + "node": ">=8" } }, - "node_modules/tiny-lr/node_modules/debug": { - "version": "3.2.7", + "node_modules/randombytes": { + "version": "2.1.0", "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.1" + "safe-buffer": "^5.1.0" } }, - "node_modules/titleize": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", - "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "node_modules/range-parser": { + "version": "1.2.1", "dev": true, + "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.6" } }, - "node_modules/tmp": { - "version": "0.2.1", + "node_modules/raw-body": { + "version": "2.5.2", "dev": true, "license": "MIT", "dependencies": { - "rimraf": "^3.0.0" + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" }, "engines": { - "node": ">=8.17.0" - } - }, - "node_modules/to-fast-properties": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", - "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, - "engines": { - "node": ">=4" + "node": ">= 0.8" } }, - "node_modules/to-object-path": { - "version": "0.3.0", + "node_modules/raw-body/node_modules/iconv-lite": { + "version": "0.4.24", "dev": true, "license": "MIT", "dependencies": { - "kind-of": "^3.0.2" + "safer-buffer": ">= 2.1.2 < 3" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/to-object-path/node_modules/kind-of": { - "version": "3.2.2", + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/read-cache": { + "version": "1.0.0", "dev": true, "license": "MIT", "dependencies": { - "is-buffer": "^1.1.5" + "pify": "^2.3.0" + } + }, + "node_modules/read-package-json": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz", + "integrity": "sha512-uL4Z10OKV4p6vbdvIXB+OzhInYtIozl/VxUBPgNkBuUi2DeRonnuspmaVAMcrkmfjKGNmRndyQAbE7/AmzGwFg==", + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/to-regex": { + "node_modules/read-package-json-fast": { "version": "3.0.2", - "dev": true, - "license": "MIT", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", "dependencies": { - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "regex-not": "^1.0.2", - "safe-regex": "^1.1.0" + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "devOptional": true, - "license": "MIT", - "dependencies": { - "is-number": "^7.0.0" - }, + "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", "engines": { - "node": ">=8.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/to-regex/node_modules/define-property": { - "version": "2.0.2", - "dev": true, - "license": "MIT", + "node_modules/read-package-json/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dependencies": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "balanced-match": "^1.0.0" + } + }, + "node_modules/read-package-json/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" }, "engines": { - "node": ">=0.10.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/to-regex/node_modules/extend-shallow": { - "version": "3.0.2", - "dev": true, - "license": "MIT", + "node_modules/read-package-json/node_modules/hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", "dependencies": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "lru-cache": "^10.0.1" }, "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/to-regex/node_modules/is-accessor-descriptor": { - "version": "1.0.0", - "dev": true, - "license": "MIT", + "node_modules/read-package-json/node_modules/json-parse-even-better-errors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.0.tgz", + "integrity": "sha512-iZbGHafX/59r39gPwVPRBGw0QQKnA7tte5pSMrhWOW7swGsVvVTjmfyAV9pNqk8YGT7tRCdxRu8uzcgZwoDooA==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json/node_modules/lru-cache": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.0.1.tgz", + "integrity": "sha512-IJ4uwUTi2qCccrioU6g9g/5rvvVl13bsdczUUcqbciD9iLr095yj8DQKdObriEvuNSx325N1rV1O0sJFszx75g==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/read-package-json/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "dependencies": { - "kind-of": "^6.0.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/to-regex/node_modules/is-data-descriptor": { - "version": "1.0.0", - "dev": true, - "license": "MIT", + "node_modules/read-package-json/node_modules/normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", "dependencies": { - "kind-of": "^6.0.0" + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" }, "engines": { - "node": ">=0.10.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/to-regex/node_modules/is-descriptor": { - "version": "1.0.2", + "node_modules/read-pkg": { + "version": "3.0.0", "dev": true, "license": "MIT", "dependencies": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/to-regex/node_modules/is-extendable": { - "version": "1.0.1", + "node_modules/read-pkg/node_modules/path-type": { + "version": "3.0.0", "dev": true, "license": "MIT", "dependencies": { - "is-plain-object": "^2.0.4" + "pify": "^3.0.0" }, "engines": { - "node": ">=0.10.0" + "node": ">=4" } }, - "node_modules/toidentifier": { - "version": "1.0.1", + "node_modules/read-pkg/node_modules/pify": { + "version": "3.0.0", "dev": true, "license": "MIT", "engines": { - "node": ">=0.6" + "node": ">=4" } }, - "node_modules/token-stream": { - "version": "0.0.1", + "node_modules/readable-stream": { + "version": "2.3.8", "dev": true, "license": "MIT", - "optional": true - }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "dev": true, - "license": "BSD-3-Clause", "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" - }, - "engines": { - "node": ">=0.8" - } - }, - "node_modules/tree-kill": { - "version": "1.2.2", - "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" - } - }, - "node_modules/trim-newlines": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/tryor": { - "version": "0.1.2", + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", "dev": true, "license": "MIT" }, - "node_modules/ts-api-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", - "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", + "node_modules/readdirp": { + "version": "3.6.0", "dev": true, - "engines": { - "node": ">=16.13.0" + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" }, - "peerDependencies": { - "typescript": ">=4.2.0" + "engines": { + "node": ">=8.10.0" } }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", + "node_modules/rechoir": { + "version": "0.7.1", "dev": true, - "license": "Apache-2.0" - }, - "node_modules/ts-md5": { - "version": "1.3.1", "license": "MIT", + "dependencies": { + "resolve": "^1.9.0" + }, "engines": { - "node": ">=12" + "node": ">= 0.10" } }, - "node_modules/ts-node": { - "version": "10.9.1", + "node_modules/redent": { + "version": "3.0.0", "dev": true, "license": "MIT", "dependencies": { - "@cspotcode/source-map-support": "^0.8.0", - "@tsconfig/node10": "^1.0.7", - "@tsconfig/node12": "^1.0.7", - "@tsconfig/node14": "^1.0.0", - "@tsconfig/node16": "^1.0.2", - "acorn": "^8.4.1", - "acorn-walk": "^8.1.1", - "arg": "^4.1.0", - "create-require": "^1.1.0", - "diff": "^4.0.1", - "make-error": "^1.1.1", - "v8-compile-cache-lib": "^3.0.1", - "yn": "3.1.1" - }, - "bin": { - "ts-node": "dist/bin.js", - "ts-node-cwd": "dist/bin-cwd.js", - "ts-node-esm": "dist/bin-esm.js", - "ts-node-script": "dist/bin-script.js", - "ts-node-transpile-only": "dist/bin-transpile.js", - "ts-script": "dist/bin-script-deprecated.js" - }, - "peerDependencies": { - "@swc/core": ">=1.2.50", - "@swc/wasm": ">=1.2.50", - "@types/node": "*", - "typescript": ">=2.7" + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" }, - "peerDependenciesMeta": { - "@swc/core": { - "optional": true - }, - "@swc/wasm": { - "optional": true - } + "engines": { + "node": ">=8" } }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.2", + "node_modules/reflect-metadata": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.1.13.tgz", + "integrity": "sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==", + "dev": true + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==", + "dev": true + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", "dev": true, - "license": "BSD-3-Clause", + "dependencies": { + "regenerate": "^1.4.2" + }, "engines": { - "node": ">=0.3.1" + "node": ">=4" } }, - "node_modules/tsconfig-paths": { - "version": "3.14.2", + "node_modules/regenerator-runtime": { + "version": "0.14.0", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.0.tgz", + "integrity": "sha512-srw17NI0TUWHuGa5CFGGmhfNIeja30WMBfbslPNhf6JrqQlLN5gcrvig1oqPxiVaXb0oW0XRKtH6Nngs5lKCIA==", + "dev": true + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", "dev": true, - "license": "MIT", "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" + "@babel/runtime": "^7.8.4" } }, - "node_modules/tsconfig-paths/node_modules/json5": { + "node_modules/regex-not": { "version": "1.0.2", "dev": true, "license": "MIT", "dependencies": { - "minimist": "^1.2.0" + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" }, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" - }, - "node_modules/tuf-js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.1.0.tgz", - "integrity": "sha512-eD7YPPjVlMzdggrOeE8zwoegUaG/rt6Bt3jwoQPunRiNVzgcCE009UDFJKJjG+Gk9wFu6W/Vi+P5d/5QpdD9jA==", + "node_modules/regex-not/node_modules/extend-shallow": { + "version": "3.0.2", + "dev": true, + "license": "MIT", "dependencies": { - "@tufjs/models": "2.0.0", - "debug": "^4.3.4", - "make-fetch-happen": "^13.0.0" + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" }, "engines": { - "node": "^16.14.0 || >=18.0.0" + "node": ">=0.10.0" } }, - "node_modules/tunnel-agent": { - "version": "0.6.0", + "node_modules/regex-not/node_modules/is-extendable": { + "version": "1.0.1", "dev": true, - "license": "Apache-2.0", + "license": "MIT", "dependencies": { - "safe-buffer": "^5.0.1" + "is-plain-object": "^2.0.4" }, "engines": { - "node": "*" + "node": ">=0.10.0" } }, - "node_modules/tweetnacl": { - "version": "0.14.5", + "node_modules/regex-parser": { + "version": "2.2.11", "dev": true, - "license": "Unlicense" + "license": "MIT" }, - "node_modules/type-check": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", - "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "node_modules/regexp.prototype.flags": { + "version": "1.5.0", "dev": true, + "license": "MIT", "dependencies": { - "prelude-ls": "^1.2.1" + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "functions-have-names": "^1.2.3" }, "engines": { - "node": ">= 0.8.0" - } - }, - "node_modules/type-fest": { - "version": "0.21.3", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", - "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", - "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/type-is": { - "version": "1.6.18", + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", "dev": true, - "license": "MIT", "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" }, "engines": { - "node": ">= 0.6" + "node": ">=4" } }, - "node_modules/typed-array-length": { - "version": "1.0.4", + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", "dev": true, - "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "is-typed-array": "^1.1.9" + "jsesc": "~0.5.0" }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "bin": { + "regjsparser": "bin/parser" } }, - "node_modules/typed-assert": { - "version": "1.0.9", - "dev": true, - "license": "MIT" - }, - "node_modules/typescript": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", - "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", "dev": true, "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" + "jsesc": "bin/jsesc" } }, - "node_modules/ua-parser-js": { - "version": "1.0.37", - "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz", - "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==", + "node_modules/relateurl": { + "version": "0.2.7", "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/ua-parser-js" - }, - { - "type": "paypal", - "url": "https://paypal.me/faisalman" - }, - { - "type": "github", - "url": "https://github.com/sponsors/faisalman" - } - ], + "license": "MIT", "engines": { - "node": "*" + "node": ">= 0.10" } }, - "node_modules/uglify-js": { - "version": "2.7.5", + "node_modules/remove-trailing-separator": { + "version": "1.1.0", "dev": true, - "license": "BSD-2-Clause", - "optional": true, - "dependencies": { - "async": "~0.2.6", - "source-map": "~0.5.1", - "uglify-to-browserify": "~1.0.0", - "yargs": "~3.10.0" - }, - "bin": { - "uglifyjs": "bin/uglifyjs" - }, - "engines": { - "node": ">=0.8.0" - } + "license": "ISC" }, - "node_modules/uglify-js/node_modules/async": { - "version": "0.2.10", + "node_modules/repeat-element": { + "version": "1.1.4", "dev": true, - "optional": true + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/uglify-js/node_modules/camelcase": { - "version": "1.2.1", + "node_modules/repeat-string": { + "version": "1.6.1", "dev": true, "license": "MIT", - "optional": true, "engines": { - "node": ">=0.10.0" + "node": ">=0.10" } }, - "node_modules/uglify-js/node_modules/cliui": { - "version": "2.1.0", + "node_modules/request": { + "version": "2.88.2", "dev": true, - "license": "ISC", - "optional": true, + "license": "Apache-2.0", "dependencies": { - "center-align": "^0.1.1", - "right-align": "^0.1.1", - "wordwrap": "0.0.2" + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + }, + "engines": { + "node": ">= 6" } }, - "node_modules/uglify-js/node_modules/source-map": { - "version": "0.5.7", + "node_modules/request/node_modules/qs": { + "version": "6.5.3", "dev": true, "license": "BSD-3-Clause", - "optional": true, "engines": { - "node": ">=0.10.0" + "node": ">=0.6" } }, - "node_modules/uglify-js/node_modules/wordwrap": { - "version": "0.0.2", - "dev": true, - "license": "MIT/X11", - "optional": true, + "node_modules/require-directory": { + "version": "2.1.1", + "license": "MIT", "engines": { - "node": ">=0.4.0" + "node": ">=0.10.0" } }, - "node_modules/uglify-js/node_modules/yargs": { - "version": "3.10.0", - "dev": true, + "node_modules/require-from-string": { + "version": "2.0.2", "license": "MIT", - "optional": true, - "dependencies": { - "camelcase": "^1.0.2", - "cliui": "^2.1.0", - "decamelize": "^1.0.0", - "window-size": "0.1.0" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/uglify-to-browserify": { - "version": "1.0.2", - "license": "MIT" + "node_modules/require-main-filename": { + "version": "2.0.0", + "dev": true, + "license": "ISC" }, - "node_modules/unbox-primitive": { - "version": "1.0.2", + "node_modules/requires-port": { + "version": "1.0.0", "dev": true, - "license": "MIT", + "license": "MIT" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", "dependencies": { - "call-bind": "^1.0.2", - "has-bigints": "^1.0.2", - "has-symbols": "^1.0.3", - "which-boxed-primitive": "^1.0.2" + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/unc-path-regex": { - "version": "0.1.2", + "node_modules/resolve-dir": { + "version": "1.0.1", "dev": true, "license": "MIT", + "dependencies": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + }, "engines": { "node": ">=0.10.0" } }, - "node_modules/underscore": { - "version": "1.13.6", + "node_modules/resolve-from": { + "version": "5.0.0", "dev": true, - "license": "MIT" - }, - "node_modules/underscore.string": { - "version": "2.3.3", + "license": "MIT", "engines": { - "node": "*" + "node": ">=8" } }, - "node_modules/undici": { - "version": "5.27.2", - "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", - "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", + "node_modules/resolve-global": { + "version": "1.0.0", "dev": true, + "license": "MIT", "dependencies": { - "@fastify/busboy": "^2.0.0" + "global-dirs": "^0.1.1" }, "engines": { - "node": ">=14.0" + "node": ">=8" } }, - "node_modules/unicode-canonical-property-names-ecmascript": { + "node_modules/resolve-pkg": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", - "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", "dev": true, + "license": "MIT", + "dependencies": { + "resolve-from": "^5.0.0" + }, "engines": { - "node": ">=4" + "node": ">=8" } }, - "node_modules/unicode-match-property-ecmascript": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", - "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "node_modules/resolve-url": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve-url-loader": { + "version": "5.0.0", "dev": true, + "license": "MIT", "dependencies": { - "unicode-canonical-property-names-ecmascript": "^2.0.0", - "unicode-property-aliases-ecmascript": "^2.0.0" + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" }, "engines": { - "node": ">=4" + "node": ">=12" } }, - "node_modules/unicode-match-property-value-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", - "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "node_modules/resolve-url-loader/node_modules/loader-utils": { + "version": "2.0.4", "dev": true, + "license": "MIT", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, "engines": { - "node": ">=4" + "node": ">=8.9.0" } }, - "node_modules/unicode-property-aliases-ecmascript": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", - "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/union-value": { - "version": "1.0.1", + "node_modules/resp-modifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz", + "integrity": "sha512-U1+0kWC/+4ncRFYqQWTx/3qkfE6a4B/h3XXgmXypfa0SPZ3t7cbbaFk297PjQS/yov24R18h6OZe6iZwj3NSLw==", "dev": true, - "license": "MIT", "dependencies": { - "arr-union": "^3.1.0", - "get-value": "^2.0.6", - "is-extendable": "^0.1.1", - "set-value": "^2.0.1" + "debug": "^2.2.0", + "minimatch": "^3.0.2" }, "engines": { - "node": ">=0.10.0" + "node": ">= 0.8.0" } }, - "node_modules/unique-filename": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", - "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "node_modules/resp-modifier/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, "dependencies": { - "unique-slug": "^4.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "ms": "2.0.0" } }, - "node_modules/unique-slug": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", - "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "node_modules/resp-modifier/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "license": "MIT", "dependencies": { - "imurmurhash": "^0.1.4" + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" }, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": ">=8" } }, - "node_modules/universalify": { - "version": "2.0.0", + "node_modules/ret": { + "version": "0.1.15", "dev": true, "license": "MIT", "engines": { - "node": ">= 10.0.0" + "node": ">=0.12" } }, - "node_modules/unpipe": { - "version": "1.0.0", - "dev": true, - "license": "MIT", + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "engines": { - "node": ">= 0.8" + "node": ">= 4" } }, - "node_modules/unset-value": { - "version": "1.0.0", + "node_modules/reusify": { + "version": "1.0.4", "dev": true, "license": "MIT", - "dependencies": { - "has-value": "^0.3.1", - "isobject": "^3.0.0" - }, "engines": { + "iojs": ">=1.0.0", "node": ">=0.10.0" } }, - "node_modules/unset-value/node_modules/has-value": { - "version": "0.3.1", + "node_modules/rfdc": { + "version": "1.3.0", + "license": "MIT" + }, + "node_modules/right-align": { + "version": "0.1.3", "dev": true, "license": "MIT", + "optional": true, "dependencies": { - "get-value": "^2.0.3", - "has-values": "^0.1.4", - "isobject": "^2.0.0" + "align-text": "^0.1.1" }, "engines": { "node": ">=0.10.0" } }, - "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { - "version": "2.1.0", + "node_modules/rimraf": { + "version": "3.0.2", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "isarray": "1.0.0" + "glob": "^7.1.3" }, - "engines": { - "node": ">=0.10.0" + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/unset-value/node_modules/has-values": { - "version": "0.1.4", + "node_modules/rimraf/node_modules/glob": { + "version": "7.2.3", "dev": true, - "license": "MIT", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, "engines": { - "node": ">=0.10.0" + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/unset-value/node_modules/isarray": { - "version": "1.0.0", + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, - "license": "MIT" + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } }, - "node_modules/untildify": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", - "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "node_modules/run-applescript": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-5.0.0.tgz", + "integrity": "sha512-XcT5rBksx1QdIhlFOCtgZkB99ZEouFZ1E2Kc2LHqNW13U3/74YGdkQRmThTwxy4QIyookibDKYZOPqX//6BlAg==", "dev": true, + "dependencies": { + "execa": "^5.0.0" + }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/upath": { - "version": "1.2.0", - "dev": true, - "license": "MIT", + "node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", "engines": { - "node": ">=4", - "yarn": "*" + "node": ">=0.12.0" } }, - "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "node_modules/run-parallel": { + "version": "1.2.0", "dev": true, "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" + "type": "github", + "url": "https://github.com/sponsors/feross" }, { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/browserslist" + "type": "patreon", + "url": "https://www.patreon.com/feross" }, { - "type": "github", - "url": "https://github.com/sponsors/ai" + "type": "consulting", + "url": "https://feross.org/support" } ], + "license": "MIT", "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" - }, - "bin": { - "update-browserslist-db": "cli.js" - }, - "peerDependencies": { - "browserslist": ">= 4.21.0" + "queue-microtask": "^1.2.2" } }, - "node_modules/upper-case": { - "version": "1.1.3", - "dev": true, - "license": "MIT" + "node_modules/rx": { + "version": "2.3.24", + "dev": true }, - "node_modules/uri-js": { - "version": "4.4.1", - "license": "BSD-2-Clause", + "node_modules/rxjs": { + "version": "7.4.0", + "license": "Apache-2.0", "dependencies": { - "punycode": "^2.1.0" - } - }, - "node_modules/uri-path": { - "version": "1.0.0", - "dev": true, - "license": "WTFPL OR MIT", - "engines": { - "node": ">= 0.10" + "tslib": "~2.1.0" } }, - "node_modules/urix": { - "version": "0.1.0", - "dev": true, - "license": "MIT" - }, - "node_modules/use": { - "version": "3.1.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "node_modules/rxjs/node_modules/tslib": { + "version": "2.1.0", + "license": "0BSD" }, - "node_modules/util-deprecate": { - "version": "1.0.2", + "node_modules/safe-buffer": { + "version": "5.1.2", "license": "MIT" }, - "node_modules/utils-merge": { + "node_modules/safe-json-parse": { "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } + "dev": true }, - "node_modules/uuid": { - "version": "3.4.0", + "node_modules/safe-regex": { + "version": "1.1.0", "dev": true, "license": "MIT", - "bin": { - "uuid": "bin/uuid" + "dependencies": { + "ret": "~0.1.10" } }, - "node_modules/v8-compile-cache": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", - "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", - "dev": true - }, - "node_modules/v8-compile-cache-lib": { - "version": "3.0.1", - "dev": true, - "license": "MIT" - }, - "node_modules/v8flags": { - "version": "3.2.0", + "node_modules/safe-regex-test": { + "version": "1.0.0", "dev": true, "license": "MIT", "dependencies": { - "homedir-polyfill": "^1.0.1" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "is-regex": "^1.1.4" }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/validate-npm-package-name": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", - "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", - "dependencies": { - "builtins": "^5.0.0" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "node_modules/safer-buffer": { + "version": "2.1.2", + "license": "MIT" }, - "node_modules/vary": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } + "node_modules/safevalues": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/safevalues/-/safevalues-0.3.4.tgz", + "integrity": "sha512-LRneZZRXNgjzwG4bDQdOTSbze3fHm1EAKN/8bePxnlEZiBmkYEDggaHbuvHI9/hoqHbGfsEA7tWS9GhYHZBBsw==" }, - "node_modules/verror": { - "version": "1.10.0", + "node_modules/sass": { + "version": "1.69.5", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.69.5.tgz", + "integrity": "sha512-qg2+UCJibLr2LCVOt3OlPhr/dqVHWOa9XtZf2OjbLs/T4VPSJ00udtgJxH3neXZm+QqX8B+3cU7RaLqp1iVfcQ==", "dev": true, - "engines": [ - "node >=0.6.0" - ], - "license": "MIT", "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" } }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "dev": true, - "license": "MIT" - }, - "node_modules/vite": { - "version": "4.5.0", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", - "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", + "node_modules/sass-loader": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-13.3.2.tgz", + "integrity": "sha512-CQbKl57kdEv+KDLquhC+gE3pXt74LEAzm+tzywcA0/aHZuub8wTErbjAoNI57rPUWRYRNC5WUnNl8eGJNbDdwg==", "dev": true, "dependencies": { - "esbuild": "^0.18.10", - "postcss": "^8.4.27", - "rollup": "^3.27.1" - }, - "bin": { - "vite": "bin/vite.js" + "neo-async": "^2.6.2" }, "engines": { - "node": "^14.18.0 || >=16.0.0" + "node": ">= 14.15.0" }, "funding": { - "url": "https://github.com/vitejs/vite?sponsor=1" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" + "type": "opencollective", + "url": "https://opencollective.com/webpack" }, "peerDependencies": { - "@types/node": ">= 14", - "less": "*", - "lightningcss": "^1.21.0", - "sass": "*", - "stylus": "*", - "sugarss": "*", - "terser": "^5.4.0" + "fibers": ">= 3.1.0", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" }, "peerDependenciesMeta": { - "@types/node": { - "optional": true - }, - "less": { + "fibers": { "optional": true }, - "lightningcss": { + "node-sass": { "optional": true }, "sass": { "optional": true }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { + "sass-embedded": { "optional": true } } }, - "node_modules/void-elements": { - "version": "2.0.1", + "node_modules/sass/node_modules/immutable": { + "version": "4.3.0", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "license": "MIT" }, - "node_modules/watchpack": { - "version": "2.4.0", + "node_modules/saucelabs": { + "version": "1.5.0", "dev": true, - "license": "MIT", "dependencies": { - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.1.2" + "https-proxy-agent": "^2.2.1" }, "engines": { - "node": ">=10.13.0" + "node": "*" } }, - "node_modules/wbuf": { - "version": "1.7.3", - "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", - "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "node_modules/saucelabs/node_modules/agent-base": { + "version": "4.3.0", "dev": true, - "dependencies": { - "minimalistic-assert": "^1.0.0" - } - }, - "node_modules/wcwidth": { - "version": "1.0.1", "license": "MIT", "dependencies": { - "defaults": "^1.0.3" - } - }, - "node_modules/web-streams-polyfill": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", - "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "es6-promisify": "^5.0.0" + }, "engines": { - "node": ">= 8" + "node": ">= 4.0.0" } }, - "node_modules/webdriver-js-extender": { - "version": "2.1.0", + "node_modules/saucelabs/node_modules/debug": { + "version": "3.2.7", "dev": true, "license": "MIT", "dependencies": { - "@types/selenium-webdriver": "^3.0.0", - "selenium-webdriver": "^3.0.1" - }, - "engines": { - "node": ">=6.9.x" + "ms": "^2.1.1" } }, - "node_modules/webdriver-manager": { - "version": "12.1.9", + "node_modules/saucelabs/node_modules/https-proxy-agent": { + "version": "2.2.4", "dev": true, "license": "MIT", "dependencies": { - "adm-zip": "^0.5.2", - "chalk": "^1.1.1", - "del": "^2.2.0", - "glob": "^7.0.3", - "ini": "^1.3.4", - "minimist": "^1.2.0", - "q": "^1.4.1", - "request": "^2.87.0", - "rimraf": "^2.5.2", - "semver": "^5.3.0", - "xml2js": "^0.4.17" - }, - "bin": { - "webdriver-manager": "bin/webdriver-manager" + "agent-base": "^4.3.0", + "debug": "^3.1.0" }, "engines": { - "node": ">=6.9.x" + "node": ">= 4.5.0" } }, - "node_modules/webdriver-manager/node_modules/ansi-regex": { - "version": "2.1.1", + "node_modules/sax": { + "version": "1.2.4", "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "license": "ISC" }, - "node_modules/webdriver-manager/node_modules/ansi-styles": { - "version": "2.2.1", + "node_modules/schema-utils": { + "version": "4.0.1", "dev": true, "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/webdriver-manager/node_modules/chalk": { - "version": "1.1.3", + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==", + "dev": true + }, + "node_modules/selenium-webdriver": { + "version": "3.6.0", "dev": true, - "license": "MIT", + "license": "Apache-2.0", "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "jszip": "^3.1.3", + "rimraf": "^2.5.4", + "tmp": "0.0.30", + "xml2js": "^0.4.17" }, "engines": { - "node": ">=0.10.0" + "node": ">= 6.9.0" } }, - "node_modules/webdriver-manager/node_modules/glob": { + "node_modules/selenium-webdriver/node_modules/glob": { "version": "7.2.3", "dev": true, "license": "ISC", @@ -24549,12 +24633,7 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/webdriver-manager/node_modules/ini": { - "version": "1.3.8", - "dev": true, - "license": "ISC" - }, - "node_modules/webdriver-manager/node_modules/rimraf": { + "node_modules/selenium-webdriver/node_modules/rimraf": { "version": "2.7.1", "dev": true, "license": "ISC", @@ -24565,719 +24644,3441 @@ "rimraf": "bin.js" } }, - "node_modules/webdriver-manager/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/webdriver-manager/node_modules/strip-ansi": { - "version": "3.0.1", + "node_modules/selenium-webdriver/node_modules/tmp": { + "version": "0.0.30", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^2.0.0" + "os-tmpdir": "~1.0.1" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.4.0" } }, - "node_modules/webdriver-manager/node_modules/supports-color": { - "version": "2.0.0", + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", "dev": true, - "license": "MIT", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, "engines": { - "node": ">=0.8.0" + "node": ">=10" } }, - "node_modules/webpack": { - "version": "5.89.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", - "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", - "dev": true, + "node_modules/semver": { + "version": "7.5.3", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.3.tgz", + "integrity": "sha512-QBlUtyVk/5EeHbi7X0fw6liDZc7BBmEaSYn01fMU1OUYbf6GPsbTtd8WmnqbI20SeycoHSeiybkE/q1Q+qlThQ==", "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.0", - "@webassemblyjs/ast": "^1.11.5", - "@webassemblyjs/wasm-edit": "^1.11.5", - "@webassemblyjs/wasm-parser": "^1.11.5", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.14.5", - "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.15.0", - "es-module-lexer": "^1.2.1", - "eslint-scope": "5.1.1", - "events": "^3.2.0", - "glob-to-regexp": "^0.4.1", - "graceful-fs": "^4.2.9", - "json-parse-even-better-errors": "^2.3.1", - "loader-runner": "^4.2.0", - "mime-types": "^2.1.27", - "neo-async": "^2.6.2", - "schema-utils": "^3.2.0", - "tapable": "^2.1.1", - "terser-webpack-plugin": "^5.3.7", - "watchpack": "^2.4.0", - "webpack-sources": "^3.2.3" + "lru-cache": "^6.0.0" }, "bin": { - "webpack": "bin/webpack.js" + "semver": "bin/semver.js" }, "engines": { - "node": ">=10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependenciesMeta": { - "webpack-cli": { - "optional": true - } + "node": ">=10" } }, - "node_modules/webpack-dev-middleware": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.1.tgz", - "integrity": "sha512-y51HrHaFeeWir0YO4f0g+9GwZawuigzcAdRNon6jErXy/SqV/+O6eaVAzDqE6t3e3NpGeR5CS+cCDaTC+V3yEQ==", - "dev": true, + "node_modules/semver/node_modules/lru-cache": { + "version": "6.0.0", + "license": "ISC", "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.12", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" + "yallist": "^4.0.0" }, "engines": { - "node": ">= 14.15.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - } + "node": ">=10" } }, - "node_modules/webpack-dev-server": { - "version": "4.15.1", - "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", - "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "node_modules/semver/node_modules/yallist": { + "version": "4.0.0", + "license": "ISC" + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", "dev": true, "dependencies": { - "@types/bonjour": "^3.5.9", - "@types/connect-history-api-fallback": "^1.3.5", - "@types/express": "^4.17.13", - "@types/serve-index": "^1.9.1", - "@types/serve-static": "^1.13.10", - "@types/sockjs": "^0.3.33", - "@types/ws": "^8.5.5", - "ansi-html-community": "^0.0.8", - "bonjour-service": "^1.0.11", - "chokidar": "^3.5.3", - "colorette": "^2.0.10", - "compression": "^1.7.4", - "connect-history-api-fallback": "^2.0.0", - "default-gateway": "^6.0.3", - "express": "^4.17.3", - "graceful-fs": "^4.2.6", - "html-entities": "^2.3.2", - "http-proxy-middleware": "^2.0.3", - "ipaddr.js": "^2.0.1", - "launch-editor": "^2.6.0", - "open": "^8.0.9", - "p-retry": "^4.5.0", - "rimraf": "^3.0.2", - "schema-utils": "^4.0.0", - "selfsigned": "^2.1.1", - "serve-index": "^1.9.1", - "sockjs": "^0.3.24", - "spdy": "^4.0.2", - "webpack-dev-middleware": "^5.3.1", - "ws": "^8.13.0" - }, - "bin": { - "webpack-dev-server": "bin/webpack-dev-server.js" + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" }, "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.37.0 || ^5.0.0" - }, - "peerDependenciesMeta": { - "webpack": { - "optional": true - }, - "webpack-cli": { - "optional": true - } + "node": ">= 0.8.0" } }, - "node_modules/webpack-dev-server/node_modules/connect-history-api-fallback": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", - "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, - "engines": { - "node": ">=0.8" + "dependencies": { + "ms": "2.0.0" } }, - "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { - "version": "5.3.3", - "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", - "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", "dev": true, - "dependencies": { - "colorette": "^2.0.10", - "memfs": "^3.4.3", - "mime-types": "^2.1.31", - "range-parser": "^1.2.1", - "schema-utils": "^4.0.0" + "bin": { + "mime": "cli.js" }, "engines": { - "node": ">= 12.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" - }, - "peerDependencies": { - "webpack": "^4.0.0 || ^5.0.0" + "node": ">=4" } }, - "node_modules/webpack-dev-server/node_modules/ws": { - "version": "8.14.2", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", - "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", - "dev": true, - "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } - } + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true }, - "node_modules/webpack-merge": { - "version": "5.10.0", - "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", - "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "dependencies": { - "clone-deep": "^4.0.1", - "flat": "^5.0.2", - "wildcard": "^2.0.0" + "ee-first": "1.1.1" }, "engines": { - "node": ">=10.0.0" + "node": ">= 0.8" } }, - "node_modules/webpack-sources": { - "version": "3.2.3", + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", "dev": true, - "license": "MIT", "engines": { - "node": ">=10.13.0" + "node": ">= 0.8" } }, - "node_modules/webpack-subresource-integrity": { - "version": "5.1.0", + "node_modules/serialize-javascript": { + "version": "6.0.1", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", "dev": true, "license": "MIT", "dependencies": { - "typed-assert": "^1.0.8" + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" }, "engines": { - "node": ">= 12" - }, - "peerDependencies": { - "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", - "webpack": "^5.12.0" - }, - "peerDependenciesMeta": { - "html-webpack-plugin": { - "optional": true - } + "node": ">= 0.8.0" } }, - "node_modules/webpack/node_modules/ajv": { - "version": "6.12.6", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", - "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", "dev": true, + "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "ms": "2.0.0" } }, - "node_modules/webpack/node_modules/ajv-keywords": { - "version": "3.5.2", - "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", - "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", "dev": true, - "peerDependencies": { - "ajv": "^6.9.1" + "license": "MIT", + "engines": { + "node": ">= 0.6" } }, - "node_modules/webpack/node_modules/eslint-scope": { - "version": "5.1.1", + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", "dev": true, - "license": "BSD-2-Clause", + "license": "MIT", "dependencies": { - "esrecurse": "^4.3.0", - "estraverse": "^4.1.1" + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" }, "engines": { - "node": ">=8.0.0" + "node": ">= 0.6" } }, - "node_modules/webpack/node_modules/estraverse": { - "version": "4.3.0", + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", "dev": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=4.0" - } + "license": "ISC" }, - "node_modules/webpack/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" }, - "node_modules/webpack/node_modules/schema-utils": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", - "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", "dev": true, - "dependencies": { - "@types/json-schema": "^7.0.8", - "ajv": "^6.12.5", - "ajv-keywords": "^3.5.2" - }, + "license": "ISC" + }, + "node_modules/serve-index/node_modules/statuses": { + "version": "1.5.0", + "dev": true, + "license": "MIT", "engines": { - "node": ">= 10.13.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/webpack" + "node": ">= 0.6" } }, - "node_modules/websocket-driver": { - "version": "0.7.4", + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", "dev": true, - "license": "Apache-2.0", "dependencies": { - "http-parser-js": ">=0.5.1", - "safe-buffer": ">=5.1.0", - "websocket-extensions": ">=0.1.1" + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" }, "engines": { - "node": ">=0.8.0" + "node": ">= 0.8.0" } }, - "node_modules/websocket-extensions": { - "version": "0.1.4", + "node_modules/server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", + "dev": true + }, + "node_modules/set-blocking": { + "version": "2.0.0", "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">=0.8.0" - } + "license": "ISC" }, - "node_modules/which": { - "version": "2.0.2", - "license": "ISC", + "node_modules/set-value": { + "version": "2.0.1", + "dev": true, + "license": "MIT", "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" }, "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, - "node_modules/which-boxed-primitive": { - "version": "1.0.2", + "node_modules/setimmediate": { + "version": "1.0.5", "dev": true, - "license": "MIT", - "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } + "license": "MIT" }, - "node_modules/which-module": { - "version": "2.0.1", + "node_modules/setprototypeof": { + "version": "1.2.0", "dev": true, "license": "ISC" }, - "node_modules/which-typed-array": { - "version": "1.1.9", + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", "dev": true, - "license": "MIT", "dependencies": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0", - "is-typed-array": "^1.1.10" + "kind-of": "^6.0.2" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/wildcard": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", - "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", - "dev": true + "node_modules/shebang-command": { + "version": "2.0.0", + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } }, - "node_modules/window-size": { - "version": "0.1.0", + "node_modules/shebang-regex": { + "version": "3.0.0", + "license": "MIT", "engines": { - "node": ">= 0.8.0" + "node": ">=8" } }, - "node_modules/with": { - "version": "5.1.1", + "node_modules/shell-quote": { + "version": "1.8.1", "dev": true, "license": "MIT", - "optional": true, - "dependencies": { - "acorn": "^3.1.0", - "acorn-globals": "^3.0.0" + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/with/node_modules/acorn": { - "version": "3.3.0", + "node_modules/shelljs": { + "version": "0.3.0", "dev": true, - "license": "MIT", - "optional": true, + "license": "BSD*", "bin": { - "acorn": "bin/acorn" + "shjs": "bin/shjs" }, "engines": { - "node": ">=0.4.0" + "node": ">=0.8.0" } }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "license": "MIT", + "node_modules/showdown": { + "version": "1.3.0", + "license": "BSD-2-Clause", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" + "yargs": "^3.15.0" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "bin": { + "showdown": "bin/showdown.js" } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/showdown/node_modules/ansi-regex": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/showdown/node_modules/camelcase": { + "version": "2.1.1", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/showdown/node_modules/cliui": { + "version": "3.2.0", + "license": "ISC", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "node_modules/showdown/node_modules/is-fullwidth-code-point": { + "version": "1.0.0", + "license": "MIT", + "dependencies": { + "number-is-nan": "^1.0.0" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "node_modules/showdown/node_modules/string-width": { + "version": "1.0.2", + "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/wrap-ansi-cjs/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/showdown/node_modules/strip-ansi": { + "version": "3.0.1", + "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "ansi-regex": "^2.0.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=0.10.0" } }, - "node_modules/wrap-ansi-cjs/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "node_modules/showdown/node_modules/window-size": { + "version": "0.1.4", + "license": "MIT", + "bin": { + "window-size": "cli.js" + }, + "engines": { + "node": ">= 0.10.0" + } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", + "node_modules/showdown/node_modules/wrap-ansi": { + "version": "2.1.0", "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" }, "engines": { - "node": ">=8" + "node": ">=0.10.0" + } + }, + "node_modules/showdown/node_modules/y18n": { + "version": "3.2.2", + "license": "ISC" + }, + "node_modules/showdown/node_modules/yargs": { + "version": "3.32.0", + "license": "MIT", + "dependencies": { + "camelcase": "^2.0.1", + "cliui": "^3.0.3", + "decamelize": "^1.1.1", + "os-locale": "^1.4.0", + "string-width": "^1.0.1", + "window-size": "^0.1.4", + "y18n": "^3.2.0" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "license": "MIT", + "node_modules/sigmund": { + "version": "1.0.1", + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "license": "ISC" + }, + "node_modules/sigstore": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.1.0.tgz", + "integrity": "sha512-kPIj+ZLkyI3QaM0qX8V/nSsweYND3W448pwkDgS6CQ74MfhEkIR8ToK5Iyx46KJYRjseVcD3Rp9zAmUAj6ZjPw==", "dependencies": { - "color-name": "~1.1.4" + "@sigstore/bundle": "^2.1.0", + "@sigstore/protobuf-specs": "^0.2.1", + "@sigstore/sign": "^2.1.0", + "@sigstore/tuf": "^2.1.0" }, "engines": { - "node": ">=7.0.0" + "node": "^16.14.0 || >=18.0.0" } }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", + "node_modules/simple-fmt": { + "version": "0.1.0", + "dev": true, "license": "MIT" }, - "node_modules/wrappy": { - "version": "1.0.2", + "node_modules/simple-is": { + "version": "0.2.0", "dev": true, - "license": "ISC" + "license": "MIT" }, - "node_modules/ws": { - "version": "8.11.0", + "node_modules/slash": { + "version": "3.0.0", "dev": true, "license": "MIT", "engines": { - "node": ">=10.0.0" - }, - "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": "^5.0.2" - }, - "peerDependenciesMeta": { - "bufferutil": { - "optional": true - }, - "utf-8-validate": { - "optional": true - } + "node": ">=8" } }, - "node_modules/xml2js": { - "version": "0.4.23", + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/snapdragon": { + "version": "0.8.2", "dev": true, "license": "MIT", "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" }, "engines": { - "node": ">=4.0.0" + "node": ">=0.10.0" } }, - "node_modules/xmlbuilder": { - "version": "11.0.1", + "node_modules/snapdragon-node": { + "version": "2.1.1", "dev": true, "license": "MIT", + "dependencies": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, "engines": { - "node": ">=4.0" + "node": ">=0.10.0" } }, - "node_modules/xmlhttprequest-ssl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", - "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "node_modules/snapdragon-node/node_modules/define-property": { + "version": "1.0.0", "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.0" + }, "engines": { - "node": ">=0.4.0" + "node": ">=0.10.0" } }, - "node_modules/xregexp": { - "version": "3.1.0", + "node_modules/snapdragon-node/node_modules/is-accessor-descriptor": { + "version": "1.0.0", "dev": true, - "license": "MIT" - }, - "node_modules/y18n": { - "version": "5.0.8", - "license": "ISC", + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.0" + }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/yallist": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", - "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", - "dev": true + "node_modules/snapdragon-node/node_modules/is-data-descriptor": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } }, - "node_modules/yaml": { - "version": "1.10.2", + "node_modules/snapdragon-node/node_modules/is-descriptor": { + "version": "1.0.2", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, "engines": { - "node": ">= 6" + "node": ">=0.10.0" } }, - "node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "node_modules/snapdragon-util": { + "version": "3.0.1", + "dev": true, + "license": "MIT", "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "kind-of": "^3.2.0" }, "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/yargs-parser": { - "version": "20.2.9", + "node_modules/snapdragon-util/node_modules/kind-of": { + "version": "3.2.2", "dev": true, - "license": "ISC", + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, "engines": { - "node": ">=10" + "node": ">=0.10.0" } }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "21.1.1", - "license": "ISC", + "node_modules/snapdragon/node_modules/debug": { + "version": "2.6.9", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/snapdragon/node_modules/ms": { + "version": "2.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/snapdragon/node_modules/source-map": { + "version": "0.5.7", + "dev": true, + "license": "BSD-3-Clause", "engines": { - "node": ">=12" + "node": ">=0.10.0" } }, - "node_modules/yn": { - "version": "3.1.1", + "node_modules/socket.io": { + "version": "4.6.1", "dev": true, "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "debug": "~4.3.2", + "engine.io": "~6.4.1", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.1" + }, "engines": { - "node": ">=6" + "node": ">=10.0.0" } }, - "node_modules/yocto-queue": { - "version": "0.1.0", + "node_modules/socket.io-adapter": { + "version": "2.5.2", "dev": true, "license": "MIT", + "dependencies": { + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-client": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.2.tgz", + "integrity": "sha512-vtA0uD4ibrYD793SOIAwlo8cj6haOeMHrGvwPxJsxH7CeIksqJ+3Zc06RvWTIFgiSqx4A3sOnTXpfAEE2Zyz6w==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, "engines": { - "node": ">=10" + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "dev": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=10.0.0" } }, - "node_modules/zlib-browserify": { - "version": "0.0.1", - "license": "MIT" + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dev": true, + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } }, - "node_modules/zone.js": { - "version": "0.14.2", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.2.tgz", - "integrity": "sha512-X4U7J1isDhoOmHmFWiLhloWc2lzMkdnumtfQ1LXzf/IOZp5NQYuMUTaviVzG/q1ugMBIXzin2AqeVJUoSEkNyQ==", + "node_modules/sockjs/node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dev": true, "dependencies": { - "tslib": "^2.3.0" + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" } - } - }, - "dependencies": { - "@aashutoshrathi/word-wrap": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", - "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", - "dev": true }, - "@alloc/quick-lru": { - "version": "5.2.0", - "dev": true + "node_modules/sockjs/node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "dev": true, + "bin": { + "uuid": "dist/bin/uuid" + } }, - "@ampproject/remapping": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", - "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", + "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/socks/node_modules/ip": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", + "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", "dev": true, - "requires": { - "@jridgewell/gen-mapping": "^0.3.0", - "@jridgewell/trace-mapping": "^0.3.9" + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" } }, - "@angular-devkit/architect": { - "version": "0.1700.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1700.1.tgz", - "integrity": "sha512-w84luzQNRjlt7XxX3+jyzcwBBv3gAjjvFWTjN1E5mlpDCUXgYmQ3CMowFHeu0U06HD5Sapap9p2l6GoajuZK5Q==", - "requires": { - "@angular-devkit/core": "17.0.1", - "rxjs": "7.8.1" + "node_modules/source-map-loader": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "abab": "^2.0.6", + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" }, + "peerDependencies": { + "webpack": "^5.72.1" + } + }, + "node_modules/source-map-resolve": { + "version": "0.5.3", + "dev": true, + "license": "MIT", "dependencies": { - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "requires": { - "tslib": "^2.1.0" - } - } + "atob": "^2.1.2", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" } }, - "@angular-devkit/build-angular": { - "version": "17.0.1", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-17.0.1.tgz", - "integrity": "sha512-OomGAeBg/OOxzPpoU7EkdD3WwhKip+0Giy/cGtkalSgQ5vWTuZhf8UnxwTf7xEXW5LtvfoTtv7sKmb1dJT7FzA==", + "node_modules/source-map-support": { + "version": "0.5.21", "dev": true, - "requires": { - "@ampproject/remapping": "2.2.1", + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-url": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/spawn-command": { + "version": "0.0.2-1", + "dev": true, + "license": "MIT" + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "license": "Apache-2.0", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.3.0", + "license": "CC-BY-3.0" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.13", + "license": "CC0-1.0" + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dev": true, + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/split-string": { + "version": "3.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "extend-shallow": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/extend-shallow": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split-string/node_modules/is-extendable": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/split2": { + "version": "3.2.2", + "dev": true, + "license": "ISC", + "dependencies": { + "readable-stream": "^3.0.0" + } + }, + "node_modules/split2/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/sshpk": { + "version": "1.17.0", + "dev": true, + "license": "MIT", + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/stable": { + "version": "0.1.8", + "dev": true, + "license": "MIT" + }, + "node_modules/static-extend": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/statuses": { + "version": "1.3.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stream-throttle": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz", + "integrity": "sha512-889+B9vN9dq7/vLbGyuHeZ6/ctf5sNuGWsDy89uNxkFTAgzy0eK7+w5fL3KLNRTkLle7EgZGvHUphZW0Q26MnQ==", + "dev": true, + "dependencies": { + "commander": "^2.2.0", + "limiter": "^1.0.5" + }, + "bin": { + "throttleproxy": "bin/throttleproxy.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/streamroller": { + "version": "3.1.5", + "dev": true, + "license": "MIT", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/streamroller/node_modules/fs-extra": { + "version": "8.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, + "node_modules/streamroller/node_modules/jsonfile": { + "version": "4.0.0", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/streamroller/node_modules/universalify": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-template": { + "version": "0.2.1", + "dev": true + }, + "node_modules/string-width": { + "version": "4.2.3", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.padend": { + "version": "3.1.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.6", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.4", + "es-abstract": "^1.20.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/stringmap": { + "version": "0.2.2", + "dev": true, + "license": "MIT" + }, + "node_modules/stringset": { + "version": "0.2.1", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/strong-log-transformer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", + "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", + "dev": true, + "dependencies": { + "duplexer": "^0.1.1", + "minimist": "^1.2.0", + "through": "^2.3.4" + }, + "bin": { + "sl-log-transformer": "bin/sl-log-transformer.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/sucrase": { + "version": "3.32.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.2", + "commander": "^4.0.0", + "glob": "7.1.6", + "lines-and-columns": "^1.1.6", + "mz": "^2.7.0", + "pirates": "^4.0.1", + "ts-interface-checker": "^0.1.9" + }, + "bin": { + "sucrase": "bin/sucrase", + "sucrase-node": "bin/sucrase-node" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/sucrase/node_modules/commander": { + "version": "4.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6" + } + }, + "node_modules/sucrase/node_modules/glob": { + "version": "7.1.6", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/synckit": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.5.tgz", + "integrity": "sha512-L1dapNV6vu2s/4Sputv8xGsCdAVlb5nRDMFU/E27D44l5U6cw1g0dGd45uLc+OXjNMmF4ntiMdCimzcjFKQI8Q==", + "dev": true, + "dependencies": { + "@pkgr/utils": "^2.3.1", + "tslib": "^2.5.0" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/tailwindcss": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.3.tgz", + "integrity": "sha512-A0KgSkef7eE4Mf+nKJ83i75TMyq8HqY3qmFIJSWy8bNt0v1lG7jUcpGpoTFxAwYcWOphcTBLPPJg+bDfhDf52w==", + "dev": true, + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "arg": "^5.0.2", + "chokidar": "^3.5.3", + "didyoumean": "^1.2.2", + "dlv": "^1.1.3", + "fast-glob": "^3.2.12", + "glob-parent": "^6.0.2", + "is-glob": "^4.0.3", + "jiti": "^1.18.2", + "lilconfig": "^2.1.0", + "micromatch": "^4.0.5", + "normalize-path": "^3.0.0", + "object-hash": "^3.0.0", + "picocolors": "^1.0.0", + "postcss": "^8.4.23", + "postcss-import": "^15.1.0", + "postcss-js": "^4.0.1", + "postcss-load-config": "^4.0.1", + "postcss-nested": "^6.0.1", + "postcss-selector-parser": "^6.0.11", + "resolve": "^1.22.2", + "sucrase": "^3.32.0" + }, + "bin": { + "tailwind": "lib/cli.js", + "tailwindcss": "lib/cli.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tailwindcss/node_modules/arg": { + "version": "5.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/tailwindcss/node_modules/glob-parent": { + "version": "6.0.2", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.0.tgz", + "integrity": "sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/terser": { + "version": "5.24.0", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.24.0.tgz", + "integrity": "sha512-ZpGR4Hy3+wBEzVEnHvstMvqpD/nABNelQn/z2r0fjVWGQsN3bpOLzQlqDxmb4CDZnXq5lpjnQ+mHQLAOpfM5iw==", + "dev": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.7", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.17", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.16.5" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv": { + "version": "6.12.6", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/terser-webpack-plugin/node_modules/ajv-keywords": { + "version": "3.5.2", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/terser-webpack-plugin/node_modules/json-schema-traverse": { + "version": "0.4.1", + "dev": true, + "license": "MIT" + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.1.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/test-exclude/node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/text-extensions": { + "version": "1.9.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "dev": true, + "license": "MIT" + }, + "node_modules/thenify": { + "version": "3.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "any-promise": "^1.0.0" + } + }, + "node_modules/thenify-all": { + "version": "1.6.0", + "dev": true, + "license": "MIT", + "dependencies": { + "thenify": ">= 3.1.0 < 4" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/through": { + "version": "2.3.8", + "dev": true, + "license": "MIT" + }, + "node_modules/through2": { + "version": "4.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "3.6.2", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==", + "dev": true + }, + "node_modules/tiny-lr": { + "version": "1.1.1", + "dev": true, + "license": "MIT", + "dependencies": { + "body": "^5.1.0", + "debug": "^3.1.0", + "faye-websocket": "~0.10.0", + "livereload-js": "^2.3.0", + "object-assign": "^4.1.0", + "qs": "^6.4.0" + } + }, + "node_modules/tiny-lr/node_modules/debug": { + "version": "3.2.7", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/titleize": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/titleize/-/titleize-3.0.0.tgz", + "integrity": "sha512-KxVu8EYHDPBdUYdKZdKtU2aj2XfEx9AfjXxE/Aj0vT06w2icA09Vus1rh6eSu1y01akYg6BjIK/hxyLJINoMLQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/tmp": { + "version": "0.2.1", + "dev": true, + "license": "MIT", + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-object-path": { + "version": "0.3.0", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^3.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-object-path/node_modules/kind-of": { + "version": "3.2.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-buffer": "^1.1.5" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/to-regex/node_modules/define-property": { + "version": "2.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/extend-shallow": { + "version": "3.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-accessor-descriptor": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-data-descriptor": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "kind-of": "^6.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-descriptor": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/to-regex/node_modules/is-extendable": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "is-plain-object": "^2.0.4" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/token-stream": { + "version": "0.0.1", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/tough-cookie": { + "version": "2.5.0", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/trim-newlines": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/tryor": { + "version": "0.1.2", + "dev": true, + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", + "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", + "dev": true, + "engines": { + "node": ">=16.13.0" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-interface-checker": { + "version": "0.1.13", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/ts-md5": { + "version": "1.3.1", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "dev": true, + "license": "MIT", + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "4.0.2", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.14.2", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tsconfig-paths/node_modules/json5": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/tuf-js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.1.0.tgz", + "integrity": "sha512-eD7YPPjVlMzdggrOeE8zwoegUaG/rt6Bt3jwoQPunRiNVzgcCE009UDFJKJjG+Gk9wFu6W/Vi+P5d/5QpdD9jA==", + "dependencies": { + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "dev": true, + "license": "Unlicense" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-assert": { + "version": "1.0.9", + "dev": true, + "license": "MIT" + }, + "node_modules/typescript": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.2.2.tgz", + "integrity": "sha512-mI4WrpHsbCIcwT9cF4FZvr80QUeKvsUsUvKDoR+X/7XHQH98xYD8YHZg7ANtz2GtZt/CBq2QJ0thkGJMHfqc1w==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "1.0.37", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.37.tgz", + "integrity": "sha512-bhTyI94tZofjo+Dn8SN6Zv8nBDvyXTymAdM3LDI/0IboIUwTu1rEhW7v2TfiVsoYWgkQ4kOVqnI8APUFbIQIFQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/uglify-js": { + "version": "2.7.5", + "dev": true, + "license": "BSD-2-Clause", + "optional": true, + "dependencies": { + "async": "~0.2.6", + "source-map": "~0.5.1", + "uglify-to-browserify": "~1.0.0", + "yargs": "~3.10.0" + }, + "bin": { + "uglifyjs": "bin/uglifyjs" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/uglify-js/node_modules/async": { + "version": "0.2.10", + "dev": true, + "optional": true + }, + "node_modules/uglify-js/node_modules/camelcase": { + "version": "1.2.1", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uglify-js/node_modules/cliui": { + "version": "2.1.0", + "dev": true, + "license": "ISC", + "optional": true, + "dependencies": { + "center-align": "^0.1.1", + "right-align": "^0.1.1", + "wordwrap": "0.0.2" + } + }, + "node_modules/uglify-js/node_modules/source-map": { + "version": "0.5.7", + "dev": true, + "license": "BSD-3-Clause", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/uglify-js/node_modules/wordwrap": { + "version": "0.0.2", + "dev": true, + "license": "MIT/X11", + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/uglify-js/node_modules/yargs": { + "version": "3.10.0", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "camelcase": "^1.0.2", + "cliui": "^2.1.0", + "decamelize": "^1.0.0", + "window-size": "0.1.0" + } + }, + "node_modules/uglify-to-browserify": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/unc-path-regex": { + "version": "0.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/underscore": { + "version": "1.13.6", + "dev": true, + "license": "MIT" + }, + "node_modules/underscore.string": { + "version": "2.3.3", + "engines": { + "node": "*" + } + }, + "node_modules/undici": { + "version": "5.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-5.27.2.tgz", + "integrity": "sha512-iS857PdOEy/y3wlM3yRp+6SNQQ6xU0mmZcwRSriqk+et/cwWAtwmIGf6WkoDN2EK/AMdCO/dfXzIwi+rFMrjjQ==", + "dev": true, + "dependencies": { + "@fastify/busboy": "^2.0.0" + }, + "engines": { + "node": ">=14.0" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dev": true, + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/union-value": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/unset-value": { + "version": "1.0.0", + "dev": true, + "license": "MIT", + "dependencies": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value": { + "version": "0.3.1", + "dev": true, + "license": "MIT", + "dependencies": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-value/node_modules/isobject": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "isarray": "1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/has-values": { + "version": "0.1.4", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/unset-value/node_modules/isarray": { + "version": "1.0.0", + "dev": true, + "license": "MIT" + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/upath": { + "version": "1.2.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4", + "yarn": "*" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/upper-case": { + "version": "1.1.3", + "dev": true, + "license": "MIT" + }, + "node_modules/uri-js": { + "version": "4.4.1", + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/uri-path": { + "version": "1.0.0", + "dev": true, + "license": "WTFPL OR MIT", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/urix": { + "version": "0.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/use": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "license": "MIT" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "3.4.0", + "dev": true, + "license": "MIT", + "bin": { + "uuid": "bin/uuid" + } + }, + "node_modules/v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "dev": true, + "license": "MIT" + }, + "node_modules/v8flags": { + "version": "3.2.0", + "dev": true, + "license": "MIT", + "dependencies": { + "homedir-polyfill": "^1.0.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "license": "Apache-2.0", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "dev": true, + "engines": [ + "node >=0.6.0" + ], + "license": "MIT", + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.0.tgz", + "integrity": "sha512-ulr8rNLA6rkyFAlVWw2q5YJ91v098AFQ2R0PRFwPzREXOUJQPtFUG0t+/ZikhaOCDqFoDhN6/v8Sq0o4araFAw==", + "dev": true, + "dependencies": { + "esbuild": "^0.18.10", + "postcss": "^8.4.27", + "rollup": "^3.27.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + }, + "peerDependencies": { + "@types/node": ">= 14", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/void-elements": { + "version": "2.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/watchpack": { + "version": "2.4.0", + "dev": true, + "license": "MIT", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dev": true, + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "license": "MIT", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.2.1.tgz", + "integrity": "sha512-e0MO3wdXWKrLbL0DgGnUV7WHVuw9OUvL4hjgnPkIeEvESk74gAITi5G606JtZPp39cd8HA9VQzCIvA49LpPN5Q==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/webdriver-js-extender": { + "version": "2.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/selenium-webdriver": "^3.0.0", + "selenium-webdriver": "^3.0.1" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/webdriver-manager": { + "version": "12.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "adm-zip": "^0.5.2", + "chalk": "^1.1.1", + "del": "^2.2.0", + "glob": "^7.0.3", + "ini": "^1.3.4", + "minimist": "^1.2.0", + "q": "^1.4.1", + "request": "^2.87.0", + "rimraf": "^2.5.2", + "semver": "^5.3.0", + "xml2js": "^0.4.17" + }, + "bin": { + "webdriver-manager": "bin/webdriver-manager" + }, + "engines": { + "node": ">=6.9.x" + } + }, + "node_modules/webdriver-manager/node_modules/ansi-regex": { + "version": "2.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/ansi-styles": { + "version": "2.2.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/chalk": { + "version": "1.1.3", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/glob": { + "version": "7.2.3", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/webdriver-manager/node_modules/ini": { + "version": "1.3.8", + "dev": true, + "license": "ISC" + }, + "node_modules/webdriver-manager/node_modules/rimraf": { + "version": "2.7.1", + "dev": true, + "license": "ISC", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + } + }, + "node_modules/webdriver-manager/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/webdriver-manager/node_modules/strip-ansi": { + "version": "3.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/webdriver-manager/node_modules/supports-color": { + "version": "2.0.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/webpack": { + "version": "5.89.0", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.89.0.tgz", + "integrity": "sha512-qyfIC10pOr70V+jkmud8tMfajraGCZMBWJtrmuBymQKCrLTRejBI8STDp1MCyZu/QTdZSeacCQYpYNQVOzX5kw==", + "dev": true, + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.0", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.14.5", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.7", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.1.tgz", + "integrity": "sha512-y51HrHaFeeWir0YO4f0g+9GwZawuigzcAdRNon6jErXy/SqV/+O6eaVAzDqE6t3e3NpGeR5CS+cCDaTC+V3yEQ==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.12", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "dev": true, + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "dev": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { + "version": "5.3.3", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.3.tgz", + "integrity": "sha512-hj5CYrY0bZLB+eTO+x/j67Pkrquiy7kWepMHmUMoPsmcUaeEnQJqFzHJOyxgWlq746/wUuA64p9ta34Kyb01pA==", + "dev": true, + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-dev-server/node_modules/ws": { + "version": "8.14.2", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", + "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", + "dev": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dev": true, + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "dev": true, + "license": "MIT", + "dependencies": { + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "node_modules/webpack/node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/webpack/node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "dev": true, + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/webpack/node_modules/eslint-scope": { + "version": "5.1.1", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/webpack/node_modules/estraverse": { + "version": "4.3.0", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/webpack/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.1", + "dev": true, + "license": "ISC" + }, + "node_modules/which-typed-array": { + "version": "1.1.9", + "dev": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==", + "dev": true + }, + "node_modules/window-size": { + "version": "0.1.0", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/with": { + "version": "5.1.1", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "acorn": "^3.1.0", + "acorn-globals": "^3.0.0" + } + }, + "node_modules/with/node_modules/acorn": { + "version": "3.3.0", + "dev": true, + "license": "MIT", + "optional": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "license": "MIT" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.11.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml2js": { + "version": "0.4.23", + "dev": true, + "license": "MIT", + "dependencies": { + "sax": ">=0.6.0", + "xmlbuilder": "~11.0.0" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/xmlbuilder": { + "version": "11.0.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xregexp": { + "version": "3.1.0", + "dev": true, + "license": "MIT" + }, + "node_modules/y18n": { + "version": "5.0.8", + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yaml": { + "version": "1.10.2", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.9", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "21.1.1", + "license": "ISC", + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zlib-browserify": { + "version": "0.0.1", + "license": "MIT" + }, + "node_modules/zone.js": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.2.tgz", + "integrity": "sha512-X4U7J1isDhoOmHmFWiLhloWc2lzMkdnumtfQ1LXzf/IOZp5NQYuMUTaviVzG/q1ugMBIXzin2AqeVJUoSEkNyQ==", + "dependencies": { + "tslib": "^2.3.0" + } + } + }, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, + "@alloc/quick-lru": { + "version": "5.2.0", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz", + "integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@angular-devkit/architect": { + "version": "0.1700.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1700.1.tgz", + "integrity": "sha512-w84luzQNRjlt7XxX3+jyzcwBBv3gAjjvFWTjN1E5mlpDCUXgYmQ3CMowFHeu0U06HD5Sapap9p2l6GoajuZK5Q==", + "requires": { + "@angular-devkit/core": "17.0.1", + "rxjs": "7.8.1" + }, + "dependencies": { + "rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "requires": { + "tslib": "^2.1.0" + } + } + } + }, + "@angular-devkit/build-angular": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-17.0.1.tgz", + "integrity": "sha512-OomGAeBg/OOxzPpoU7EkdD3WwhKip+0Giy/cGtkalSgQ5vWTuZhf8UnxwTf7xEXW5LtvfoTtv7sKmb1dJT7FzA==", + "dev": true, + "requires": { + "@ampproject/remapping": "2.2.1", "@angular-devkit/architect": "0.1700.1", "@angular-devkit/build-webpack": "0.1700.1", "@angular-devkit/core": "17.0.1", @@ -26327,8 +29128,7 @@ "version": "7.21.0-placeholder-for-preset-env.2", "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", - "dev": true, - "requires": {} + "dev": true }, "@babel/plugin-syntax-async-generators": { "version": "7.8.4", @@ -28707,8 +31507,7 @@ "version": "17.0.1", "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-17.0.1.tgz", "integrity": "sha512-IfiWIBY1GntfJFV/U1CSOHZ7zF5p0zFMFzux7/iGXUXit299LTdJ5mZTe9++lFcH6dPHgEPWlinuYAfzorY4ng==", - "dev": true, - "requires": {} + "dev": true }, "@nodelib/fs.scandir": { "version": "2.1.5", @@ -29055,6 +31854,28 @@ "version": "3.1.0", "dev": true }, + "@swimlane/ngx-charts": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@swimlane/ngx-charts/-/ngx-charts-20.5.0.tgz", + "integrity": "sha512-PNBIHdu/R3ceD7jnw1uCBVOj4k3T6IxfdW6xsDsglGkZyoWMEEq4tLoEurjLEKzmDtRv9c35kVNOXy0lkOuXeA==", + "requires": { + "d3-array": "^3.1.1", + "d3-brush": "^3.0.0", + "d3-color": "^3.1.0", + "d3-ease": "^3.0.1", + "d3-format": "^3.1.0", + "d3-hierarchy": "^3.1.0", + "d3-interpolate": "^3.0.1", + "d3-sankey": "^0.12.3", + "d3-scale": "^4.0.2", + "d3-selection": "^3.0.0", + "d3-shape": "^3.2.0", + "d3-time-format": "^3.0.0", + "d3-transition": "^3.0.1", + "rfdc": "^1.3.0", + "tslib": "^2.0.0" + } + }, "@tsconfig/node10": { "version": "1.0.9", "dev": true @@ -29586,15 +32407,13 @@ } }, "@uirouter/angularjs": { - "version": "1.1.0", - "requires": {} + "version": "1.1.0" }, "@uirouter/core": { "version": "6.1.0" }, "@uirouter/rx": { - "version": "1.0.0", - "requires": {} + "version": "1.0.0" }, "@ungap/structured-clone": { "version": "1.2.0", @@ -29606,8 +32425,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.0.1.tgz", "integrity": "sha512-pcub+YbFtFhaGRTo1832FQHQSHvMrlb43974e2eS8EKleR3p1cDdkJFPci1UhwkEf1J9Bz+wKBSzqpKp7nNj2A==", - "dev": true, - "requires": {} + "dev": true }, "@webassemblyjs/ast": { "version": "1.11.6", @@ -29839,15 +32657,13 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", - "dev": true, - "requires": {} + "dev": true }, "acorn-jsx": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, - "requires": {} + "dev": true }, "acorn-walk": { "version": "8.2.0", @@ -30068,16 +32884,13 @@ } }, "grunt-contrib-clean": { - "version": "0.4.1", - "requires": {} + "version": "0.4.1" }, "grunt-contrib-concat": { - "version": "0.3.0", - "requires": {} + "version": "0.3.0" }, "grunt-contrib-copy": { - "version": "0.4.1", - "requires": {} + "version": "0.4.1" }, "grunt-contrib-uglify": { "version": "0.2.7", @@ -30239,8 +33052,7 @@ "version": "1.5.11" }, "angular-ui-bootstrap": { - "version": "0.13.4", - "requires": {} + "version": "0.13.4" }, "angular-ui-codemirror": { "version": "0.3.0" @@ -30255,8 +33067,7 @@ "version": "1.0.3" }, "angulartics-google-analytics": { - "version": "0.1.4", - "requires": {} + "version": "0.1.4" }, "ansi-colors": { "version": "4.1.3" @@ -30291,7 +33102,7 @@ }, "anymatch": { "version": "3.1.3", - "devOptional": true, + "dev": true, "requires": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -30763,7 +33574,7 @@ }, "binary-extensions": { "version": "2.2.0", - "devOptional": true + "dev": true }, "bindings": { "version": "1.5.0", @@ -30925,7 +33736,7 @@ }, "braces": { "version": "3.0.2", - "devOptional": true, + "dev": true, "requires": { "fill-range": "^7.0.1" } @@ -31467,7 +34278,7 @@ }, "chokidar": { "version": "3.5.3", - "devOptional": true, + "dev": true, "requires": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -32153,6 +34964,191 @@ "d3": { "version": "3.5.17" }, + "d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "requires": { + "internmap": "1 - 2" + } + }, + "d3-brush": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-brush/-/d3-brush-3.0.0.tgz", + "integrity": "sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-drag": "2 - 3", + "d3-interpolate": "1 - 3", + "d3-selection": "3", + "d3-transition": "3" + } + }, + "d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==" + }, + "d3-dispatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-dispatch/-/d3-dispatch-3.0.1.tgz", + "integrity": "sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==" + }, + "d3-drag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-drag/-/d3-drag-3.0.0.tgz", + "integrity": "sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==", + "requires": { + "d3-dispatch": "1 - 3", + "d3-selection": "3" + } + }, + "d3-ease": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-ease/-/d3-ease-3.0.1.tgz", + "integrity": "sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==" + }, + "d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==" + }, + "d3-hierarchy": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/d3-hierarchy/-/d3-hierarchy-3.1.2.tgz", + "integrity": "sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==" + }, + "d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "requires": { + "d3-color": "1 - 3" + } + }, + "d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==" + }, + "d3-sankey": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/d3-sankey/-/d3-sankey-0.12.3.tgz", + "integrity": "sha512-nQhsBRmM19Ax5xEIPLMY9ZmJ/cDvd1BG3UVvt5h3WRxKg5zGRbvnteTyWAbzeSvlh3tW7ZEmq4VwR5mB3tutmQ==", + "requires": { + "d3-array": "1 - 2", + "d3-shape": "^1.2.0" + }, + "dependencies": { + "d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "requires": { + "internmap": "^1.0.0" + } + }, + "d3-path": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-1.0.9.tgz", + "integrity": "sha512-VLaYcn81dtHVTjEHd8B+pbe9yHWpXKZUC87PzoFmsFrJqgFwDe/qxfp5MlfsfM1V5E/iVt0MmEbWQ7FVIXh/bg==" + }, + "d3-shape": { + "version": "1.3.7", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-1.3.7.tgz", + "integrity": "sha512-EUkvKjqPFUAZyOlhY5gzCxCeI0Aep04LwIRpsZ/mLFelJiUfnK56jo5JMDSE7yyP2kLSb6LtF+S5chMk7uqPqw==", + "requires": { + "d3-path": "1" + } + }, + "internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" + } + } + }, + "d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "requires": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + } + }, + "d3-selection": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz", + "integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==" + }, + "d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "requires": { + "d3-path": "^3.1.0" + } + }, + "d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "requires": { + "d3-array": "2 - 3" + } + }, + "d3-time-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", + "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", + "requires": { + "d3-time": "1 - 2" + }, + "dependencies": { + "d3-array": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", + "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", + "requires": { + "internmap": "^1.0.0" + } + }, + "d3-time": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", + "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", + "requires": { + "d3-array": "2" + } + }, + "internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==" + } + } + }, + "d3-timer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", + "integrity": "sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==" + }, + "d3-transition": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-transition/-/d3-transition-3.0.1.tgz", + "integrity": "sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==", + "requires": { + "d3-color": "1 - 3", + "d3-dispatch": "1 - 3", + "d3-ease": "1 - 3", + "d3-interpolate": "1 - 3", + "d3-timer": "1 - 3" + } + }, "dargs": { "version": "7.0.0", "dev": true @@ -33061,8 +36057,7 @@ }, "eslint-config-prettier": { "version": "8.8.0", - "dev": true, - "requires": {} + "dev": true }, "eslint-import-resolver-node": { "version": "0.3.7", @@ -33158,8 +36153,7 @@ }, "eslint-plugin-prefer-arrow": { "version": "1.2.3", - "dev": true, - "requires": {} + "dev": true }, "eslint-plugin-prettier": { "version": "5.0.1", @@ -33661,7 +36655,7 @@ }, "fill-range": { "version": "7.0.1", - "devOptional": true, + "dev": true, "requires": { "to-regex-range": "^5.0.1" } @@ -33885,310 +36879,913 @@ "functions-have-names": "^1.2.2" } }, - "functions-have-names": { - "version": "1.2.3", - "dev": true - }, - "gaze": { - "version": "1.1.3", + "functions-have-names": { + "version": "1.2.3", + "dev": true + }, + "gaze": { + "version": "1.1.3", + "dev": true, + "requires": { + "globule": "^1.0.0" + } + }, + "gensync": { + "version": "1.0.0-beta.2", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5" + }, + "get-intrinsic": { + "version": "1.2.0", + "requires": { + "function-bind": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.3" + } + }, + "get-package-type": { + "version": "0.1.0", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "dev": true + }, + "get-symbol-description": { + "version": "1.0.0", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, + "get-value": { + "version": "2.0.6", + "dev": true + }, + "getobject": { + "version": "1.0.2", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "git-raw-commits": { + "version": "2.0.11", + "dev": true, + "requires": { + "dargs": "^7.0.0", + "lodash": "^4.17.15", + "meow": "^8.0.0", + "split2": "^3.0.0", + "through2": "^4.0.0" + } + }, + "glob": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", + "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "dev": true + }, + "global-dirs": { + "version": "0.1.1", + "dev": true, + "requires": { + "ini": "^1.3.4" + }, + "dependencies": { + "ini": { + "version": "1.3.8", + "dev": true + } + } + }, + "global-modules": { + "version": "1.0.0", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + }, + "dependencies": { + "ini": { + "version": "1.3.8", + "dev": true + }, + "which": { + "version": "1.3.1", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globalthis": { + "version": "1.0.3", + "dev": true, + "requires": { + "define-properties": "^1.1.3" + } + }, + "globby": { + "version": "11.1.0", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "globule": { + "version": "1.3.4", + "dev": true, + "requires": { + "glob": "~7.1.1", + "lodash": "^4.17.21", + "minimatch": "~3.0.2" + }, + "dependencies": { + "glob": { + "version": "7.1.7", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.0.8", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "gopd": { + "version": "1.0.1", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.11" + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "grunt": { + "version": "1.6.1", + "dev": true, + "requires": { + "dateformat": "~4.6.2", + "eventemitter2": "~0.4.13", + "exit": "~0.1.2", + "findup-sync": "~5.0.0", + "glob": "~7.1.6", + "grunt-cli": "~1.4.3", + "grunt-known-options": "~2.0.0", + "grunt-legacy-log": "~3.0.0", + "grunt-legacy-util": "~2.0.1", + "iconv-lite": "~0.6.3", + "js-yaml": "~3.14.0", + "minimatch": "~3.0.4", + "nopt": "~3.0.6" + }, + "dependencies": { + "glob": { + "version": "7.1.7", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "minimatch": { + "version": "3.0.8", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + } + } + }, + "grunt-bump": { + "version": "0.8.0", + "dev": true, + "requires": { + "semver": "^5.1.0" + }, + "dependencies": { + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + } + } + }, + "grunt-cli": { + "version": "1.4.3", + "dev": true, + "requires": { + "grunt-known-options": "~2.0.0", + "interpret": "~1.1.0", + "liftup": "~3.0.1", + "nopt": "~4.0.1", + "v8flags": "~3.2.0" + }, + "dependencies": { + "nopt": { + "version": "4.0.3", + "dev": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + } + } + }, + "grunt-coffeelint": { + "version": "0.0.16", + "dev": true, + "requires": { + "coffeelint": "^1", + "coffeelint-stylish": "~0.1.0" + } + }, + "grunt-contrib-clean": { + "version": "1.0.0", + "dev": true, + "requires": { + "async": "^1.5.2", + "rimraf": "^2.5.1" + }, + "dependencies": { + "glob": { + "version": "7.2.3", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "rimraf": { + "version": "2.7.1", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + } + } + }, + "grunt-contrib-coffee": { + "version": "1.0.0", "dev": true, "requires": { - "globule": "^1.0.0" - } - }, - "gensync": { - "version": "1.0.0-beta.2", - "dev": true - }, - "get-caller-file": { - "version": "2.0.5" - }, - "get-intrinsic": { - "version": "1.2.0", - "requires": { - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.3" + "chalk": "~1.0.0", + "coffee-script": "~1.10.0", + "lodash": "~4.3.0", + "uri-path": "~1.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "1.1.1", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "dev": true + }, + "chalk": { + "version": "1.0.0", + "dev": true, + "requires": { + "ansi-styles": "^2.0.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^1.0.3", + "strip-ansi": "^2.0.1", + "supports-color": "^1.3.0" + } + }, + "coffee-script": { + "version": "1.10.0", + "dev": true + }, + "has-ansi": { + "version": "1.0.3", + "dev": true, + "requires": { + "ansi-regex": "^1.1.0", + "get-stdin": "^4.0.1" + } + }, + "lodash": { + "version": "4.3.0", + "dev": true + }, + "strip-ansi": { + "version": "2.0.1", + "dev": true, + "requires": { + "ansi-regex": "^1.0.0" + } + }, + "supports-color": { + "version": "1.3.1", + "dev": true + } } }, - "get-package-type": { - "version": "0.1.0", - "dev": true - }, - "get-stdin": { - "version": "4.0.1", - "dev": true - }, - "get-stream": { - "version": "6.0.1", - "dev": true - }, - "get-symbol-description": { - "version": "1.0.0", + "grunt-contrib-concat": { + "version": "1.0.1", "dev": true, "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.1.1" + "chalk": "^1.0.0", + "source-map": "^0.5.3" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "source-map": { + "version": "0.5.7", + "dev": true + }, + "strip-ansi": { + "version": "3.0.1", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "dev": true + } } }, - "get-value": { - "version": "2.0.6", - "dev": true - }, - "getobject": { + "grunt-contrib-connect": { "version": "1.0.2", - "dev": true - }, - "getpass": { - "version": "0.1.7", "dev": true, "requires": { - "assert-plus": "^1.0.0" + "async": "^1.5.2", + "connect": "^3.4.0", + "connect-livereload": "^0.5.0", + "http2": "^3.3.4", + "morgan": "^1.6.1", + "opn": "^4.0.0", + "portscanner": "^1.0.0", + "serve-index": "^1.7.1", + "serve-static": "^1.10.0" + }, + "dependencies": { + "opn": { + "version": "4.0.2", + "dev": true, + "requires": { + "object-assign": "^4.0.1", + "pinkie-promise": "^2.0.0" + } + }, + "portscanner": { + "version": "1.2.0", + "dev": true, + "requires": { + "async": "1.5.2" + } + } } }, - "git-raw-commits": { - "version": "2.0.11", + "grunt-contrib-copy": { + "version": "1.0.0", "dev": true, "requires": { - "dargs": "^7.0.0", - "lodash": "^4.17.15", - "meow": "^8.0.0", - "split2": "^3.0.0", - "through2": "^4.0.0" + "chalk": "^1.1.1", + "file-sync-cmp": "^0.1.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "dev": true + } } }, - "glob": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.4.tgz", - "integrity": "sha512-hkLPepehmnKk41pUGm3sYxoFs/umurYfYJCerbXEyFIWcAzvpipAgVkBqqT9RBKMGjnq6kMuyYwha6csxbiM1A==", + "grunt-contrib-jshint": { + "version": "1.0.0", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "chalk": "^1.1.1", + "hooker": "^0.2.3", + "jshint": "~2.9.1" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "dev": true + }, + "ansi-styles": { + "version": "2.2.1", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "dev": true + } } }, - "glob-parent": { - "version": "5.1.2", - "devOptional": true, + "grunt-contrib-watch": { + "version": "1.1.0", + "dev": true, "requires": { - "is-glob": "^4.0.1" + "async": "^2.6.0", + "gaze": "^1.1.0", + "lodash": "^4.17.10", + "tiny-lr": "^1.1.1" + }, + "dependencies": { + "async": { + "version": "2.6.4", + "dev": true, + "requires": { + "lodash": "^4.17.14" + } + } } }, - "glob-to-regexp": { - "version": "0.4.1", - "dev": true - }, - "global-dirs": { - "version": "0.1.1", + "grunt-env": { + "version": "0.4.4", "dev": true, "requires": { - "ini": "^1.3.4" + "ini": "~1.3.0", + "lodash": "~2.4.1" }, "dependencies": { "ini": { "version": "1.3.8", "dev": true + }, + "lodash": { + "version": "2.4.2", + "dev": true } } }, - "global-modules": { - "version": "1.0.0", + "grunt-html2js": { + "version": "0.6.0", "dev": true, "requires": { - "global-prefix": "^1.0.1", - "is-windows": "^1.0.1", - "resolve-dir": "^1.0.0" + "chokidar": "^2", + "html-minifier": "^3", + "pug": "^2" + }, + "dependencies": { + "anymatch": { + "version": "2.0.0", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + }, + "dependencies": { + "normalize-path": { + "version": "2.1.1", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + } + } + }, + "binary-extensions": { + "version": "1.13.1", + "dev": true + }, + "braces": { + "version": "2.3.2", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + } + }, + "chokidar": { + "version": "2.1.8", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.1", + "braces": "^2.3.2", + "fsevents": "^1.2.7", + "glob-parent": "^3.1.0", + "inherits": "^2.0.3", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "normalize-path": "^3.0.0", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.2.1", + "upath": "^1.1.1" + } + }, + "define-property": { + "version": "2.0.2", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + } + }, + "fill-range": { + "version": "4.0.0", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + } + }, + "fsevents": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", + "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", + "dev": true, + "optional": true, + "requires": { + "bindings": "^1.5.0", + "nan": "^2.12.1" + } + }, + "glob-parent": { + "version": "3.1.0", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-binary-path": { + "version": "1.0.1", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-extendable": { + "version": "1.0.1", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + }, + "is-number": { + "version": "3.0.0", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "micromatch": { + "version": "3.1.10", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + }, + "dependencies": { + "extend-shallow": { + "version": "3.0.2", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } + } + } + }, + "readdirp": { + "version": "2.2.1", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "to-regex-range": { + "version": "2.1.1", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + } } }, - "global-prefix": { - "version": "1.0.2", + "grunt-karma": { + "version": "2.0.0", "dev": true, "requires": { - "expand-tilde": "^2.0.2", - "homedir-polyfill": "^1.0.1", - "ini": "^1.3.4", - "is-windows": "^1.0.1", - "which": "^1.2.14" + "lodash": "^3.10.1" }, "dependencies": { - "ini": { - "version": "1.3.8", + "lodash": { + "version": "3.10.1", "dev": true - }, - "which": { - "version": "1.3.1", - "dev": true, - "requires": { - "isexe": "^2.0.0" - } } } }, - "globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "grunt-known-options": { + "version": "2.0.0", "dev": true }, - "globalthis": { - "version": "1.0.3", - "dev": true, - "requires": { - "define-properties": "^1.1.3" - } - }, - "globby": { - "version": "11.1.0", + "grunt-legacy-log": { + "version": "3.0.0", "dev": true, "requires": { - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.2.9", - "ignore": "^5.2.0", - "merge2": "^1.4.1", - "slash": "^3.0.0" + "colors": "~1.1.2", + "grunt-legacy-log-utils": "~2.1.0", + "hooker": "~0.2.3", + "lodash": "~4.17.19" } }, - "globule": { - "version": "1.3.4", + "grunt-legacy-log-utils": { + "version": "2.1.0", "dev": true, "requires": { - "glob": "~7.1.1", - "lodash": "^4.17.21", - "minimatch": "~3.0.2" + "chalk": "~4.1.0", + "lodash": "~4.17.19" }, "dependencies": { - "glob": { - "version": "7.1.7", + "ansi-styles": { + "version": "4.3.0", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "color-convert": "^2.0.1" } }, - "minimatch": { - "version": "3.0.8", + "chalk": { + "version": "4.1.2", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" } - } - } - }, - "gopd": { - "version": "1.0.1", - "dev": true, - "requires": { - "get-intrinsic": "^1.1.3" - } - }, - "graceful-fs": { - "version": "4.2.11" - }, - "graphemer": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true - }, - "grunt": { - "version": "1.6.1", - "dev": true, - "requires": { - "dateformat": "~4.6.2", - "eventemitter2": "~0.4.13", - "exit": "~0.1.2", - "findup-sync": "~5.0.0", - "glob": "~7.1.6", - "grunt-cli": "~1.4.3", - "grunt-known-options": "~2.0.0", - "grunt-legacy-log": "~3.0.0", - "grunt-legacy-util": "~2.0.1", - "iconv-lite": "~0.6.3", - "js-yaml": "~3.14.0", - "minimatch": "~3.0.4", - "nopt": "~3.0.6" - }, - "dependencies": { - "glob": { - "version": "7.1.7", + }, + "color-convert": { + "version": "2.0.1", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.0.4", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "color-name": "~1.1.4" } }, - "minimatch": { - "version": "3.0.8", + "color-name": { + "version": "1.1.4", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "dev": true + }, + "supports-color": { + "version": "7.2.0", "dev": true, "requires": { - "brace-expansion": "^1.1.7" + "has-flag": "^4.0.0" } } } }, - "grunt-bump": { - "version": "0.8.0", + "grunt-legacy-util": { + "version": "2.0.1", "dev": true, "requires": { - "semver": "^5.1.0" + "async": "~3.2.0", + "exit": "~0.1.2", + "getobject": "~1.0.0", + "hooker": "~0.2.3", + "lodash": "~4.17.21", + "underscore.string": "~3.3.5", + "which": "~2.0.2" }, "dependencies": { - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "async": { + "version": "3.2.4", "dev": true - } - } - }, - "grunt-cli": { - "version": "1.4.3", - "dev": true, - "requires": { - "grunt-known-options": "~2.0.0", - "interpret": "~1.1.0", - "liftup": "~3.0.1", - "nopt": "~4.0.1", - "v8flags": "~3.2.0" - }, - "dependencies": { - "nopt": { - "version": "4.0.3", + }, + "sprintf-js": { + "version": "1.1.2", + "dev": true + }, + "underscore.string": { + "version": "3.3.6", "dev": true, "requires": { - "abbrev": "1", - "osenv": "^0.1.4" + "sprintf-js": "^1.1.1", + "util-deprecate": "^1.0.2" } } } }, - "grunt-coffeelint": { - "version": "0.0.16", - "dev": true, + "grunt-lib-contrib": { + "version": "0.6.1", "requires": { - "coffeelint": "^1", - "coffeelint-stylish": "~0.1.0" + "zlib-browserify": "0.0.1" } }, - "grunt-contrib-clean": { - "version": "1.0.0", + "grunt-newer": { + "version": "1.3.0", "dev": true, "requires": { "async": "^1.5.2", - "rimraf": "^2.5.1" + "rimraf": "^2.5.2" }, "dependencies": { "glob": { @@ -34212,1265 +37809,1347 @@ } } }, - "grunt-contrib-coffee": { - "version": "1.0.0", + "grunt-ng-annotate": { + "version": "3.0.0", "dev": true, "requires": { - "chalk": "~1.0.0", - "coffee-script": "~1.10.0", - "lodash": "~4.3.0", - "uri-path": "~1.0.0" + "lodash.clonedeep": "^4.5.0", + "ng-annotate": "^1.2.1" + } + }, + "grunt-postcss": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/grunt-postcss/-/grunt-postcss-0.8.0.tgz", + "integrity": "sha512-Y/GlBwlSXET86uudGM6Sn5Qtjas5PT2AwjMGqKNnSaoxJSfhNY4chpAnOs72VQ4y3LqrP0y5f/i7CroyZqsuJA==", + "dev": true, + "requires": { + "chalk": "^1.0.0", + "diff": "^2.0.2", + "postcss": "^5.0.0" }, "dependencies": { "ansi-regex": { - "version": "1.1.1", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true }, "ansi-styles": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true }, "chalk": { - "version": "1.0.0", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "requires": { - "ansi-styles": "^2.0.1", + "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", - "has-ansi": "^1.0.3", - "strip-ansi": "^2.0.1", - "supports-color": "^1.3.0" + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" } }, - "coffee-script": { - "version": "1.10.0", + "has-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", "dev": true }, - "has-ansi": { - "version": "1.0.3", + "postcss": { + "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "requires": { - "ansi-regex": "^1.1.0", - "get-stdin": "^4.0.1" + "chalk": "^1.1.3", + "js-base64": "^2.1.9", + "source-map": "^0.5.6", + "supports-color": "^3.2.3" + }, + "dependencies": { + "supports-color": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, + "requires": { + "has-flag": "^1.0.0" + } + } } }, - "lodash": { - "version": "4.3.0", + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true }, "strip-ansi": { - "version": "2.0.1", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "requires": { - "ansi-regex": "^1.0.0" + "ansi-regex": "^2.0.0" } }, "supports-color": { - "version": "1.3.1", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true } } }, - "grunt-contrib-concat": { - "version": "1.0.1", + "grunt-preprocess": { + "version": "5.1.0", "dev": true, "requires": { - "chalk": "^1.0.0", - "source-map": "^0.5.3" + "lodash": "^4.5.0", + "preprocess": "^3.0.2" + } + }, + "grunt-sass": { + "version": "3.1.0", + "dev": true + }, + "grunt-sass-globbing": { + "version": "1.5.1", + "dev": true + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "dev": true + }, + "har-schema": { + "version": "2.0.0", + "dev": true + }, + "har-validator": { + "version": "5.1.5", + "dev": true, + "requires": { + "ajv": "^6.12.3", + "har-schema": "^2.0.0" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "dev": true - }, - "chalk": { - "version": "1.1.3", + "ajv": { + "version": "6.12.6", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" } }, - "source-map": { - "version": "0.5.7", + "json-schema-traverse": { + "version": "0.4.1", "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", + } + } + }, + "hard-rejection": { + "version": "2.1.0", + "dev": true + }, + "has": { + "version": "1.0.3", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", "dev": true } } }, - "grunt-contrib-connect": { + "has-bigints": { "version": "1.0.2", + "dev": true + }, + "has-flag": { + "version": "3.0.0", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.0", "dev": true, "requires": { - "async": "^1.5.2", - "connect": "^3.4.0", - "connect-livereload": "^0.5.0", - "http2": "^3.3.4", - "morgan": "^1.6.1", - "opn": "^4.0.0", - "portscanner": "^1.0.0", - "serve-index": "^1.7.1", - "serve-static": "^1.10.0" + "get-intrinsic": "^1.1.1" + } + }, + "has-proto": { + "version": "1.0.1", + "dev": true + }, + "has-symbols": { + "version": "1.0.3" + }, + "has-tostringtag": { + "version": "1.0.0", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "has-value": { + "version": "1.0.0", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" }, "dependencies": { - "opn": { - "version": "4.0.2", + "is-number": { + "version": "3.0.0", "dev": true, "requires": { - "object-assign": "^4.0.1", - "pinkie-promise": "^2.0.0" + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } } }, - "portscanner": { - "version": "1.2.0", + "kind-of": { + "version": "4.0.0", "dev": true, "requires": { - "async": "1.5.2" + "is-buffer": "^1.1.5" } } } }, - "grunt-contrib-copy": { - "version": "1.0.0", + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "requires": { + "function-bind": "^1.1.2" + } + }, + "hdr-histogram-js": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", + "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "dev": true, + "requires": { + "@assemblyscript/loader": "^0.10.1", + "base64-js": "^1.2.0", + "pako": "^1.0.3" + } + }, + "hdr-histogram-percentiles-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", + "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "dev": true + }, + "he": { + "version": "1.2.0", + "dev": true + }, + "homedir-polyfill": { + "version": "1.0.3", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hooker": { + "version": "0.2.3" + }, + "hosted-git-info": { + "version": "2.8.9", + "dev": true + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "html-entities": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", + "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", + "dev": true + }, + "html-escaper": { + "version": "2.0.2", + "dev": true + }, + "html-minifier": { + "version": "3.5.21", "dev": true, "requires": { - "chalk": "^1.1.1", - "file-sync-cmp": "^0.1.0" + "camel-case": "3.0.x", + "clean-css": "4.2.x", + "commander": "2.17.x", + "he": "1.2.x", + "param-case": "2.1.x", + "relateurl": "0.2.x", + "uglify-js": "3.4.x" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", + "commander": { + "version": "2.17.1", "dev": true }, - "ansi-styles": { - "version": "2.2.1", + "source-map": { + "version": "0.6.1", "dev": true }, - "chalk": { - "version": "1.1.3", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "strip-ansi": { - "version": "3.0.1", + "uglify-js": { + "version": "3.4.10", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "commander": "~2.19.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "commander": { + "version": "2.19.0", + "dev": true + } } - }, - "supports-color": { - "version": "2.0.0", - "dev": true } } }, - "grunt-contrib-jshint": { - "version": "1.0.0", + "htmlparser2": { + "version": "3.8.3", "dev": true, "requires": { - "chalk": "^1.1.1", - "hooker": "^0.2.3", - "jshint": "~2.9.1" + "domelementtype": "1", + "domhandler": "2.3", + "domutils": "1.5", + "entities": "1.0", + "readable-stream": "1.1" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "dev": true + "dom-serializer": { + "version": "0.2.2", + "dev": true, + "requires": { + "domelementtype": "^2.0.1", + "entities": "^2.0.0" + }, + "dependencies": { + "domelementtype": { + "version": "2.3.0", + "dev": true + }, + "entities": { + "version": "2.2.0", + "dev": true + } + } }, - "ansi-styles": { - "version": "2.2.1", + "domelementtype": { + "version": "1.3.1", "dev": true }, - "chalk": { - "version": "1.1.3", + "domhandler": { + "version": "2.3.0", "dev": true, "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" + "domelementtype": "1" } }, - "strip-ansi": { - "version": "3.0.1", + "domutils": { + "version": "1.5.1", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "dom-serializer": "0", + "domelementtype": "1" } }, - "supports-color": { - "version": "2.0.0", + "entities": { + "version": "1.0.0", + "dev": true + }, + "isarray": { + "version": "0.0.1", + "dev": true + }, + "readable-stream": { + "version": "1.1.14", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "string_decoder": { + "version": "0.10.31", "dev": true } } }, - "grunt-contrib-watch": { - "version": "1.1.0", + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", "dev": true, "requires": { - "async": "^2.6.0", - "gaze": "^1.1.0", - "lodash": "^4.17.10", - "tiny-lr": "^1.1.1" + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" }, "dependencies": { - "async": { - "version": "2.6.4", - "dev": true, - "requires": { - "lodash": "^4.17.14" - } + "statuses": { + "version": "2.0.1", + "dev": true } } }, - "grunt-env": { - "version": "0.4.4", + "http-parser-js": { + "version": "0.5.8", + "dev": true + }, + "http-proxy": { + "version": "1.18.1", "dev": true, "requires": { - "ini": "~1.3.0", - "lodash": "~2.4.1" + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", + "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dev": true, + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" }, "dependencies": { - "ini": { - "version": "1.3.8", - "dev": true - }, - "lodash": { - "version": "2.4.2", + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", "dev": true } } }, - "grunt-html2js": { - "version": "0.6.0", + "http-signature": { + "version": "1.2.0", "dev": true, "requires": { - "chokidar": "^2", - "html-minifier": "^3", - "pug": "^2" + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "http2": { + "version": "3.3.7", + "dev": true + }, + "https-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", + "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, + "human-signals": { + "version": "2.1.0", + "dev": true + }, + "husky": { + "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", + "dev": true + }, + "iconv-lite": { + "version": "0.6.3", + "devOptional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "dev": true + }, + "ieee754": { + "version": "1.2.1" + }, + "ignore": { + "version": "5.2.4", + "dev": true + }, + "ignore-walk": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", + "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", + "requires": { + "minimatch": "^9.0.0" }, "dependencies": { - "anymatch": { - "version": "2.0.0", - "dev": true, - "requires": { - "micromatch": "^3.1.4", - "normalize-path": "^2.1.1" - }, - "dependencies": { - "normalize-path": { - "version": "2.1.1", - "dev": true, - "requires": { - "remove-trailing-separator": "^1.0.1" - } - } - } - }, - "binary-extensions": { - "version": "1.13.1", - "dev": true - }, - "braces": { - "version": "2.3.2", - "dev": true, - "requires": { - "arr-flatten": "^1.1.0", - "array-unique": "^0.3.2", - "extend-shallow": "^2.0.1", - "fill-range": "^4.0.0", - "isobject": "^3.0.1", - "repeat-element": "^1.1.2", - "snapdragon": "^0.8.1", - "snapdragon-node": "^2.0.1", - "split-string": "^3.0.2", - "to-regex": "^3.0.1" - } - }, - "chokidar": { - "version": "2.1.8", - "dev": true, - "requires": { - "anymatch": "^2.0.0", - "async-each": "^1.0.1", - "braces": "^2.3.2", - "fsevents": "^1.2.7", - "glob-parent": "^3.1.0", - "inherits": "^2.0.3", - "is-binary-path": "^1.0.0", - "is-glob": "^4.0.0", - "normalize-path": "^3.0.0", - "path-is-absolute": "^1.0.0", - "readdirp": "^2.2.1", - "upath": "^1.1.1" - } - }, - "define-property": { - "version": "2.0.2", - "dev": true, - "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" - } - }, - "fill-range": { - "version": "4.0.0", - "dev": true, - "requires": { - "extend-shallow": "^2.0.1", - "is-number": "^3.0.0", - "repeat-string": "^1.6.1", - "to-regex-range": "^2.1.0" - } - }, - "fsevents": { - "version": "1.2.13", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.13.tgz", - "integrity": "sha512-oWb1Z6mkHIskLzEJ/XWX0srkpkTQ7vaopMQkyaEIoq0fmtFVxOthb8cCxeT+p3ynTdkk/RZwbgG4brR5BeWECw==", - "dev": true, - "optional": true, - "requires": { - "bindings": "^1.5.0", - "nan": "^2.12.1" - } - }, - "glob-parent": { - "version": "3.1.0", - "dev": true, - "requires": { - "is-glob": "^3.1.0", - "path-dirname": "^1.0.0" - }, - "dependencies": { - "is-glob": { - "version": "3.1.0", - "dev": true, - "requires": { - "is-extglob": "^2.1.0" - } - } - } - }, - "is-accessor-descriptor": { - "version": "1.0.0", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-binary-path": { - "version": "1.0.1", - "dev": true, - "requires": { - "binary-extensions": "^1.0.0" - } - }, - "is-data-descriptor": { - "version": "1.0.0", - "dev": true, - "requires": { - "kind-of": "^6.0.0" - } - }, - "is-descriptor": { - "version": "1.0.2", - "dev": true, - "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" - } - }, - "is-extendable": { - "version": "1.0.1", - "dev": true, - "requires": { - "is-plain-object": "^2.0.4" - } - }, - "is-number": { - "version": "3.0.0", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "micromatch": { - "version": "3.1.10", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "braces": "^2.3.1", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "extglob": "^2.0.4", - "fragment-cache": "^0.2.1", - "kind-of": "^6.0.2", - "nanomatch": "^1.2.9", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.2" - }, - "dependencies": { - "extend-shallow": { - "version": "3.0.2", - "dev": true, - "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" - } - } - } - }, - "readdirp": { - "version": "2.2.1", - "dev": true, + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "requires": { - "graceful-fs": "^4.1.11", - "micromatch": "^3.1.10", - "readable-stream": "^2.0.2" + "balanced-match": "^1.0.0" } }, - "to-regex-range": { - "version": "2.1.1", - "dev": true, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", "requires": { - "is-number": "^3.0.0", - "repeat-string": "^1.6.1" + "brace-expansion": "^2.0.1" } } } }, - "grunt-karma": { - "version": "2.0.0", + "image-size": { + "version": "0.5.5", + "dev": true, + "optional": true + }, + "immediate": { + "version": "3.0.6", + "dev": true + }, + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", "dev": true, "requires": { - "lodash": "^3.10.1" + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" }, "dependencies": { - "lodash": { - "version": "3.10.1", + "resolve-from": { + "version": "4.0.0", "dev": true } } }, - "grunt-known-options": { - "version": "2.0.0", - "dev": true + "imurmurhash": { + "version": "0.1.4" }, - "grunt-legacy-log": { - "version": "3.0.0", - "dev": true, - "requires": { - "colors": "~1.1.2", - "grunt-legacy-log-utils": "~2.1.0", - "hooker": "~0.2.3", - "lodash": "~4.17.19" + "indent-string": { + "version": "4.0.0" + }, + "inflight": { + "version": "1.0.6", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" } }, - "grunt-legacy-log-utils": { - "version": "2.1.0", - "dev": true, + "inherits": { + "version": "2.0.4" + }, + "ini": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", + "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==" + }, + "inquirer": { + "version": "9.2.11", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.11.tgz", + "integrity": "sha512-B2LafrnnhbRzCWfAdOXisUzL89Kg8cVJlYmhqoi3flSiV/TveO+nsXwgKr9h9PIo+J1hz7nBSk6gegRIMBBf7g==", "requires": { - "chalk": "~4.1.0", - "lodash": "~4.17.19" + "@ljharb/through": "^2.3.9", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "figures": "^5.0.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" }, "dependencies": { "ansi-styles": { "version": "4.3.0", - "dev": true, + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "requires": { "color-convert": "^2.0.1" } }, "chalk": { - "version": "4.1.2", - "dev": true, - "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - } + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==" }, "color-convert": { "version": "2.0.1", - "dev": true, + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "requires": { "color-name": "~1.1.4" } }, "color-name": { "version": "1.1.4", - "dev": true + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, - "has-flag": { - "version": "4.0.0", - "dev": true + "rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "requires": { + "tslib": "^2.1.0" + } }, - "supports-color": { - "version": "7.2.0", - "dev": true, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "requires": { - "has-flag": "^4.0.0" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" } } } }, - "grunt-legacy-util": { - "version": "2.0.1", + "internal-slot": { + "version": "1.0.5", "dev": true, "requires": { - "async": "~3.2.0", - "exit": "~0.1.2", - "getobject": "~1.0.0", - "hooker": "~0.2.3", - "lodash": "~4.17.21", - "underscore.string": "~3.3.5", - "which": "~2.0.2" - }, - "dependencies": { - "async": { - "version": "3.2.4", - "dev": true - }, - "sprintf-js": { - "version": "1.1.2", - "dev": true - }, - "underscore.string": { - "version": "3.3.6", - "dev": true, - "requires": { - "sprintf-js": "^1.1.1", - "util-deprecate": "^1.0.2" - } - } + "get-intrinsic": "^1.2.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" } }, - "grunt-lib-contrib": { - "version": "0.6.1", + "internmap": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==" + }, + "interpret": { + "version": "1.1.0", + "dev": true + }, + "invert-kv": { + "version": "1.0.0" + }, + "ip": { + "version": "1.1.8", + "dev": true + }, + "ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "dev": true + }, + "is-absolute": { + "version": "1.0.0", + "dev": true, "requires": { - "zlib-browserify": "0.0.1" + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" } }, - "grunt-newer": { - "version": "1.3.0", + "is-accessor-descriptor": { + "version": "0.1.6", "dev": true, "requires": { - "async": "^1.5.2", - "rimraf": "^2.5.2" + "kind-of": "^3.0.2" }, "dependencies": { - "glob": { - "version": "7.2.3", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "rimraf": { - "version": "2.7.1", + "kind-of": { + "version": "3.2.2", "dev": true, "requires": { - "glob": "^7.1.3" + "is-buffer": "^1.1.5" } } } }, - "grunt-ng-annotate": { - "version": "3.0.0", + "is-array-buffer": { + "version": "3.0.2", "dev": true, "requires": { - "lodash.clonedeep": "^4.5.0", - "ng-annotate": "^1.2.1" + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.0", + "is-typed-array": "^1.1.10" } }, - "grunt-postcss": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/grunt-postcss/-/grunt-postcss-0.8.0.tgz", - "integrity": "sha512-Y/GlBwlSXET86uudGM6Sn5Qtjas5PT2AwjMGqKNnSaoxJSfhNY4chpAnOs72VQ4y3LqrP0y5f/i7CroyZqsuJA==", + "is-arrayish": { + "version": "0.2.1", + "dev": true + }, + "is-bigint": { + "version": "1.0.4", "dev": true, "requires": { - "chalk": "^1.0.0", - "diff": "^2.0.2", - "postcss": "^5.0.0" - }, - "dependencies": { - "ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true - }, - "ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true - }, - "chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "requires": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - } - }, - "has-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", - "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", - "dev": true - }, - "postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "requires": { - "chalk": "^1.1.3", - "js-base64": "^2.1.9", - "source-map": "^0.5.6", - "supports-color": "^3.2.3" - }, - "dependencies": { - "supports-color": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", - "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", - "dev": true, - "requires": { - "has-flag": "^1.0.0" - } - } - } - }, - "source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true - }, - "strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "requires": { - "ansi-regex": "^2.0.0" - } - }, - "supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true - } + "has-bigints": "^1.0.1" } }, - "grunt-preprocess": { - "version": "5.1.0", + "is-binary-path": { + "version": "2.1.0", "dev": true, "requires": { - "lodash": "^4.5.0", - "preprocess": "^3.0.2" + "binary-extensions": "^2.0.0" } }, - "grunt-sass": { - "version": "3.1.0", - "dev": true, - "requires": {} - }, - "grunt-sass-globbing": { - "version": "1.5.1", + "is-boolean-object": { + "version": "1.1.2", "dev": true, - "requires": {} + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } }, - "handle-thing": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", - "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==", + "is-buffer": { + "version": "1.1.6", "dev": true }, - "har-schema": { - "version": "2.0.0", + "is-callable": { + "version": "1.2.7", "dev": true }, - "har-validator": { - "version": "5.1.5", + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "requires": { + "hasown": "^2.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", "dev": true, "requires": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" + "kind-of": "^3.0.2" }, "dependencies": { - "ajv": { - "version": "6.12.6", + "kind-of": { + "version": "3.2.2", "dev": true, "requires": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" + "is-buffer": "^1.1.5" } - }, - "json-schema-traverse": { - "version": "0.4.1", - "dev": true } } }, - "hard-rejection": { - "version": "2.1.0", - "dev": true - }, - "has": { - "version": "1.0.3", + "is-date-object": { + "version": "1.0.5", + "dev": true, "requires": { - "function-bind": "^1.1.1" + "has-tostringtag": "^1.0.0" } }, - "has-ansi": { - "version": "2.0.0", + "is-descriptor": { + "version": "0.1.6", "dev": true, "requires": { - "ansi-regex": "^2.0.0" + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" }, "dependencies": { - "ansi-regex": { - "version": "2.1.1", + "kind-of": { + "version": "5.1.0", "dev": true } } }, - "has-bigints": { - "version": "1.0.2", - "dev": true + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" }, - "has-flag": { + "is-expression": { "version": "3.0.0", + "dev": true, + "optional": true, + "requires": { + "acorn": "~4.0.2", + "object-assign": "^4.0.1" + }, + "dependencies": { + "acorn": { + "version": "4.0.13", + "dev": true, + "optional": true + } + } + }, + "is-extendable": { + "version": "0.1.1", "dev": true }, - "has-property-descriptors": { + "is-extglob": { + "version": "2.1.1", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0" + }, + "is-glob": { + "version": "4.0.3", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-inside-container": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", "dev": true, "requires": { - "get-intrinsic": "^1.1.1" + "is-docker": "^3.0.0" + }, + "dependencies": { + "is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true + } } }, - "has-proto": { + "is-interactive": { + "version": "1.0.0" + }, + "is-lambda": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" + }, + "is-negative-zero": { + "version": "2.0.2", "dev": true }, - "has-symbols": { - "version": "1.0.3" + "is-number": { + "version": "7.0.0", + "dev": true }, - "has-tostringtag": { - "version": "1.0.0", + "is-number-like": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz", + "integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==", "dev": true, "requires": { - "has-symbols": "^1.0.2" + "lodash.isfinite": "^3.3.2" } }, - "has-value": { - "version": "1.0.0", + "is-number-object": { + "version": "1.0.7", "dev": true, "requires": { - "get-value": "^2.0.6", - "has-values": "^1.0.0", - "isobject": "^3.0.0" + "has-tostringtag": "^1.0.0" } }, - "has-values": { + "is-obj": { + "version": "2.0.0", + "dev": true + }, + "is-path-cwd": { "version": "1.0.0", + "dev": true + }, + "is-path-in-cwd": { + "version": "1.0.1", "dev": true, "requires": { - "is-number": "^3.0.0", - "kind-of": "^4.0.0" + "is-path-inside": "^1.0.0" }, "dependencies": { - "is-number": { - "version": "3.0.0", - "dev": true, - "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } - } - }, - "kind-of": { - "version": "4.0.0", + "is-path-inside": { + "version": "1.0.1", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "path-is-inside": "^1.0.1" } } } }, - "hasown": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", - "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "is-path-inside": { + "version": "3.0.3", + "dev": true + }, + "is-plain-obj": { + "version": "1.1.0", + "dev": true + }, + "is-plain-object": { + "version": "2.0.4", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-promise": { + "version": "2.2.2", + "dev": true, + "optional": true + }, + "is-regex": { + "version": "1.1.4", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-relative": { + "version": "1.0.0", + "dev": true, + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.2", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, + "is-stream": { + "version": "2.0.1", + "dev": true + }, + "is-string": { + "version": "1.0.7", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-text-path": { + "version": "1.0.1", + "dev": true, "requires": { - "function-bind": "^1.1.2" + "text-extensions": "^1.0.0" } }, - "hdr-histogram-js": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/hdr-histogram-js/-/hdr-histogram-js-2.0.3.tgz", - "integrity": "sha512-Hkn78wwzWHNCp2uarhzQ2SGFLU3JY8SBDDd3TAABK4fc30wm+MuPOrg5QVFVfkKOQd6Bfz3ukJEI+q9sXEkK1g==", + "is-typed-array": { + "version": "1.1.10", "dev": true, "requires": { - "@assemblyscript/loader": "^0.10.1", - "base64-js": "^1.2.0", - "pako": "^1.0.3" + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.0" } }, - "hdr-histogram-percentiles-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/hdr-histogram-percentiles-obj/-/hdr-histogram-percentiles-obj-3.0.0.tgz", - "integrity": "sha512-7kIufnBqdsBGcSZLPJwqHT3yhk1QTsSlFsVD3kx5ixH/AlgBs9yM1q6DPhXZ8f8gtdqgh7N7/5btRLpQsS2gHw==", + "is-typedarray": { + "version": "1.0.0", "dev": true }, - "he": { - "version": "1.2.0", - "dev": true + "is-unc-path": { + "version": "1.0.0", + "dev": true, + "requires": { + "unc-path-regex": "^0.1.2" + } }, - "homedir-polyfill": { - "version": "1.0.3", + "is-unicode-supported": { + "version": "0.1.0" + }, + "is-weakref": { + "version": "1.0.2", "dev": true, "requires": { - "parse-passwd": "^1.0.0" + "call-bind": "^1.0.2" } }, - "hooker": { - "version": "0.2.3" + "is-what": { + "version": "3.14.1", + "dev": true }, - "hosted-git-info": { - "version": "2.8.9", + "is-windows": { + "version": "1.0.2", "dev": true }, - "hpack.js": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", - "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", - "dev": true, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", "requires": { - "inherits": "^2.0.1", - "obuf": "^1.0.0", - "readable-stream": "^2.0.1", - "wbuf": "^1.1.0" + "is-docker": "^2.0.0" } }, - "html-entities": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.4.0.tgz", - "integrity": "sha512-igBTJcNNNhvZFRtm8uA6xMY6xYleeDwn3PeBCkDz7tHttv4F2hsDI2aPgNERWzvRcNYHNT3ymRaQzllmXj4YsQ==", + "isbinaryfile": { + "version": "4.0.10", "dev": true }, - "html-escaper": { - "version": "2.0.2", + "isexe": { + "version": "2.0.0" + }, + "isobject": { + "version": "3.0.1", "dev": true }, - "html-minifier": { - "version": "3.5.21", + "isstream": { + "version": "0.1.2", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.2.1", "dev": true, "requires": { - "camel-case": "3.0.x", - "clean-css": "4.2.x", - "commander": "2.17.x", - "he": "1.2.x", - "param-case": "2.1.x", - "relateurl": "0.2.x", - "uglify-js": "3.4.x" + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" }, "dependencies": { - "commander": { - "version": "2.17.1", + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true - }, - "source-map": { - "version": "0.6.1", + } + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", "dev": true }, - "uglify-js": { - "version": "3.4.10", + "supports-color": { + "version": "7.2.0", "dev": true, "requires": { - "commander": "~2.19.0", - "source-map": "~0.6.1" - }, - "dependencies": { - "commander": { - "version": "2.19.0", - "dev": true - } + "has-flag": "^4.0.0" } } } }, - "htmlparser2": { - "version": "3.8.3", + "istanbul-lib-source-maps": { + "version": "3.0.6", "dev": true, "requires": { - "domelementtype": "1", - "domhandler": "2.3", - "domutils": "1.5", - "entities": "1.0", - "readable-stream": "1.1" + "debug": "^4.1.1", + "istanbul-lib-coverage": "^2.0.5", + "make-dir": "^2.1.0", + "rimraf": "^2.6.3", + "source-map": "^0.6.1" }, "dependencies": { - "dom-serializer": { - "version": "0.2.2", + "glob": { + "version": "7.2.3", "dev": true, "requires": { - "domelementtype": "^2.0.1", - "entities": "^2.0.0" - }, - "dependencies": { - "domelementtype": { - "version": "2.3.0", - "dev": true - }, - "entities": { - "version": "2.2.0", - "dev": true - } + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, - "domelementtype": { - "version": "1.3.1", + "istanbul-lib-coverage": { + "version": "2.0.5", "dev": true }, - "domhandler": { - "version": "2.3.0", - "dev": true, - "requires": { - "domelementtype": "1" - } - }, - "domutils": { - "version": "1.5.1", + "make-dir": { + "version": "2.1.0", "dev": true, "requires": { - "dom-serializer": "0", - "domelementtype": "1" + "pify": "^4.0.1", + "semver": "^5.6.0" } }, - "entities": { - "version": "1.0.0", - "dev": true - }, - "isarray": { - "version": "0.0.1", + "pify": { + "version": "4.0.1", "dev": true }, - "readable-stream": { - "version": "1.1.14", + "rimraf": { + "version": "2.7.1", "dev": true, "requires": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.1", - "isarray": "0.0.1", - "string_decoder": "~0.10.x" + "glob": "^7.1.3" } }, - "string_decoder": { - "version": "0.10.31", + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true - } - } - }, - "http-cache-semantics": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", - "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" - }, - "http-deceiver": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", - "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==", - "dev": true - }, - "http-errors": { - "version": "2.0.0", - "dev": true, - "requires": { - "depd": "2.0.0", - "inherits": "2.0.4", - "setprototypeof": "1.2.0", - "statuses": "2.0.1", - "toidentifier": "1.0.1" - }, - "dependencies": { - "statuses": { - "version": "2.0.1", + }, + "source-map": { + "version": "0.6.1", "dev": true } } }, - "http-parser-js": { - "version": "0.5.8", - "dev": true - }, - "http-proxy": { - "version": "1.18.1", + "istanbul-reports": { + "version": "3.1.5", "dev": true, "requires": { - "eventemitter3": "^4.0.0", - "follow-redirects": "^1.0.0", - "requires-port": "^1.0.0" + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" } }, - "http-proxy-agent": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.0.tgz", - "integrity": "sha512-+ZT+iBxVUQ1asugqnD6oWoRiS25AkjNfG085dKJGtGxkdwLQrMKU5wJr2bOOFAXzKcTuqq+7fZlTMgG3SRfIYQ==", + "jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", "requires": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" } }, - "http-proxy-middleware": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", - "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "jake": { + "version": "10.8.7", + "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", + "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", "dev": true, "requires": { - "@types/http-proxy": "^1.17.8", - "http-proxy": "^1.18.1", - "is-glob": "^4.0.1", - "is-plain-obj": "^3.0.0", - "micromatch": "^4.0.2" + "async": "^3.2.3", + "chalk": "^4.0.2", + "filelist": "^1.0.4", + "minimatch": "^3.1.2" }, "dependencies": { - "is-plain-obj": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", - "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "async": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } } } }, - "http-signature": { - "version": "1.2.0", - "dev": true, - "requires": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - } - }, - "http2": { - "version": "3.3.7", - "dev": true - }, - "https-proxy-agent": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.2.tgz", - "integrity": "sha512-NmLNjm6ucYwtcUmL7JQC1ZQ57LmHP4lT15FQ8D61nak1rO6DH+fz5qNK2Ap5UN4ZapYICE3/0KodcLYSPsPbaA==", - "requires": { - "agent-base": "^7.0.2", - "debug": "4" - } - }, - "human-signals": { - "version": "2.1.0", - "dev": true - }, - "husky": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", - "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", - "dev": true - }, - "iconv-lite": { - "version": "0.6.3", - "devOptional": true, - "requires": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - } - }, - "icss-utils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", - "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "jasmine": { + "version": "2.8.0", "dev": true, - "requires": {} - }, - "ieee754": { - "version": "1.2.1" - }, - "ignore": { - "version": "5.2.4", - "dev": true - }, - "ignore-walk": { - "version": "6.0.3", - "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.3.tgz", - "integrity": "sha512-C7FfFoTA+bI10qfeydT8aZbvr91vAEU+2W5BZUlzPec47oNb07SsOfwYrtxuvOYdUApPP/Qlh4DtAO51Ekk2QA==", "requires": { - "minimatch": "^9.0.0" + "exit": "^0.1.2", + "glob": "^7.0.6", + "jasmine-core": "~2.8.0" }, "dependencies": { - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "glob": { + "version": "7.2.3", + "dev": true, "requires": { - "balanced-match": "^1.0.0" + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" } }, - "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "requires": { - "brace-expansion": "^2.0.1" - } + "jasmine-core": { + "version": "2.8.0", + "dev": true } } }, - "image-size": { - "version": "0.5.5", - "dev": true, - "optional": true - }, - "immediate": { - "version": "3.0.6", - "dev": true - }, - "immutable": { - "version": "3.8.2", - "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", - "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==", + "jasmine-core": { + "version": "4.1.1", "dev": true }, - "import-fresh": { - "version": "3.3.0", + "jasmine-spec-reporter": { + "version": "5.0.2", "dev": true, "requires": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "colors": "1.4.0" }, "dependencies": { - "resolve-from": { - "version": "4.0.0", + "colors": { + "version": "1.4.0", "dev": true } } }, - "imurmurhash": { - "version": "0.1.4" - }, - "indent-string": { - "version": "4.0.0" - }, - "inflight": { - "version": "1.0.6", - "dev": true, - "requires": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "inherits": { - "version": "2.0.4" - }, - "ini": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", - "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==" - }, - "inquirer": { - "version": "9.2.11", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.11.tgz", - "integrity": "sha512-B2LafrnnhbRzCWfAdOXisUzL89Kg8cVJlYmhqoi3flSiV/TveO+nsXwgKr9h9PIo+J1hz7nBSk6gegRIMBBf7g==", - "requires": { - "@ljharb/through": "^2.3.9", - "ansi-escapes": "^4.3.2", - "chalk": "^5.3.0", - "cli-cursor": "^3.1.0", - "cli-width": "^4.1.0", - "external-editor": "^3.1.0", - "figures": "^5.0.0", - "lodash": "^4.17.21", - "mute-stream": "1.0.0", - "ora": "^5.4.1", - "run-async": "^3.0.0", - "rxjs": "^7.8.1", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" + "jasminewd2": { + "version": "2.2.0", + "dev": true + }, + "jest-diff": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", + "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.6.3", + "jest-get-type": "^29.6.3", + "pretty-format": "^29.7.0" }, "dependencies": { "ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, "requires": { "color-convert": "^2.0.1" } }, "chalk": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", - "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==" + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } }, "color-convert": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, "requires": { "color-name": "~1.1.4" } @@ -35478,561 +39157,657 @@ "color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true }, - "rxjs": { - "version": "7.8.1", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", - "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", - "requires": { - "tslib": "^2.1.0" - } + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true }, - "wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, "requires": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "has-flag": "^4.0.0" } } } }, - "internal-slot": { - "version": "1.0.5", + "jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "dev": true + }, + "jest-worker": { + "version": "27.5.1", "dev": true, "requires": { - "get-intrinsic": "^1.2.0", - "has": "^1.0.3", - "side-channel": "^1.0.4" + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } } }, - "interpret": { - "version": "1.1.0", + "jiti": { + "version": "1.18.2", "dev": true }, - "invert-kv": { - "version": "1.0.0" + "jquery": { + "version": "2.1.4" }, - "ip": { - "version": "1.1.8", + "js-base64": { + "version": "2.6.4", "dev": true }, - "ipaddr.js": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", - "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "js-stringify": { + "version": "1.0.2", + "dev": true, + "optional": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true }, - "is-absolute": { - "version": "1.0.0", + "js-yaml": { + "version": "3.14.1", "dev": true, "requires": { - "is-relative": "^1.0.0", - "is-windows": "^1.0.1" + "argparse": "^1.0.7", + "esprima": "^4.0.0" } }, - "is-accessor-descriptor": { - "version": "0.1.6", + "jsbn": { + "version": "0.1.1", + "dev": true + }, + "jsdoc-type-pratt-parser": { + "version": "3.1.0", + "dev": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "jshint": { + "version": "2.9.7", "dev": true, "requires": { - "kind-of": "^3.0.2" + "cli": "~1.0.0", + "console-browserify": "1.1.x", + "exit": "0.1.x", + "htmlparser2": "3.8.x", + "lodash": "~4.17.10", + "minimatch": "~3.0.2", + "shelljs": "0.3.x", + "strip-json-comments": "1.0.x" }, "dependencies": { - "kind-of": { - "version": "3.2.2", + "minimatch": { + "version": "3.0.8", "dev": true, "requires": { - "is-buffer": "^1.1.5" + "brace-expansion": "^1.1.7" } + }, + "strip-json-comments": { + "version": "1.0.4", + "dev": true } } }, - "is-array-buffer": { - "version": "3.0.2", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.0", - "is-typed-array": "^1.1.10" - } + "json-parse-better-errors": { + "version": "1.0.2", + "dev": true }, - "is-arrayish": { - "version": "0.2.1", + "json-parse-even-better-errors": { + "version": "2.3.1", "dev": true }, - "is-bigint": { - "version": "1.0.4", - "dev": true, - "requires": { - "has-bigints": "^1.0.1" - } + "json-schema": { + "version": "0.4.0", + "dev": true }, - "is-binary-path": { - "version": "2.1.0", - "devOptional": true, - "requires": { - "binary-extensions": "^2.0.0" - } + "json-schema-traverse": { + "version": "1.0.0" }, - "is-boolean-object": { - "version": "1.1.2", - "dev": true, - "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" - } + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "dev": true }, - "is-buffer": { - "version": "1.1.6", + "json-stringify-safe": { + "version": "5.0.1", "dev": true }, - "is-callable": { - "version": "1.2.7", + "json5": { + "version": "2.2.3", "dev": true }, - "is-core-module": { - "version": "2.13.1", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", - "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", - "requires": { - "hasown": "^2.0.0" - } + "jsonc-parser": { + "version": "3.2.0" }, - "is-data-descriptor": { - "version": "0.1.4", + "jsonfile": { + "version": "6.1.0", "dev": true, "requires": { - "kind-of": "^3.0.2" - }, - "dependencies": { - "kind-of": { - "version": "3.2.2", - "dev": true, - "requires": { - "is-buffer": "^1.1.5" - } - } + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" } }, - "is-date-object": { - "version": "1.0.5", + "jsonparse": { + "version": "1.3.1" + }, + "JSONStream": { + "version": "1.3.5", "dev": true, "requires": { - "has-tostringtag": "^1.0.0" + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" } }, - "is-descriptor": { - "version": "0.1.6", + "jsprim": { + "version": "1.4.2", "dev": true, "requires": { - "is-accessor-descriptor": "^0.1.6", - "is-data-descriptor": "^0.1.4", - "kind-of": "^5.0.0" - }, - "dependencies": { - "kind-of": { - "version": "5.1.0", - "dev": true - } + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" } }, - "is-docker": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", - "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" - }, - "is-expression": { - "version": "3.0.0", + "jstransformer": { + "version": "1.0.0", "dev": true, "optional": true, "requires": { - "acorn": "~4.0.2", - "object-assign": "^4.0.1" - }, - "dependencies": { - "acorn": { - "version": "4.0.13", - "dev": true, - "optional": true - } + "is-promise": "^2.0.0", + "promise": "^7.0.1" } }, - "is-extendable": { - "version": "0.1.1", - "dev": true - }, - "is-extglob": { - "version": "2.1.1", - "devOptional": true - }, - "is-fullwidth-code-point": { - "version": "3.0.0" - }, - "is-glob": { - "version": "4.0.3", - "devOptional": true, + "jszip": { + "version": "3.10.1", + "dev": true, "requires": { - "is-extglob": "^2.1.1" + "lie": "~3.3.0", + "pako": "~1.0.2", + "readable-stream": "~2.3.6", + "setimmediate": "^1.0.5" } }, - "is-inside-container": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", - "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "karma": { + "version": "6.4.2", "dev": true, "requires": { - "is-docker": "^3.0.0" + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" }, "dependencies": { - "is-docker": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", - "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "cliui": { + "version": "7.0.4", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "connect": { + "version": "3.7.0", + "dev": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + } + }, + "debug": { + "version": "2.6.9", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "finalhandler": { + "version": "1.1.2", + "dev": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + } + }, + "glob": { + "version": "7.2.3", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "dev": true + }, + "source-map": { + "version": "0.6.1", + "dev": true + }, + "statuses": { + "version": "1.5.0", + "dev": true + }, + "ua-parser-js": { + "version": "0.7.35", "dev": true + }, + "yargs": { + "version": "16.2.0", + "dev": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + } } } }, - "is-interactive": { - "version": "1.0.0" - }, - "is-lambda": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", - "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" - }, - "is-negative-zero": { - "version": "2.0.2", - "dev": true - }, - "is-number": { - "version": "7.0.0", - "devOptional": true - }, - "is-number-like": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz", - "integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==", - "dev": true, - "requires": { - "lodash.isfinite": "^3.3.2" - } - }, - "is-number-object": { - "version": "1.0.7", - "dev": true, - "requires": { - "has-tostringtag": "^1.0.0" - } - }, - "is-obj": { - "version": "2.0.0", - "dev": true - }, - "is-path-cwd": { - "version": "1.0.0", - "dev": true - }, - "is-path-in-cwd": { - "version": "1.0.1", + "karma-chrome-launcher": { + "version": "3.1.1", "dev": true, "requires": { - "is-path-inside": "^1.0.0" + "which": "^1.2.1" }, "dependencies": { - "is-path-inside": { - "version": "1.0.1", + "which": { + "version": "1.3.1", "dev": true, "requires": { - "path-is-inside": "^1.0.1" + "isexe": "^2.0.0" } } } }, - "is-path-inside": { + "karma-coverage-istanbul-reporter": { "version": "3.0.3", - "dev": true - }, - "is-plain-obj": { - "version": "1.1.0", - "dev": true - }, - "is-plain-object": { - "version": "2.0.4", "dev": true, "requires": { - "isobject": "^3.0.1" + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^3.0.6", + "istanbul-reports": "^3.0.2", + "minimatch": "^3.0.4" } }, - "is-promise": { - "version": "2.2.2", - "dev": true, - "optional": true - }, - "is-regex": { - "version": "1.1.4", + "karma-jasmine": { + "version": "4.0.2", "dev": true, "requires": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "jasmine-core": "^3.6.0" + }, + "dependencies": { + "jasmine-core": { + "version": "3.99.1", + "dev": true + } } }, - "is-relative": { - "version": "1.0.0", - "dev": true, - "requires": { - "is-unc-path": "^1.0.0" - } + "karma-jasmine-html-reporter": { + "version": "1.7.0", + "dev": true }, - "is-shared-array-buffer": { - "version": "1.0.2", + "karma-source-map-support": { + "version": "1.4.0", "dev": true, "requires": { - "call-bind": "^1.0.2" + "source-map-support": "^0.5.5" } }, - "is-stream": { - "version": "2.0.1", + "kind-of": { + "version": "6.0.3", + "dev": true + }, + "klona": { + "version": "2.0.6", "dev": true }, - "is-string": { - "version": "1.0.7", + "launch-editor": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", + "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", "dev": true, "requires": { - "has-tostringtag": "^1.0.0" + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" } }, - "is-symbol": { + "lazy-cache": { "version": "1.0.4", "dev": true, + "optional": true + }, + "lcid": { + "version": "1.0.0", "requires": { - "has-symbols": "^1.0.2" + "invert-kv": "^1.0.0" } }, - "is-text-path": { - "version": "1.0.1", + "less": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", "dev": true, "requires": { - "text-extensions": "^1.0.0" + "copy-anything": "^2.0.1", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "parse-node-version": "^1.0.1", + "source-map": "~0.6.0", + "tslib": "^2.3.0" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "dev": true, + "optional": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "mime": { + "version": "1.6.0", + "dev": true, + "optional": true + }, + "pify": { + "version": "4.0.1", + "dev": true, + "optional": true + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "optional": true + }, + "source-map": { + "version": "0.6.1", + "dev": true, + "optional": true + } } }, - "is-typed-array": { - "version": "1.1.10", + "less-loader": { + "version": "11.1.0", "dev": true, "requires": { - "available-typed-arrays": "^1.0.5", - "call-bind": "^1.0.2", - "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-tostringtag": "^1.0.0" + "klona": "^2.0.4" } }, - "is-typedarray": { - "version": "1.0.0", - "dev": true - }, - "is-unc-path": { - "version": "1.0.0", + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "dev": true, "requires": { - "unc-path-regex": "^0.1.2" + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" } }, - "is-unicode-supported": { - "version": "0.1.0" - }, - "is-weakref": { - "version": "1.0.2", + "license-webpack-plugin": { + "version": "4.0.2", "dev": true, "requires": { - "call-bind": "^1.0.2" + "webpack-sources": "^3.0.0" } }, - "is-what": { - "version": "3.14.1", - "dev": true - }, - "is-windows": { - "version": "1.0.2", - "dev": true + "lie": { + "version": "3.3.0", + "dev": true, + "requires": { + "immediate": "~3.0.5" + } }, - "is-wsl": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", - "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "liftup": { + "version": "3.0.1", + "dev": true, "requires": { - "is-docker": "^2.0.0" + "extend": "^3.0.2", + "findup-sync": "^4.0.0", + "fined": "^1.2.0", + "flagged-respawn": "^1.0.1", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.1", + "rechoir": "^0.7.0", + "resolve": "^1.19.0" + }, + "dependencies": { + "findup-sync": { + "version": "4.0.0", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^4.0.2", + "resolve-dir": "^1.0.1" + } + } } }, - "isbinaryfile": { - "version": "4.0.10", + "lilconfig": { + "version": "2.1.0", "dev": true }, - "isexe": { - "version": "2.0.0" - }, - "isobject": { - "version": "3.0.1", + "limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==", "dev": true }, - "isstream": { - "version": "0.1.2", + "lines-and-columns": { + "version": "1.2.4", "dev": true }, - "istanbul-lib-coverage": { - "version": "3.2.0", + "livereload-js": { + "version": "2.4.0", "dev": true }, - "istanbul-lib-instrument": { - "version": "5.2.1", + "load-grunt-tasks": { + "version": "5.1.0", "dev": true, "requires": { - "@babel/core": "^7.12.3", - "@babel/parser": "^7.14.7", - "@istanbuljs/schema": "^0.1.2", - "istanbul-lib-coverage": "^3.2.0", - "semver": "^6.3.0" - }, - "dependencies": { - "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true - } + "arrify": "^2.0.1", + "multimatch": "^4.0.0", + "pkg-up": "^3.1.0", + "resolve-pkg": "^2.0.0" } }, - "istanbul-lib-report": { - "version": "3.0.0", + "load-json-file": { + "version": "4.0.0", "dev": true, "requires": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^3.0.0", - "supports-color": "^7.1.0" + "graceful-fs": "^4.1.2", + "parse-json": "^4.0.0", + "pify": "^3.0.0", + "strip-bom": "^3.0.0" }, "dependencies": { - "has-flag": { + "parse-json": { "version": "4.0.0", - "dev": true - }, - "supports-color": { - "version": "7.2.0", "dev": true, "requires": { - "has-flag": "^4.0.0" + "error-ex": "^1.3.1", + "json-parse-better-errors": "^1.0.1" } + }, + "pify": { + "version": "3.0.0", + "dev": true } } }, - "istanbul-lib-source-maps": { - "version": "3.0.6", + "loader-runner": { + "version": "4.3.0", + "dev": true + }, + "loader-utils": { + "version": "3.2.1", + "dev": true + }, + "localtunnel": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-2.0.2.tgz", + "integrity": "sha512-n418Cn5ynvJd7m/N1d9WVJISLJF/ellZnfsLnx8WBWGzxv/ntNcFkJ1o6se5quUhCplfLGBNL5tYHiq5WF3Nug==", "dev": true, "requires": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" + "axios": "0.21.4", + "debug": "4.3.2", + "openurl": "1.1.1", + "yargs": "17.1.1" }, "dependencies": { - "glob": { - "version": "7.2.3", + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" } }, - "istanbul-lib-coverage": { - "version": "2.0.5", - "dev": true - }, - "make-dir": { - "version": "2.1.0", + "debug": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", + "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", "dev": true, "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "ms": "2.1.2" } }, - "pify": { - "version": "4.0.1", - "dev": true - }, - "rimraf": { - "version": "2.7.1", + "yargs": { + "version": "17.1.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.1.1.tgz", + "integrity": "sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ==", "dev": true, "requires": { - "glob": "^7.1.3" + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" } - }, - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "dev": true } } }, - "istanbul-reports": { - "version": "3.1.5", + "locate-path": { + "version": "6.0.0", "dev": true, "requires": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" + "p-locate": "^5.0.0" } }, - "jackspeak": { - "version": "2.3.6", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", - "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", - "requires": { - "@isaacs/cliui": "^8.0.2", - "@pkgjs/parseargs": "^0.11.0" - } + "lodash": { + "version": "4.17.21" }, - "jake": { - "version": "10.8.7", - "resolved": "https://registry.npmjs.org/jake/-/jake-10.8.7.tgz", - "integrity": "sha512-ZDi3aP+fG/LchyBzUM804VjddnwfSfsdeYkwt8NcbKRvo4rFkjhs456iLFn3k2ZUWvNe4i48WACDbza8fhq2+w==", - "dev": true, + "lodash.clonedeep": { + "version": "4.5.0", + "dev": true + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "dev": true + }, + "lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "dev": true + }, + "log-symbols": { + "version": "4.1.0", "requires": { - "async": "^3.2.3", - "chalk": "^4.0.2", - "filelist": "^1.0.4", - "minimatch": "^3.1.2" + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" }, "dependencies": { "ansi-styles": { "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "requires": { "color-convert": "^2.0.1" } }, - "async": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true - }, "chalk": { "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "requires": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -36040,1739 +39815,2580 @@ }, "color-convert": { "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "requires": { "color-name": "~1.1.4" } }, "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "version": "1.1.4" }, "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "version": "4.0.0" }, "supports-color": { "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "requires": { "has-flag": "^4.0.0" } } } }, - "jasmine": { - "version": "2.8.0", + "log4js": { + "version": "6.9.1", "dev": true, "requires": { - "exit": "^0.1.2", - "glob": "^7.0.6", - "jasmine-core": "~2.8.0" - }, - "dependencies": { - "glob": { - "version": "7.2.3", - "dev": true, - "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - } - }, - "jasmine-core": { - "version": "2.8.0", - "dev": true - } + "date-format": "^4.0.14", + "debug": "^4.3.4", + "flatted": "^3.2.7", + "rfdc": "^1.3.0", + "streamroller": "^3.1.5" } }, - "jasmine-core": { - "version": "4.1.1", + "longest": { + "version": "1.0.1", + "dev": true, + "optional": true + }, + "lottie-web": { + "version": "5.12.2", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz", + "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==" + }, + "lower-case": { + "version": "1.1.4", "dev": true }, - "jasmine-spec-reporter": { - "version": "5.0.2", + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", "dev": true, "requires": { - "colors": "1.4.0" + "yallist": "^3.0.2" + } + }, + "magic-string": { + "version": "0.30.5", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", + "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "make-dir": { + "version": "3.1.0", + "dev": true, + "requires": { + "semver": "^6.0.0" }, "dependencies": { - "colors": { - "version": "1.4.0", + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", "dev": true } } }, - "jasminewd2": { - "version": "2.2.0", + "make-error": { + "version": "1.3.6", "dev": true }, - "jest-diff": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", - "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", + "make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "requires": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + } + }, + "make-iterator": { + "version": "1.0.1", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "map-cache": { + "version": "0.2.2", + "dev": true + }, + "map-obj": { + "version": "4.3.0", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "marked": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-10.0.0.tgz", + "integrity": "sha512-YiGcYcWj50YrwBgNzFoYhQ1hT6GmQbFG8SksnYJX1z4BXTHSOrz1GB5/Jm2yQvMg4nN1FHP4M6r03R10KrVUiA==" + }, + "media-typer": { + "version": "0.3.0", + "dev": true + }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dev": true, + "requires": { + "fs-monkey": "^1.0.4" + } + }, + "memorystream": { + "version": "0.3.1", + "dev": true + }, + "meow": { + "version": "8.1.2", "dev": true, "requires": { - "chalk": "^4.0.0", - "diff-sequences": "^29.6.3", - "jest-get-type": "^29.6.3", - "pretty-format": "^29.7.0" + "@types/minimist": "^1.2.0", + "camelcase-keys": "^6.2.2", + "decamelize-keys": "^1.1.0", + "hard-rejection": "^2.1.0", + "minimist-options": "4.1.0", + "normalize-package-data": "^3.0.0", + "read-pkg-up": "^7.0.1", + "redent": "^3.0.0", + "trim-newlines": "^3.0.0", + "type-fest": "^0.18.0", + "yargs-parser": "^20.2.3" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "find-up": { + "version": "4.1.0", "dev": true, "requires": { - "color-convert": "^2.0.1" + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" } }, - "chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "hosted-git-info": { + "version": "4.1.0", "dev": true, "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "lru-cache": "^6.0.0" } }, - "color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "locate-path": { + "version": "5.0.0", "dev": true, "requires": { - "color-name": "~1.1.4" + "p-locate": "^4.1.0" } }, - "color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "lru-cache": { + "version": "6.0.0", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } }, - "has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true + "normalize-package-data": { + "version": "3.0.3", + "dev": true, + "requires": { + "hosted-git-info": "^4.0.1", + "is-core-module": "^2.5.0", + "semver": "^7.3.4", + "validate-npm-package-license": "^3.0.1" + } }, - "supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "p-limit": { + "version": "2.3.0", "dev": true, "requires": { - "has-flag": "^4.0.0" + "p-try": "^2.0.0" } - } - } - }, - "jest-get-type": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", - "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true - }, - "jest-worker": { - "version": "27.5.1", - "dev": true, - "requires": { - "@types/node": "*", - "merge-stream": "^2.0.0", - "supports-color": "^8.0.0" - }, - "dependencies": { - "has-flag": { - "version": "4.0.0", - "dev": true }, - "supports-color": { - "version": "8.1.1", + "p-locate": { + "version": "4.1.0", "dev": true, "requires": { - "has-flag": "^4.0.0" + "p-limit": "^2.2.0" + } + }, + "read-pkg": { + "version": "5.2.0", + "dev": true, + "requires": { + "@types/normalize-package-data": "^2.4.0", + "normalize-package-data": "^2.5.0", + "parse-json": "^5.0.0", + "type-fest": "^0.6.0" + }, + "dependencies": { + "hosted-git-info": { + "version": "2.8.9", + "dev": true + }, + "normalize-package-data": { + "version": "2.5.0", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true + }, + "type-fest": { + "version": "0.6.0", + "dev": true + } + } + }, + "read-pkg-up": { + "version": "7.0.1", + "dev": true, + "requires": { + "find-up": "^4.1.0", + "read-pkg": "^5.2.0", + "type-fest": "^0.8.1" + }, + "dependencies": { + "type-fest": { + "version": "0.8.1", + "dev": true + } } + }, + "type-fest": { + "version": "0.18.1", + "dev": true + }, + "yallist": { + "version": "4.0.0", + "dev": true } } }, - "jiti": { - "version": "1.18.2", + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", "dev": true }, - "jquery": { - "version": "2.1.4" - }, - "js-base64": { - "version": "2.6.4", + "merge-stream": { + "version": "2.0.0", "dev": true }, - "js-stringify": { - "version": "1.0.2", - "dev": true, - "optional": true + "merge2": { + "version": "1.4.1", + "dev": true }, - "js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", "dev": true }, - "js-yaml": { - "version": "3.14.1", + "micromatch": { + "version": "4.0.5", "dev": true, "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "braces": "^3.0.2", + "picomatch": "^2.3.1" } }, - "jsbn": { - "version": "0.1.1", - "dev": true - }, - "jsdoc-type-pratt-parser": { - "version": "3.1.0", + "mime": { + "version": "2.6.0", "dev": true }, - "jsesc": { - "version": "2.5.2", - "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", - "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "mime-db": { + "version": "1.52.0", "dev": true }, - "jshint": { - "version": "2.9.7", + "mime-types": { + "version": "2.1.35", "dev": true, "requires": { - "cli": "~1.0.0", - "console-browserify": "1.1.x", - "exit": "0.1.x", - "htmlparser2": "3.8.x", - "lodash": "~4.17.10", - "minimatch": "~3.0.2", - "shelljs": "0.3.x", - "strip-json-comments": "1.0.x" - }, - "dependencies": { - "minimatch": { - "version": "3.0.8", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "strip-json-comments": { - "version": "1.0.4", - "dev": true - } + "mime-db": "1.52.0" } }, - "json-parse-better-errors": { - "version": "1.0.2", - "dev": true - }, - "json-parse-even-better-errors": { - "version": "2.3.1", - "dev": true - }, - "json-schema": { - "version": "0.4.0", - "dev": true - }, - "json-schema-traverse": { - "version": "1.0.0" + "mimic-fn": { + "version": "2.1.0" }, - "json-stable-stringify-without-jsonify": { + "min-indent": { "version": "1.0.1", "dev": true }, - "json-stringify-safe": { - "version": "5.0.1", - "dev": true - }, - "json5": { - "version": "2.2.3", - "dev": true - }, - "jsonc-parser": { - "version": "3.2.0" - }, - "jsonfile": { - "version": "6.1.0", + "mini-css-extract-plugin": { + "version": "2.7.6", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", + "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", "dev": true, "requires": { - "graceful-fs": "^4.1.6", - "universalify": "^2.0.0" + "schema-utils": "^4.0.0" } }, - "jsonparse": { - "version": "1.3.1" + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true }, - "JSONStream": { - "version": "1.3.5", + "minimatch": { + "version": "3.1.2", "dev": true, "requires": { - "jsonparse": "^1.2.0", - "through": ">=2.2.7 <3" + "brace-expansion": "^1.1.7" } }, - "jsprim": { - "version": "1.4.2", + "minimist": { + "version": "1.2.8", + "dev": true + }, + "minimist-options": { + "version": "4.1.0", "dev": true, "requires": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" + "arrify": "^1.0.1", + "is-plain-obj": "^1.1.0", + "kind-of": "^6.0.3" + }, + "dependencies": { + "arrify": { + "version": "1.0.1", + "dev": true + } } }, - "jstransformer": { - "version": "1.0.0", - "dev": true, - "optional": true, + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==" + }, + "minipass-collect": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", + "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", "requires": { - "is-promise": "^2.0.0", - "promise": "^7.0.1" + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } } }, - "jszip": { - "version": "3.10.1", - "dev": true, + "minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", "requires": { - "lie": "~3.3.0", - "pako": "~1.0.2", - "readable-stream": "~2.3.6", - "setimmediate": "^1.0.5" + "encoding": "^0.1.13", + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" } }, - "karma": { - "version": "6.4.2", - "dev": true, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", "requires": { - "@colors/colors": "1.5.0", - "body-parser": "^1.19.0", - "braces": "^3.0.2", - "chokidar": "^3.5.1", - "connect": "^3.7.0", - "di": "^0.0.1", - "dom-serialize": "^2.2.1", - "glob": "^7.1.7", - "graceful-fs": "^4.2.6", - "http-proxy": "^1.18.1", - "isbinaryfile": "^4.0.8", - "lodash": "^4.17.21", - "log4js": "^6.4.1", - "mime": "^2.5.2", - "minimatch": "^3.0.4", - "mkdirp": "^0.5.5", - "qjobs": "^1.2.0", - "range-parser": "^1.2.1", - "rimraf": "^3.0.2", - "socket.io": "^4.4.1", - "source-map": "^0.6.1", - "tmp": "^0.2.1", - "ua-parser-js": "^0.7.30", - "yargs": "^16.1.1" + "minipass": "^3.0.0" }, "dependencies": { - "cliui": { - "version": "7.0.4", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "connect": { - "version": "3.7.0", - "dev": true, + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "requires": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" + "yallist": "^4.0.0" } }, - "debug": { - "version": "2.6.9", - "dev": true, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "requires": { - "ms": "2.0.0" + "yallist": "^4.0.0" } }, - "finalhandler": { - "version": "1.1.2", - "dev": true, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "requires": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "yallist": "^4.0.0" } }, - "glob": { - "version": "7.2.3", - "dev": true, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "requires": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" + "yallist": "^4.0.0" } }, - "ms": { - "version": "2.0.0", - "dev": true - }, - "source-map": { - "version": "0.6.1", - "dev": true - }, - "statuses": { - "version": "1.5.0", - "dev": true - }, - "ua-parser-js": { - "version": "0.7.35", - "dev": true - }, - "yargs": { - "version": "16.2.0", - "dev": true, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" + "yallist": "^4.0.0" } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" } } }, - "karma-chrome-launcher": { - "version": "3.1.1", + "mitt": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz", + "integrity": "sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==", + "dev": true + }, + "mixin-deep": { + "version": "1.3.2", "dev": true, "requires": { - "which": "^1.2.1" + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" }, "dependencies": { - "which": { - "version": "1.3.1", + "is-extendable": { + "version": "1.0.1", "dev": true, "requires": { - "isexe": "^2.0.0" + "is-plain-object": "^2.0.4" } } } }, - "karma-coverage-istanbul-reporter": { - "version": "3.0.3", + "mkdirp": { + "version": "0.5.6", "dev": true, "requires": { - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^3.0.2", - "minimatch": "^3.0.4" + "minimist": "^1.2.6" } }, - "karma-jasmine": { - "version": "4.0.2", + "moment": { + "version": "2.29.4" + }, + "morgan": { + "version": "1.10.0", "dev": true, "requires": { - "jasmine-core": "^3.6.0" + "basic-auth": "~2.0.1", + "debug": "2.6.9", + "depd": "~2.0.0", + "on-finished": "~2.3.0", + "on-headers": "~1.0.2" }, "dependencies": { - "jasmine-core": { - "version": "3.99.1", + "debug": { + "version": "2.6.9", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", "dev": true } } }, - "karma-jasmine-html-reporter": { - "version": "1.7.0", - "dev": true, - "requires": {} + "mrmime": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", + "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", + "dev": true }, - "karma-source-map-support": { - "version": "1.4.0", + "ms": { + "version": "2.1.2" + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", "dev": true, "requires": { - "source-map-support": "^0.5.5" + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" } }, - "kind-of": { - "version": "6.0.3", - "dev": true + "multimatch": { + "version": "4.0.0", + "dev": true, + "requires": { + "@types/minimatch": "^3.0.3", + "array-differ": "^3.0.0", + "array-union": "^2.1.0", + "arrify": "^2.0.1", + "minimatch": "^3.0.4" + } }, - "klona": { - "version": "2.0.6", - "dev": true + "mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==" }, - "launch-editor": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", - "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", + "mz": { + "version": "2.7.0", "dev": true, "requires": { - "picocolors": "^1.0.0", - "shell-quote": "^1.8.1" + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" } }, - "lazy-cache": { - "version": "1.0.4", + "nan": { + "version": "2.17.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", + "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", "dev": true, "optional": true }, - "lcid": { - "version": "1.0.0", - "requires": { - "invert-kv": "^1.0.0" - } + "nanoid": { + "version": "3.3.6", + "dev": true }, - "less": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", - "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "nanomatch": { + "version": "1.2.13", "dev": true, "requires": { - "copy-anything": "^2.0.1", - "errno": "^0.1.1", - "graceful-fs": "^4.1.2", - "image-size": "~0.5.0", - "make-dir": "^2.1.0", - "mime": "^1.4.1", - "needle": "^3.1.0", - "parse-node-version": "^1.0.1", - "source-map": "~0.6.0", - "tslib": "^2.3.0" + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" }, "dependencies": { - "make-dir": { - "version": "2.1.0", + "define-property": { + "version": "2.0.2", "dev": true, - "optional": true, "requires": { - "pify": "^4.0.1", - "semver": "^5.6.0" + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" } }, - "mime": { - "version": "1.6.0", + "extend-shallow": { + "version": "3.0.2", "dev": true, - "optional": true + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + } }, - "pify": { - "version": "4.0.1", + "is-accessor-descriptor": { + "version": "1.0.0", "dev": true, - "optional": true + "requires": { + "kind-of": "^6.0.0" + } }, - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "is-data-descriptor": { + "version": "1.0.0", "dev": true, - "optional": true + "requires": { + "kind-of": "^6.0.0" + } }, - "source-map": { - "version": "0.6.1", + "is-descriptor": { + "version": "1.0.2", "dev": true, - "optional": true + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + }, + "is-extendable": { + "version": "1.0.1", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } } } }, - "less-loader": { - "version": "11.1.0", - "dev": true, - "requires": { - "klona": "^2.0.4" - } - }, - "levn": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", - "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, - "requires": { - "prelude-ls": "^1.2.1", - "type-check": "~0.4.0" - } - }, - "license-webpack-plugin": { - "version": "4.0.2", - "dev": true, - "requires": { - "webpack-sources": "^3.0.0" - } - }, - "lie": { - "version": "3.3.0", - "dev": true, - "requires": { - "immediate": "~3.0.5" - } + "natural-compare": { + "version": "1.4.0", + "dev": true }, - "liftup": { - "version": "3.0.1", + "needle": { + "version": "3.2.0", "dev": true, + "optional": true, "requires": { - "extend": "^3.0.2", - "findup-sync": "^4.0.0", - "fined": "^1.2.0", - "flagged-respawn": "^1.0.1", - "is-plain-object": "^2.0.4", - "object.map": "^1.0.1", - "rechoir": "^0.7.0", - "resolve": "^1.19.0" + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" }, "dependencies": { - "findup-sync": { - "version": "4.0.0", + "debug": { + "version": "3.2.7", "dev": true, + "optional": true, "requires": { - "detect-file": "^1.0.0", - "is-glob": "^4.0.0", - "micromatch": "^4.0.2", - "resolve-dir": "^1.0.1" + "ms": "^2.1.1" } } } }, - "lilconfig": { - "version": "2.1.0", - "dev": true - }, - "limiter": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", - "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==", - "dev": true - }, - "lines-and-columns": { - "version": "1.2.4", - "dev": true + "negotiator": { + "version": "0.6.3" }, - "livereload-js": { - "version": "2.4.0", + "neo-async": { + "version": "2.6.2", "dev": true }, - "load-grunt-tasks": { - "version": "5.1.0", - "dev": true, - "requires": { - "arrify": "^2.0.1", - "multimatch": "^4.0.0", - "pkg-up": "^3.1.0", - "resolve-pkg": "^2.0.0" - } - }, - "load-json-file": { - "version": "4.0.0", + "ng-annotate": { + "version": "1.2.2", "dev": true, "requires": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" + "acorn": "~2.6.4", + "alter": "~0.2.0", + "convert-source-map": "~1.1.2", + "optimist": "~0.6.1", + "ordered-ast-traverse": "~1.1.1", + "simple-fmt": "~0.1.0", + "simple-is": "~0.2.0", + "source-map": "~0.5.3", + "stable": "~0.1.5", + "stringmap": "~0.2.2", + "stringset": "~0.2.1", + "tryor": "~0.1.2" }, "dependencies": { - "parse-json": { - "version": "4.0.0", - "dev": true, - "requires": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } + "acorn": { + "version": "2.6.4", + "dev": true }, - "pify": { - "version": "3.0.0", + "convert-source-map": { + "version": "1.1.3", + "dev": true + }, + "source-map": { + "version": "0.5.7", "dev": true } } }, - "loader-runner": { - "version": "4.3.0", - "dev": true + "ng-csv": { + "version": "0.2.3" }, - "loader-utils": { - "version": "3.2.1", - "dev": true + "ng-file-upload": { + "version": "5.0.9" }, - "localtunnel": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/localtunnel/-/localtunnel-2.0.2.tgz", - "integrity": "sha512-n418Cn5ynvJd7m/N1d9WVJISLJF/ellZnfsLnx8WBWGzxv/ntNcFkJ1o6se5quUhCplfLGBNL5tYHiq5WF3Nug==", - "dev": true, + "ng2-pdf-viewer": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-10.0.0.tgz", + "integrity": "sha512-zEefcAsTpDoxFceQYs3ycPMaUAkt5UX4OcTstVQoNqRK6w+vOY+V8z8aFCuBwnt+7iN1EHaIpquOf4S9mWc04g==", "requires": { - "axios": "0.21.4", - "debug": "4.3.2", - "openurl": "1.1.1", - "yargs": "17.1.1" - }, - "dependencies": { - "cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dev": true, - "requires": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "debug": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.2.tgz", - "integrity": "sha512-mOp8wKcvj7XxC78zLgw/ZA+6TSgkoE2C/ienthhRD298T7UNwAg9diBpLRxC0mOezLl4B0xV7M0cCO6P/O0Xhw==", - "dev": true, - "requires": { - "ms": "2.1.2" - } - }, - "yargs": { - "version": "17.1.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.1.1.tgz", - "integrity": "sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ==", - "dev": true, - "requires": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - } - } + "pdfjs-dist": "~2.16.105", + "tslib": "^2.3.0" } }, - "locate-path": { - "version": "6.0.0", - "dev": true, + "ngx-bootstrap": { + "version": "6.2.0" + }, + "ngx-entity-service": { + "version": "0.0.37", + "resolved": "https://registry.npmjs.org/ngx-entity-service/-/ngx-entity-service-0.0.37.tgz", + "integrity": "sha512-clUk5EVKoxECHau0NB+VSvJh2hjtCd4TF5gJBFHEBBBZOZKYKagv/oQKIVntQweuKx6gQMAvy8g8CuTpUb9k0g==", "requires": { - "p-locate": "^5.0.0" + "tslib": "^2.3.0" } }, - "lodash": { - "version": "4.17.21" + "ngx-lottie": { + "version": "10.0.0", + "requires": { + "@scarf/scarf": "^1.1.1", + "tslib": "^2.3.0" + } }, - "lodash.clonedeep": { - "version": "4.5.0", - "dev": true + "nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "dev": true, + "optional": true, + "requires": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } }, - "lodash.debounce": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", - "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==", + "nice-try": { + "version": "1.0.5", "dev": true }, - "lodash.isfinite": { - "version": "3.3.2", - "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", - "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==", - "dev": true + "no-case": { + "version": "2.3.2", + "dev": true, + "requires": { + "lower-case": "^1.1.1" + } }, - "lodash.merge": { - "version": "4.6.2", + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "dev": true, + "optional": true + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", "dev": true }, - "log-symbols": { - "version": "4.1.0", + "node-gyp": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", + "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", "requires": { - "chalk": "^4.1.0", - "is-unicode-supported": "^0.1.0" + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" }, "dependencies": { - "ansi-styles": { - "version": "4.3.0", - "requires": { - "color-convert": "^2.0.1" - } + "abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==" }, - "chalk": { - "version": "4.1.2", + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "requires": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "balanced-match": "^1.0.0" } }, - "color-convert": { - "version": "2.0.1", + "glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", "requires": { - "color-name": "~1.1.4" + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" } }, - "color-name": { - "version": "1.1.4" + "isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==" }, - "has-flag": { - "version": "4.0.0" + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "requires": { + "brace-expansion": "^2.0.1" + } }, - "supports-color": { + "nopt": { "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", "requires": { - "has-flag": "^4.0.0" + "abbrev": "^2.0.0" + } + }, + "which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "requires": { + "isexe": "^3.1.1" } } } }, - "log4js": { - "version": "6.9.1", - "dev": true, - "requires": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "flatted": "^3.2.7", - "rfdc": "^1.3.0", - "streamroller": "^3.1.5" - } - }, - "longest": { - "version": "1.0.1", + "node-gyp-build": { + "version": "4.6.1", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", + "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", "dev": true, "optional": true }, - "lottie-web": { - "version": "5.12.2", - "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.12.2.tgz", - "integrity": "sha512-uvhvYPC8kGPjXT3MyKMrL3JitEAmDMp30lVkuq/590Mw9ok6pWcFCwXJveo0t5uqYw1UREQHofD+jVpdjBv8wg==" + "node-machine-id": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz", + "integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==", + "dev": true }, - "lower-case": { - "version": "1.1.4", + "node-releases": { + "version": "2.0.13", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", + "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", "dev": true }, - "lru-cache": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", - "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "nopt": { + "version": "3.0.6", "dev": true, "requires": { - "yallist": "^3.0.2" - } - }, - "magic-string": { - "version": "0.30.5", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.5.tgz", - "integrity": "sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==", - "requires": { - "@jridgewell/sourcemap-codec": "^1.4.15" + "abbrev": "1" } }, - "make-dir": { - "version": "3.1.0", + "normalize-package-data": { + "version": "2.5.0", "dev": true, "requires": { - "semver": "^6.0.0" + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" }, "dependencies": { "semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true } } }, - "make-error": { - "version": "1.3.6", - "dev": true - }, - "make-fetch-happen": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", - "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", - "requires": { - "@npmcli/agent": "^2.0.0", - "cacache": "^18.0.0", - "http-cache-semantics": "^4.1.1", - "is-lambda": "^1.0.1", - "minipass": "^7.0.2", - "minipass-fetch": "^3.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^0.6.3", - "promise-retry": "^2.0.1", - "ssri": "^10.0.0" - } - }, - "make-iterator": { - "version": "1.0.1", - "dev": true, - "requires": { - "kind-of": "^6.0.2" - } - }, - "map-cache": { - "version": "0.2.2", - "dev": true - }, - "map-obj": { - "version": "4.3.0", - "dev": true - }, - "map-visit": { - "version": "1.0.0", - "dev": true, - "requires": { - "object-visit": "^1.0.0" - } - }, - "marked": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-10.0.0.tgz", - "integrity": "sha512-YiGcYcWj50YrwBgNzFoYhQ1hT6GmQbFG8SksnYJX1z4BXTHSOrz1GB5/Jm2yQvMg4nN1FHP4M6r03R10KrVUiA==" - }, - "media-typer": { - "version": "0.3.0", + "normalize-path": { + "version": "3.0.0", "dev": true }, - "memfs": { - "version": "3.5.3", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", - "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", - "dev": true, - "requires": { - "fs-monkey": "^1.0.4" - } - }, - "memorystream": { - "version": "0.3.1", + "normalize-range": { + "version": "0.1.2", "dev": true }, - "meow": { - "version": "8.1.2", - "dev": true, + "npm": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/npm/-/npm-10.4.0.tgz", + "integrity": "sha512-RS7Mx0OVfXlOcQLRePuDIYdFCVBPCNapWHplDK+mh7GDdP/Tvor4ocuybRRPSvfcRb2vjRJt1fHCqw3cr8qACQ==", "requires": { - "@types/minimist": "^1.2.0", - "camelcase-keys": "^6.2.2", - "decamelize-keys": "^1.1.0", - "hard-rejection": "^2.1.0", - "minimist-options": "4.1.0", - "normalize-package-data": "^3.0.0", - "read-pkg-up": "^7.0.1", - "redent": "^3.0.0", - "trim-newlines": "^3.0.0", - "type-fest": "^0.18.0", - "yargs-parser": "^20.2.3" - }, - "dependencies": { - "find-up": { - "version": "4.1.0", - "dev": true, + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/arborist": "^7.2.1", + "@npmcli/config": "^8.0.2", + "@npmcli/fs": "^3.1.0", + "@npmcli/map-workspaces": "^3.0.4", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.1", + "@npmcli/run-script": "^7.0.4", + "@sigstore/tuf": "^2.3.0", + "abbrev": "^2.0.0", + "archy": "~1.0.0", + "cacache": "^18.0.2", + "chalk": "^5.3.0", + "ci-info": "^4.0.0", + "cli-columns": "^4.0.0", + "cli-table3": "^0.6.3", + "columnify": "^1.6.0", + "fastest-levenshtein": "^1.0.16", + "fs-minipass": "^3.0.3", + "glob": "^10.3.10", + "graceful-fs": "^4.2.11", + "hosted-git-info": "^7.0.1", + "ini": "^4.1.1", + "init-package-json": "^6.0.0", + "is-cidr": "^5.0.3", + "json-parse-even-better-errors": "^3.0.1", + "libnpmaccess": "^8.0.1", + "libnpmdiff": "^6.0.3", + "libnpmexec": "^7.0.4", + "libnpmfund": "^5.0.1", + "libnpmhook": "^10.0.0", + "libnpmorg": "^6.0.1", + "libnpmpack": "^6.0.3", + "libnpmpublish": "^9.0.2", + "libnpmsearch": "^7.0.0", + "libnpmteam": "^6.0.0", + "libnpmversion": "^5.0.1", + "make-fetch-happen": "^13.0.0", + "minimatch": "^9.0.3", + "minipass": "^7.0.4", + "minipass-pipeline": "^1.2.4", + "ms": "^2.1.2", + "node-gyp": "^10.0.1", + "nopt": "^7.2.0", + "normalize-package-data": "^6.0.0", + "npm-audit-report": "^5.0.0", + "npm-install-checks": "^6.3.0", + "npm-package-arg": "^11.0.1", + "npm-pick-manifest": "^9.0.0", + "npm-profile": "^9.0.0", + "npm-registry-fetch": "^16.1.0", + "npm-user-validate": "^2.0.0", + "npmlog": "^7.0.1", + "p-map": "^4.0.0", + "pacote": "^17.0.6", + "parse-conflict-json": "^3.0.1", + "proc-log": "^3.0.0", + "qrcode-terminal": "^0.12.0", + "read": "^2.1.0", + "semver": "^7.5.4", + "spdx-expression-parse": "^3.0.1", + "ssri": "^10.0.5", + "supports-color": "^9.4.0", + "tar": "^6.2.0", + "text-table": "~0.2.0", + "tiny-relative-date": "^1.3.0", + "treeverse": "^3.0.0", + "validate-npm-package-name": "^5.0.0", + "which": "^4.0.0", + "write-file-atomic": "^5.0.1" + }, + "dependencies": { + "@colors/colors": { + "version": "1.5.0", + "bundled": true, + "optional": true + }, + "@isaacs/cliui": { + "version": "8.0.2", + "bundled": true, + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "bundled": true + }, + "emoji-regex": { + "version": "9.2.2", + "bundled": true + }, + "string-width": { + "version": "5.1.2", + "bundled": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "bundled": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "@isaacs/string-locale-compare": { + "version": "1.1.0", + "bundled": true + }, + "@npmcli/agent": { + "version": "2.2.0", + "bundled": true, + "requires": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + } + }, + "@npmcli/arborist": { + "version": "7.3.1", + "bundled": true, + "requires": { + "@isaacs/string-locale-compare": "^1.1.0", + "@npmcli/fs": "^3.1.0", + "@npmcli/installed-package-contents": "^2.0.2", + "@npmcli/map-workspaces": "^3.0.2", + "@npmcli/metavuln-calculator": "^7.0.0", + "@npmcli/name-from-folder": "^2.0.0", + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/query": "^3.0.1", + "@npmcli/run-script": "^7.0.2", + "bin-links": "^4.0.1", + "cacache": "^18.0.0", + "common-ancestor-path": "^1.0.1", + "hosted-git-info": "^7.0.1", + "json-parse-even-better-errors": "^3.0.0", + "json-stringify-nice": "^1.1.4", + "minimatch": "^9.0.0", + "nopt": "^7.0.0", + "npm-install-checks": "^6.2.0", + "npm-package-arg": "^11.0.1", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "npmlog": "^7.0.1", + "pacote": "^17.0.4", + "parse-conflict-json": "^3.0.0", + "proc-log": "^3.0.0", + "promise-all-reject-late": "^1.0.0", + "promise-call-limit": "^3.0.1", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "ssri": "^10.0.5", + "treeverse": "^3.0.0", + "walk-up-path": "^3.0.1" + } + }, + "@npmcli/config": { + "version": "8.1.0", + "bundled": true, + "requires": { + "@npmcli/map-workspaces": "^3.0.2", + "ci-info": "^4.0.0", + "ini": "^4.1.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.5", + "walk-up-path": "^3.0.1" + } + }, + "@npmcli/disparity-colors": { + "version": "3.0.0", + "bundled": true, + "requires": { + "ansi-styles": "^4.3.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "bundled": true, + "requires": { + "color-convert": "^2.0.1" + } + } + } + }, + "@npmcli/fs": { + "version": "3.1.0", + "bundled": true, + "requires": { + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "5.0.4", + "bundled": true, + "requires": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + } + }, + "@npmcli/installed-package-contents": { + "version": "2.0.2", + "bundled": true, + "requires": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "@npmcli/map-workspaces": { + "version": "3.0.4", + "bundled": true, + "requires": { + "@npmcli/name-from-folder": "^2.0.0", + "glob": "^10.2.2", + "minimatch": "^9.0.0", + "read-package-json-fast": "^3.0.0" + } + }, + "@npmcli/metavuln-calculator": { + "version": "7.0.0", + "bundled": true, + "requires": { + "cacache": "^18.0.0", + "json-parse-even-better-errors": "^3.0.0", + "pacote": "^17.0.0", + "semver": "^7.3.5" + } + }, + "@npmcli/name-from-folder": { + "version": "2.0.0", + "bundled": true + }, + "@npmcli/node-gyp": { + "version": "3.0.0", + "bundled": true + }, + "@npmcli/package-json": { + "version": "5.0.0", + "bundled": true, + "requires": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + } + }, + "@npmcli/promise-spawn": { + "version": "7.0.1", + "bundled": true, + "requires": { + "which": "^4.0.0" + } + }, + "@npmcli/query": { + "version": "3.0.1", + "bundled": true, + "requires": { + "postcss-selector-parser": "^6.0.10" + } + }, + "@npmcli/run-script": { + "version": "7.0.4", + "bundled": true, + "requires": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "which": "^4.0.0" + } + }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "bundled": true, + "optional": true + }, + "@sigstore/bundle": { + "version": "2.1.1", + "bundled": true, + "requires": { + "@sigstore/protobuf-specs": "^0.2.1" + } + }, + "@sigstore/core": { + "version": "0.2.0", + "bundled": true + }, + "@sigstore/protobuf-specs": { + "version": "0.2.1", + "bundled": true + }, + "@sigstore/sign": { + "version": "2.2.1", + "bundled": true, + "requires": { + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", + "@sigstore/protobuf-specs": "^0.2.1", + "make-fetch-happen": "^13.0.0" + } + }, + "@sigstore/tuf": { + "version": "2.3.0", + "bundled": true, + "requires": { + "@sigstore/protobuf-specs": "^0.2.1", + "tuf-js": "^2.2.0" + } + }, + "@sigstore/verify": { + "version": "0.1.0", + "bundled": true, + "requires": { + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", + "@sigstore/protobuf-specs": "^0.2.1" + } + }, + "@tufjs/canonical-json": { + "version": "2.0.0", + "bundled": true + }, + "@tufjs/models": { + "version": "2.0.0", + "bundled": true, + "requires": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.3" + } + }, + "abbrev": { + "version": "2.0.0", + "bundled": true + }, + "agent-base": { + "version": "7.1.0", + "bundled": true, + "requires": { + "debug": "^4.3.4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "bundled": true, + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ansi-regex": { + "version": "5.0.1", + "bundled": true + }, + "ansi-styles": { + "version": "6.2.1", + "bundled": true + }, + "aproba": { + "version": "2.0.0", + "bundled": true + }, + "archy": { + "version": "1.0.0", + "bundled": true + }, + "are-we-there-yet": { + "version": "4.0.2", + "bundled": true + }, + "balanced-match": { + "version": "1.0.2", + "bundled": true + }, + "bin-links": { + "version": "4.0.3", + "bundled": true, + "requires": { + "cmd-shim": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "read-cmd-shim": "^4.0.0", + "write-file-atomic": "^5.0.0" + } + }, + "binary-extensions": { + "version": "2.2.0", + "bundled": true + }, + "brace-expansion": { + "version": "2.0.1", + "bundled": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "builtins": { + "version": "5.0.1", + "bundled": true, + "requires": { + "semver": "^7.0.0" + } + }, + "cacache": { + "version": "18.0.2", + "bundled": true, + "requires": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + } + }, + "chalk": { + "version": "5.3.0", + "bundled": true + }, + "chownr": { + "version": "2.0.0", + "bundled": true + }, + "ci-info": { + "version": "4.0.0", + "bundled": true + }, + "cidr-regex": { + "version": "4.0.3", + "bundled": true, + "requires": { + "ip-regex": "^5.0.0" + } + }, + "clean-stack": { + "version": "2.2.0", + "bundled": true + }, + "cli-columns": { + "version": "4.0.0", + "bundled": true, + "requires": { + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1" + } + }, + "cli-table3": { + "version": "0.6.3", + "bundled": true, + "requires": { + "@colors/colors": "1.5.0", + "string-width": "^4.2.0" + } + }, + "clone": { + "version": "1.0.4", + "bundled": true + }, + "cmd-shim": { + "version": "6.0.2", + "bundled": true + }, + "color-convert": { + "version": "2.0.1", + "bundled": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "bundled": true + }, + "color-support": { + "version": "1.1.3", + "bundled": true + }, + "columnify": { + "version": "1.6.0", + "bundled": true, + "requires": { + "strip-ansi": "^6.0.1", + "wcwidth": "^1.0.0" + } + }, + "common-ancestor-path": { + "version": "1.0.1", + "bundled": true + }, + "console-control-strings": { + "version": "1.1.0", + "bundled": true + }, + "cross-spawn": { + "version": "7.0.3", + "bundled": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "dependencies": { + "which": { + "version": "2.0.2", + "bundled": true, + "requires": { + "isexe": "^2.0.0" + } + } + } + }, + "cssesc": { + "version": "3.0.0", + "bundled": true + }, + "debug": { + "version": "4.3.4", + "bundled": true, + "requires": { + "ms": "2.1.2" + }, + "dependencies": { + "ms": { + "version": "2.1.2", + "bundled": true + } + } + }, + "defaults": { + "version": "1.0.4", + "bundled": true, + "requires": { + "clone": "^1.0.2" + } + }, + "diff": { + "version": "5.1.0", + "bundled": true + }, + "eastasianwidth": { + "version": "0.2.0", + "bundled": true + }, + "emoji-regex": { + "version": "8.0.0", + "bundled": true + }, + "encoding": { + "version": "0.1.13", + "bundled": true, + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + } + }, + "env-paths": { + "version": "2.2.1", + "bundled": true + }, + "err-code": { + "version": "2.0.3", + "bundled": true + }, + "exponential-backoff": { + "version": "3.1.1", + "bundled": true + }, + "fastest-levenshtein": { + "version": "1.0.16", + "bundled": true + }, + "foreground-child": { + "version": "3.1.1", + "bundled": true, + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + } + }, + "fs-minipass": { + "version": "3.0.3", + "bundled": true, + "requires": { + "minipass": "^7.0.3" + } + }, + "function-bind": { + "version": "1.1.2", + "bundled": true + }, + "gauge": { + "version": "5.0.1", + "bundled": true, + "requires": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.3", + "console-control-strings": "^1.1.0", + "has-unicode": "^2.0.1", + "signal-exit": "^4.0.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.5" + } + }, + "glob": { + "version": "10.3.10", + "bundled": true, + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + } + }, + "graceful-fs": { + "version": "4.2.11", + "bundled": true + }, + "has-unicode": { + "version": "2.0.1", + "bundled": true + }, + "hasown": { + "version": "2.0.0", + "bundled": true, + "requires": { + "function-bind": "^1.1.2" + } + }, + "hosted-git-info": { + "version": "7.0.1", + "bundled": true, + "requires": { + "lru-cache": "^10.0.1" + } + }, + "http-cache-semantics": { + "version": "4.1.1", + "bundled": true + }, + "http-proxy-agent": { + "version": "7.0.0", + "bundled": true, + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "https-proxy-agent": { + "version": "7.0.2", + "bundled": true, + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, + "iconv-lite": { + "version": "0.6.3", + "bundled": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "ignore-walk": { + "version": "6.0.4", + "bundled": true, + "requires": { + "minimatch": "^9.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "bundled": true + }, + "indent-string": { + "version": "4.0.0", + "bundled": true + }, + "ini": { + "version": "4.1.1", + "bundled": true + }, + "init-package-json": { + "version": "6.0.0", + "bundled": true, + "requires": { + "npm-package-arg": "^11.0.0", + "promzard": "^1.0.0", + "read": "^2.0.0", + "read-package-json": "^7.0.0", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4", + "validate-npm-package-name": "^5.0.0" + } + }, + "ip": { + "version": "2.0.0", + "bundled": true + }, + "ip-regex": { + "version": "5.0.0", + "bundled": true + }, + "is-cidr": { + "version": "5.0.3", + "bundled": true, + "requires": { + "cidr-regex": "4.0.3" + } + }, + "is-core-module": { + "version": "2.13.1", + "bundled": true, + "requires": { + "hasown": "^2.0.0" + } + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "bundled": true + }, + "is-lambda": { + "version": "1.0.1", + "bundled": true + }, + "isexe": { + "version": "2.0.0", + "bundled": true + }, + "jackspeak": { + "version": "2.3.6", + "bundled": true, "requires": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" } }, - "hosted-git-info": { - "version": "4.1.0", - "dev": true, + "json-parse-even-better-errors": { + "version": "3.0.1", + "bundled": true + }, + "json-stringify-nice": { + "version": "1.1.4", + "bundled": true + }, + "jsonparse": { + "version": "1.3.1", + "bundled": true + }, + "just-diff": { + "version": "6.0.2", + "bundled": true + }, + "just-diff-apply": { + "version": "5.5.0", + "bundled": true + }, + "libnpmaccess": { + "version": "8.0.2", + "bundled": true, "requires": { - "lru-cache": "^6.0.0" + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0" } }, - "locate-path": { - "version": "5.0.0", - "dev": true, + "libnpmdiff": { + "version": "6.0.6", + "bundled": true, "requires": { - "p-locate": "^4.1.0" + "@npmcli/arborist": "^7.2.1", + "@npmcli/disparity-colors": "^3.0.0", + "@npmcli/installed-package-contents": "^2.0.2", + "binary-extensions": "^2.2.0", + "diff": "^5.1.0", + "minimatch": "^9.0.0", + "npm-package-arg": "^11.0.1", + "pacote": "^17.0.4", + "tar": "^6.2.0" + } + }, + "libnpmexec": { + "version": "7.0.7", + "bundled": true, + "requires": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/run-script": "^7.0.2", + "ci-info": "^4.0.0", + "npm-package-arg": "^11.0.1", + "npmlog": "^7.0.1", + "pacote": "^17.0.4", + "proc-log": "^3.0.0", + "read": "^2.0.0", + "read-package-json-fast": "^3.0.2", + "semver": "^7.3.7", + "walk-up-path": "^3.0.1" + } + }, + "libnpmfund": { + "version": "5.0.4", + "bundled": true, + "requires": { + "@npmcli/arborist": "^7.2.1" + } + }, + "libnpmhook": { + "version": "10.0.1", + "bundled": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + } + }, + "libnpmorg": { + "version": "6.0.2", + "bundled": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + } + }, + "libnpmpack": { + "version": "6.0.6", + "bundled": true, + "requires": { + "@npmcli/arborist": "^7.2.1", + "@npmcli/run-script": "^7.0.2", + "npm-package-arg": "^11.0.1", + "pacote": "^17.0.4" + } + }, + "libnpmpublish": { + "version": "9.0.4", + "bundled": true, + "requires": { + "ci-info": "^4.0.0", + "normalize-package-data": "^6.0.0", + "npm-package-arg": "^11.0.1", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7", + "sigstore": "^2.2.0", + "ssri": "^10.0.5" + } + }, + "libnpmsearch": { + "version": "7.0.1", + "bundled": true, + "requires": { + "npm-registry-fetch": "^16.0.0" + } + }, + "libnpmteam": { + "version": "6.0.1", + "bundled": true, + "requires": { + "aproba": "^2.0.0", + "npm-registry-fetch": "^16.0.0" + } + }, + "libnpmversion": { + "version": "5.0.2", + "bundled": true, + "requires": { + "@npmcli/git": "^5.0.3", + "@npmcli/run-script": "^7.0.2", + "json-parse-even-better-errors": "^3.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.7" } }, "lru-cache": { - "version": "6.0.0", - "dev": true, + "version": "10.1.0", + "bundled": true + }, + "make-fetch-happen": { + "version": "13.0.0", + "bundled": true, + "requires": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "bundled": true, "requires": { - "yallist": "^4.0.0" + "brace-expansion": "^2.0.1" } }, - "normalize-package-data": { - "version": "3.0.3", - "dev": true, + "minipass": { + "version": "7.0.4", + "bundled": true + }, + "minipass-collect": { + "version": "2.0.1", + "bundled": true, "requires": { - "hosted-git-info": "^4.0.1", - "is-core-module": "^2.5.0", - "semver": "^7.3.4", - "validate-npm-package-license": "^3.0.1" + "minipass": "^7.0.3" } }, - "p-limit": { - "version": "2.3.0", - "dev": true, + "minipass-fetch": { + "version": "3.0.4", + "bundled": true, "requires": { - "p-try": "^2.0.0" + "encoding": "^0.1.13", + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" } }, - "p-locate": { - "version": "4.1.0", - "dev": true, + "minipass-flush": { + "version": "1.0.5", + "bundled": true, "requires": { - "p-limit": "^2.2.0" + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "requires": { + "yallist": "^4.0.0" + } + } } }, - "read-pkg": { - "version": "5.2.0", - "dev": true, + "minipass-json-stream": { + "version": "1.0.1", + "bundled": true, "requires": { - "@types/normalize-package-data": "^2.4.0", - "normalize-package-data": "^2.5.0", - "parse-json": "^5.0.0", - "type-fest": "^0.6.0" + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" }, "dependencies": { - "hosted-git-info": { - "version": "2.8.9", - "dev": true - }, - "normalize-package-data": { - "version": "2.5.0", - "dev": true, + "minipass": { + "version": "3.3.6", + "bundled": true, "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "yallist": "^4.0.0" } - }, - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true - }, - "type-fest": { - "version": "0.6.0", - "dev": true } } }, - "read-pkg-up": { - "version": "7.0.1", - "dev": true, + "minipass-pipeline": { + "version": "1.2.4", + "bundled": true, "requires": { - "find-up": "^4.1.0", - "read-pkg": "^5.2.0", - "type-fest": "^0.8.1" + "minipass": "^3.0.0" }, "dependencies": { - "type-fest": { - "version": "0.8.1", - "dev": true + "minipass": { + "version": "3.3.6", + "bundled": true, + "requires": { + "yallist": "^4.0.0" + } } } }, - "type-fest": { - "version": "0.18.1", - "dev": true + "minipass-sized": { + "version": "1.0.3", + "bundled": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "requires": { + "yallist": "^4.0.0" + } + } + } }, - "yallist": { - "version": "4.0.0", - "dev": true - } - } - }, - "merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==", - "dev": true - }, - "merge-stream": { - "version": "2.0.0", - "dev": true - }, - "merge2": { - "version": "1.4.1", - "dev": true - }, - "methods": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", - "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", - "dev": true - }, - "micromatch": { - "version": "4.0.5", - "dev": true, - "requires": { - "braces": "^3.0.2", - "picomatch": "^2.3.1" - } - }, - "mime": { - "version": "2.6.0", - "dev": true - }, - "mime-db": { - "version": "1.52.0", - "dev": true - }, - "mime-types": { - "version": "2.1.35", - "dev": true, - "requires": { - "mime-db": "1.52.0" - } - }, - "mimic-fn": { - "version": "2.1.0" - }, - "min-indent": { - "version": "1.0.1", - "dev": true - }, - "mini-css-extract-plugin": { - "version": "2.7.6", - "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.7.6.tgz", - "integrity": "sha512-Qk7HcgaPkGG6eD77mLvZS1nmxlao3j+9PkrT9Uc7HAE1id3F41+DdBRYRYkbyfNRGzm8/YWtzhw7nVPmwhqTQw==", - "dev": true, - "requires": { - "schema-utils": "^4.0.0" - } - }, - "minimalistic-assert": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", - "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", - "dev": true - }, - "minimatch": { - "version": "3.1.2", - "dev": true, - "requires": { - "brace-expansion": "^1.1.7" - } - }, - "minimist": { - "version": "1.2.8", - "dev": true - }, - "minimist-options": { - "version": "4.1.0", - "dev": true, - "requires": { - "arrify": "^1.0.1", - "is-plain-obj": "^1.1.0", - "kind-of": "^6.0.3" - }, - "dependencies": { - "arrify": { - "version": "1.0.1", - "dev": true - } - } - }, - "minipass": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", - "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==" - }, - "minipass-collect": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz", - "integrity": "sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA==", - "requires": { - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "minizlib": { + "version": "2.1.2", + "bundled": true, "requires": { + "minipass": "^3.0.0", "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "requires": { + "yallist": "^4.0.0" + } + } } }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "minipass-fetch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", - "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", - "requires": { - "encoding": "^0.1.13", - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^2.1.2" - } - }, - "minipass-flush": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", - "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", - "requires": { - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "mkdirp": { + "version": "1.0.4", + "bundled": true + }, + "ms": { + "version": "2.1.3", + "bundled": true + }, + "mute-stream": { + "version": "1.0.0", + "bundled": true + }, + "negotiator": { + "version": "0.6.3", + "bundled": true + }, + "node-gyp": { + "version": "10.0.1", + "bundled": true, + "requires": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + } + }, + "nopt": { + "version": "7.2.0", + "bundled": true, "requires": { - "yallist": "^4.0.0" + "abbrev": "^2.0.0" } }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "minipass-json-stream": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", - "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", - "requires": { - "jsonparse": "^1.3.1", - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "normalize-package-data": { + "version": "6.0.0", + "bundled": true, "requires": { - "yallist": "^4.0.0" + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" } }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "minipass-pipeline": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", - "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", - "requires": { - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "npm-audit-report": { + "version": "5.0.0", + "bundled": true + }, + "npm-bundled": { + "version": "3.0.0", + "bundled": true, "requires": { - "yallist": "^4.0.0" + "npm-normalize-package-bin": "^3.0.0" } }, - "yallist": { + "npm-install-checks": { + "version": "6.3.0", + "bundled": true, + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "3.0.1", + "bundled": true + }, + "npm-package-arg": { + "version": "11.0.1", + "bundled": true, + "requires": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + } + }, + "npm-packlist": { + "version": "8.0.2", + "bundled": true, + "requires": { + "ignore-walk": "^6.0.4" + } + }, + "npm-pick-manifest": { + "version": "9.0.0", + "bundled": true, + "requires": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + } + }, + "npm-profile": { + "version": "9.0.0", + "bundled": true, + "requires": { + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0" + } + }, + "npm-registry-fetch": { + "version": "16.1.0", + "bundled": true, + "requires": { + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" + } + }, + "npm-user-validate": { + "version": "2.0.0", + "bundled": true + }, + "npmlog": { + "version": "7.0.1", + "bundled": true, + "requires": { + "are-we-there-yet": "^4.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^5.0.0", + "set-blocking": "^2.0.0" + } + }, + "p-map": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "minipass-sized": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", - "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", - "requires": { - "minipass": "^3.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "bundled": true, + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "pacote": { + "version": "17.0.6", + "bundled": true, + "requires": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + } + }, + "parse-conflict-json": { + "version": "3.0.1", + "bundled": true, "requires": { - "yallist": "^4.0.0" + "json-parse-even-better-errors": "^3.0.0", + "just-diff": "^6.0.0", + "just-diff-apply": "^5.2.0" } }, - "yallist": { + "path-key": { + "version": "3.1.1", + "bundled": true + }, + "path-scurry": { + "version": "1.10.1", + "bundled": true, + "requires": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.15", + "bundled": true, + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "proc-log": { + "version": "3.0.0", + "bundled": true + }, + "promise-all-reject-late": { + "version": "1.0.1", + "bundled": true + }, + "promise-call-limit": { + "version": "3.0.1", + "bundled": true + }, + "promise-inflight": { + "version": "1.0.1", + "bundled": true + }, + "promise-retry": { + "version": "2.0.1", + "bundled": true, + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "promzard": { + "version": "1.0.0", + "bundled": true, + "requires": { + "read": "^2.0.0" + } + }, + "qrcode-terminal": { + "version": "0.12.0", + "bundled": true + }, + "read": { + "version": "2.1.0", + "bundled": true, + "requires": { + "mute-stream": "~1.0.0" + } + }, + "read-cmd-shim": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "requires": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "dependencies": { - "minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "bundled": true + }, + "read-package-json": { + "version": "7.0.0", + "bundled": true, + "requires": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "read-package-json-fast": { + "version": "3.0.2", + "bundled": true, + "requires": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "retry": { + "version": "0.12.0", + "bundled": true + }, + "safer-buffer": { + "version": "2.1.2", + "bundled": true, + "optional": true + }, + "semver": { + "version": "7.5.4", + "bundled": true, + "requires": { + "lru-cache": "^6.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "bundled": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "set-blocking": { + "version": "2.0.0", + "bundled": true + }, + "shebang-command": { + "version": "2.0.0", + "bundled": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "bundled": true + }, + "signal-exit": { + "version": "4.1.0", + "bundled": true + }, + "sigstore": { + "version": "2.2.0", + "bundled": true, "requires": { - "yallist": "^4.0.0" + "@sigstore/bundle": "^2.1.1", + "@sigstore/core": "^0.2.0", + "@sigstore/protobuf-specs": "^0.2.1", + "@sigstore/sign": "^2.2.1", + "@sigstore/tuf": "^2.3.0", + "@sigstore/verify": "^0.1.0" } }, - "yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } - }, - "mitt": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz", - "integrity": "sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==", - "dev": true - }, - "mixin-deep": { - "version": "1.3.2", - "dev": true, - "requires": { - "for-in": "^1.0.2", - "is-extendable": "^1.0.1" - }, - "dependencies": { - "is-extendable": { - "version": "1.0.1", - "dev": true, + "smart-buffer": { + "version": "4.2.0", + "bundled": true + }, + "socks": { + "version": "2.7.1", + "bundled": true, "requires": { - "is-plain-object": "^2.0.4" + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" } - } - } - }, - "mkdirp": { - "version": "0.5.6", - "dev": true, - "requires": { - "minimist": "^1.2.6" - } - }, - "moment": { - "version": "2.29.4" - }, - "morgan": { - "version": "1.10.0", - "dev": true, - "requires": { - "basic-auth": "~2.0.1", - "debug": "2.6.9", - "depd": "~2.0.0", - "on-finished": "~2.3.0", - "on-headers": "~1.0.2" - }, - "dependencies": { - "debug": { - "version": "2.6.9", - "dev": true, + }, + "socks-proxy-agent": { + "version": "8.0.2", + "bundled": true, "requires": { - "ms": "2.0.0" + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" } }, - "ms": { - "version": "2.0.0", - "dev": true - } - } - }, - "mrmime": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-1.0.1.tgz", - "integrity": "sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==", - "dev": true - }, - "ms": { - "version": "2.1.2" - }, - "multicast-dns": { - "version": "7.2.5", - "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", - "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", - "dev": true, - "requires": { - "dns-packet": "^5.2.2", - "thunky": "^1.0.2" - } - }, - "multimatch": { - "version": "4.0.0", - "dev": true, - "requires": { - "@types/minimatch": "^3.0.3", - "array-differ": "^3.0.0", - "array-union": "^2.1.0", - "arrify": "^2.0.1", - "minimatch": "^3.0.4" - } - }, - "mute-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", - "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==" - }, - "mz": { - "version": "2.7.0", - "dev": true, - "requires": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, - "nan": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.17.0.tgz", - "integrity": "sha512-2ZTgtl0nJsO0KQCjEpxcIr5D+Yv90plTitZt9JBfQvVJDS5seMl3FOvsh3+9CoYWXf/1l5OaZzzF6nDm4cagaQ==", - "dev": true, - "optional": true - }, - "nanoid": { - "version": "3.3.6", - "dev": true - }, - "nanomatch": { - "version": "1.2.13", - "dev": true, - "requires": { - "arr-diff": "^4.0.0", - "array-unique": "^0.3.2", - "define-property": "^2.0.2", - "extend-shallow": "^3.0.2", - "fragment-cache": "^0.2.1", - "is-windows": "^1.0.2", - "kind-of": "^6.0.2", - "object.pick": "^1.3.0", - "regex-not": "^1.0.0", - "snapdragon": "^0.8.1", - "to-regex": "^3.0.1" - }, - "dependencies": { - "define-property": { - "version": "2.0.2", - "dev": true, + "spdx-correct": { + "version": "3.2.0", + "bundled": true, "requires": { - "is-descriptor": "^1.0.2", - "isobject": "^3.0.1" + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" } }, - "extend-shallow": { - "version": "3.0.2", - "dev": true, + "spdx-exceptions": { + "version": "2.3.0", + "bundled": true + }, + "spdx-expression-parse": { + "version": "3.0.1", + "bundled": true, "requires": { - "assign-symbols": "^1.0.0", - "is-extendable": "^1.0.1" + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" } }, - "is-accessor-descriptor": { - "version": "1.0.0", - "dev": true, + "spdx-license-ids": { + "version": "3.0.16", + "bundled": true + }, + "ssri": { + "version": "10.0.5", + "bundled": true, "requires": { - "kind-of": "^6.0.0" + "minipass": "^7.0.3" } }, - "is-data-descriptor": { - "version": "1.0.0", - "dev": true, + "string-width": { + "version": "4.2.3", + "bundled": true, "requires": { - "kind-of": "^6.0.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, - "is-descriptor": { - "version": "1.0.2", - "dev": true, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "bundled": true, "requires": { - "is-accessor-descriptor": "^1.0.0", - "is-data-descriptor": "^1.0.0", - "kind-of": "^6.0.2" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" } }, - "is-extendable": { - "version": "1.0.1", - "dev": true, + "strip-ansi": { + "version": "6.0.1", + "bundled": true, "requires": { - "is-plain-object": "^2.0.4" + "ansi-regex": "^5.0.1" } - } - } - }, - "natural-compare": { - "version": "1.4.0", - "dev": true - }, - "needle": { - "version": "3.2.0", - "dev": true, - "optional": true, - "requires": { - "debug": "^3.2.6", - "iconv-lite": "^0.6.3", - "sax": "^1.2.4" - }, - "dependencies": { - "debug": { - "version": "3.2.7", - "dev": true, - "optional": true, + }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "bundled": true, "requires": { - "ms": "^2.1.1" + "ansi-regex": "^5.0.1" } - } - } - }, - "negotiator": { - "version": "0.6.3" - }, - "neo-async": { - "version": "2.6.2", - "dev": true - }, - "ng-annotate": { - "version": "1.2.2", - "dev": true, - "requires": { - "acorn": "~2.6.4", - "alter": "~0.2.0", - "convert-source-map": "~1.1.2", - "optimist": "~0.6.1", - "ordered-ast-traverse": "~1.1.1", - "simple-fmt": "~0.1.0", - "simple-is": "~0.2.0", - "source-map": "~0.5.3", - "stable": "~0.1.5", - "stringmap": "~0.2.2", - "stringset": "~0.2.1", - "tryor": "~0.1.2" - }, - "dependencies": { - "acorn": { - "version": "2.6.4", - "dev": true }, - "convert-source-map": { - "version": "1.1.3", - "dev": true + "supports-color": { + "version": "9.4.0", + "bundled": true }, - "source-map": { - "version": "0.5.7", - "dev": true - } - } - }, - "ng-csv": { - "version": "0.2.3" - }, - "ng-file-upload": { - "version": "5.0.9" - }, - "ng2-pdf-viewer": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-10.0.0.tgz", - "integrity": "sha512-zEefcAsTpDoxFceQYs3ycPMaUAkt5UX4OcTstVQoNqRK6w+vOY+V8z8aFCuBwnt+7iN1EHaIpquOf4S9mWc04g==", - "requires": { - "pdfjs-dist": "~2.16.105", - "tslib": "^2.3.0" - } - }, - "ngx-bootstrap": { - "version": "6.2.0", - "requires": {} - }, - "ngx-entity-service": { - "version": "0.0.37", - "resolved": "https://registry.npmjs.org/ngx-entity-service/-/ngx-entity-service-0.0.37.tgz", - "integrity": "sha512-clUk5EVKoxECHau0NB+VSvJh2hjtCd4TF5gJBFHEBBBZOZKYKagv/oQKIVntQweuKx6gQMAvy8g8CuTpUb9k0g==", - "requires": { - "tslib": "^2.3.0" - } - }, - "ngx-lottie": { - "version": "10.0.0", - "requires": { - "@scarf/scarf": "^1.1.1", - "tslib": "^2.3.0" - } - }, - "nice-napi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", - "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", - "dev": true, - "optional": true, - "requires": { - "node-addon-api": "^3.0.0", - "node-gyp-build": "^4.2.2" - } - }, - "nice-try": { - "version": "1.0.5", - "dev": true - }, - "no-case": { - "version": "2.3.2", - "dev": true, - "requires": { - "lower-case": "^1.1.1" - } - }, - "node-addon-api": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", - "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", - "dev": true, - "optional": true - }, - "node-forge": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", - "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", - "dev": true - }, - "node-gyp": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", - "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", - "requires": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "glob": "^10.3.10", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^13.0.0", - "nopt": "^7.0.0", - "proc-log": "^3.0.0", - "semver": "^7.3.5", - "tar": "^6.1.2", - "which": "^4.0.0" - }, - "dependencies": { - "abbrev": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", - "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==" + "tar": { + "version": "6.2.0", + "bundled": true, + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "fs-minipass": { + "version": "2.1.0", + "bundled": true, + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "bundled": true, + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass": { + "version": "5.0.0", + "bundled": true + } + } }, - "brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "text-table": { + "version": "0.2.0", + "bundled": true + }, + "tiny-relative-date": { + "version": "1.3.0", + "bundled": true + }, + "treeverse": { + "version": "3.0.0", + "bundled": true + }, + "tuf-js": { + "version": "2.2.0", + "bundled": true, "requires": { - "balanced-match": "^1.0.0" + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" } }, - "glob": { - "version": "10.3.10", - "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", - "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "unique-filename": { + "version": "3.0.0", + "bundled": true, "requires": { - "foreground-child": "^3.1.0", - "jackspeak": "^2.3.5", - "minimatch": "^9.0.1", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", - "path-scurry": "^1.10.1" + "unique-slug": "^4.0.0" } }, - "isexe": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", - "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==" + "unique-slug": { + "version": "4.0.0", + "bundled": true, + "requires": { + "imurmurhash": "^0.1.4" + } }, - "minimatch": { - "version": "9.0.3", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", - "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "util-deprecate": { + "version": "1.0.2", + "bundled": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "bundled": true, "requires": { - "brace-expansion": "^2.0.1" + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" } }, - "nopt": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", - "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "validate-npm-package-name": { + "version": "5.0.0", + "bundled": true, "requires": { - "abbrev": "^2.0.0" + "builtins": "^5.0.0" + } + }, + "walk-up-path": { + "version": "3.0.1", + "bundled": true + }, + "wcwidth": { + "version": "1.0.1", + "bundled": true, + "requires": { + "defaults": "^1.0.3" } }, "which": { "version": "4.0.0", - "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", - "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "bundled": true, "requires": { "isexe": "^3.1.1" + }, + "dependencies": { + "isexe": { + "version": "3.1.1", + "bundled": true + } } + }, + "wide-align": { + "version": "1.1.5", + "bundled": true, + "requires": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "bundled": true, + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "bundled": true + }, + "emoji-regex": { + "version": "9.2.2", + "bundled": true + }, + "string-width": { + "version": "5.1.2", + "bundled": true, + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "bundled": true, + "requires": { + "ansi-regex": "^6.0.1" + } + } + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "bundled": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "bundled": true, + "requires": { + "color-convert": "^2.0.1" + } + } + } + }, + "write-file-atomic": { + "version": "5.0.1", + "bundled": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^4.0.1" + } + }, + "yallist": { + "version": "4.0.0", + "bundled": true } } }, - "node-gyp-build": { - "version": "4.6.1", - "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.1.tgz", - "integrity": "sha512-24vnklJmyRS8ViBNI8KbtK/r/DmXQMRiOMXTNz2nrTnAYUwjmEEbnnpB/+kt+yWRv73bPsSPRFddrcIbAxSiMQ==", - "dev": true, - "optional": true - }, - "node-machine-id": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz", - "integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==", - "dev": true - }, - "node-releases": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.13.tgz", - "integrity": "sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==", - "dev": true - }, - "nopt": { - "version": "3.0.6", - "dev": true, - "requires": { - "abbrev": "1" - } - }, - "normalize-package-data": { - "version": "2.5.0", - "dev": true, - "requires": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - }, - "dependencies": { - "semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true - } - } - }, - "normalize-path": { - "version": "3.0.0", - "devOptional": true - }, - "normalize-range": { - "version": "0.1.2", - "dev": true - }, "npm-bundled": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", @@ -37935,8 +42551,7 @@ "version": "1.0.1" }, "nvd3": { - "version": "1.8.6", - "requires": {} + "version": "1.8.6" }, "nx": { "version": "17.0.3", @@ -38625,7 +43240,7 @@ }, "picomatch": { "version": "2.3.1", - "devOptional": true + "dev": true }, "pidtree": { "version": "0.3.1", @@ -38874,8 +43489,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", - "dev": true, - "requires": {} + "dev": true }, "postcss-modules-local-by-default": { "version": "4.0.3", @@ -39620,7 +44234,7 @@ }, "readdirp": { "version": "3.6.0", - "devOptional": true, + "dev": true, "requires": { "picomatch": "^2.2.1" } @@ -39921,8 +44535,7 @@ "dev": true }, "rfdc": { - "version": "1.3.0", - "dev": true + "version": "1.3.0" }, "right-align": { "version": "0.1.3", @@ -41233,8 +45846,7 @@ }, "ajv-keywords": { "version": "3.5.2", - "dev": true, - "requires": {} + "dev": true }, "json-schema-traverse": { "version": "0.4.1", @@ -41440,7 +46052,7 @@ }, "to-regex-range": { "version": "5.0.1", - "devOptional": true, + "dev": true, "requires": { "is-number": "^7.0.0" } @@ -41478,8 +46090,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz", "integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==", - "dev": true, - "requires": {} + "dev": true }, "ts-interface-checker": { "version": "0.1.13", @@ -42072,8 +46683,7 @@ "version": "3.5.2", "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", - "dev": true, - "requires": {} + "dev": true }, "eslint-scope": { "version": "5.1.1", @@ -42180,8 +46790,7 @@ "version": "8.14.2", "resolved": "https://registry.npmjs.org/ws/-/ws-8.14.2.tgz", "integrity": "sha512-wEBG1ftX4jcglPxgFCMJmZ2PLtSbJ2Peg6TmpJFTbe9GZYOQCDPdMYu/Tm0/bGZkw8paZnJY45J4K2PZrLYq8g==", - "dev": true, - "requires": {} + "dev": true } } }, @@ -42342,8 +46951,7 @@ }, "ws": { "version": "8.11.0", - "dev": true, - "requires": {} + "dev": true }, "xml2js": { "version": "0.4.23", diff --git a/package.json b/package.json index 3a7fa99f4c..614fb17a03 100644 --- a/package.json +++ b/package.json @@ -42,6 +42,7 @@ "@angular/service-worker": "^17.0.3", "@angular/upgrade": "^17.0.3", "@ctrl/ngx-emoji-mart": "^9.2.0", + "@swimlane/ngx-charts": "^20.5.0", "@uirouter/angular": "^12.0", "@uirouter/angular-hybrid": "^16.0", "@uirouter/angularjs": "^1.0.30", @@ -83,6 +84,7 @@ "ngx-bootstrap": "^6.1.0", "ngx-entity-service": "^0.0.37", "ngx-lottie": "^10.0.0", + "npm": "^10.4.0", "nvd3": "1.8.6", "rxjs": "~7.4.0", "showdown": "1.3.0", diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 18cf37a91b..37ae44744b 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -7,6 +7,7 @@ import { UpgradeModule } from '@angular/upgrade/static'; import { AppInjector, setAppInjector } from './app-injector'; import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; +import { NgxChartsModule } from '@swimlane/ngx-charts'; // Lottie animation module import { LottieModule, LottieCacheModule } from 'ngx-lottie'; @@ -229,6 +230,8 @@ import { FUnitTaskListComponent } from './units/states/tasks/viewer/directives/f import { FTaskDetailsViewComponent } from './units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component'; import { FTaskSheetViewComponent } from './units/states/tasks/viewer/directives/f-task-sheet-view/f-task-sheet-view.component'; import { TasksViewerComponent } from './units/states/tasks/tasks-viewer/tasks-viewer.component'; +import { ProgressBurndownChartComponent } from './visualisations/progress-burndown-chart/progressburndownchart.component'; +import { TaskVisualisationComponent } from './visualisations/task-visualisation/taskvisualisation.component'; @NgModule({ // Components we declare @@ -327,6 +330,9 @@ import { TasksViewerComponent } from './units/states/tasks/tasks-viewer/tasks-vi TasksViewerComponent, FUsersComponent, FUnitsComponent, + ProgressBurndownChartComponent, + TaskVisualisationComponent + ], // Module Imports imports: [ @@ -390,6 +396,7 @@ import { TasksViewerComponent } from './units/states/tasks/tasks-viewer/tasks-vi MatDatepickerModule, MatNativeDateModule, MatDialogModuleNew, + NgxChartsModule ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index e84dd192a2..c827862990 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -239,6 +239,8 @@ import { FUnitTaskListComponent } from './units/states/tasks/viewer/directives/f import { FTaskDetailsViewComponent } from './units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component'; import { FTaskSheetViewComponent } from './units/states/tasks/viewer/directives/f-task-sheet-view/f-task-sheet-view.component'; import { TasksViewerComponent } from './units/states/tasks/tasks-viewer/tasks-viewer.component'; +import { ProgressBurndownChartComponent } from './visualisations/progress-burndown-chart/progressburndownchart.component'; +import { TaskVisualisationComponent } from './visualisations/task-visualisation/taskvisualisation.component'; import { FUnitsComponent } from './admin/states/f-units/f-units.component'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ @@ -398,3 +400,14 @@ const otherwiseConfigBlock = [ }, ]; DoubtfireAngularJSModule.config(otherwiseConfigBlock); + + +DoubtfireAngularJSModule.directive( + 'appProgressBurndownChart', + downgradeComponent({ component: ProgressBurndownChartComponent }) +); + +DoubtfireAngularJSModule.directive( + 'appTaskVisualisation', + downgradeComponent({ component: TaskVisualisationComponent }) +); diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.tpl.html b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.tpl.html index 763c0e37ce..d2becf0880 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.tpl.html +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.tpl.html @@ -26,7 +26,7 @@

Progress Burndown

- +
- - + +
- - +
From 64b1bfb2918993e58a6659948d9621fc7d0b8ba4 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sat, 13 Apr 2024 21:56:47 +1000 Subject: [PATCH 0062/1280] fix: use modal for Numbas and enable authentication --- src/app/ajs-upgraded-providers.ts | 7 ++ src/app/api/services/numbas.service.ts | 55 -------------- .../api/services/spec/numbas.service.spec.ts | 66 ---------------- .../numbas-component.component.html | 7 +- .../numbas-component.component.scss | 17 +++++ .../numbas-component.component.ts | 76 ++++++------------- .../numbas-modal.component.ts | 20 +++++ src/app/doubtfire-angular.module.ts | 4 +- src/app/doubtfire-angularjs.module.ts | 2 + .../upload-submission-modal.coffee | 5 +- .../upload-submission-modal.tpl.html | 6 +- 11 files changed, 83 insertions(+), 182 deletions(-) delete mode 100644 src/app/api/services/numbas.service.ts delete mode 100644 src/app/api/services/spec/numbas.service.spec.ts create mode 100644 src/app/common/numbas-component/numbas-modal.component.ts diff --git a/src/app/ajs-upgraded-providers.ts b/src/app/ajs-upgraded-providers.ts index 795869225d..9d5b0f0203 100644 --- a/src/app/ajs-upgraded-providers.ts +++ b/src/app/ajs-upgraded-providers.ts @@ -18,6 +18,7 @@ export const rootScope = new InjectionToken('$rootScope'); export const calendarModal = new InjectionToken('CalendarModal'); export const aboutDoubtfireModal = new InjectionToken('AboutDoubtfireModal'); export const plagiarismReportModal = new InjectionToken('PlagiarismReportModal'); +export const numbasModal = new InjectionToken('NumbasModal'); // Define a provider for the above injection token... // It will get the service from AngularJS via the factory @@ -116,3 +117,9 @@ export const UnitStudentEnrolmentModalProvider = { useFactory: (i) => i.get('UnitStudentEnrolmentModal'), deps: ['$injector'], }; + +export const numbasModalProvider = { + provide: numbasModal, + useFactory: (i) => i.get('NumbasModal'), + deps: ['$injector'], +}; \ No newline at end of file diff --git a/src/app/api/services/numbas.service.ts b/src/app/api/services/numbas.service.ts deleted file mode 100644 index f8812f1ac7..0000000000 --- a/src/app/api/services/numbas.service.ts +++ /dev/null @@ -1,55 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient, HttpErrorResponse } from '@angular/common/http'; -import { Observable, throwError } from 'rxjs'; -import { catchError, map, retry } from 'rxjs/operators'; -import API_URL from 'src/app/config/constants/apiURL'; - -@Injectable({ - providedIn: 'root' -}) -export class NumbasService { - constructor(private http: HttpClient) {} - - /** - * Fetches a specified resource for a given unit and task. - * - * @param taskDefId - The ID of the task definition - * @param resourcePath - Path to the desired resource - * @returns An Observable with the Blob of the fetched resource - */ - fetchResource(taskDefId: number, resourcePath: string): Observable { - const resourceUrl = `${API_URL}/numbas_api/${taskDefId}/${resourcePath}`; - const resourceMimeType = this.getMimeType(resourcePath); - - return this.http.get(resourceUrl, { responseType: 'blob' }).pipe( - retry(3), - map((blob) => new Blob([blob], { type: resourceMimeType })), - catchError((error: HttpErrorResponse) => { - console.error('Error fetching Numbas resource:', error); - return throwError('Error fetching Numbas resource.'); - }) - ); - } - - /** - * Determines the MIME type of a resource based on its extension. - * - * @param resourcePath - Path of the resource - * @returns MIME type string corresponding to the resource's extension - */ - getMimeType(resourcePath: string): string { - const extension = resourcePath.split('.').pop()?.toLowerCase(); - const mimeTypeMap: { [key: string]: string } = { - 'html': 'text/html', - 'css': 'text/css', - 'js': 'application/javascript', - 'json': 'application/json', - 'png': 'image/png', - 'jpg': 'image/jpeg', - 'gif': 'image/gif', - 'svg': 'image/svg+xml' - }; - - return mimeTypeMap[extension || ''] || 'text/plain'; - } -} diff --git a/src/app/api/services/spec/numbas.service.spec.ts b/src/app/api/services/spec/numbas.service.spec.ts deleted file mode 100644 index a29b13e149..0000000000 --- a/src/app/api/services/spec/numbas.service.spec.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { TestBed, fakeAsync, tick } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { NumbasService } from '../numbas.service'; -import { HttpRequest } from '@angular/common/http'; - - -describe('NumbasService', () => { - let numbasService: NumbasService; - let httpMock: HttpTestingController; - - beforeEach(() => { - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [NumbasService], - }); - - numbasService = TestBed.inject(NumbasService); - httpMock = TestBed.inject(HttpTestingController); - }); - - afterEach(() => { - httpMock.verify(); - }); - - it('should fetch resource as expected', fakeAsync(() => { - const dummyBlob = new Blob(['dummy blob'], { type: 'text/html' }); - - const unitId = 'sampleUnitId'; - const taskId = 'sampleTaskId'; - const resourcePath = 'sampleResource.html'; - - numbasService.fetchResource(unitId, taskId, resourcePath).subscribe((blob) => { - expect(blob.size).toBe(dummyBlob.size); - expect(blob.type).toBe(dummyBlob.type); - }); - - const req = httpMock.expectOne(`http://localhost:3000/api/numbas_api/${unitId}/${taskId}/${resourcePath}`); - expect(req.request.method).toBe('GET'); - - req.flush(dummyBlob); - - tick(); - })); - - it('should upload test as expected', fakeAsync(() => { - const dummyResponse = { success: true, message: 'File uploaded successfully' }; - - const unitId = 'sampleUnitId'; - const taskId = 'sampleTaskId'; - const file = new File(['dummy content'], 'sample.txt', { type: 'text/plain' }); - - numbasService.uploadTest(unitId, taskId, file).subscribe((response) => { - expect(response).toEqual(dummyResponse); - }); - - const req = httpMock.expectOne(`http://localhost:3000/api/numbas_api/uploadNumbasTest`); - expect(req.request.method).toBe('POST'); - - req.flush(dummyResponse); - - tick(); - })); - -}); - - diff --git a/src/app/common/numbas-component/numbas-component.component.html b/src/app/common/numbas-component/numbas-component.component.html index dba53ea116..d562f02239 100644 --- a/src/app/common/numbas-component/numbas-component.component.html +++ b/src/app/common/numbas-component/numbas-component.component.html @@ -1,3 +1,4 @@ - +
+ + +
\ No newline at end of file diff --git a/src/app/common/numbas-component/numbas-component.component.scss b/src/app/common/numbas-component/numbas-component.component.scss index e69de29bb2..5e24cc5d9e 100644 --- a/src/app/common/numbas-component/numbas-component.component.scss +++ b/src/app/common/numbas-component/numbas-component.component.scss @@ -0,0 +1,17 @@ +.mat-dialog-content { + position: relative; +} + +iframe { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 95%; +} + +button { + position: absolute; + bottom: 20px; + right: 20px; +} \ No newline at end of file diff --git a/src/app/common/numbas-component/numbas-component.component.ts b/src/app/common/numbas-component/numbas-component.component.ts index 529a64b9ae..6c8369ab77 100644 --- a/src/app/common/numbas-component/numbas-component.component.ts +++ b/src/app/common/numbas-component/numbas-component.component.ts @@ -1,7 +1,11 @@ -import { Component, Input, OnInit, OnChanges, SimpleChanges } from '@angular/core'; +import { Component, OnInit, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import { Task } from 'src/app/api/models/task'; import { NumbasLmsService } from 'src/app/api/services/numbas-lms.service'; -import { NumbasService } from 'src/app/api/services/numbas.service'; +import { UserService } from 'src/app/api/services/user.service'; +import { AppInjector } from 'src/app/app-injector'; +import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; declare global { interface Window { API_1484_11: any; } @@ -10,20 +14,29 @@ declare global { @Component({ selector: 'f-numbas-component', templateUrl: './numbas-component.component.html', - styleUrls: ['numbas-component.component.scss'], + styleUrls: ['./numbas-component.component.scss'], }) -export class NumbasComponent implements OnInit, OnChanges { - @Input() task: Task; - +export class NumbasComponent implements OnInit { + task: Task; currentMode: 'attempt' | 'review' = 'attempt'; + iframeSrc: SafeResourceUrl; constructor( - private numbasService: NumbasService, + private dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: { task: Task, mode: 'attempt' | 'review' }, private lmsService: NumbasLmsService, + private userService: UserService, + private sanitizer: DomSanitizer ) {} ngOnInit(): void { - this.interceptIframeRequests(); + this.task = this.data.task; + this.lmsService.setTask(this.task); + + this.currentMode = this.data.mode; + + const user = this.userService.currentUser; + this.iframeSrc = this.sanitizer.bypassSecurityTrustResourceUrl(`${AppInjector.get(DoubtfireConstants).API_URL}/numbas_api/${this.task.taskDefId}/${user.authenticationToken}/${user.username}/index.html`); window.API_1484_11 = { Initialize: () => this.lmsService.Initialize(this.currentMode), @@ -37,50 +50,7 @@ export class NumbasComponent implements OnInit, OnChanges { }; } - ngOnChanges(changes: SimpleChanges): void { - if (changes.task) { - this.task = changes.task.currentValue; - this.lmsService.setTask(this.task); - } - } - - launchNumbasTest(mode: 'attempt' | 'review' = 'attempt'): void { - this.currentMode = mode; - - const iframe = document.createElement('iframe'); - iframe.src = `http://localhost:3000/api/numbas_api/${this.task.taskDefId}/index.html`; - - iframe.style.position = 'fixed'; - iframe.style.top = '0'; - iframe.style.left = '0'; - iframe.style.width = '100%'; - iframe.style.height = '100%'; - iframe.style.zIndex = '9999'; - - document.body.appendChild(iframe); - } - - interceptIframeRequests(): void { - const originalOpen = XMLHttpRequest.prototype.open; - const numbasService = this.numbasService; - const taskDefId = this.task.taskDefId; - XMLHttpRequest.prototype.open = function (this: XMLHttpRequest, method: string, url: string | URL, async: boolean = true, username?: string | null, password?: string | null) { - if (typeof url === 'string' && url.startsWith('/api/numbas_api/')) { - const resourcePath = url.replace('/api/numbas_api/', ''); - this.abort(); - numbasService.fetchResource(taskDefId, resourcePath).subscribe( - (resourceData) => { - if (this.onload) { - this.onload.call(this, resourceData); - } - }, - (error) => { - console.error('Error fetching Numbas resource:', error); - } - ); - } else { - originalOpen.call(this, method, url, async, username, password); - } - }; + removeNumbasTest(): void { + this.dialogRef.close(); } } diff --git a/src/app/common/numbas-component/numbas-modal.component.ts b/src/app/common/numbas-component/numbas-modal.component.ts new file mode 100644 index 0000000000..73b2122c17 --- /dev/null +++ b/src/app/common/numbas-component/numbas-modal.component.ts @@ -0,0 +1,20 @@ +import { Injectable } from '@angular/core'; +import { MatDialog, MatDialogRef } from '@angular/material/dialog'; +import { NumbasComponent } from './numbas-component.component'; +import { Task } from 'src/app/api/models/task'; + +@Injectable({ + providedIn: 'root', +}) +export class NumbasModal { + constructor(public dialog: MatDialog) { } + + public show(task: Task, mode: 'attempt' | 'review'): void { + let dialogRef: MatDialogRef; + + dialogRef = this.dialog.open(NumbasComponent, { + data: { task, mode }, + width: '95%', height: '90%' + }); + } +} diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index d15c23b234..48f54027d1 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -226,7 +226,7 @@ import {TasksViewerComponent} from './units/states/tasks/tasks-viewer/tasks-view import {UnitCodeComponent} from './common/unit-code/unit-code.component'; import {GradeService} from './common/services/grade.service'; import {NumbasComponent} from './common/numbas-component/numbas-component.component'; -import {NumbasService} from './api/services/numbas.service'; +import {NumbasModal} from './common/numbas-component/numbas-modal.component'; import {NumbasLmsService} from './api/services/numbas-lms.service'; @NgModule({ @@ -402,7 +402,7 @@ import {NumbasLmsService} from './api/services/numbas-lms.service'; TasksForInboxSearchPipe, IsActiveUnitRole, CreateNewUnitModal, - NumbasService, + NumbasModal, NumbasLmsService, provideLottieOptions({ player: () => player, diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 317094dc2e..b88fbeb298 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -226,6 +226,7 @@ import {MarkedPipe} from './common/pipes/marked.pipe'; import {AlertService} from './common/services/alert.service'; import {GradeService} from './common/services/grade.service'; import {NumbasComponent} from './common/numbas-component/numbas-component.component'; +import {NumbasModal} from './common/numbas-component/numbas-modal.component'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -308,6 +309,7 @@ DoubtfireAngularJSModule.factory( downgradeInjectable(EditProfileDialogService), ); DoubtfireAngularJSModule.factory('CreateNewUnitModal', downgradeInjectable(CreateNewUnitModal)); +DoubtfireAngularJSModule.factory('NumbasModal', downgradeInjectable(NumbasModal)); // directive -> component DoubtfireAngularJSModule.directive( diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee index 485843f780..68d742362e 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee @@ -32,7 +32,7 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) UploadSubmissionModal ) -.controller('UploadSubmissionModalCtrl', ($scope, $rootScope, $timeout, $modalInstance, newTaskService, newProjectService, task, reuploadEvidence, outcomeService, PrivacyPolicy) -> +.controller('UploadSubmissionModalCtrl', ($scope, $rootScope, $timeout, $modalInstance, NumbasModal, newTaskService, newProjectService, task, reuploadEvidence, outcomeService, PrivacyPolicy) -> $scope.privacyPolicy = PrivacyPolicy # Expose task to scope $scope.task = task @@ -155,6 +155,9 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) previous: states.previous } + $scope.launchNumbasDialog = -> + NumbasModal.show $scope.task, 'attempt' + # Whether or not we should disable this button $scope.shouldDisableBtn = { next: -> diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html index 0b99e7eb8f..0527aadd40 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html @@ -52,12 +52,14 @@

Attempt Numbas Test

- + Complete the Numbas test first to proceed to upload evidence of your task completion.
- +
From bcaa8af150aaf68b5cf5fb07ad9cb72037212d5d Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Fri, 26 Apr 2024 22:10:46 +1000 Subject: [PATCH 0063/1280] fix: add accepted Numbas file types --- .../task-definition-numbas.component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-numbas/task-definition-numbas.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-numbas/task-definition-numbas.component.ts index 6588453430..f6687a4af9 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-numbas/task-definition-numbas.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-numbas/task-definition-numbas.component.ts @@ -41,7 +41,9 @@ export class TaskDefinitionNumbasComponent { } public uploadNumbasTest(files: FileList) { - const validFiles = Array.from(files as ArrayLike).filter((f) => f.type === 'application/zip'); + console.log(Array.from(files).map(f => f.type)); + const validMimeTypes = ['application/zip', 'application/x-zip-compressed', 'multipart/x-zip']; + const validFiles = Array.from(files as ArrayLike).filter(f => validMimeTypes.includes(f.type)); if (validFiles.length > 0) { const file = validFiles[0]; this.taskDefinitionService.uploadNumbasData(this.taskDefinition, file).subscribe({ From 5d0606c56eaeb929d5873cae7038ce729581512c Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:30:07 +1000 Subject: [PATCH 0064/1280] fix: initialise SCORM API wrapper before iframe loads --- .../numbas-component/numbas-component.component.ts | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/src/app/common/numbas-component/numbas-component.component.ts b/src/app/common/numbas-component/numbas-component.component.ts index 6c8369ab77..488c0a6333 100644 --- a/src/app/common/numbas-component/numbas-component.component.ts +++ b/src/app/common/numbas-component/numbas-component.component.ts @@ -3,7 +3,6 @@ import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import { Task } from 'src/app/api/models/task'; import { NumbasLmsService } from 'src/app/api/services/numbas-lms.service'; -import { UserService } from 'src/app/api/services/user.service'; import { AppInjector } from 'src/app/app-injector'; import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; @@ -25,7 +24,6 @@ export class NumbasComponent implements OnInit { private dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: { task: Task, mode: 'attempt' | 'review' }, private lmsService: NumbasLmsService, - private userService: UserService, private sanitizer: DomSanitizer ) {} @@ -33,11 +31,6 @@ export class NumbasComponent implements OnInit { this.task = this.data.task; this.lmsService.setTask(this.task); - this.currentMode = this.data.mode; - - const user = this.userService.currentUser; - this.iframeSrc = this.sanitizer.bypassSecurityTrustResourceUrl(`${AppInjector.get(DoubtfireConstants).API_URL}/numbas_api/${this.task.taskDefId}/${user.authenticationToken}/${user.username}/index.html`); - window.API_1484_11 = { Initialize: () => this.lmsService.Initialize(this.currentMode), Terminate: () => this.lmsService.Terminate(), @@ -48,6 +41,10 @@ export class NumbasComponent implements OnInit { GetErrorString: (errorCode: string) => this.lmsService.GetErrorString(errorCode), GetDiagnostic: (errorCode: string) => this.lmsService.GetDiagnostic(errorCode) }; + + this.currentMode = this.data.mode; + + this.iframeSrc = this.sanitizer.bypassSecurityTrustResourceUrl(`${AppInjector.get(DoubtfireConstants).API_URL}/numbas_api/${this.task.taskDefId}/index.html`); } removeNumbasTest(): void { From 2810ce65d423a137600d621a98bf27dbc221921c Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 30 Apr 2024 11:32:29 +1000 Subject: [PATCH 0065/1280] fix: retrieve test attempt data correctly --- src/app/api/services/numbas-lms.service.ts | 29 ++++++++-------------- 1 file changed, 11 insertions(+), 18 deletions(-) diff --git a/src/app/api/services/numbas-lms.service.ts b/src/app/api/services/numbas-lms.service.ts index de5a25bcc9..a24c8d31ed 100644 --- a/src/app/api/services/numbas-lms.service.ts +++ b/src/app/api/services/numbas-lms.service.ts @@ -1,7 +1,5 @@ -import { Injectable, Input } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; -import { BehaviorSubject, Observable, throwError } from 'rxjs'; -import { TaskService } from './task.service'; +import { Injectable } from '@angular/core'; +import { BehaviorSubject } from 'rxjs'; import { UserService } from './user.service'; import API_URL from 'src/app/config/constants/apiURL'; import { Task } from '../models/task'; @@ -10,7 +8,6 @@ import { Task } from '../models/task'; providedIn: 'root' }) export class NumbasLmsService { - private readonly apiBaseUrl = `${API_URL}/test_attempts`; private defaultValues: { [key: string]: string } = { @@ -35,11 +32,7 @@ export class NumbasLmsService { dataStore: { [key: string]: any } = this.getDefaultDataStore(); - constructor( - private http: HttpClient, - private taskService: TaskService, - private userService: UserService - ) { + constructor(private userService: UserService) { this.learnerId = this.userService.currentUser.studentId; } @@ -74,7 +67,7 @@ export class NumbasLmsService { try { const completedTest = JSON.parse(xhr.responseText); - const parsedExamData = JSON.parse(completedTest.data.exam_data || '{}'); + const parsedExamData = JSON.parse(completedTest.exam_data || '{}'); // Set entire suspendData string to cmi.suspend_data this.SetValue('cmi.suspend_data', JSON.stringify(parsedExamData)); @@ -108,17 +101,17 @@ export class NumbasLmsService { try { latestTest = JSON.parse(xhr.responseText); console.log('Latest test result:', latestTest); - this.testId = latestTest.data.id; + this.testId = latestTest.id; - if (latestTest.data['cmi_entry'] === 'ab-initio') { + if (latestTest['cmi_entry'] === 'ab-initio') { console.log("starting new test"); this.SetValue('cmi.learner_id', this.learnerId); this.dataStore['name'] = examName; - this.dataStore['attempt_number'] = latestTest.data['attempt_number']; + this.dataStore['attempt_number'] = latestTest['attempt_number']; console.log(this.dataStore); - } else if (latestTest.data['cmi_entry'] === 'resume') { + } else if (latestTest['cmi_entry'] === 'resume') { console.log("resuming test"); - const parsedExamData = JSON.parse(latestTest.data.exam_data || '{}'); + const parsedExamData = JSON.parse(latestTest.exam_data || '{}'); this.dataStore = JSON.parse(JSON.stringify(parsedExamData)); @@ -127,7 +120,7 @@ export class NumbasLmsService { this.initializationComplete$.next(true); - console.log("finished initlizing"); + console.log("finished initializing"); return 'true'; } catch (error) { console.error('Error:', error); @@ -153,7 +146,7 @@ export class NumbasLmsService { this.SetValue('cmi.entry', 'RO'); const cmientry = this.GetValue('cmi.entry'); const data = { - task_id: this.taskId, + id: this.taskId, name: ExamName, attempt_number: currentAttemptNumber, pass_status: status === 'passed', From e46214dd59d86014bb04d1c31f3a3bf21240e32b Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 30 Apr 2024 13:02:50 +1000 Subject: [PATCH 0066/1280] fix: send task id with numbas completed attempt data --- src/app/api/services/numbas-lms.service.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/api/services/numbas-lms.service.ts b/src/app/api/services/numbas-lms.service.ts index a24c8d31ed..40ce0942b3 100644 --- a/src/app/api/services/numbas-lms.service.ts +++ b/src/app/api/services/numbas-lms.service.ts @@ -69,7 +69,7 @@ export class NumbasLmsService { const completedTest = JSON.parse(xhr.responseText); const parsedExamData = JSON.parse(completedTest.exam_data || '{}'); - // Set entire suspendData string to cmi.suspend_data + // Set entire parsedExamData string to cmi.suspend_data this.SetValue('cmi.suspend_data', JSON.stringify(parsedExamData)); // Use SetValue to set parsedExamData values to dataStore @@ -146,14 +146,14 @@ export class NumbasLmsService { this.SetValue('cmi.entry', 'RO'); const cmientry = this.GetValue('cmi.entry'); const data = { - id: this.taskId, name: ExamName, attempt_number: currentAttemptNumber, pass_status: status === 'passed', exam_data: JSON.stringify(this.dataStore), completed: true, exam_result: examResult, - cmi_entry: cmientry + cmi_entry: cmientry, + task_id: this.taskId }; const xhr = new XMLHttpRequest(); From 84646dcf7b28c65c8c28f046197d08d3325795be Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sun, 5 May 2024 16:33:19 +1000 Subject: [PATCH 0067/1280] refactor: modify numbas files to match PoC --- src/app/api/services/numbas-lms.service.ts | 38 +++++++++---------- .../services/spec/numbas-lms.service.spec.ts | 2 +- .../numbas-component.component.ts | 2 + 3 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/app/api/services/numbas-lms.service.ts b/src/app/api/services/numbas-lms.service.ts index 40ce0942b3..6479a6ed93 100644 --- a/src/app/api/services/numbas-lms.service.ts +++ b/src/app/api/services/numbas-lms.service.ts @@ -17,7 +17,7 @@ export class NumbasLmsService { 'numbas.duration_extension.units': 'seconds', 'cmi.mode': 'normal', 'cmi.undefinedlearner_response': '1', - 'cmi.undefinedresult' : '0' + 'cmi.undefinedresult': '0' }; private testId: number = 0; @@ -67,14 +67,14 @@ export class NumbasLmsService { try { const completedTest = JSON.parse(xhr.responseText); - const parsedExamData = JSON.parse(completedTest.exam_data || '{}'); + let parsedSuspendData = JSON.parse(completedTest.data.suspend_data || '{}'); - // Set entire parsedExamData string to cmi.suspend_data - this.SetValue('cmi.suspend_data', JSON.stringify(parsedExamData)); + // Set entire suspendData string to cmi.suspend_data + this.SetValue('cmi.suspend_data', JSON.stringify(parsedSuspendData)); - // Use SetValue to set parsedExamData values to dataStore - Object.keys(parsedExamData).forEach(key => { - this.SetValue(key, parsedExamData[key]); + // Use SetValue to set parsedSuspendData values to dataStore + Object.keys(parsedSuspendData).forEach(key => { + this.SetValue(key, parsedSuspendData[key]); }); this.SetValue('cmi.entry', 'RO'); @@ -101,19 +101,19 @@ export class NumbasLmsService { try { latestTest = JSON.parse(xhr.responseText); console.log('Latest test result:', latestTest); - this.testId = latestTest.id; + this.testId = latestTest.data.id; - if (latestTest['cmi_entry'] === 'ab-initio') { + if (latestTest.data['cmi_entry'] === 'ab-initio') { console.log("starting new test"); this.SetValue('cmi.learner_id', this.learnerId); this.dataStore['name'] = examName; - this.dataStore['attempt_number'] = latestTest['attempt_number']; + this.dataStore['attempt_number'] = latestTest.data['attempt_number']; console.log(this.dataStore); - } else if (latestTest['cmi_entry'] === 'resume') { + } else if (latestTest.data['cmi_entry'] === 'resume') { console.log("resuming test"); - const parsedExamData = JSON.parse(latestTest.exam_data || '{}'); + let parsedSuspendData = JSON.parse(latestTest.data.suspend_data || '{}'); - this.dataStore = JSON.parse(JSON.stringify(parsedExamData)); + this.dataStore = JSON.parse(JSON.stringify(parsedSuspendData)); console.log(this.dataStore); } @@ -149,7 +149,7 @@ export class NumbasLmsService { name: ExamName, attempt_number: currentAttemptNumber, pass_status: status === 'passed', - exam_data: JSON.stringify(this.dataStore), + suspend_data: JSON.stringify(this.dataStore), completed: true, exam_result: examResult, cmi_entry: cmientry, @@ -184,7 +184,7 @@ export class NumbasLmsService { return 'true'; } - //function to save the state of the exam. + // Saves the state of the exam. Commit(): string { if (!this.initializationComplete$.getValue()) { console.warn('Initialization not complete. Cannot commit.'); @@ -198,12 +198,9 @@ export class NumbasLmsService { } console.log("Committing dataStore:", this.dataStore); - // Directly stringify the dataStore - const jsonData = JSON.stringify(this.dataStore); - // Use XHR to send the request const xhr = new XMLHttpRequest(); - xhr.open('PUT', `${this.apiBaseUrl}/${this.testId}/exam_data`, true); + xhr.open('PUT', `${this.apiBaseUrl}/${this.testId}/suspend`, true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onload = () => { @@ -218,7 +215,8 @@ export class NumbasLmsService { console.error('Request failed.'); }; - xhr.send(jsonData); + const requestData = { suspend_data: this.dataStore }; + xhr.send(JSON.stringify(requestData)); return 'true'; } diff --git a/src/app/api/services/spec/numbas-lms.service.spec.ts b/src/app/api/services/spec/numbas-lms.service.spec.ts index f456d5a894..7d29ef75e0 100644 --- a/src/app/api/services/spec/numbas-lms.service.spec.ts +++ b/src/app/api/services/spec/numbas-lms.service.spec.ts @@ -55,7 +55,7 @@ describe('NumbasLmsService', () => { it('should handle review mode and get latest completed test result', () => { const mockResponse = { data: { - exam_data: JSON.stringify({ someData: 'value' }) + suspend_data: JSON.stringify({ someData: 'value' }) } }; diff --git a/src/app/common/numbas-component/numbas-component.component.ts b/src/app/common/numbas-component/numbas-component.component.ts index 488c0a6333..f5453e0dcc 100644 --- a/src/app/common/numbas-component/numbas-component.component.ts +++ b/src/app/common/numbas-component/numbas-component.component.ts @@ -48,6 +48,8 @@ export class NumbasComponent implements OnInit { } removeNumbasTest(): void { + const iframe = document.getElementsByTagName('iframe')[0]; + iframe?.parentNode?.removeChild(iframe); this.dialogRef.close(); } } From 48a31da1442f1e14f497c614053d9002c9f2631b Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 7 May 2024 03:00:27 +1000 Subject: [PATCH 0068/1280] feat: display numbas task comments --- src/app/api/models/task.ts | 6 +++ src/app/doubtfire-angular.module.ts | 2 + .../numbas-comment.component.html | 10 ++++ .../numbas-comment.component.scss | 51 +++++++++++++++++++ .../numbas-comment.component.ts | 21 ++++++++ .../task-comments-viewer.component.html | 8 +++ .../task-comments-viewer.component.scss | 2 +- .../task-comments-viewer.component.ts | 6 ++- 8 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.html create mode 100644 src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.scss create mode 100644 src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index 2aa167adfd..403165cfee 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -507,6 +507,12 @@ export class Task extends Entity { ); } + public get numbasEnabled(): boolean { + return ( + this.definition.hasEnabledNumbasTest && this.definition.hasNumbasData + ); + } + public submissionUrl(asAttachment: boolean = false): string { return `${AppInjector.get(DoubtfireConstants).API_URL}/projects/${ this.project.id diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 48f54027d1..c634965f6f 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -228,6 +228,7 @@ import {GradeService} from './common/services/grade.service'; import {NumbasComponent} from './common/numbas-component/numbas-component.component'; import {NumbasModal} from './common/numbas-component/numbas-modal.component'; import {NumbasLmsService} from './api/services/numbas-lms.service'; +import {NumbasCommentComponent} from './tasks/task-comments-viewer/numbas-comment/numbas-comment.component'; @NgModule({ // Components we declare @@ -331,6 +332,7 @@ import {NumbasLmsService} from './api/services/numbas-lms.service'; FTaskBadgeComponent, FUnitsComponent, NumbasComponent, + NumbasCommentComponent, ], // Services we provide providers: [ diff --git a/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.html b/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.html new file mode 100644 index 0000000000..d87863bee8 --- /dev/null +++ b/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.html @@ -0,0 +1,10 @@ +
+
+
+
+
+ +
+
+
+
diff --git a/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.scss b/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.scss new file mode 100644 index 0000000000..31df73023a --- /dev/null +++ b/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.scss @@ -0,0 +1,51 @@ +div { + width: 100%; +} + +p { + color: #2c2c2c; + text-align: center; +} + +hr { + width: 100%; +} + +.hr-fade { + background: linear-gradient(to right, transparent, #9696969d, transparent); + width: 100%; + margin-top: 1px; +} + +.hr-text { + margin: 0; + line-height: 1em; + position: relative; + outline: 0; + border: 0; + color: black; + text-align: center; + height: 1.5em; + opacity: 0.8; + &:before { + content: ""; + background: linear-gradient(to right, transparent, #9696969d, transparent); + position: absolute; + left: 0; + top: 50%; + width: 100%; + height: 1px; + } + &:after { + content: attr(data-content); + position: relative; + display: inline-block; + color: black; + + padding: 0 0.5em; + line-height: 1.5em; + + color: #9696969d; + background-color: #fff; + } +} diff --git a/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts b/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts new file mode 100644 index 0000000000..eed512fe19 --- /dev/null +++ b/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts @@ -0,0 +1,21 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { Task, TaskComment } from 'src/app/api/models/doubtfire-model'; +import { NumbasModal } from 'src/app/common/numbas-component/numbas-modal.component'; + +@Component({ + selector: 'numbas-comment', + templateUrl: './numbas-comment.component.html', + styleUrls: ['./numbas-comment.component.scss'], +}) +export class NumbasCommentComponent implements OnInit { + @Input() task: Task; + @Input() comment: TaskComment; + + constructor(private modalService: NumbasModal) {} + + ngOnInit() {} + + reviewNumbasTest() { + this.modalService.show(this.task, 'review'); + } +} diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html index d104df63af..cd18eda9ba 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html @@ -72,6 +72,14 @@ > +
+ +
+
{ if ( @@ -150,7 +154,7 @@ export class TaskCommentsViewerComponent implements OnChanges, OnInit { } shouldShowAuthorIcon(commentType: string) { - return !(commentType === 'extension' || commentType === 'status' || commentType == 'assessment'); + return !(commentType === 'extension' || commentType === 'status' || commentType == 'assessment' || commentType == 'numbas'); } commentClasses(comment: TaskComment): object { From 0652b56f69eb850c2dfb43be54d07beb4c4eb469 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 7 May 2024 07:10:54 +1000 Subject: [PATCH 0069/1280] feat: add test attempt service and minor numbas related changes --- src/app/api/models/test-attempt.ts | 14 +++++++++++--- src/app/api/services/numbas-lms.service.ts | 12 ++++++------ src/app/api/services/task-comment.service.ts | 2 +- src/app/doubtfire-angular.module.ts | 2 ++ src/app/doubtfire-angularjs.module.ts | 2 ++ .../upload-submission-modal.coffee | 2 +- 6 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/app/api/models/test-attempt.ts b/src/app/api/models/test-attempt.ts index 77e4af1724..e6f2e5d61d 100644 --- a/src/app/api/models/test-attempt.ts +++ b/src/app/api/models/test-attempt.ts @@ -1,14 +1,22 @@ import { Entity } from "ngx-entity-service"; +import { Task } from "./task"; export class TestAttempt extends Entity { - id: number; + public id: number; name: string; attemptNumber: number; passStatus: boolean; - examData: string; + suspendData: string; completed: boolean; cmiEntry: string; examResult: string; attemptedAt: Date; - associatedTaskId: number; + taskId: number; + + task: Task; + + constructor(task: Task) { + super(); + this.task = task; + } } diff --git a/src/app/api/services/numbas-lms.service.ts b/src/app/api/services/numbas-lms.service.ts index 6479a6ed93..59d94e0526 100644 --- a/src/app/api/services/numbas-lms.service.ts +++ b/src/app/api/services/numbas-lms.service.ts @@ -21,7 +21,7 @@ export class NumbasLmsService { }; private testId: number = 0; - private taskId: number; + private task: Task; private learnerId: string; initializationComplete$ = new BehaviorSubject(false); @@ -37,7 +37,7 @@ export class NumbasLmsService { } setTask(task: Task) { - this.taskId = task.id; + this.task = task; } getDefaultDataStore() { @@ -56,7 +56,7 @@ export class NumbasLmsService { if (mode === 'review') { this.SetValue('cmi.mode', 'review'); - xhr.open("GET", `${this.apiBaseUrl}/completed-latest?task_id=${this.taskId}`, false); + xhr.open("GET", `${this.apiBaseUrl}/completed-latest?task_id=${this.task.id}`, false); xhr.send(); console.log(xhr.responseText); @@ -88,7 +88,7 @@ export class NumbasLmsService { } } - xhr.open("GET", `${this.apiBaseUrl}/latest?task_id=${this.taskId}`, false); + xhr.open("GET", `${this.apiBaseUrl}/latest?task_id=${this.task.id}`, false); xhr.send(); console.log(xhr.responseText); @@ -139,7 +139,7 @@ export class NumbasLmsService { Terminate(): string { console.log('Terminate Called'); const examResult = this.dataStore["cmi.score.raw"]; - const status = this.GetValue("cmi.completion_status"); + const status = this.GetValue("cmi.success_status"); this.dataStore['completed'] = true; const currentAttemptNumber = this.dataStore['attempt_number'] || 0; const ExamName = this.dataStore['name']; @@ -153,7 +153,7 @@ export class NumbasLmsService { completed: true, exam_result: examResult, cmi_entry: cmientry, - task_id: this.taskId + task_id: this.task.id }; const xhr = new XMLHttpRequest(); diff --git a/src/app/api/services/task-comment.service.ts b/src/app/api/services/task-comment.service.ts index 9e646be77d..e3c80797a4 100644 --- a/src/app/api/services/task-comment.service.ts +++ b/src/app/api/services/task-comment.service.ts @@ -145,7 +145,7 @@ export class TaskCommentService extends CachedEntityService { const opts: RequestOptions = { endpointFormat: this.commentEndpointFormat }; // Based on the comment type - add to the body and configure the end point - if (commentType === 'text') { + if (commentType === 'text' || commentType === 'numbas') { body.append('comment', data); } else if (commentType === 'discussion') { opts.endpointFormat = this.discussionEndpointFormat; diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index c634965f6f..e1f4d2356f 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -229,6 +229,7 @@ import {NumbasComponent} from './common/numbas-component/numbas-component.compon import {NumbasModal} from './common/numbas-component/numbas-modal.component'; import {NumbasLmsService} from './api/services/numbas-lms.service'; import {NumbasCommentComponent} from './tasks/task-comments-viewer/numbas-comment/numbas-comment.component'; +import {TestAttemptService} from './api/services/test-attempt.service'; @NgModule({ // Components we declare @@ -406,6 +407,7 @@ import {NumbasCommentComponent} from './tasks/task-comments-viewer/numbas-commen CreateNewUnitModal, NumbasModal, NumbasLmsService, + TestAttemptService, provideLottieOptions({ player: () => player, }), diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index b88fbeb298..fa817ced4e 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -227,6 +227,7 @@ import {AlertService} from './common/services/alert.service'; import {GradeService} from './common/services/grade.service'; import {NumbasComponent} from './common/numbas-component/numbas-component.component'; import {NumbasModal} from './common/numbas-component/numbas-modal.component'; +import {TestAttemptService} from './api/services/test-attempt.service'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -310,6 +311,7 @@ DoubtfireAngularJSModule.factory( ); DoubtfireAngularJSModule.factory('CreateNewUnitModal', downgradeInjectable(CreateNewUnitModal)); DoubtfireAngularJSModule.factory('NumbasModal', downgradeInjectable(NumbasModal)); +DoubtfireAngularJSModule.factory('testAttemptService', downgradeInjectable(TestAttemptService)); // directive -> component DoubtfireAngularJSModule.directive( diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee index 68d742362e..f9552b3567 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee @@ -128,7 +128,7 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) removed.push('group') if !isRFF || !task.isGroupTask() removed.push('alignment') if !isRFF || !task.unit.ilos.length > 0 removed.push('comments') if isTestSubmission - removed.push('numbas') if !task.definition.hasEnabledNumbasTest + removed.push('numbas') if !isRFF || !task.definition.hasEnabledNumbasTest removed # Initialises the states initialise: -> From a576f484bc434728eab9632c022bccf1ed26cb01 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 7 May 2024 07:11:52 +1000 Subject: [PATCH 0070/1280] feat: add test attempt service --- src/app/api/services/test-attempt.service.ts | 40 ++++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 src/app/api/services/test-attempt.service.ts diff --git a/src/app/api/services/test-attempt.service.ts b/src/app/api/services/test-attempt.service.ts new file mode 100644 index 0000000000..094f2baa0c --- /dev/null +++ b/src/app/api/services/test-attempt.service.ts @@ -0,0 +1,40 @@ +import { Injectable } from "@angular/core"; +import { EntityService } from "ngx-entity-service"; +import { TestAttempt } from "../models/test-attempt"; +import { HttpClient } from "@angular/common/http"; +import API_URL from "src/app/config/constants/apiURL"; +import { Task } from "../models/task"; +import { Observable } from "rxjs"; +import { AppInjector } from "src/app/app-injector"; +import { DoubtfireConstants } from "src/app/config/constants/doubtfire-constants"; + +@Injectable() +export class TestAttemptService extends EntityService { + protected readonly endpointFormat = '/test_attempts?id=:id:'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'name', + 'attemptNumber', + 'passStatus', + 'suspendData', + 'completed', + 'cmiEntry', + 'examResult', + 'attemptedAt', + 'taskId' + ); + } + + public createInstanceFrom(json: object, other?: any): TestAttempt { + return new TestAttempt(other as Task); + } + + public getLatestCompletedTestAttempt(task: Task): Observable { + const url = `${AppInjector.get(DoubtfireConstants).API_URL}/test_attempts/completed-latest?task_id=${task.id}`; + return AppInjector.get(HttpClient).get(url); + } +} \ No newline at end of file From 2b1dcfc717eb770dd623c62ac99d8d961d1c3124 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Tue, 7 May 2024 16:29:44 +1000 Subject: [PATCH 0071/1280] fix: ensure counters are incremented after object creation --- src/app/api/services/numbas-lms.service.ts | 25 ++++++++++++++++------ 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/src/app/api/services/numbas-lms.service.ts b/src/app/api/services/numbas-lms.service.ts index 59d94e0526..5593fba3f0 100644 --- a/src/app/api/services/numbas-lms.service.ts +++ b/src/app/api/services/numbas-lms.service.ts @@ -13,16 +13,16 @@ export class NumbasLmsService { private defaultValues: { [key: string]: string } = { 'cmi.completion_status': 'not attempted', 'cmi.entry': 'ab-initio', + 'cmi.objectives._count': '0', + 'cmi.interactions._count': '0', 'numbas.user_role': 'learner', - 'numbas.duration_extension.units': 'seconds', 'cmi.mode': 'normal', - 'cmi.undefinedlearner_response': '1', - 'cmi.undefinedresult': '0' }; private testId: number = 0; private task: Task; - private learnerId: string; + private readonly learnerId: string; + private readonly learnerName: string; initializationComplete$ = new BehaviorSubject(false); private scormErrors: { [key: string]: string } = { @@ -33,7 +33,9 @@ export class NumbasLmsService { dataStore: { [key: string]: any } = this.getDefaultDataStore(); constructor(private userService: UserService) { - this.learnerId = this.userService.currentUser.studentId; + const user = this.userService.currentUser; + this.learnerId = user.studentId; + this.learnerName = user.firstName + user.lastName; } setTask(task: Task) { @@ -106,6 +108,7 @@ export class NumbasLmsService { if (latestTest.data['cmi_entry'] === 'ab-initio') { console.log("starting new test"); this.SetValue('cmi.learner_id', this.learnerId); + this.SetValue('cmi.learner_name', this.learnerName); this.dataStore['name'] = examName; this.dataStore['attempt_number'] = latestTest.data['attempt_number']; console.log(this.dataStore); @@ -178,9 +181,17 @@ export class NumbasLmsService { } SetValue(element: string, value: any): string { - if (element.startsWith('cmi.')) { - this.dataStore[element] = value; + console.log(`SetValue:`, element, value); + this.dataStore[element] = value; + if (element.match('cmi.interactions.\\d+.id')) { + console.log('Incrementing cmi.interactions._count'); + this.dataStore['cmi.interactions._count']++; } + if (element.match('cmi.objectives.\\d+.id')) { + console.log('Incrementing cmi.objectives._count'); + this.dataStore['cmi.objectives._count']++; + } + // console.log("dataStore after value set:", this.dataStore); return 'true'; } From aa20a273f6a4e8e0f597da164adb330deaff470c Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Tue, 7 May 2024 23:20:13 +1000 Subject: [PATCH 0072/1280] refactor: rename scorm service --- .../{numbas-lms.service.ts => scorm-lms.service.ts} | 2 +- src/app/api/services/spec/numbas-lms.service.spec.ts | 8 ++++---- .../common/numbas-component/numbas-component.component.ts | 4 ++-- src/app/doubtfire-angular.module.ts | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) rename src/app/api/services/{numbas-lms.service.ts => scorm-lms.service.ts} (99%) diff --git a/src/app/api/services/numbas-lms.service.ts b/src/app/api/services/scorm-lms.service.ts similarity index 99% rename from src/app/api/services/numbas-lms.service.ts rename to src/app/api/services/scorm-lms.service.ts index 5593fba3f0..bd7b5f1085 100644 --- a/src/app/api/services/numbas-lms.service.ts +++ b/src/app/api/services/scorm-lms.service.ts @@ -7,7 +7,7 @@ import { Task } from '../models/task'; @Injectable({ providedIn: 'root' }) -export class NumbasLmsService { +export class ScormLmsService { private readonly apiBaseUrl = `${API_URL}/test_attempts`; private defaultValues: { [key: string]: string } = { diff --git a/src/app/api/services/spec/numbas-lms.service.spec.ts b/src/app/api/services/spec/numbas-lms.service.spec.ts index 7d29ef75e0..f38d5fc080 100644 --- a/src/app/api/services/spec/numbas-lms.service.spec.ts +++ b/src/app/api/services/spec/numbas-lms.service.spec.ts @@ -1,12 +1,12 @@ import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { NumbasLmsService } from '../numbas-lms.service'; +import { ScormLmsService } from '../scorm-lms.service'; import { TaskService } from '../task.service'; import { UserService } from '../user.service'; import { of } from 'rxjs'; describe('NumbasLmsService', () => { - let service: NumbasLmsService; + let service: ScormLmsService; let httpTestingController: HttpTestingController; let mockUserService: Partial; let mockTaskService: Partial; @@ -27,13 +27,13 @@ describe('NumbasLmsService', () => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [ - NumbasLmsService, + ScormLmsService, { provide: UserService, useValue: mockUserService }, { provide: TaskService, useValue: mockTaskService } ] }); - service = TestBed.inject(NumbasLmsService); + service = TestBed.inject(ScormLmsService); httpTestingController = TestBed.inject(HttpTestingController); }); diff --git a/src/app/common/numbas-component/numbas-component.component.ts b/src/app/common/numbas-component/numbas-component.component.ts index f5453e0dcc..2f977ef60c 100644 --- a/src/app/common/numbas-component/numbas-component.component.ts +++ b/src/app/common/numbas-component/numbas-component.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import { Task } from 'src/app/api/models/task'; -import { NumbasLmsService } from 'src/app/api/services/numbas-lms.service'; +import { ScormLmsService } from 'src/app/api/services/scorm-lms.service'; import { AppInjector } from 'src/app/app-injector'; import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; @@ -23,7 +23,7 @@ export class NumbasComponent implements OnInit { constructor( private dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: { task: Task, mode: 'attempt' | 'review' }, - private lmsService: NumbasLmsService, + private lmsService: ScormLmsService, private sanitizer: DomSanitizer ) {} diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index e1f4d2356f..e5b2e1b2a7 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -227,7 +227,7 @@ import {UnitCodeComponent} from './common/unit-code/unit-code.component'; import {GradeService} from './common/services/grade.service'; import {NumbasComponent} from './common/numbas-component/numbas-component.component'; import {NumbasModal} from './common/numbas-component/numbas-modal.component'; -import {NumbasLmsService} from './api/services/numbas-lms.service'; +import {ScormLmsService} from './api/services/scorm-lms.service'; import {NumbasCommentComponent} from './tasks/task-comments-viewer/numbas-comment/numbas-comment.component'; import {TestAttemptService} from './api/services/test-attempt.service'; @@ -406,7 +406,7 @@ import {TestAttemptService} from './api/services/test-attempt.service'; IsActiveUnitRole, CreateNewUnitModal, NumbasModal, - NumbasLmsService, + ScormLmsService, TestAttemptService, provideLottieOptions({ player: () => player, From fdd5667d1744f5ad135bba946a8d2daee6648605 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Wed, 8 May 2024 22:08:12 +1000 Subject: [PATCH 0073/1280] refactor: generalize scorm player components and services --- src/app/ajs-upgraded-providers.ts | 10 +++--- ...ms.service.ts => scorm-adapter.service.ts} | 8 ++--- ....spec.ts => scorm-adapter.service.spec.ts} | 11 +++--- .../scorm-player-modal.component.ts} | 10 +++--- .../scorm-player.component.html} | 4 +-- .../scorm-player.component.scss} | 0 .../scorm-player.component.spec.ts} | 12 +++---- .../scorm-player.component.ts} | 36 ++++++++++--------- src/app/doubtfire-angular.module.ts | 12 +++---- src/app/doubtfire-angularjs.module.ts | 11 +++--- .../upload-submission-modal.coffee | 11 +++--- .../upload-submission-modal.tpl.html | 8 ++--- .../numbas-comment.component.ts | 4 +-- 13 files changed, 71 insertions(+), 66 deletions(-) rename src/app/api/services/{scorm-lms.service.ts => scorm-adapter.service.ts} (97%) rename src/app/api/services/spec/{numbas-lms.service.spec.ts => scorm-adapter.service.spec.ts} (91%) rename src/app/common/{numbas-component/numbas-modal.component.ts => scorm-player/scorm-player-modal.component.ts} (64%) rename src/app/common/{numbas-component/numbas-component.component.html => scorm-player/scorm-player.component.html} (74%) rename src/app/common/{numbas-component/numbas-component.component.scss => scorm-player/scorm-player.component.scss} (100%) rename src/app/common/{numbas-component/numbas-component.component.spec.ts => scorm-player/scorm-player.component.spec.ts} (51%) rename src/app/common/{numbas-component/numbas-component.component.ts => scorm-player/scorm-player.component.ts} (50%) diff --git a/src/app/ajs-upgraded-providers.ts b/src/app/ajs-upgraded-providers.ts index 9d5b0f0203..f114da1c79 100644 --- a/src/app/ajs-upgraded-providers.ts +++ b/src/app/ajs-upgraded-providers.ts @@ -18,7 +18,7 @@ export const rootScope = new InjectionToken('$rootScope'); export const calendarModal = new InjectionToken('CalendarModal'); export const aboutDoubtfireModal = new InjectionToken('AboutDoubtfireModal'); export const plagiarismReportModal = new InjectionToken('PlagiarismReportModal'); -export const numbasModal = new InjectionToken('NumbasModal'); +export const scormPlayerModal = new InjectionToken('ScormPlayerModal'); // Define a provider for the above injection token... // It will get the service from AngularJS via the factory @@ -118,8 +118,8 @@ export const UnitStudentEnrolmentModalProvider = { deps: ['$injector'], }; -export const numbasModalProvider = { - provide: numbasModal, - useFactory: (i) => i.get('NumbasModal'), +export const ScormPlayerModalProvider = { + provide: scormPlayerModal, + useFactory: (i) => i.get('ScormPlayerModal'), deps: ['$injector'], -}; \ No newline at end of file +}; diff --git a/src/app/api/services/scorm-lms.service.ts b/src/app/api/services/scorm-adapter.service.ts similarity index 97% rename from src/app/api/services/scorm-lms.service.ts rename to src/app/api/services/scorm-adapter.service.ts index bd7b5f1085..3202331804 100644 --- a/src/app/api/services/scorm-lms.service.ts +++ b/src/app/api/services/scorm-adapter.service.ts @@ -7,7 +7,7 @@ import { Task } from '../models/task'; @Injectable({ providedIn: 'root' }) -export class ScormLmsService { +export class ScormAdapterService { private readonly apiBaseUrl = `${API_URL}/test_attempts`; private defaultValues: { [key: string]: string } = { @@ -207,7 +207,7 @@ export class ScormLmsService { if (!this.isTestCompleted()) { this.dataStore['cmi.exit'] = 'suspend'; } - console.log("Committing dataStore:", this.dataStore); + console.log("Committing DataModel:", this.dataStore); // Use XHR to send the request const xhr = new XMLHttpRequest(); @@ -216,9 +216,9 @@ export class ScormLmsService { xhr.onload = () => { if (xhr.status >= 200 && xhr.status < 400) { - console.log('Suspend data saved successfully.'); + console.log('DataModel saved successfully.'); } else { - console.error('Error saving suspend data:', xhr.responseText); + console.error('Error saving DataModel:', xhr.responseText); } }; diff --git a/src/app/api/services/spec/numbas-lms.service.spec.ts b/src/app/api/services/spec/scorm-adapter.service.spec.ts similarity index 91% rename from src/app/api/services/spec/numbas-lms.service.spec.ts rename to src/app/api/services/spec/scorm-adapter.service.spec.ts index f38d5fc080..5d3a52caac 100644 --- a/src/app/api/services/spec/numbas-lms.service.spec.ts +++ b/src/app/api/services/spec/scorm-adapter.service.spec.ts @@ -1,12 +1,11 @@ import { TestBed } from '@angular/core/testing'; import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { ScormLmsService } from '../scorm-lms.service'; +import { ScormAdapterService } from '../scorm-adapter.service'; import { TaskService } from '../task.service'; import { UserService } from '../user.service'; -import { of } from 'rxjs'; -describe('NumbasLmsService', () => { - let service: ScormLmsService; +describe('ScormAdapterService', () => { + let service: ScormAdapterService; let httpTestingController: HttpTestingController; let mockUserService: Partial; let mockTaskService: Partial; @@ -27,13 +26,13 @@ describe('NumbasLmsService', () => { TestBed.configureTestingModule({ imports: [HttpClientTestingModule], providers: [ - ScormLmsService, + ScormAdapterService, { provide: UserService, useValue: mockUserService }, { provide: TaskService, useValue: mockTaskService } ] }); - service = TestBed.inject(ScormLmsService); + service = TestBed.inject(ScormAdapterService); httpTestingController = TestBed.inject(HttpTestingController); }); diff --git a/src/app/common/numbas-component/numbas-modal.component.ts b/src/app/common/scorm-player/scorm-player-modal.component.ts similarity index 64% rename from src/app/common/numbas-component/numbas-modal.component.ts rename to src/app/common/scorm-player/scorm-player-modal.component.ts index 73b2122c17..443add9bed 100644 --- a/src/app/common/numbas-component/numbas-modal.component.ts +++ b/src/app/common/scorm-player/scorm-player-modal.component.ts @@ -1,18 +1,18 @@ import { Injectable } from '@angular/core'; import { MatDialog, MatDialogRef } from '@angular/material/dialog'; -import { NumbasComponent } from './numbas-component.component'; +import { ScormPlayerComponent } from './scorm-player.component'; import { Task } from 'src/app/api/models/task'; @Injectable({ providedIn: 'root', }) -export class NumbasModal { +export class ScormPlayerModal { constructor(public dialog: MatDialog) { } - + public show(task: Task, mode: 'attempt' | 'review'): void { - let dialogRef: MatDialogRef; + let dialogRef: MatDialogRef; - dialogRef = this.dialog.open(NumbasComponent, { + dialogRef = this.dialog.open(ScormPlayerComponent, { data: { task, mode }, width: '95%', height: '90%' }); diff --git a/src/app/common/numbas-component/numbas-component.component.html b/src/app/common/scorm-player/scorm-player.component.html similarity index 74% rename from src/app/common/numbas-component/numbas-component.component.html rename to src/app/common/scorm-player/scorm-player.component.html index d562f02239..5089ad9de3 100644 --- a/src/app/common/numbas-component/numbas-component.component.html +++ b/src/app/common/scorm-player/scorm-player.component.html @@ -1,4 +1,4 @@
- -
\ No newline at end of file + +
diff --git a/src/app/common/numbas-component/numbas-component.component.scss b/src/app/common/scorm-player/scorm-player.component.scss similarity index 100% rename from src/app/common/numbas-component/numbas-component.component.scss rename to src/app/common/scorm-player/scorm-player.component.scss diff --git a/src/app/common/numbas-component/numbas-component.component.spec.ts b/src/app/common/scorm-player/scorm-player.component.spec.ts similarity index 51% rename from src/app/common/numbas-component/numbas-component.component.spec.ts rename to src/app/common/scorm-player/scorm-player.component.spec.ts index 31dad5e305..7980df7c3c 100644 --- a/src/app/common/numbas-component/numbas-component.component.spec.ts +++ b/src/app/common/scorm-player/scorm-player.component.spec.ts @@ -1,18 +1,18 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { NumbasComponent } from './numbas-component.component'; +import { ScormPlayerComponent } from './scorm-player.component'; -describe('NumbasComponent', () => { - let component: NumbasComponent; - let fixture: ComponentFixture; +describe('ScormPlayerComponent', () => { + let component: ScormPlayerComponent; + let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ NumbasComponent ] + declarations: [ ScormPlayerComponent ] }) .compileComponents(); - fixture = TestBed.createComponent(NumbasComponent); + fixture = TestBed.createComponent(ScormPlayerComponent); component = fixture.componentInstance; fixture.detectChanges(); }); diff --git a/src/app/common/numbas-component/numbas-component.component.ts b/src/app/common/scorm-player/scorm-player.component.ts similarity index 50% rename from src/app/common/numbas-component/numbas-component.component.ts rename to src/app/common/scorm-player/scorm-player.component.ts index 2f977ef60c..7ed98b3cfe 100644 --- a/src/app/common/numbas-component/numbas-component.component.ts +++ b/src/app/common/scorm-player/scorm-player.component.ts @@ -2,7 +2,7 @@ import { Component, OnInit, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; import { Task } from 'src/app/api/models/task'; -import { ScormLmsService } from 'src/app/api/services/scorm-lms.service'; +import { ScormAdapterService } from 'src/app/api/services/scorm-adapter.service'; import { AppInjector } from 'src/app/app-injector'; import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; @@ -11,35 +11,35 @@ declare global { } @Component({ - selector: 'f-numbas-component', - templateUrl: './numbas-component.component.html', - styleUrls: ['./numbas-component.component.scss'], + selector: 'f-scorm-player', + templateUrl: './scorm-player.component.html', + styleUrls: ['./scorm-player.component.scss'], }) -export class NumbasComponent implements OnInit { +export class ScormPlayerComponent implements OnInit { task: Task; currentMode: 'attempt' | 'review' = 'attempt'; iframeSrc: SafeResourceUrl; constructor( - private dialogRef: MatDialogRef, + private dialogRef: MatDialogRef, @Inject(MAT_DIALOG_DATA) public data: { task: Task, mode: 'attempt' | 'review' }, - private lmsService: ScormLmsService, + private scormAdapter: ScormAdapterService, private sanitizer: DomSanitizer ) {} ngOnInit(): void { this.task = this.data.task; - this.lmsService.setTask(this.task); + this.scormAdapter.setTask(this.task); window.API_1484_11 = { - Initialize: () => this.lmsService.Initialize(this.currentMode), - Terminate: () => this.lmsService.Terminate(), - GetValue: (element: string) => this.lmsService.GetValue(element), - SetValue: (element: string, value: string) => this.lmsService.SetValue(element, value), - Commit: () => this.lmsService.Commit(), - GetLastError: () => this.lmsService.GetLastError(), - GetErrorString: (errorCode: string) => this.lmsService.GetErrorString(errorCode), - GetDiagnostic: (errorCode: string) => this.lmsService.GetDiagnostic(errorCode) + Initialize: () => this.scormAdapter.Initialize(this.currentMode), + Terminate: () => this.scormAdapter.Terminate(), + GetValue: (element: string) => this.scormAdapter.GetValue(element), + SetValue: (element: string, value: string) => this.scormAdapter.SetValue(element, value), + Commit: () => this.scormAdapter.Commit(), + GetLastError: () => this.scormAdapter.GetLastError(), + GetErrorString: (errorCode: string) => this.scormAdapter.GetErrorString(errorCode), + GetDiagnostic: (errorCode: string) => this.scormAdapter.GetDiagnostic(errorCode) }; this.currentMode = this.data.mode; @@ -47,7 +47,9 @@ export class NumbasComponent implements OnInit { this.iframeSrc = this.sanitizer.bypassSecurityTrustResourceUrl(`${AppInjector.get(DoubtfireConstants).API_URL}/numbas_api/${this.task.taskDefId}/index.html`); } - removeNumbasTest(): void { + close(): void { + console.log('SCORM player closing, commiting DataModel!'); + this.scormAdapter.Commit(); const iframe = document.getElementsByTagName('iframe')[0]; iframe?.parentNode?.removeChild(iframe); this.dialogRef.close(); diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index e5b2e1b2a7..23145ccaea 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -72,6 +72,7 @@ import { gradeTaskModalProvider, uploadSubmissionModalProvider, ConfirmationModalProvider, + ScormPlayerModalProvider, } from './ajs-upgraded-providers'; import { TaskCommentComposerComponent, @@ -225,9 +226,8 @@ import {FTaskSheetViewComponent} from './units/states/tasks/viewer/directives/f- import {TasksViewerComponent} from './units/states/tasks/tasks-viewer/tasks-viewer.component'; import {UnitCodeComponent} from './common/unit-code/unit-code.component'; import {GradeService} from './common/services/grade.service'; -import {NumbasComponent} from './common/numbas-component/numbas-component.component'; -import {NumbasModal} from './common/numbas-component/numbas-modal.component'; -import {ScormLmsService} from './api/services/scorm-lms.service'; +import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component'; +import {ScormAdapterService} from './api/services/scorm-adapter.service'; import {NumbasCommentComponent} from './tasks/task-comments-viewer/numbas-comment/numbas-comment.component'; import {TestAttemptService} from './api/services/test-attempt.service'; @@ -332,7 +332,7 @@ import {TestAttemptService} from './api/services/test-attempt.service'; FUsersComponent, FTaskBadgeComponent, FUnitsComponent, - NumbasComponent, + ScormPlayerComponent, NumbasCommentComponent, ], // Services we provide @@ -405,8 +405,8 @@ import {TestAttemptService} from './api/services/test-attempt.service'; TasksForInboxSearchPipe, IsActiveUnitRole, CreateNewUnitModal, - NumbasModal, - ScormLmsService, + ScormPlayerModalProvider, + ScormAdapterService, TestAttemptService, provideLottieOptions({ player: () => player, diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index fa817ced4e..3cd6555bd8 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -225,8 +225,8 @@ import {FUnitsComponent} from './admin/states/f-units/f-units.component'; import {MarkedPipe} from './common/pipes/marked.pipe'; import {AlertService} from './common/services/alert.service'; import {GradeService} from './common/services/grade.service'; -import {NumbasComponent} from './common/numbas-component/numbas-component.component'; -import {NumbasModal} from './common/numbas-component/numbas-modal.component'; +import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component'; +import {ScormPlayerModal} from './common/scorm-player/scorm-player-modal.component'; import {TestAttemptService} from './api/services/test-attempt.service'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ @@ -310,7 +310,7 @@ DoubtfireAngularJSModule.factory( downgradeInjectable(EditProfileDialogService), ); DoubtfireAngularJSModule.factory('CreateNewUnitModal', downgradeInjectable(CreateNewUnitModal)); -DoubtfireAngularJSModule.factory('NumbasModal', downgradeInjectable(NumbasModal)); +DoubtfireAngularJSModule.factory('ScormPlayerModal', downgradeInjectable(ScormPlayerModal)); DoubtfireAngularJSModule.factory('testAttemptService', downgradeInjectable(TestAttemptService)); // directive -> component @@ -446,7 +446,10 @@ DoubtfireAngularJSModule.directive( ); DoubtfireAngularJSModule.directive('fUnits', downgradeComponent({component: FUnitsComponent})); -DoubtfireAngularJSModule.directive('fNumbasComponent', downgradeComponent({component: NumbasComponent})); +DoubtfireAngularJSModule.directive( + 'fScormPlayerComponent', + downgradeComponent({component: ScormPlayerComponent}), +); // Global configuration DoubtfireAngularJSModule.directive( diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee index f9552b3567..6a17bd558c 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee @@ -32,7 +32,7 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) UploadSubmissionModal ) -.controller('UploadSubmissionModalCtrl', ($scope, $rootScope, $timeout, $modalInstance, NumbasModal, newTaskService, newProjectService, task, reuploadEvidence, outcomeService, PrivacyPolicy) -> +.controller('UploadSubmissionModalCtrl', ($scope, $rootScope, $timeout, $modalInstance, ScormPlayerModal, newTaskService, newProjectService, task, reuploadEvidence, outcomeService, PrivacyPolicy) -> $scope.privacyPolicy = PrivacyPolicy # Expose task to scope $scope.task = task @@ -100,7 +100,7 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) # States functionality states = { # All possible states - all: ['group', 'numbas', 'files', 'alignment', 'comments', 'uploading'] + all: ['group', 'scorm-assessment', 'files', 'alignment', 'comments', 'uploading'] # Only states which are shown (populated in initialise) shown: [] # The currently active state (set in initialise) @@ -128,7 +128,7 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) removed.push('group') if !isRFF || !task.isGroupTask() removed.push('alignment') if !isRFF || !task.unit.ilos.length > 0 removed.push('comments') if isTestSubmission - removed.push('numbas') if !isRFF || !task.definition.hasEnabledNumbasTest + removed.push('scorm-assessment') if !isRFF || !task.definition.hasEnabledNumbasTest removed # Initialises the states initialise: -> @@ -155,8 +155,9 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) previous: states.previous } - $scope.launchNumbasDialog = -> - NumbasModal.show $scope.task, 'attempt' + $scope.launchScormPlayer = -> + console.clear() + ScormPlayerModal.show $scope.task, 'attempt' # Whether or not we should disable this button $scope.shouldDisableBtn = { diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html index 0527aadd40..8b6c89bea3 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html @@ -44,9 +44,9 @@

+ class="state state-scorm-assessment" + ng-class="{'state-hidden-left': isHidden('scorm-assessment').left, + 'state-hidden-right': isHidden('scorm-assessment').right}">

@@ -57,7 +57,7 @@

-
diff --git a/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts b/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts index eed512fe19..650a110d0f 100644 --- a/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts @@ -1,6 +1,6 @@ import { Component, OnInit, Input } from '@angular/core'; import { Task, TaskComment } from 'src/app/api/models/doubtfire-model'; -import { NumbasModal } from 'src/app/common/numbas-component/numbas-modal.component'; +import { ScormPlayerModal } from 'src/app/common/scorm-player/scorm-player-modal.component'; @Component({ selector: 'numbas-comment', @@ -11,7 +11,7 @@ export class NumbasCommentComponent implements OnInit { @Input() task: Task; @Input() comment: TaskComment; - constructor(private modalService: NumbasModal) {} + constructor(private modalService: ScormPlayerModal) {} ngOnInit() {} From 226d9193251fb675c92bec8265508477857a4ec9 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Wed, 8 May 2024 22:29:37 +1000 Subject: [PATCH 0074/1280] fix: use nullish coalescing when retrieving data from the datamodel also disallow dismissing modal to ensure datamodel is committed --- src/app/api/services/scorm-adapter.service.ts | 10 +++++----- .../scorm-player/scorm-player-modal.component.ts | 3 ++- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/app/api/services/scorm-adapter.service.ts b/src/app/api/services/scorm-adapter.service.ts index 3202331804..22c0205a33 100644 --- a/src/app/api/services/scorm-adapter.service.ts +++ b/src/app/api/services/scorm-adapter.service.ts @@ -69,7 +69,7 @@ export class ScormAdapterService { try { const completedTest = JSON.parse(xhr.responseText); - let parsedSuspendData = JSON.parse(completedTest.data.suspend_data || '{}'); + let parsedSuspendData = JSON.parse(completedTest.data.suspend_data ?? '{}'); // Set entire suspendData string to cmi.suspend_data this.SetValue('cmi.suspend_data', JSON.stringify(parsedSuspendData)); @@ -114,7 +114,7 @@ export class ScormAdapterService { console.log(this.dataStore); } else if (latestTest.data['cmi_entry'] === 'resume') { console.log("resuming test"); - let parsedSuspendData = JSON.parse(latestTest.data.suspend_data || '{}'); + let parsedSuspendData = JSON.parse(latestTest.data.suspend_data ?? '{}'); this.dataStore = JSON.parse(JSON.stringify(parsedSuspendData)); @@ -132,7 +132,7 @@ export class ScormAdapterService { } isTestCompleted(): boolean { - return this.dataStore?.['completed'] || false; + return this.dataStore?.['completed'] ?? false; } private resetDataStore() { @@ -144,7 +144,7 @@ export class ScormAdapterService { const examResult = this.dataStore["cmi.score.raw"]; const status = this.GetValue("cmi.success_status"); this.dataStore['completed'] = true; - const currentAttemptNumber = this.dataStore['attempt_number'] || 0; + const currentAttemptNumber = this.dataStore['attempt_number'] ?? 0; const ExamName = this.dataStore['name']; this.SetValue('cmi.entry', 'RO'); const cmientry = this.GetValue('cmi.entry'); @@ -177,7 +177,7 @@ export class ScormAdapterService { } GetValue(element: string): string { - return this.dataStore[element] || ''; + return this.dataStore[element] ?? ''; } SetValue(element: string, value: any): string { diff --git a/src/app/common/scorm-player/scorm-player-modal.component.ts b/src/app/common/scorm-player/scorm-player-modal.component.ts index 443add9bed..190e7bf570 100644 --- a/src/app/common/scorm-player/scorm-player-modal.component.ts +++ b/src/app/common/scorm-player/scorm-player-modal.component.ts @@ -14,7 +14,8 @@ export class ScormPlayerModal { dialogRef = this.dialog.open(ScormPlayerComponent, { data: { task, mode }, - width: '95%', height: '90%' + width: '95%', height: '90%', + disableClose: true, }); } } From 20472257c87711955b79008fa3cb7517151a4424 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Thu, 9 May 2024 06:18:20 +1000 Subject: [PATCH 0075/1280] refactor: separate out scorm datamodel and player context --- src/app/api/models/doubtfire-model.ts | 2 + src/app/api/models/scorm-datamodel.ts | 58 ++++++ src/app/api/models/scorm-player-context.ts | 33 +++ src/app/api/services/scorm-adapter.service.ts | 190 +++++++++--------- .../scorm-player/scorm-player.component.ts | 4 +- 5 files changed, 193 insertions(+), 94 deletions(-) create mode 100644 src/app/api/models/scorm-datamodel.ts create mode 100644 src/app/api/models/scorm-player-context.ts diff --git a/src/app/api/models/doubtfire-model.ts b/src/app/api/models/doubtfire-model.ts index 3cb4911083..baca2f22d2 100644 --- a/src/app/api/models/doubtfire-model.ts +++ b/src/app/api/models/doubtfire-model.ts @@ -32,6 +32,8 @@ export * from './task-comment/discussion-comment'; export * from '../services/task-outcome-alignment.service'; export * from './task-similarity'; export * from './tii-action'; +export * from './scorm-datamodel'; +export * from './scorm-player-context'; // Users -- are students or staff export * from './user/user'; diff --git a/src/app/api/models/scorm-datamodel.ts b/src/app/api/models/scorm-datamodel.ts new file mode 100644 index 0000000000..e9d105f3c7 --- /dev/null +++ b/src/app/api/models/scorm-datamodel.ts @@ -0,0 +1,58 @@ +export class ScormDataModel { + initState: {[key: string]: string} = { + 'cmi.completion_status': 'not attempted', + 'cmi.entry': 'ab-initio', + 'cmi.objectives._count': '0', + 'cmi.interactions._count': '0', + 'cmi.mode': 'normal', + }; + + dataModel: {[key: string]: any} = {}; + readonly msgPrefix = 'SCORM DataModel: '; + + constructor() { + this.dataModel = {}; + } + + public init() { + console.log(this.msgPrefix + 'initializing DataModel with default values'); + this.dataModel = this.initState; + } + + public restore(dataModel: {[key: string]: any} = {}) { + console.log(this.msgPrefix + 'restoring DataModel with provided data'); + this.dataModel = dataModel; + } + + public get(key: string): string { + return this.dataModel[key] ?? ''; + } + + public dump(): {[key: string]: any} { + return this.dataModel; + } + + public set(key: string, value: any): string { + console.log(this.msgPrefix + 'set: ', key, value); + this.dataModel[key] = value; + if (key.match('cmi.interactions.\\d+.id')) { + const interactionPath = key.match('cmi.interactions.\\d+'); + const objectivesCounterForInteraction = interactionPath.toString() + '.objectives._count'; + console.log('Incrementing cmi.interactions._count'); + this.dataModel['cmi.interactions._count']++; + console.log(`Initializing ${objectivesCounterForInteraction}`); + this.dataModel[objectivesCounterForInteraction] = 0; + } + if (key.match('cmi.interactions.\\d+.objectives.\\d+.id')) { + const interactionPath = key.match('cmi.interactions.\\d+.objectives'); + const objectivesCounterForInteraction = interactionPath.toString() + '._count'; + console.log(`Incrementing ${objectivesCounterForInteraction}`); + this.dataModel[objectivesCounterForInteraction.toString()]++; + } + if (key.match('cmi.objectives.\\d+.id')) { + console.log('Incrementing cmi.objectives._count'); + this.dataModel['cmi.objectives._count']++; + } + return 'true'; + } +} diff --git a/src/app/api/models/scorm-player-context.ts b/src/app/api/models/scorm-player-context.ts new file mode 100644 index 0000000000..5f1c4bd3ba --- /dev/null +++ b/src/app/api/models/scorm-player-context.ts @@ -0,0 +1,33 @@ +import { Task, User } from 'src/app/api/models/doubtfire-model'; + +export class ScormPlayerContext { + task: Task; + mode: 'browse' | 'normal' | 'review'; + user: User; + attemptNumber: number; + attemptId: number; + learnerName: string; + learnerId: number; + + constructor(user: User) { + this.user = user; + this.learnerId = user.id; + this.learnerName = user.firstName + ' ' + user.lastName; + } + + public setTask(task: Task): void { + this.task = task; + } + + public setMode(mode: 'browse' | 'normal' | 'review'): void { + this.mode = mode; + } + + public setAttemptNumber(attemptNumber: number = 1): void { + this.attemptNumber = attemptNumber; + } + + public setAttemptId(attemptId: number): void { + this.attemptId = attemptId; + } +} diff --git a/src/app/api/services/scorm-adapter.service.ts b/src/app/api/services/scorm-adapter.service.ts index 22c0205a33..6c5353746b 100644 --- a/src/app/api/services/scorm-adapter.service.ts +++ b/src/app/api/services/scorm-adapter.service.ts @@ -2,63 +2,76 @@ import { Injectable } from '@angular/core'; import { BehaviorSubject } from 'rxjs'; import { UserService } from './user.service'; import API_URL from 'src/app/config/constants/apiURL'; -import { Task } from '../models/task'; +import { Task, ScormDataModel, ScormPlayerContext } from 'src/app/api/models/doubtfire-model'; @Injectable({ providedIn: 'root' }) export class ScormAdapterService { private readonly apiBaseUrl = `${API_URL}/test_attempts`; + private dataModel: ScormDataModel; + private playerContext: ScormPlayerContext; - private defaultValues: { [key: string]: string } = { - 'cmi.completion_status': 'not attempted', - 'cmi.entry': 'ab-initio', - 'cmi.objectives._count': '0', - 'cmi.interactions._count': '0', - 'numbas.user_role': 'learner', - 'cmi.mode': 'normal', - }; - - private testId: number = 0; - private task: Task; - private readonly learnerId: string; - private readonly learnerName: string; initializationComplete$ = new BehaviorSubject(false); - private scormErrors: { [key: string]: string } = { - "0": "No error", - "101": "General exception", + private scormErrorCodes: {[key: string]: string} = { + '0': 'No Error', + '101': 'General Exception', + '102': 'General Initialization Failure', + '103': 'Already Initialized', + '104': 'Content Instance Terminated', + '111': 'General Termination Failure', + '112': 'Termination Before Initialization', + '113': 'Termination After Termination', + '122': 'Retrieve Data Before Initialization', + '123': 'Retrieve Data After Termination', + '132': 'Store Data Before Initialization', + '133': 'Store Data After Termination', + '142': 'Commit Before Initialization', + '143': 'Commit After Termination', + '201': 'General Argument Error', + '301': 'General Get Failure', + '351': 'General Set Failure', + '391': 'General Commit Failure', + '401': 'Undefined Data Model Element', + '402': 'Unimplemented Data Model Element', + '403': 'Data Model Element Value Not Initialized', + '404': 'Data Model Element Is Read Only', + '405': 'Data Model Element Is Write Only', + '406': 'Data Model Element Type Mismatch', + '407': 'Data Model Element Value Out Of Range', + '408': 'Data Model Dependency Not Established', }; - dataStore: { [key: string]: any } = this.getDefaultDataStore(); - constructor(private userService: UserService) { - const user = this.userService.currentUser; - this.learnerId = user.studentId; - this.learnerName = user.firstName + user.lastName; + this.dataModel = new ScormDataModel(); + this.playerContext = new ScormPlayerContext(this.userService.currentUser); } setTask(task: Task) { - this.task = task; + this.playerContext.setTask(task); } - getDefaultDataStore() { - // Use spread operator to merge defaultValues into the dataStore - return { - ...this.defaultValues, - pass_status: false, - completed: false, - }; - } + // getDefaultDataStore() { + // // Use spread operator to merge defaultValues into the dataStore + // return { + // ...this.defaultValues, + // pass_status: false, + // completed: false, + // }; + // } Initialize(mode: 'attempt' | 'review' = 'attempt'): string { console.log('Initialize() function called'); - const examName = 'test Exam Name 1'; - let xhr = new XMLHttpRequest(); + const xhr = new XMLHttpRequest(); if (mode === 'review') { this.SetValue('cmi.mode', 'review'); - xhr.open("GET", `${this.apiBaseUrl}/completed-latest?task_id=${this.task.id}`, false); + xhr.open( + 'GET', + `${this.apiBaseUrl}/completed-latest?task_id=${this.playerContext.task.id}`, + false, + ); xhr.send(); console.log(xhr.responseText); @@ -69,15 +82,17 @@ export class ScormAdapterService { try { const completedTest = JSON.parse(xhr.responseText); - let parsedSuspendData = JSON.parse(completedTest.data.suspend_data ?? '{}'); + const parsedDataModel = JSON.parse(completedTest.data.suspend_data ?? '{}'); // Set entire suspendData string to cmi.suspend_data - this.SetValue('cmi.suspend_data', JSON.stringify(parsedSuspendData)); + this.SetValue('cmi.suspend_data', JSON.stringify(parsedDataModel)); - // Use SetValue to set parsedSuspendData values to dataStore - Object.keys(parsedSuspendData).forEach(key => { - this.SetValue(key, parsedSuspendData[key]); - }); + // // Use SetValue to set parsedSuspendData values to dataStore + // Object.keys(parsedDataModel).forEach((key) => { + // this.SetValue(key, parsedDataModel[key]); + // }); + + this.dataModel.restore(parsedDataModel); this.SetValue('cmi.entry', 'RO'); this.SetValue('cmi.mode', 'review'); @@ -90,7 +105,7 @@ export class ScormAdapterService { } } - xhr.open("GET", `${this.apiBaseUrl}/latest?task_id=${this.task.id}`, false); + xhr.open('GET', `${this.apiBaseUrl}/latest?task_id=${this.playerContext.task.id}`, false); xhr.send(); console.log(xhr.responseText); @@ -103,27 +118,27 @@ export class ScormAdapterService { try { latestTest = JSON.parse(xhr.responseText); console.log('Latest test result:', latestTest); - this.testId = latestTest.data.id; + this.playerContext.attemptId = latestTest.data.id; if (latestTest.data['cmi_entry'] === 'ab-initio') { - console.log("starting new test"); - this.SetValue('cmi.learner_id', this.learnerId); - this.SetValue('cmi.learner_name', this.learnerName); - this.dataStore['name'] = examName; - this.dataStore['attempt_number'] = latestTest.data['attempt_number']; - console.log(this.dataStore); - } else if (latestTest.data['cmi_entry'] === 'resume') { - console.log("resuming test"); - let parsedSuspendData = JSON.parse(latestTest.data.suspend_data ?? '{}'); + console.log('starting new test'); + this.dataModel.init(); + this.SetValue('cmi.learner_id', this.playerContext.learnerId); + this.SetValue('cmi.learner_name', this.playerContext.learnerName); - this.dataStore = JSON.parse(JSON.stringify(parsedSuspendData)); + this.dataModel.set('attempt_number', latestTest.data['attempt_number']); + console.log(this.dataModel.dump()); + } else if (latestTest.data['cmi_entry'] === 'resume') { + console.log('resuming test'); + const restoredDataModel = JSON.parse(latestTest.data.suspend_data ?? '{}'); + this.dataModel.restore(JSON.parse(JSON.stringify(restoredDataModel))); - console.log(this.dataStore); + console.log(this.dataModel.dump()); } this.initializationComplete$.next(true); - console.log("finished initializing"); + console.log('finished initializing'); return 'true'; } catch (error) { console.error('Error:', error); @@ -131,67 +146,56 @@ export class ScormAdapterService { } } - isTestCompleted(): boolean { - return this.dataStore?.['completed'] ?? false; - } - - private resetDataStore() { - this.dataStore = this.getDefaultDataStore(); - } + // isTestCompleted(): boolean { + // return this.dataModel.get('completed') ?? false; + // } Terminate(): string { console.log('Terminate Called'); - const examResult = this.dataStore["cmi.score.raw"]; - const status = this.GetValue("cmi.success_status"); - this.dataStore['completed'] = true; - const currentAttemptNumber = this.dataStore['attempt_number'] ?? 0; - const ExamName = this.dataStore['name']; - this.SetValue('cmi.entry', 'RO'); - const cmientry = this.GetValue('cmi.entry'); + const examResult = this.dataModel.get('cmi.score.raw'); + const status = this.dataModel.get('cmi.success_status'); + this.dataModel.set('completed', true); + const currentAttemptNumber = this.dataModel.get('attempt_number') ?? 0; + const ExamName = this.dataModel.get('name'); + this.dataModel.set('cmi.entry', 'RO'); + const cmientry = this.dataModel.get('cmi.entry'); const data = { name: ExamName, attempt_number: currentAttemptNumber, pass_status: status === 'passed', - suspend_data: JSON.stringify(this.dataStore), + suspend_data: JSON.stringify(this.dataModel.dump()), completed: true, exam_result: examResult, cmi_entry: cmientry, - task_id: this.task.id + task_id: this.playerContext.task.id }; const xhr = new XMLHttpRequest(); - if (this.testId) { - xhr.open("PUT", `${this.apiBaseUrl}/${this.testId}`, false); + if (this.playerContext.attemptId) { + xhr.open('PUT', `${this.apiBaseUrl}/${this.playerContext.attemptId}`, false); } else { - xhr.open("POST", this.apiBaseUrl, false); + xhr.open('POST', this.apiBaseUrl, false); } - xhr.setRequestHeader("Content-Type", "application/json;charset=UTF-8"); + xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); xhr.send(JSON.stringify(data)); if (xhr.status !== 200) { console.error('Error sending test data:', xhr.statusText); return 'false'; } - this.resetDataStore(); + this.dataModel.init(); return 'true'; } GetValue(element: string): string { - return this.dataStore[element] ?? ''; + const value = this.dataModel.get(element); + console.log(`GetValue:`, element, value); + return value; } SetValue(element: string, value: any): string { console.log(`SetValue:`, element, value); - this.dataStore[element] = value; - if (element.match('cmi.interactions.\\d+.id')) { - console.log('Incrementing cmi.interactions._count'); - this.dataStore['cmi.interactions._count']++; - } - if (element.match('cmi.objectives.\\d+.id')) { - console.log('Incrementing cmi.objectives._count'); - this.dataStore['cmi.objectives._count']++; - } - // console.log("dataStore after value set:", this.dataStore); + this.dataModel.set(element, value); return 'true'; } @@ -203,15 +207,15 @@ export class ScormAdapterService { } // Set cmi.entry to 'resume' before committing dataStore - this.dataStore['cmi.entry'] = 'resume'; - if (!this.isTestCompleted()) { - this.dataStore['cmi.exit'] = 'suspend'; - } - console.log("Committing DataModel:", this.dataStore); + this.dataModel.set('cmi.entry', 'resume'); + // if (!this.isTestCompleted()) { + // this.dataModel.set('cmi.exit', 'suspend'); + // } + console.log('Committing DataModel:', this.dataModel.dump()); // Use XHR to send the request const xhr = new XMLHttpRequest(); - xhr.open('PUT', `${this.apiBaseUrl}/${this.testId}/suspend`, true); + xhr.open('PUT', `${this.apiBaseUrl}/${this.playerContext.attemptId}/suspend`, true); xhr.setRequestHeader('Content-Type', 'application/json'); xhr.onload = () => { @@ -226,7 +230,7 @@ export class ScormAdapterService { console.error('Request failed.'); }; - const requestData = { suspend_data: this.dataStore }; + const requestData = { suspend_data: this.dataModel.dump() }; xhr.send(JSON.stringify(requestData)); return 'true'; } diff --git a/src/app/common/scorm-player/scorm-player.component.ts b/src/app/common/scorm-player/scorm-player.component.ts index 7ed98b3cfe..428f6869b7 100644 --- a/src/app/common/scorm-player/scorm-player.component.ts +++ b/src/app/common/scorm-player/scorm-player.component.ts @@ -1,7 +1,7 @@ import { Component, OnInit, Inject } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; -import { Task } from 'src/app/api/models/task'; +import { Task, ScormDataModel, ScormPlayerContext } from 'src/app/api/models/doubtfire-model'; import { ScormAdapterService } from 'src/app/api/services/scorm-adapter.service'; import { AppInjector } from 'src/app/app-injector'; import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; @@ -16,6 +16,8 @@ declare global { styleUrls: ['./scorm-player.component.scss'], }) export class ScormPlayerComponent implements OnInit { + context: ScormPlayerContext; + task: Task; currentMode: 'attempt' | 'review' = 'attempt'; iframeSrc: SafeResourceUrl; From b0863c7cf9319862b224705b50a238d2fabc5ec9 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Sun, 12 May 2024 08:43:22 +1000 Subject: [PATCH 0076/1280] refactor: rewrite test attempt code --- src/app/api/models/scorm-datamodel.ts | 24 +- src/app/api/models/scorm-player-context.ts | 69 +++- src/app/api/models/task-definition.ts | 14 +- src/app/api/models/task.ts | 2 +- src/app/api/services/scorm-adapter.service.ts | 350 +++++++++--------- src/app/api/services/task-comment.service.ts | 2 +- .../api/services/task-definition.service.ts | 10 +- .../scorm-player-modal.component.ts | 15 +- .../scorm-player/scorm-player.component.ts | 41 +- .../upload-submission-modal.coffee | 2 +- .../numbas-comment.component.ts | 6 +- .../task-comments-viewer.component.html | 2 +- .../task-comments-viewer.component.scss | 2 +- .../task-definition-numbas.component.html | 10 +- 14 files changed, 289 insertions(+), 260 deletions(-) diff --git a/src/app/api/models/scorm-datamodel.ts b/src/app/api/models/scorm-datamodel.ts index e9d105f3c7..9454db78f6 100644 --- a/src/app/api/models/scorm-datamodel.ts +++ b/src/app/api/models/scorm-datamodel.ts @@ -1,12 +1,4 @@ export class ScormDataModel { - initState: {[key: string]: string} = { - 'cmi.completion_status': 'not attempted', - 'cmi.entry': 'ab-initio', - 'cmi.objectives._count': '0', - 'cmi.interactions._count': '0', - 'cmi.mode': 'normal', - }; - dataModel: {[key: string]: any} = {}; readonly msgPrefix = 'SCORM DataModel: '; @@ -14,17 +6,13 @@ export class ScormDataModel { this.dataModel = {}; } - public init() { - console.log(this.msgPrefix + 'initializing DataModel with default values'); - this.dataModel = this.initState; - } - - public restore(dataModel: {[key: string]: any} = {}) { + public restore(dataModel: string) { console.log(this.msgPrefix + 'restoring DataModel with provided data'); - this.dataModel = dataModel; + this.dataModel = JSON.parse(dataModel); } public get(key: string): string { + // console.log(`SCORM DataModel: get ${key} ${this.dataModel[key]}`); return this.dataModel[key] ?? ''; } @@ -33,23 +21,27 @@ export class ScormDataModel { } public set(key: string, value: any): string { - console.log(this.msgPrefix + 'set: ', key, value); + // console.log(this.msgPrefix + 'set: ', key, value); this.dataModel[key] = value; if (key.match('cmi.interactions.\\d+.id')) { + // cmi.interactions._count must be incremented after a new interaction is crated const interactionPath = key.match('cmi.interactions.\\d+'); const objectivesCounterForInteraction = interactionPath.toString() + '.objectives._count'; console.log('Incrementing cmi.interactions._count'); this.dataModel['cmi.interactions._count']++; + // cmi.interactions.n.objectives._count must be initialized after an interaction is created console.log(`Initializing ${objectivesCounterForInteraction}`); this.dataModel[objectivesCounterForInteraction] = 0; } if (key.match('cmi.interactions.\\d+.objectives.\\d+.id')) { const interactionPath = key.match('cmi.interactions.\\d+.objectives'); const objectivesCounterForInteraction = interactionPath.toString() + '._count'; + // cmi.interactions.n.objectives._count must be incremented after objective creation console.log(`Incrementing ${objectivesCounterForInteraction}`); this.dataModel[objectivesCounterForInteraction.toString()]++; } if (key.match('cmi.objectives.\\d+.id')) { + // cmi.objectives._count must be incremented after a new objective is crated console.log('Incrementing cmi.objectives._count'); this.dataModel['cmi.objectives._count']++; } diff --git a/src/app/api/models/scorm-player-context.ts b/src/app/api/models/scorm-player-context.ts index 5f1c4bd3ba..f3b3b8a13f 100644 --- a/src/app/api/models/scorm-player-context.ts +++ b/src/app/api/models/scorm-player-context.ts @@ -1,9 +1,56 @@ -import { Task, User } from 'src/app/api/models/doubtfire-model'; +import {Task, User} from 'src/app/api/models/doubtfire-model'; + +type DataModelState = 'Uninitialized' | 'Initialized' | 'Terminated'; + +type DataModelError = Record; +const CMIErrorCodes: DataModelError = { + 0: 'No Error', + 101: 'General Exception', + 102: 'General Initialization Failure', + 103: 'Already Initialized', + 104: 'Content Instance Terminated', + 111: 'General Termination Failure', + 112: 'Termination Before Initialization', + 113: 'Termination After Termination', + 122: 'Retrieve Data Before Initialization', + 123: 'Retrieve Data After Termination', + 132: 'Store Data Before Initialization', + 133: 'Store Data After Termination', + 142: 'Commit Before Initialization', + 143: 'Commit After Termination', + 201: 'General Argument Error', + 301: 'General Get Failure', + 351: 'General Set Failure', + 391: 'General Commit Failure', + 401: 'Undefined Data Model Element', + 402: 'Unimplemented Data Model Element', + 403: 'Data Model Element Value Not Initialized', + 404: 'Data Model Element Is Read Only', + 405: 'Data Model Element Is Write Only', + 406: 'Data Model Element Type Mismatch', + 407: 'Data Model Element Value Out Of Range', + 408: 'Data Model Dependency Not Established', +}; export class ScormPlayerContext { - task: Task; mode: 'browse' | 'normal' | 'review'; + state: DataModelState; + + private _errorCode: number; + get errorCode() { + return this._errorCode; + } + set errorCode(value: number) { + this._errorCode = value; + } + + getErrorMessage(value: string): string { + return CMIErrorCodes[value]; + } + + task: Task; user: User; + attemptNumber: number; attemptId: number; learnerName: string; @@ -13,21 +60,7 @@ export class ScormPlayerContext { this.user = user; this.learnerId = user.id; this.learnerName = user.firstName + ' ' + user.lastName; - } - - public setTask(task: Task): void { - this.task = task; - } - - public setMode(mode: 'browse' | 'normal' | 'review'): void { - this.mode = mode; - } - - public setAttemptNumber(attemptNumber: number = 1): void { - this.attemptNumber = attemptNumber; - } - - public setAttemptId(attemptId: number): void { - this.attemptId = attemptId; + this.state = 'Uninitialized'; + this.errorCode = 0; } } diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index a669b2fe36..985b810137 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -31,10 +31,10 @@ export class TaskDefinition extends Entity { groupSet: GroupSet = null; hasTaskSheet: boolean; hasTaskResources: boolean; - hasEnabledNumbasTest: boolean; - hasNumbasData: boolean; - hasNumbasTimeDelay: boolean; - numbasAttemptLimit: number = 0; + scormEnabled: boolean; + hasScormData: boolean; + scormTimeDelayEnabled: boolean; + scormAttemptLimit: number = 0; hasTaskAssessmentResources: boolean; isGraded: boolean; maxQualityPts: number; @@ -158,7 +158,7 @@ export class TaskDefinition extends Entity { public getNumbasTestUrl(asAttachment: boolean = false) { const constants = AppInjector.get(DoubtfireConstants); - return `${constants.API_URL}/units/${this.unit.id}/task_definitions/${this.id}/numbas_data.json${ + return `${constants.API_URL}/units/${this.unit.id}/task_definitions/${this.id}/scorm_data.json${ asAttachment ? '?as_attachment=true' : '' }`; } @@ -190,7 +190,7 @@ export class TaskDefinition extends Entity { public get numbasTestUploadUrl(): string { return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.unit.id}/task_definitions/${ this.id - }/numbas_data`; + }/scorm_data`; } public get taskAssessmentResourcesUploadUrl(): string { @@ -217,7 +217,7 @@ export class TaskDefinition extends Entity { public deleteNumbasTest(): Observable { const httpClient = AppInjector.get(HttpClient); - return httpClient.delete(this.numbasTestUploadUrl).pipe(tap(() => (this.hasNumbasData = false))); + return httpClient.delete(this.numbasTestUploadUrl).pipe(tap(() => (this.hasScormData = false))); } public deleteTaskAssessmentResources(): Observable { diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index 403165cfee..3803d325b6 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -509,7 +509,7 @@ export class Task extends Entity { public get numbasEnabled(): boolean { return ( - this.definition.hasEnabledNumbasTest && this.definition.hasNumbasData + this.definition.scormEnabled && this.definition.hasScormData ); } diff --git a/src/app/api/services/scorm-adapter.service.ts b/src/app/api/services/scorm-adapter.service.ts index 6c5353746b..8886121031 100644 --- a/src/app/api/services/scorm-adapter.service.ts +++ b/src/app/api/services/scorm-adapter.service.ts @@ -1,222 +1,212 @@ -import { Injectable } from '@angular/core'; -import { BehaviorSubject } from 'rxjs'; -import { UserService } from './user.service'; +import {Injectable} from '@angular/core'; +import {UserService} from './user.service'; import API_URL from 'src/app/config/constants/apiURL'; -import { Task, ScormDataModel, ScormPlayerContext } from 'src/app/api/models/doubtfire-model'; +import {Task, ScormDataModel, ScormPlayerContext} from 'src/app/api/models/doubtfire-model'; @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class ScormAdapterService { private readonly apiBaseUrl = `${API_URL}/test_attempts`; private dataModel: ScormDataModel; - private playerContext: ScormPlayerContext; - - initializationComplete$ = new BehaviorSubject(false); - - private scormErrorCodes: {[key: string]: string} = { - '0': 'No Error', - '101': 'General Exception', - '102': 'General Initialization Failure', - '103': 'Already Initialized', - '104': 'Content Instance Terminated', - '111': 'General Termination Failure', - '112': 'Termination Before Initialization', - '113': 'Termination After Termination', - '122': 'Retrieve Data Before Initialization', - '123': 'Retrieve Data After Termination', - '132': 'Store Data Before Initialization', - '133': 'Store Data After Termination', - '142': 'Commit Before Initialization', - '143': 'Commit After Termination', - '201': 'General Argument Error', - '301': 'General Get Failure', - '351': 'General Set Failure', - '391': 'General Commit Failure', - '401': 'Undefined Data Model Element', - '402': 'Unimplemented Data Model Element', - '403': 'Data Model Element Value Not Initialized', - '404': 'Data Model Element Is Read Only', - '405': 'Data Model Element Is Write Only', - '406': 'Data Model Element Type Mismatch', - '407': 'Data Model Element Value Out Of Range', - '408': 'Data Model Dependency Not Established', - }; + private context: ScormPlayerContext; + private xhr: XMLHttpRequest; constructor(private userService: UserService) { this.dataModel = new ScormDataModel(); - this.playerContext = new ScormPlayerContext(this.userService.currentUser); + this.context = new ScormPlayerContext(this.userService.currentUser); + this.xhr = new XMLHttpRequest(); } - setTask(task: Task) { - this.playerContext.setTask(task); + set task(task: Task) { + this.context.task = task; } - // getDefaultDataStore() { - // // Use spread operator to merge defaultValues into the dataStore - // return { - // ...this.defaultValues, - // pass_status: false, - // completed: false, - // }; - // } - - Initialize(mode: 'attempt' | 'review' = 'attempt'): string { - console.log('Initialize() function called'); - const xhr = new XMLHttpRequest(); - if (mode === 'review') { - this.SetValue('cmi.mode', 'review'); - - xhr.open( - 'GET', - `${this.apiBaseUrl}/completed-latest?task_id=${this.playerContext.task.id}`, - false, - ); - xhr.send(); - console.log(xhr.responseText); + get state() { + return this.context.state; + } - if (xhr.status !== 200) { - console.error('Error fetching latest completed test result:', xhr.statusText); - return 'false'; - } + destroy() { + this.dataModel = new ScormDataModel(); + this.context.state = 'Uninitialized'; + } - try { - const completedTest = JSON.parse(xhr.responseText); - const parsedDataModel = JSON.parse(completedTest.data.suspend_data ?? '{}'); + Initialize(): string { + console.log('API_1484_11: Initialize'); + + // TODO: error handling and reporting + switch (this.context.state) { + case 'Initialized': + this.context.errorCode = 103; + console.log('Already Initialized'); + break; + case 'Terminated': + this.context.errorCode = 104; + console.log('Content Instance Terminated'); + break; + } - // Set entire suspendData string to cmi.suspend_data - this.SetValue('cmi.suspend_data', JSON.stringify(parsedDataModel)); + // TODO: move this part into the player component + this.xhr.open('GET', `${this.apiBaseUrl}/${this.context.task.id}/latest`, false); - // // Use SetValue to set parsedSuspendData values to dataStore - // Object.keys(parsedDataModel).forEach((key) => { - // this.SetValue(key, parsedDataModel[key]); - // }); + let noTestFound = false; + let startNewTest = false; - this.dataModel.restore(parsedDataModel); + this.xhr.onload = () => { + if (this.xhr.status >= 200 && this.xhr.status < 400) { + console.log('Retrieved the latest attempt.'); + } else if (this.xhr.status == 404) { + console.log('Not found.'); + noTestFound = true; + } else { + console.error('Error saving DataModel:', this.xhr.responseText); + } + }; - this.SetValue('cmi.entry', 'RO'); - this.SetValue('cmi.mode', 'review'); + this.xhr.send(); + console.log(this.xhr.responseText); - console.log('Latest completed test data:', completedTest); - return 'true'; - } catch (error) { - console.error('Error:', error); - return 'false'; + if (!noTestFound) { + const latestSession = JSON.parse(this.xhr.responseText); + console.log('Latest exam session:', latestSession); + this.context.attemptId = latestSession.id; + if (latestSession.completion_status) { + startNewTest = true; } + } else { + startNewTest = true; } - xhr.open('GET', `${this.apiBaseUrl}/latest?task_id=${this.playerContext.task.id}`, false); - xhr.send(); - console.log(xhr.responseText); - - if (xhr.status !== 200) { - console.error('Error fetching latest test result:', xhr.statusText); - return 'false'; + if (!startNewTest) { + this.xhr.open( + 'PATCH', + `${this.apiBaseUrl}/${this.context.task.id}/session/${this.context.attemptId}`, + false, + ); + this.xhr.send(); + console.log(this.xhr.responseText); + + const currentSession = JSON.parse(this.xhr.responseText); + console.log('Current exam session:', currentSession); + this.context.attemptId = currentSession.id; + this.dataModel.restore(currentSession.cmi_datamodel); + console.log(this.dataModel.dump()); + } else { + this.xhr.open('POST', `${this.apiBaseUrl}/${this.context.task.id}/session`, false); + this.xhr.send(); + console.log(this.xhr.responseText); + + const currentSession = JSON.parse(this.xhr.responseText); + console.log('Current exam session:', currentSession); + this.context.attemptId = currentSession.id; + this.dataModel.restore(currentSession.cmi_datamodel); + console.log(this.dataModel.dump()); } - let latestTest; - try { - latestTest = JSON.parse(xhr.responseText); - console.log('Latest test result:', latestTest); - this.playerContext.attemptId = latestTest.data.id; - - if (latestTest.data['cmi_entry'] === 'ab-initio') { - console.log('starting new test'); - this.dataModel.init(); - this.SetValue('cmi.learner_id', this.playerContext.learnerId); - this.SetValue('cmi.learner_name', this.playerContext.learnerName); - - this.dataModel.set('attempt_number', latestTest.data['attempt_number']); - console.log(this.dataModel.dump()); - } else if (latestTest.data['cmi_entry'] === 'resume') { - console.log('resuming test'); - const restoredDataModel = JSON.parse(latestTest.data.suspend_data ?? '{}'); - this.dataModel.restore(JSON.parse(JSON.stringify(restoredDataModel))); - - console.log(this.dataModel.dump()); - } - - this.initializationComplete$.next(true); - - console.log('finished initializing'); - return 'true'; - } catch (error) { - console.error('Error:', error); - return 'false'; - } + this.context.state = 'Initialized'; + return 'true'; } - // isTestCompleted(): boolean { - // return this.dataModel.get('completed') ?? false; - // } - Terminate(): string { - console.log('Terminate Called'); - const examResult = this.dataModel.get('cmi.score.raw'); - const status = this.dataModel.get('cmi.success_status'); - this.dataModel.set('completed', true); - const currentAttemptNumber = this.dataModel.get('attempt_number') ?? 0; - const ExamName = this.dataModel.get('name'); - this.dataModel.set('cmi.entry', 'RO'); - const cmientry = this.dataModel.get('cmi.entry'); - const data = { - name: ExamName, - attempt_number: currentAttemptNumber, - pass_status: status === 'passed', - suspend_data: JSON.stringify(this.dataModel.dump()), - completed: true, - exam_result: examResult, - cmi_entry: cmientry, - task_id: this.playerContext.task.id - }; - - const xhr = new XMLHttpRequest(); - if (this.playerContext.attemptId) { - xhr.open('PUT', `${this.apiBaseUrl}/${this.playerContext.attemptId}`, false); - } else { - xhr.open('POST', this.apiBaseUrl, false); + console.log('API_1484_11: Terminate'); + + // TODO: error handling and reporting + switch (this.context.state) { + case 'Uninitialized': + this.context.errorCode = 112; + console.log('Termination Before Initialization'); + break; + case 'Terminated': + this.context.errorCode = 113; + console.log('Termination After Termination'); + break; } - xhr.setRequestHeader('Content-Type', 'application/json;charset=UTF-8'); - xhr.send(JSON.stringify(data)); - if (xhr.status !== 200) { - console.error('Error sending test data:', xhr.statusText); - return 'false'; - } - this.dataModel.init(); + this.xhr.open( + 'PATCH', + `${this.apiBaseUrl}/${this.context.task.id}/session/${this.context.attemptId}`, + false, + ); + this.xhr.setRequestHeader('Content-Type', 'application/json'); + const requestData = { + terminated: true, + }; + this.xhr.send(JSON.stringify(requestData)); + console.log(this.xhr.responseText); + + // all done, clearing datamodel and setting state to terminated + this.dataModel = new ScormDataModel(); + this.context.state = 'Terminated'; return 'true'; } GetValue(element: string): string { const value = this.dataModel.get(element); - console.log(`GetValue:`, element, value); + + // TODO: error reporting + // TODO: can't get until init is done + switch (this.context.state) { + case 'Uninitialized': + this.context.errorCode = 122; + console.log('Retrieve Data Before Initialization'); + break; + case 'Terminated': + this.context.errorCode = 123; + console.log('Retrieve Data After Termination'); + break; + } + + console.log(`API_1484_11: GetValue:`, element, value); return value; } SetValue(element: string, value: any): string { - console.log(`SetValue:`, element, value); + console.log(`API_1484_11: SetValue:`, element, value); + + // TODO: error reporting + // TODO: can't set until init is done + switch (this.context.state) { + case 'Uninitialized': + this.context.errorCode = 132; + console.log('Store Data Before Initialization'); + break; + case 'Terminated': + this.context.errorCode = 133; + console.log('Store Data After Termination'); + break; + } + this.dataModel.set(element, value); return 'true'; } - // Saves the state of the exam. Commit(): string { - if (!this.initializationComplete$.getValue()) { - console.warn('Initialization not complete. Cannot commit.'); - return 'false'; + console.log('API_1484_11: Commit'); + + // TODO: error reporting + // TODO: can't commit until init is done + switch (this.context.state) { + case 'Uninitialized': + this.context.errorCode = 142; + console.log('Commit Before Initialization'); + break; + case 'Terminated': + this.context.errorCode = 143; + console.log('Commit After Termination'); + break; } - // Set cmi.entry to 'resume' before committing dataStore - this.dataModel.set('cmi.entry', 'resume'); - // if (!this.isTestCompleted()) { - // this.dataModel.set('cmi.exit', 'suspend'); - // } - console.log('Committing DataModel:', this.dataModel.dump()); - - // Use XHR to send the request const xhr = new XMLHttpRequest(); - xhr.open('PUT', `${this.apiBaseUrl}/${this.playerContext.attemptId}/suspend`, true); + xhr.open( + 'PATCH', + `${this.apiBaseUrl}/${this.context.task.id}/session/${this.context.attemptId}`, + true, + ); xhr.setRequestHeader('Content-Type', 'application/json'); + const requestData = { + cmi_datamodel: JSON.stringify(this.dataModel.dump()), + }; + xhr.send(JSON.stringify(requestData)); xhr.onload = () => { if (xhr.status >= 200 && xhr.status < 400) { @@ -230,23 +220,27 @@ export class ScormAdapterService { console.error('Request failed.'); }; - const requestData = { suspend_data: this.dataModel.dump() }; - xhr.send(JSON.stringify(requestData)); + this.context.errorCode = 0; return 'true'; } - // Placeholder methods for SCORM error handling GetLastError(): string { - //console.log('Get Last Error called'); - return "0"; + const lastError = this.context.errorCode.toString(); + if (lastError !== '0') { + console.log(`API_1484_11: GetLastError: ${lastError}`); + } + return lastError; } GetErrorString(errorCode: string): string { - return ''; + const errorString = this.context.getErrorMessage(errorCode); + console.log(`API_1484_11: GetErrorString:`, errorCode, errorString); + return errorString; } GetDiagnostic(errorCode: string): string { - //console.log('Get Diagnoistic called'); - return ''; + // TODO: implement this + console.log(`API_1484_11: GetDiagnostic:`, errorCode); + return 'GetDiagnostic is currently not implemented'; } } diff --git a/src/app/api/services/task-comment.service.ts b/src/app/api/services/task-comment.service.ts index e3c80797a4..5f034b870d 100644 --- a/src/app/api/services/task-comment.service.ts +++ b/src/app/api/services/task-comment.service.ts @@ -145,7 +145,7 @@ export class TaskCommentService extends CachedEntityService { const opts: RequestOptions = { endpointFormat: this.commentEndpointFormat }; // Based on the comment type - add to the body and configure the end point - if (commentType === 'text' || commentType === 'numbas') { + if (commentType === 'text' || commentType === 'scorm') { body.append('comment', data); } else if (commentType === 'discussion') { opts.endpointFormat = this.discussionEndpointFormat; diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index 6047af0546..a738626884 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -93,10 +93,10 @@ export class TaskDefinitionService extends CachedEntityService { 'hasTaskSheet', 'hasTaskResources', 'hasTaskAssessmentResources', - 'hasEnabledNumbasTest', - 'hasNumbasData', - 'hasNumbasTimeDelay', - 'numbasAttemptLimit', + 'scormEnabled', + 'hasScormData', + 'scormTimeDelayEnabled', + 'scormAttemptLimit', 'isGraded', 'maxQualityPts', 'overseerImageId', @@ -108,7 +108,7 @@ export class TaskDefinitionService extends CachedEntityService { 'hasTaskSheet', 'hasTaskResources', 'hasTaskAssessmentResources', - 'hasNumbasData' + 'hasScormData' ); } diff --git a/src/app/common/scorm-player/scorm-player-modal.component.ts b/src/app/common/scorm-player/scorm-player-modal.component.ts index 190e7bf570..2fb4630263 100644 --- a/src/app/common/scorm-player/scorm-player-modal.component.ts +++ b/src/app/common/scorm-player/scorm-player-modal.component.ts @@ -1,20 +1,21 @@ -import { Injectable } from '@angular/core'; -import { MatDialog, MatDialogRef } from '@angular/material/dialog'; -import { ScormPlayerComponent } from './scorm-player.component'; -import { Task } from 'src/app/api/models/task'; +import {Injectable} from '@angular/core'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; +import {ScormPlayerComponent} from './scorm-player.component'; +import {Task} from 'src/app/api/models/task'; @Injectable({ providedIn: 'root', }) export class ScormPlayerModal { - constructor(public dialog: MatDialog) { } + constructor(public dialog: MatDialog) {} public show(task: Task, mode: 'attempt' | 'review'): void { let dialogRef: MatDialogRef; dialogRef = this.dialog.open(ScormPlayerComponent, { - data: { task, mode }, - width: '95%', height: '90%', + data: {task, mode}, + width: '95%', + height: '90%', disableClose: true, }); } diff --git a/src/app/common/scorm-player/scorm-player.component.ts b/src/app/common/scorm-player/scorm-player.component.ts index 428f6869b7..1b89e36bae 100644 --- a/src/app/common/scorm-player/scorm-player.component.ts +++ b/src/app/common/scorm-player/scorm-player.component.ts @@ -1,13 +1,15 @@ -import { Component, OnInit, Inject } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; -import { Task, ScormDataModel, ScormPlayerContext } from 'src/app/api/models/doubtfire-model'; -import { ScormAdapterService } from 'src/app/api/services/scorm-adapter.service'; -import { AppInjector } from 'src/app/app-injector'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; +import {Component, OnInit, Inject} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser'; +import {Task, ScormPlayerContext} from 'src/app/api/models/doubtfire-model'; +import {ScormAdapterService} from 'src/app/api/services/scorm-adapter.service'; +import {AppInjector} from 'src/app/app-injector'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; declare global { - interface Window { API_1484_11: any; } + interface Window { + API_1484_11: any; + } } @Component({ @@ -24,34 +26,41 @@ export class ScormPlayerComponent implements OnInit { constructor( private dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: { task: Task, mode: 'attempt' | 'review' }, + @Inject(MAT_DIALOG_DATA) public data: {task: Task; mode: 'attempt' | 'review'}, private scormAdapter: ScormAdapterService, - private sanitizer: DomSanitizer + private sanitizer: DomSanitizer, ) {} ngOnInit(): void { this.task = this.data.task; - this.scormAdapter.setTask(this.task); + this.scormAdapter.task = this.task; window.API_1484_11 = { - Initialize: () => this.scormAdapter.Initialize(this.currentMode), + Initialize: () => this.scormAdapter.Initialize(), Terminate: () => this.scormAdapter.Terminate(), GetValue: (element: string) => this.scormAdapter.GetValue(element), SetValue: (element: string, value: string) => this.scormAdapter.SetValue(element, value), Commit: () => this.scormAdapter.Commit(), GetLastError: () => this.scormAdapter.GetLastError(), GetErrorString: (errorCode: string) => this.scormAdapter.GetErrorString(errorCode), - GetDiagnostic: (errorCode: string) => this.scormAdapter.GetDiagnostic(errorCode) + GetDiagnostic: (errorCode: string) => this.scormAdapter.GetDiagnostic(errorCode), }; this.currentMode = this.data.mode; - this.iframeSrc = this.sanitizer.bypassSecurityTrustResourceUrl(`${AppInjector.get(DoubtfireConstants).API_URL}/numbas_api/${this.task.taskDefId}/index.html`); + this.iframeSrc = this.sanitizer.bypassSecurityTrustResourceUrl( + `${AppInjector.get(DoubtfireConstants).API_URL}/scorm/${this.task.taskDefId}/index.html`, + ); } close(): void { - console.log('SCORM player closing, commiting DataModel!'); - this.scormAdapter.Commit(); + if (this.scormAdapter.state == 'Initialized') { + console.log('SCORM player closing during an initialized session, commiting DataModel'); + this.scormAdapter.Commit(); + } + // TODO: would be nice if we can destroy this entire adapter object when the modal is closed + console.log('Clearing player context and DataModel'); + this.scormAdapter.destroy(); const iframe = document.getElementsByTagName('iframe')[0]; iframe?.parentNode?.removeChild(iframe); this.dialogRef.close(); diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee index 6a17bd558c..7c0baf7ee9 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee @@ -128,7 +128,7 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) removed.push('group') if !isRFF || !task.isGroupTask() removed.push('alignment') if !isRFF || !task.unit.ilos.length > 0 removed.push('comments') if isTestSubmission - removed.push('scorm-assessment') if !isRFF || !task.definition.hasEnabledNumbasTest + removed.push('scorm-assessment') if !isRFF || !task.definition.scormEnabled removed # Initialises the states initialise: -> diff --git a/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts b/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts index 650a110d0f..c8ba676c55 100644 --- a/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts @@ -1,6 +1,6 @@ -import { Component, OnInit, Input } from '@angular/core'; -import { Task, TaskComment } from 'src/app/api/models/doubtfire-model'; -import { ScormPlayerModal } from 'src/app/common/scorm-player/scorm-player-modal.component'; +import {Component, OnInit, Input} from '@angular/core'; +import {Task, TaskComment} from 'src/app/api/models/doubtfire-model'; +import {ScormPlayerModal} from 'src/app/common/scorm-player/scorm-player-modal.component'; @Component({ selector: 'numbas-comment', diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html index cd18eda9ba..0be0e7b758 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html @@ -72,7 +72,7 @@ >
-
+
- + Enable Numbas Test @@ -10,7 +10,7 @@ accept="application/zip" [desiredFileName]="'Numbas zip'" /> - @if (taskDefinition.hasNumbasData) { + @if (taskDefinition.hasScormData) {
- @if (taskDefinition.hasEnabledNumbasTest) { + @if (taskDefinition.scormEnabled) {
- + Enable incremental time delays between test attempts @@ -34,7 +34,7 @@ min="0" max="100" type="number" - [(ngModel)]="taskDefinition.numbasAttemptLimit" + [(ngModel)]="taskDefinition.scormAttemptLimit" [formControl]="attemptLimitControl" /> From 644c025e698480276a068d717589be547817ddc8 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 14 May 2024 13:18:33 +1000 Subject: [PATCH 0077/1280] refactor: rename numbas references to scorm and fix typos --- src/app/api/models/scorm-datamodel.ts | 4 +- src/app/api/models/task-definition.ts | 8 +- src/app/api/models/task.ts | 2 +- .../spec/scorm-adapter.service.spec.ts | 87 ------------------- .../api/services/task-definition.service.ts | 4 +- .../scorm-player-modal.component.ts | 2 +- .../scorm-player/scorm-player.component.ts | 4 +- src/app/doubtfire-angular.module.ts | 8 +- .../upload-submission-modal.coffee | 2 +- .../upload-submission-modal.tpl.html | 6 +- .../scorm-comment.component.html} | 4 +- .../scorm-comment.component.scss} | 0 .../scorm-comment.component.ts} | 10 +-- .../task-comments-viewer.component.html | 8 +- .../task-comments-viewer.component.ts | 6 +- .../task-definition-editor.component.html | 6 +- .../task-definition-scorm.component.html} | 14 +-- .../task-definition-scorm.component.scss} | 0 .../task-definition-scorm.component.ts} | 32 +++---- 19 files changed, 60 insertions(+), 147 deletions(-) delete mode 100644 src/app/api/services/spec/scorm-adapter.service.spec.ts rename src/app/tasks/task-comments-viewer/{numbas-comment/numbas-comment.component.html => scorm-comment/scorm-comment.component.html} (65%) rename src/app/tasks/task-comments-viewer/{numbas-comment/numbas-comment.component.scss => scorm-comment/scorm-comment.component.scss} (100%) rename src/app/tasks/task-comments-viewer/{numbas-comment/numbas-comment.component.ts => scorm-comment/scorm-comment.component.ts} (66%) rename src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/{task-definition-numbas/task-definition-numbas.component.html => task-definition-scorm/task-definition-scorm.component.html} (78%) rename src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/{task-definition-numbas/task-definition-numbas.component.scss => task-definition-scorm/task-definition-scorm.component.scss} (100%) rename src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/{task-definition-numbas/task-definition-numbas.component.ts => task-definition-scorm/task-definition-scorm.component.ts} (58%) diff --git a/src/app/api/models/scorm-datamodel.ts b/src/app/api/models/scorm-datamodel.ts index 9454db78f6..7559318eb5 100644 --- a/src/app/api/models/scorm-datamodel.ts +++ b/src/app/api/models/scorm-datamodel.ts @@ -24,7 +24,7 @@ export class ScormDataModel { // console.log(this.msgPrefix + 'set: ', key, value); this.dataModel[key] = value; if (key.match('cmi.interactions.\\d+.id')) { - // cmi.interactions._count must be incremented after a new interaction is crated + // cmi.interactions._count must be incremented after a new interaction is created const interactionPath = key.match('cmi.interactions.\\d+'); const objectivesCounterForInteraction = interactionPath.toString() + '.objectives._count'; console.log('Incrementing cmi.interactions._count'); @@ -41,7 +41,7 @@ export class ScormDataModel { this.dataModel[objectivesCounterForInteraction.toString()]++; } if (key.match('cmi.objectives.\\d+.id')) { - // cmi.objectives._count must be incremented after a new objective is crated + // cmi.objectives._count must be incremented after a new objective is created console.log('Incrementing cmi.objectives._count'); this.dataModel['cmi.objectives._count']++; } diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index 985b810137..538b449338 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -156,7 +156,7 @@ export class TaskDefinition extends Entity { }`; } - public getNumbasTestUrl(asAttachment: boolean = false) { + public getScormDataUrl(asAttachment: boolean = false) { const constants = AppInjector.get(DoubtfireConstants); return `${constants.API_URL}/units/${this.unit.id}/task_definitions/${this.id}/scorm_data.json${ asAttachment ? '?as_attachment=true' : '' @@ -187,7 +187,7 @@ export class TaskDefinition extends Entity { }/task_resources`; } - public get numbasTestUploadUrl(): string { + public get scormDataUploadUrl(): string { return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.unit.id}/task_definitions/${ this.id }/scorm_data`; @@ -215,9 +215,9 @@ export class TaskDefinition extends Entity { return httpClient.delete(this.taskResourcesUploadUrl).pipe(tap(() => (this.hasTaskResources = false))); } - public deleteNumbasTest(): Observable { + public deleteScormData(): Observable { const httpClient = AppInjector.get(HttpClient); - return httpClient.delete(this.numbasTestUploadUrl).pipe(tap(() => (this.hasScormData = false))); + return httpClient.delete(this.scormDataUploadUrl).pipe(tap(() => (this.hasScormData = false))); } public deleteTaskAssessmentResources(): Observable { diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index 3803d325b6..556d0a7dd2 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -507,7 +507,7 @@ export class Task extends Entity { ); } - public get numbasEnabled(): boolean { + public get scormEnabled(): boolean { return ( this.definition.scormEnabled && this.definition.hasScormData ); diff --git a/src/app/api/services/spec/scorm-adapter.service.spec.ts b/src/app/api/services/spec/scorm-adapter.service.spec.ts deleted file mode 100644 index 5d3a52caac..0000000000 --- a/src/app/api/services/spec/scorm-adapter.service.spec.ts +++ /dev/null @@ -1,87 +0,0 @@ -import { TestBed } from '@angular/core/testing'; -import { HttpClientTestingModule, HttpTestingController } from '@angular/common/http/testing'; -import { ScormAdapterService } from '../scorm-adapter.service'; -import { TaskService } from '../task.service'; -import { UserService } from '../user.service'; - -describe('ScormAdapterService', () => { - let service: ScormAdapterService; - let httpTestingController: HttpTestingController; - let mockUserService: Partial; - let mockTaskService: Partial; - - const mockUserData = { - currentUser: { studentId: '12345' } - }; - - beforeEach(() => { - mockUserService = { - currentUser: mockUserData.currentUser - }; - - mockTaskService = { - // you can add mocked methods if needed for the TaskService - }; - - TestBed.configureTestingModule({ - imports: [HttpClientTestingModule], - providers: [ - ScormAdapterService, - { provide: UserService, useValue: mockUserService }, - { provide: TaskService, useValue: mockTaskService } - ] - }); - - service = TestBed.inject(ScormAdapterService); - httpTestingController = TestBed.inject(HttpTestingController); - }); - - afterEach(() => { - httpTestingController.verify(); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); - - it('should initialize with default values', () => { - expect(service.GetValue('cmi.completion_status')).toBe('not attempted'); - expect(service.GetValue('cmi.entry')).toBe('ab-initio'); - }); - - describe('Initialize function', () => { - - it('should handle review mode and get latest completed test result', () => { - const mockResponse = { - data: { - suspend_data: JSON.stringify({ someData: 'value' }) - } - }; - - service.Initialize('review'); - const req = httpTestingController.expectOne(`${service['apiBaseUrl']}/completed-latest`); - expect(req.request.method).toEqual('GET'); - req.flush(mockResponse); - - expect(service.GetValue('cmi.suspend_data')).toEqual(JSON.stringify({ someData: 'value' })); - }); - - it('should handle attempt mode and get latest test result', () => { - const mockResponse = { - data: { - id: 1, - cmi_entry: 'ab-initio', - attempt_number: 2 - } - }; - - service.Initialize('attempt'); - const req = httpTestingController.expectOne(`${service['apiBaseUrl']}/latest`); - expect(req.request.method).toEqual('GET'); - req.flush(mockResponse); - - expect(service.GetValue('cmi.learner_id')).toBe('12345'); - }); - }); - -}); diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index a738626884..defd83dc77 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -134,9 +134,9 @@ export class TaskDefinitionService extends CachedEntityService { return AppInjector.get(HttpClient).post(taskDefinition.taskAssessmentResourcesUploadUrl, formData); } - public uploadNumbasData(taskDefinition: TaskDefinition, file: File): Observable { + public uploadScormData(taskDefinition: TaskDefinition, file: File): Observable { const formData = new FormData(); formData.append('file', file); - return AppInjector.get(HttpClient).post(taskDefinition.numbasTestUploadUrl, formData); + return AppInjector.get(HttpClient).post(taskDefinition.scormDataUploadUrl, formData); } } diff --git a/src/app/common/scorm-player/scorm-player-modal.component.ts b/src/app/common/scorm-player/scorm-player-modal.component.ts index 2fb4630263..cd7740571c 100644 --- a/src/app/common/scorm-player/scorm-player-modal.component.ts +++ b/src/app/common/scorm-player/scorm-player-modal.component.ts @@ -9,7 +9,7 @@ import {Task} from 'src/app/api/models/task'; export class ScormPlayerModal { constructor(public dialog: MatDialog) {} - public show(task: Task, mode: 'attempt' | 'review'): void { + public show(task: Task, mode: 'browse' | 'normal' | 'review'): void { let dialogRef: MatDialogRef; dialogRef = this.dialog.open(ScormPlayerComponent, { diff --git a/src/app/common/scorm-player/scorm-player.component.ts b/src/app/common/scorm-player/scorm-player.component.ts index 1b89e36bae..106e6a8520 100644 --- a/src/app/common/scorm-player/scorm-player.component.ts +++ b/src/app/common/scorm-player/scorm-player.component.ts @@ -21,12 +21,12 @@ export class ScormPlayerComponent implements OnInit { context: ScormPlayerContext; task: Task; - currentMode: 'attempt' | 'review' = 'attempt'; + currentMode: 'browse' | 'normal' | 'review' = 'normal'; iframeSrc: SafeResourceUrl; constructor( private dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: {task: Task; mode: 'attempt' | 'review'}, + @Inject(MAT_DIALOG_DATA) public data: {task: Task, mode: 'browse' | 'normal' | 'review'}, private scormAdapter: ScormAdapterService, private sanitizer: DomSanitizer, ) {} diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 23145ccaea..110ae4a3a2 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -204,7 +204,7 @@ import {TaskDefinitionUploadComponent} from './units/states/edit/directives/unit import {TaskDefinitionOptionsComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component'; import {TaskDefinitionResourcesComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component'; import {TaskDefinitionOverseerComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component'; -import {TaskDefinitionNumbasComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-numbas/task-definition-numbas.component'; +import {TaskDefinitionScormComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component'; import {UnitAnalyticsComponent} from './units/states/analytics/unit-analytics-route.component'; import {FileDropComponent} from './common/file-drop/file-drop.component'; import {UnitTaskEditorComponent} from './units/states/edit/directives/unit-tasks-editor/unit-task-editor.component'; @@ -228,7 +228,7 @@ import {UnitCodeComponent} from './common/unit-code/unit-code.component'; import {GradeService} from './common/services/grade.service'; import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component'; import {ScormAdapterService} from './api/services/scorm-adapter.service'; -import {NumbasCommentComponent} from './tasks/task-comments-viewer/numbas-comment/numbas-comment.component'; +import {ScormCommentComponent} from './tasks/task-comments-viewer/scorm-comment/scorm-comment.component'; import {TestAttemptService} from './api/services/test-attempt.service'; @NgModule({ @@ -268,7 +268,7 @@ import {TestAttemptService} from './api/services/test-attempt.service'; TaskDefinitionOptionsComponent, TaskDefinitionResourcesComponent, TaskDefinitionOverseerComponent, - TaskDefinitionNumbasComponent, + TaskDefinitionScormComponent, UnitAnalyticsComponent, StudentTutorialSelectComponent, StudentCampusSelectComponent, @@ -333,7 +333,7 @@ import {TestAttemptService} from './api/services/test-attempt.service'; FTaskBadgeComponent, FUnitsComponent, ScormPlayerComponent, - NumbasCommentComponent, + ScormCommentComponent, ], // Services we provide providers: [ diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee index 7c0baf7ee9..976c116f33 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee @@ -157,7 +157,7 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) $scope.launchScormPlayer = -> console.clear() - ScormPlayerModal.show $scope.task, 'attempt' + ScormPlayerModal.show $scope.task, 'normal' # Whether or not we should disable this button $scope.shouldDisableBtn = { diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html index 8b6c89bea3..0b296c2099 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html @@ -50,15 +50,15 @@

- Attempt Numbas Test + Attempt SCORM Test

- Complete the Numbas test first to proceed to upload evidence of your task completion. + Complete the SCORM test first to proceed to upload evidence of your task completion.
diff --git a/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.html b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html similarity index 65% rename from src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.html rename to src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html index d87863bee8..b74db43a07 100644 --- a/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.html +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html @@ -1,9 +1,9 @@
-
+
- +
diff --git a/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.scss b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.scss similarity index 100% rename from src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.scss rename to src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.scss diff --git a/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts similarity index 66% rename from src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts rename to src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts index c8ba676c55..817a6cd64f 100644 --- a/src/app/tasks/task-comments-viewer/numbas-comment/numbas-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts @@ -3,11 +3,11 @@ import {Task, TaskComment} from 'src/app/api/models/doubtfire-model'; import {ScormPlayerModal} from 'src/app/common/scorm-player/scorm-player-modal.component'; @Component({ - selector: 'numbas-comment', - templateUrl: './numbas-comment.component.html', - styleUrls: ['./numbas-comment.component.scss'], + selector: 'scorm-comment', + templateUrl: './scorm-comment.component.html', + styleUrls: ['./scorm-comment.component.scss'], }) -export class NumbasCommentComponent implements OnInit { +export class ScormCommentComponent implements OnInit { @Input() task: Task; @Input() comment: TaskComment; @@ -15,7 +15,7 @@ export class NumbasCommentComponent implements OnInit { ngOnInit() {} - reviewNumbasTest() { + reviewScormTest() { this.modalService.show(this.task, 'review'); } } diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html index 0be0e7b758..aa20275ff6 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html @@ -72,12 +72,12 @@ >
-
- + + *ngIf="scormEnabled" + >
diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts index 7436cd7d79..8ad719f339 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts @@ -98,8 +98,8 @@ export class TaskCommentsViewerComponent implements OnChanges, OnInit { return this.constants.IsOverseerEnabled.value; } - get numbasEnabled(): boolean { - return this.task.numbasEnabled; + get scormEnabled(): boolean { + return this.task.scormEnabled; } uploadFiles(event) { @@ -154,7 +154,7 @@ export class TaskCommentsViewerComponent implements OnChanges, OnInit { } shouldShowAuthorIcon(commentType: string) { - return !(commentType === 'extension' || commentType === 'status' || commentType == 'assessment' || commentType == 'numbas'); + return !(commentType === 'extension' || commentType === 'status' || commentType == 'assessment' || commentType == 'scorm'); } commentClasses(comment: TaskComment): object { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html index bd2c7ec65d..6bc386569e 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html @@ -105,10 +105,10 @@

-

Upload Numbas test

-

Upload the corresponding Numbas test

+

Upload SCORM test

+

Upload the corresponding SCORM 2004 test (e.g. Numbas)

- +

diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-numbas/task-definition-numbas.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html similarity index 78% rename from src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-numbas/task-definition-numbas.component.html rename to src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html index 36acb4ca4c..433405669b 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-numbas/task-definition-numbas.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html @@ -1,22 +1,22 @@
- Enable Numbas Test + Enable test for task
@if (taskDefinition.hasScormData) {
- -
} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-numbas/task-definition-numbas.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.scss similarity index 100% rename from src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-numbas/task-definition-numbas.component.scss rename to src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.scss diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-numbas/task-definition-numbas.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts similarity index 58% rename from src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-numbas/task-definition-numbas.component.ts rename to src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts index f6687a4af9..8f2b72fcb9 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-numbas/task-definition-numbas.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts @@ -7,11 +7,11 @@ import { TaskDefinitionService } from 'src/app/api/services/task-definition.serv import { FileDownloaderService } from 'src/app/common/file-downloader/file-downloader.service'; @Component({ - selector: 'f-task-definition-numbas', - templateUrl: 'task-definition-numbas.component.html', - styleUrls: ['task-definition-numbas.component.scss'], + selector: 'f-task-definition-scorm', + templateUrl: 'task-definition-scorm.component.html', + styleUrls: ['task-definition-scorm.component.scss'], }) -export class TaskDefinitionNumbasComponent { +export class TaskDefinitionScormComponent { @Input() taskDefinition: TaskDefinition; constructor( @@ -26,32 +26,32 @@ export class TaskDefinitionNumbasComponent { return this.taskDefinition?.unit; } - public downloadNumbasTest() { + public downloadScormData() { this.fileDownloaderService.downloadFile( - this.taskDefinition.getNumbasTestUrl(true), - this.taskDefinition.name + '-Numbas.zip', + this.taskDefinition.getScormDataUrl(true), + this.taskDefinition.name + '-SCORM.zip', ); } - public removeNumbasTest() { - this.taskDefinition.deleteNumbasTest().subscribe({ - next: () => this.alerts.add('success', 'Deleted Numbas test', 2000), - error: (message) => this.alerts.add('danger', message, 6000), + public removeScormData() { + this.taskDefinition.deleteScormData().subscribe({ + next: () => this.alerts.success('Deleted SCORM test data', 2000), + error: (message) => this.alerts.error(message, 6000), }); } - public uploadNumbasTest(files: FileList) { + public uploadScormData(files: FileList) { console.log(Array.from(files).map(f => f.type)); const validMimeTypes = ['application/zip', 'application/x-zip-compressed', 'multipart/x-zip']; const validFiles = Array.from(files as ArrayLike).filter(f => validMimeTypes.includes(f.type)); if (validFiles.length > 0) { const file = validFiles[0]; - this.taskDefinitionService.uploadNumbasData(this.taskDefinition, file).subscribe({ - next: () => this.alerts.add('success', 'Uploaded Numbas test data', 2000), - error: (message) => this.alerts.add('danger', message, 6000), + this.taskDefinitionService.uploadScormData(this.taskDefinition, file).subscribe({ + next: () => this.alerts.success('Uploaded SCORM test data', 2000), + error: (message) => this.alerts.error(message, 6000), }); } else { - this.alerts.add('danger', 'Please drop a zip file to upload Numbas test data for this task', 6000); + this.alerts.error('Please drop a zip file to upload SCORM test data for this task', 6000); } } } From 2ac487f13c3743f2b5b805521964bdcbca7cdc15 Mon Sep 17 00:00:00 2001 From: ublefo <90136978+ublefo@users.noreply.github.com> Date: Tue, 14 May 2024 13:25:23 +1000 Subject: [PATCH 0078/1280] fix: ensure datamodel is updated on termination --- src/app/api/services/scorm-adapter.service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/api/services/scorm-adapter.service.ts b/src/app/api/services/scorm-adapter.service.ts index 8886121031..9519f4cc2c 100644 --- a/src/app/api/services/scorm-adapter.service.ts +++ b/src/app/api/services/scorm-adapter.service.ts @@ -129,6 +129,7 @@ export class ScormAdapterService { ); this.xhr.setRequestHeader('Content-Type', 'application/json'); const requestData = { + cmi_datamodel: JSON.stringify(this.dataModel.dump()), terminated: true, }; this.xhr.send(JSON.stringify(requestData)); From fc023af462656e3557e2970f211fa4d59ee1e3d5 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 14 May 2024 14:24:31 +1000 Subject: [PATCH 0079/1280] feat: allow changing scorm review config and add minor UI changes --- src/app/api/models/task-definition.ts | 1 + .../api/services/task-definition.service.ts | 1 + .../task-definition-editor.component.html | 2 +- .../task-definition-scorm.component.html | 49 ++++++++++--------- 4 files changed, 30 insertions(+), 23 deletions(-) diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index 538b449338..ca2d188eb6 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -33,6 +33,7 @@ export class TaskDefinition extends Entity { hasTaskResources: boolean; scormEnabled: boolean; hasScormData: boolean; + scormAllowReview: boolean; scormTimeDelayEnabled: boolean; scormAttemptLimit: number = 0; hasTaskAssessmentResources: boolean; diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index defd83dc77..3776432fd8 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -95,6 +95,7 @@ export class TaskDefinitionService extends CachedEntityService { 'hasTaskAssessmentResources', 'scormEnabled', 'hasScormData', + 'scormAllowReview', 'scormTimeDelayEnabled', 'scormAttemptLimit', 'isGraded', diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html index 6bc386569e..bf75eda5b5 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html @@ -105,7 +105,7 @@

-

Upload SCORM test

+

SCORM test

Upload the corresponding SCORM 2004 test (e.g. Numbas)

diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html index 433405669b..5b3b54c111 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html @@ -3,30 +3,35 @@ Enable test for task -
- - @if (taskDefinition.hasScormData) { -
- - -
- } -
- @if (taskDefinition.scormEnabled) { +
+ + @if (taskDefinition.hasScormData) { +
+ + +
+ } +
+
- - Enable incremental time delays between test attempts - +
+ + Enable incremental time delays between test attempts + + + Allow students to review completed test attempt + +
Attempt limit Date: Tue, 14 May 2024 14:29:48 +1000 Subject: [PATCH 0080/1280] refactor: remove test attempt model and service --- src/app/api/models/test-attempt.ts | 22 ----------- src/app/api/services/test-attempt.service.ts | 40 -------------------- src/app/doubtfire-angular.module.ts | 2 - src/app/doubtfire-angularjs.module.ts | 2 - 4 files changed, 66 deletions(-) delete mode 100644 src/app/api/models/test-attempt.ts delete mode 100644 src/app/api/services/test-attempt.service.ts diff --git a/src/app/api/models/test-attempt.ts b/src/app/api/models/test-attempt.ts deleted file mode 100644 index e6f2e5d61d..0000000000 --- a/src/app/api/models/test-attempt.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { Entity } from "ngx-entity-service"; -import { Task } from "./task"; - -export class TestAttempt extends Entity { - public id: number; - name: string; - attemptNumber: number; - passStatus: boolean; - suspendData: string; - completed: boolean; - cmiEntry: string; - examResult: string; - attemptedAt: Date; - taskId: number; - - task: Task; - - constructor(task: Task) { - super(); - this.task = task; - } -} diff --git a/src/app/api/services/test-attempt.service.ts b/src/app/api/services/test-attempt.service.ts deleted file mode 100644 index 094f2baa0c..0000000000 --- a/src/app/api/services/test-attempt.service.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Injectable } from "@angular/core"; -import { EntityService } from "ngx-entity-service"; -import { TestAttempt } from "../models/test-attempt"; -import { HttpClient } from "@angular/common/http"; -import API_URL from "src/app/config/constants/apiURL"; -import { Task } from "../models/task"; -import { Observable } from "rxjs"; -import { AppInjector } from "src/app/app-injector"; -import { DoubtfireConstants } from "src/app/config/constants/doubtfire-constants"; - -@Injectable() -export class TestAttemptService extends EntityService { - protected readonly endpointFormat = '/test_attempts?id=:id:'; - - constructor(httpClient: HttpClient) { - super(httpClient, API_URL); - - this.mapping.addKeys( - 'id', - 'name', - 'attemptNumber', - 'passStatus', - 'suspendData', - 'completed', - 'cmiEntry', - 'examResult', - 'attemptedAt', - 'taskId' - ); - } - - public createInstanceFrom(json: object, other?: any): TestAttempt { - return new TestAttempt(other as Task); - } - - public getLatestCompletedTestAttempt(task: Task): Observable { - const url = `${AppInjector.get(DoubtfireConstants).API_URL}/test_attempts/completed-latest?task_id=${task.id}`; - return AppInjector.get(HttpClient).get(url); - } -} \ No newline at end of file diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 110ae4a3a2..f464c6c13d 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -229,7 +229,6 @@ import {GradeService} from './common/services/grade.service'; import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component'; import {ScormAdapterService} from './api/services/scorm-adapter.service'; import {ScormCommentComponent} from './tasks/task-comments-viewer/scorm-comment/scorm-comment.component'; -import {TestAttemptService} from './api/services/test-attempt.service'; @NgModule({ // Components we declare @@ -407,7 +406,6 @@ import {TestAttemptService} from './api/services/test-attempt.service'; CreateNewUnitModal, ScormPlayerModalProvider, ScormAdapterService, - TestAttemptService, provideLottieOptions({ player: () => player, }), diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 3cd6555bd8..eb119b464b 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -227,7 +227,6 @@ import {AlertService} from './common/services/alert.service'; import {GradeService} from './common/services/grade.service'; import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component'; import {ScormPlayerModal} from './common/scorm-player/scorm-player-modal.component'; -import {TestAttemptService} from './api/services/test-attempt.service'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -311,7 +310,6 @@ DoubtfireAngularJSModule.factory( ); DoubtfireAngularJSModule.factory('CreateNewUnitModal', downgradeInjectable(CreateNewUnitModal)); DoubtfireAngularJSModule.factory('ScormPlayerModal', downgradeInjectable(ScormPlayerModal)); -DoubtfireAngularJSModule.factory('testAttemptService', downgradeInjectable(TestAttemptService)); // directive -> component DoubtfireAngularJSModule.directive( From ce53396ab93a98b30a78d9259849262bcec5e9ff Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Wed, 15 May 2024 17:39:20 +1000 Subject: [PATCH 0081/1280] refactor: use task card and new tab for scorm and match comment display --- src/app/ajs-upgraded-providers.ts | 7 --- src/app/api/models/scorm-player-context.ts | 4 +- src/app/api/services/scorm-adapter.service.ts | 20 +++++---- .../scorm-player-modal.component.ts | 22 ---------- .../scorm-player/scorm-player.component.html | 5 +-- .../scorm-player/scorm-player.component.scss | 12 ++---- .../scorm-player/scorm-player.component.ts | 43 +++++++++++-------- src/app/doubtfire-angular.module.ts | 4 +- src/app/doubtfire-angularjs.module.ts | 13 +++--- src/app/doubtfire.states.ts | 30 +++++++++++++ .../task-scorm-card.component.html | 27 ++++++++++++ .../task-scorm-card.component.scss | 0 .../task-scorm-card.component.ts | 31 +++++++++++++ .../task-dashboard/task-dashboard.tpl.html | 1 + .../upload-submission-modal.coffee | 9 +--- .../upload-submission-modal.tpl.html | 20 --------- .../scorm-comment.component.html | 5 ++- .../scorm-comment/scorm-comment.component.ts | 5 +-- 18 files changed, 147 insertions(+), 111 deletions(-) delete mode 100644 src/app/common/scorm-player/scorm-player-modal.component.ts create mode 100644 src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html create mode 100644 src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.scss create mode 100644 src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts diff --git a/src/app/ajs-upgraded-providers.ts b/src/app/ajs-upgraded-providers.ts index f114da1c79..795869225d 100644 --- a/src/app/ajs-upgraded-providers.ts +++ b/src/app/ajs-upgraded-providers.ts @@ -18,7 +18,6 @@ export const rootScope = new InjectionToken('$rootScope'); export const calendarModal = new InjectionToken('CalendarModal'); export const aboutDoubtfireModal = new InjectionToken('AboutDoubtfireModal'); export const plagiarismReportModal = new InjectionToken('PlagiarismReportModal'); -export const scormPlayerModal = new InjectionToken('ScormPlayerModal'); // Define a provider for the above injection token... // It will get the service from AngularJS via the factory @@ -117,9 +116,3 @@ export const UnitStudentEnrolmentModalProvider = { useFactory: (i) => i.get('UnitStudentEnrolmentModal'), deps: ['$injector'], }; - -export const ScormPlayerModalProvider = { - provide: scormPlayerModal, - useFactory: (i) => i.get('ScormPlayerModal'), - deps: ['$injector'], -}; diff --git a/src/app/api/models/scorm-player-context.ts b/src/app/api/models/scorm-player-context.ts index f3b3b8a13f..ed7df07c0a 100644 --- a/src/app/api/models/scorm-player-context.ts +++ b/src/app/api/models/scorm-player-context.ts @@ -1,4 +1,4 @@ -import {Task, User} from 'src/app/api/models/doubtfire-model'; +import {User} from 'src/app/api/models/doubtfire-model'; type DataModelState = 'Uninitialized' | 'Initialized' | 'Terminated'; @@ -48,7 +48,7 @@ export class ScormPlayerContext { return CMIErrorCodes[value]; } - task: Task; + taskId: number; user: User; attemptNumber: number; diff --git a/src/app/api/services/scorm-adapter.service.ts b/src/app/api/services/scorm-adapter.service.ts index 9519f4cc2c..cb6a780952 100644 --- a/src/app/api/services/scorm-adapter.service.ts +++ b/src/app/api/services/scorm-adapter.service.ts @@ -1,7 +1,7 @@ import {Injectable} from '@angular/core'; import {UserService} from './user.service'; import API_URL from 'src/app/config/constants/apiURL'; -import {Task, ScormDataModel, ScormPlayerContext} from 'src/app/api/models/doubtfire-model'; +import {ScormDataModel, ScormPlayerContext} from 'src/app/api/models/doubtfire-model'; @Injectable({ providedIn: 'root', @@ -18,8 +18,12 @@ export class ScormAdapterService { this.xhr = new XMLHttpRequest(); } - set task(task: Task) { - this.context.task = task; + set taskId(taskId: number) { + this.context.taskId = taskId; + } + + set mode(mode: 'browse' | 'normal' | 'review') { + this.context.mode = mode; } get state() { @@ -47,7 +51,7 @@ export class ScormAdapterService { } // TODO: move this part into the player component - this.xhr.open('GET', `${this.apiBaseUrl}/${this.context.task.id}/latest`, false); + this.xhr.open('GET', `${this.apiBaseUrl}/${this.context.taskId}/latest`, false); let noTestFound = false; let startNewTest = false; @@ -80,7 +84,7 @@ export class ScormAdapterService { if (!startNewTest) { this.xhr.open( 'PATCH', - `${this.apiBaseUrl}/${this.context.task.id}/session/${this.context.attemptId}`, + `${this.apiBaseUrl}/${this.context.taskId}/session/${this.context.attemptId}`, false, ); this.xhr.send(); @@ -92,7 +96,7 @@ export class ScormAdapterService { this.dataModel.restore(currentSession.cmi_datamodel); console.log(this.dataModel.dump()); } else { - this.xhr.open('POST', `${this.apiBaseUrl}/${this.context.task.id}/session`, false); + this.xhr.open('POST', `${this.apiBaseUrl}/${this.context.taskId}/session`, false); this.xhr.send(); console.log(this.xhr.responseText); @@ -124,7 +128,7 @@ export class ScormAdapterService { this.xhr.open( 'PATCH', - `${this.apiBaseUrl}/${this.context.task.id}/session/${this.context.attemptId}`, + `${this.apiBaseUrl}/${this.context.taskId}/session/${this.context.attemptId}`, false, ); this.xhr.setRequestHeader('Content-Type', 'application/json'); @@ -200,7 +204,7 @@ export class ScormAdapterService { const xhr = new XMLHttpRequest(); xhr.open( 'PATCH', - `${this.apiBaseUrl}/${this.context.task.id}/session/${this.context.attemptId}`, + `${this.apiBaseUrl}/${this.context.taskId}/session/${this.context.attemptId}`, true, ); xhr.setRequestHeader('Content-Type', 'application/json'); diff --git a/src/app/common/scorm-player/scorm-player-modal.component.ts b/src/app/common/scorm-player/scorm-player-modal.component.ts deleted file mode 100644 index cd7740571c..0000000000 --- a/src/app/common/scorm-player/scorm-player-modal.component.ts +++ /dev/null @@ -1,22 +0,0 @@ -import {Injectable} from '@angular/core'; -import {MatDialog, MatDialogRef} from '@angular/material/dialog'; -import {ScormPlayerComponent} from './scorm-player.component'; -import {Task} from 'src/app/api/models/task'; - -@Injectable({ - providedIn: 'root', -}) -export class ScormPlayerModal { - constructor(public dialog: MatDialog) {} - - public show(task: Task, mode: 'browse' | 'normal' | 'review'): void { - let dialogRef: MatDialogRef; - - dialogRef = this.dialog.open(ScormPlayerComponent, { - data: {task, mode}, - width: '95%', - height: '90%', - disableClose: true, - }); - } -} diff --git a/src/app/common/scorm-player/scorm-player.component.html b/src/app/common/scorm-player/scorm-player.component.html index 5089ad9de3..4855cf4d2b 100644 --- a/src/app/common/scorm-player/scorm-player.component.html +++ b/src/app/common/scorm-player/scorm-player.component.html @@ -1,4 +1 @@ -
- - -
+ diff --git a/src/app/common/scorm-player/scorm-player.component.scss b/src/app/common/scorm-player/scorm-player.component.scss index 5e24cc5d9e..f011d35aee 100644 --- a/src/app/common/scorm-player/scorm-player.component.scss +++ b/src/app/common/scorm-player/scorm-player.component.scss @@ -1,5 +1,7 @@ -.mat-dialog-content { +f-scorm-player { position: relative; + height: 100vh; + width: 100vw; } iframe { @@ -7,11 +9,5 @@ iframe { top: 0; left: 0; width: 100%; - height: 95%; + height: 100%; } - -button { - position: absolute; - bottom: 20px; - right: 20px; -} \ No newline at end of file diff --git a/src/app/common/scorm-player/scorm-player.component.ts b/src/app/common/scorm-player/scorm-player.component.ts index 106e6a8520..e1c68dc872 100644 --- a/src/app/common/scorm-player/scorm-player.component.ts +++ b/src/app/common/scorm-player/scorm-player.component.ts @@ -1,10 +1,10 @@ -import {Component, OnInit, Inject} from '@angular/core'; -import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {Component, OnInit, Input, HostListener} from '@angular/core'; import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser'; -import {Task, ScormPlayerContext} from 'src/app/api/models/doubtfire-model'; +import {ScormPlayerContext} from 'src/app/api/models/doubtfire-model'; import {ScormAdapterService} from 'src/app/api/services/scorm-adapter.service'; import {AppInjector} from 'src/app/app-injector'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global-state.service'; declare global { interface Window { @@ -20,20 +20,29 @@ declare global { export class ScormPlayerComponent implements OnInit { context: ScormPlayerContext; - task: Task; - currentMode: 'browse' | 'normal' | 'review' = 'normal'; + @Input() + taskId: number; + + @Input() + taskDefId: number; + + @Input() + mode: 'browse' | 'normal' | 'review'; + iframeSrc: SafeResourceUrl; constructor( - private dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: {task: Task, mode: 'browse' | 'normal' | 'review'}, + private globalState: GlobalStateService, private scormAdapter: ScormAdapterService, private sanitizer: DomSanitizer, ) {} ngOnInit(): void { - this.task = this.data.task; - this.scormAdapter.task = this.task; + this.globalState.setView(ViewType.OTHER); + this.globalState.hideHeader(); + + this.scormAdapter.taskId = this.taskId; + this.scormAdapter.mode = this.mode; window.API_1484_11 = { Initialize: () => this.scormAdapter.Initialize(), @@ -46,23 +55,21 @@ export class ScormPlayerComponent implements OnInit { GetDiagnostic: (errorCode: string) => this.scormAdapter.GetDiagnostic(errorCode), }; - this.currentMode = this.data.mode; - this.iframeSrc = this.sanitizer.bypassSecurityTrustResourceUrl( - `${AppInjector.get(DoubtfireConstants).API_URL}/scorm/${this.task.taskDefId}/index.html`, + `${AppInjector.get(DoubtfireConstants).API_URL}/scorm/${this.taskDefId}/index.html`, ); } - close(): void { + @HostListener('window:beforeunload', ['$event']) + beforeUnload($event: any): void { if (this.scormAdapter.state == 'Initialized') { console.log('SCORM player closing during an initialized session, commiting DataModel'); this.scormAdapter.Commit(); } - // TODO: would be nice if we can destroy this entire adapter object when the modal is closed - console.log('Clearing player context and DataModel'); + } + + @HostListener('window:unload', ['$event']) + onUnload($event: any): void { this.scormAdapter.destroy(); - const iframe = document.getElementsByTagName('iframe')[0]; - iframe?.parentNode?.removeChild(iframe); - this.dialogRef.close(); } } diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index f464c6c13d..dabcd49145 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -72,7 +72,6 @@ import { gradeTaskModalProvider, uploadSubmissionModalProvider, ConfirmationModalProvider, - ScormPlayerModalProvider, } from './ajs-upgraded-providers'; import { TaskCommentComposerComponent, @@ -229,6 +228,7 @@ import {GradeService} from './common/services/grade.service'; import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component'; import {ScormAdapterService} from './api/services/scorm-adapter.service'; import {ScormCommentComponent} from './tasks/task-comments-viewer/scorm-comment/scorm-comment.component'; +import {TaskScormCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component'; @NgModule({ // Components we declare @@ -333,6 +333,7 @@ import {ScormCommentComponent} from './tasks/task-comments-viewer/scorm-comment/ FUnitsComponent, ScormPlayerComponent, ScormCommentComponent, + TaskScormCardComponent, ], // Services we provide providers: [ @@ -404,7 +405,6 @@ import {ScormCommentComponent} from './tasks/task-comments-viewer/scorm-comment/ TasksForInboxSearchPipe, IsActiveUnitRole, CreateNewUnitModal, - ScormPlayerModalProvider, ScormAdapterService, provideLottieOptions({ player: () => player, diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index eb119b464b..bc5ad5ed4a 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -225,8 +225,7 @@ import {FUnitsComponent} from './admin/states/f-units/f-units.component'; import {MarkedPipe} from './common/pipes/marked.pipe'; import {AlertService} from './common/services/alert.service'; import {GradeService} from './common/services/grade.service'; -import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component'; -import {ScormPlayerModal} from './common/scorm-player/scorm-player-modal.component'; +import {TaskScormCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -309,7 +308,6 @@ DoubtfireAngularJSModule.factory( downgradeInjectable(EditProfileDialogService), ); DoubtfireAngularJSModule.factory('CreateNewUnitModal', downgradeInjectable(CreateNewUnitModal)); -DoubtfireAngularJSModule.factory('ScormPlayerModal', downgradeInjectable(ScormPlayerModal)); // directive -> component DoubtfireAngularJSModule.directive( @@ -367,6 +365,10 @@ DoubtfireAngularJSModule.directive( 'activityTypeList', downgradeComponent({component: ActivityTypeListComponent}), ); +DoubtfireAngularJSModule.directive( + 'fTaskScormCard', + downgradeComponent({component: TaskScormCardComponent}), +); DoubtfireAngularJSModule.directive( 'fTaskStatusCard', downgradeComponent({component: TaskStatusCardComponent}), @@ -444,11 +446,6 @@ DoubtfireAngularJSModule.directive( ); DoubtfireAngularJSModule.directive('fUnits', downgradeComponent({component: FUnitsComponent})); -DoubtfireAngularJSModule.directive( - 'fScormPlayerComponent', - downgradeComponent({component: ScormPlayerComponent}), -); - // Global configuration DoubtfireAngularJSModule.directive( 'taskCommentsViewer', diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index b9f95e88af..23b60886d6 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -8,6 +8,7 @@ import {TeachingPeriodListComponent} from './admin/states/teaching-periods/teach import {AcceptEulaComponent} from './eula/accept-eula/accept-eula.component'; import {FUsersComponent} from './admin/states/f-users/f-users.component'; import {FUnitsComponent} from './admin/states/f-units/f-units.component'; +import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component'; /* * Use this file to store any states that are sourced by angular components. @@ -291,6 +292,34 @@ const ViewAllUnits: NgHybridStateDeclaration = { }, }; +/** + * Define the SCORM Player state. + */ +const ScormPlayerState: NgHybridStateDeclaration = { + name: 'scorm-player', + url: '/task_def/:task_def_id/task/:task_id/scorm-player/:mode', + resolve: { + taskId: function ($stateParams) { + return $stateParams.task_id; + }, + taskDefId: function ($stateParams) { + return $stateParams.task_def_id; + }, + mode: function ($stateParams) { + return $stateParams.mode; + }, + }, + views: { + main: { + component: ScormPlayerComponent, + }, + }, + data: { + pageTitle: 'Knowledge Check', + roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin'], + }, +}; + /** * Export the list of states we have created in angular */ @@ -306,4 +335,5 @@ export const doubtfireStates = [ ViewAllProjectsState, ViewAllUnits, AdministerUnits, + ScormPlayerState, ]; diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html new file mode 100644 index 0000000000..67265461cd --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html @@ -0,0 +1,27 @@ + + + Knowledge Check + + +

+ You have to successfully pass this knowledge check to complete the task. +

+

+ You have {{ (task.definition.scormAttemptLimit > 0) ? task.definition.scormAttemptLimit : 'unlimited' }} attempts to complete this test. +

+

+ There will be an increased time delay between test attempts. First 2 attempts will not have a time delay in between. +

+
+ + + + +
diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.scss b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts new file mode 100644 index 0000000000..7d7dce6e1b --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts @@ -0,0 +1,31 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {Task} from 'src/app/api/models/task'; +import {TaskService} from 'src/app/api/services/task.service'; + +@Component({ + selector: 'f-task-scorm-card', + templateUrl: './task-scorm-card.component.html', + styleUrls: ['./task-scorm-card.component.scss'], +}) +export class TaskScormCardComponent implements OnInit { + @Input() task: Task; + attemptsLeft: number; + + constructor( + private taskService: TaskService, + ) {} + + ngOnInit(): void { + if (this.task) { + + } + } + + launchScormPlayer(): void { + window.open(`#/task_def/${this.task.taskDefId}/task/${this.task.id}/scorm-player/normal`, '_blank'); + } + + requestMoreAttempts(): void { + + } +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html index 0962ddd82a..8402f4252c 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html @@ -42,6 +42,7 @@
+ diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee index 976c116f33..b9c9ebd2b9 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee @@ -32,7 +32,7 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) UploadSubmissionModal ) -.controller('UploadSubmissionModalCtrl', ($scope, $rootScope, $timeout, $modalInstance, ScormPlayerModal, newTaskService, newProjectService, task, reuploadEvidence, outcomeService, PrivacyPolicy) -> +.controller('UploadSubmissionModalCtrl', ($scope, $rootScope, $timeout, $modalInstance, newTaskService, newProjectService, task, reuploadEvidence, outcomeService, PrivacyPolicy) -> $scope.privacyPolicy = PrivacyPolicy # Expose task to scope $scope.task = task @@ -100,7 +100,7 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) # States functionality states = { # All possible states - all: ['group', 'scorm-assessment', 'files', 'alignment', 'comments', 'uploading'] + all: ['group', 'files', 'alignment', 'comments', 'uploading'] # Only states which are shown (populated in initialise) shown: [] # The currently active state (set in initialise) @@ -128,7 +128,6 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) removed.push('group') if !isRFF || !task.isGroupTask() removed.push('alignment') if !isRFF || !task.unit.ilos.length > 0 removed.push('comments') if isTestSubmission - removed.push('scorm-assessment') if !isRFF || !task.definition.scormEnabled removed # Initialises the states initialise: -> @@ -155,10 +154,6 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) previous: states.previous } - $scope.launchScormPlayer = -> - console.clear() - ScormPlayerModal.show $scope.task, 'normal' - # Whether or not we should disable this button $scope.shouldDisableBtn = { next: -> diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html index 0b296c2099..9caab7897e 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html @@ -43,26 +43,6 @@

-
-
-
-

- Attempt SCORM Test -

- - Complete the SCORM test first to proceed to upload evidence of your task completion. - -
-
- -
-
-
diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html index b74db43a07..ffe375f19d 100644 --- a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html @@ -1,9 +1,10 @@
-
+
- + +

diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts index 817a6cd64f..b584629668 100644 --- a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts @@ -1,6 +1,5 @@ import {Component, OnInit, Input} from '@angular/core'; import {Task, TaskComment} from 'src/app/api/models/doubtfire-model'; -import {ScormPlayerModal} from 'src/app/common/scorm-player/scorm-player-modal.component'; @Component({ selector: 'scorm-comment', @@ -11,11 +10,11 @@ export class ScormCommentComponent implements OnInit { @Input() task: Task; @Input() comment: TaskComment; - constructor(private modalService: ScormPlayerModal) {} + constructor() {} ngOnInit() {} reviewScormTest() { - this.modalService.show(this.task, 'review'); + window.open(`#/task_def/${this.task.taskDefId}/task/${this.task.id}/scorm-player/review`, '_blank'); } } From c022c925bc8b569a416c24696b54580248413001 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sat, 1 Jun 2024 20:14:54 +1000 Subject: [PATCH 0082/1280] refactor: change url params for test attempts --- src/app/api/models/scorm-player-context.ts | 3 +- src/app/api/services/scorm-adapter.service.ts | 39 +++++++++---------- .../scorm-player/scorm-player.component.ts | 5 ++- src/app/doubtfire.states.ts | 8 ++-- .../task-scorm-card.component.ts | 5 ++- .../scorm-comment/scorm-comment.component.ts | 5 ++- 6 files changed, 36 insertions(+), 29 deletions(-) diff --git a/src/app/api/models/scorm-player-context.ts b/src/app/api/models/scorm-player-context.ts index ed7df07c0a..c065957ac0 100644 --- a/src/app/api/models/scorm-player-context.ts +++ b/src/app/api/models/scorm-player-context.ts @@ -48,7 +48,8 @@ export class ScormPlayerContext { return CMIErrorCodes[value]; } - taskId: number; + projectId: number; + taskDefId: number; user: User; attemptNumber: number; diff --git a/src/app/api/services/scorm-adapter.service.ts b/src/app/api/services/scorm-adapter.service.ts index cb6a780952..233c7aed6a 100644 --- a/src/app/api/services/scorm-adapter.service.ts +++ b/src/app/api/services/scorm-adapter.service.ts @@ -7,7 +7,6 @@ import {ScormDataModel, ScormPlayerContext} from 'src/app/api/models/doubtfire-m providedIn: 'root', }) export class ScormAdapterService { - private readonly apiBaseUrl = `${API_URL}/test_attempts`; private dataModel: ScormDataModel; private context: ScormPlayerContext; private xhr: XMLHttpRequest; @@ -18,8 +17,12 @@ export class ScormAdapterService { this.xhr = new XMLHttpRequest(); } - set taskId(taskId: number) { - this.context.taskId = taskId; + set projectId(projectId: number) { + this.context.projectId = projectId; + } + + set taskDefId(taskDefId: number) { + this.context.taskDefId = taskDefId; } set mode(mode: 'browse' | 'normal' | 'review') { @@ -51,7 +54,11 @@ export class ScormAdapterService { } // TODO: move this part into the player component - this.xhr.open('GET', `${this.apiBaseUrl}/${this.context.taskId}/latest`, false); + this.xhr.open( + 'GET', + `${API_URL}/projects/${this.context.projectId}/task_def_id/${this.context.taskDefId}/test_attempts/latest`, + false, + ); let noTestFound = false; let startNewTest = false; @@ -82,11 +89,7 @@ export class ScormAdapterService { } if (!startNewTest) { - this.xhr.open( - 'PATCH', - `${this.apiBaseUrl}/${this.context.taskId}/session/${this.context.attemptId}`, - false, - ); + this.xhr.open('PATCH', `${API_URL}/test_attempts/${this.context.attemptId}`, false); this.xhr.send(); console.log(this.xhr.responseText); @@ -96,7 +99,11 @@ export class ScormAdapterService { this.dataModel.restore(currentSession.cmi_datamodel); console.log(this.dataModel.dump()); } else { - this.xhr.open('POST', `${this.apiBaseUrl}/${this.context.taskId}/session`, false); + this.xhr.open( + 'POST', + `${API_URL}/projects/${this.context.projectId}/task_def_id/${this.context.taskDefId}/test_attempts`, + false, + ); this.xhr.send(); console.log(this.xhr.responseText); @@ -126,11 +133,7 @@ export class ScormAdapterService { break; } - this.xhr.open( - 'PATCH', - `${this.apiBaseUrl}/${this.context.taskId}/session/${this.context.attemptId}`, - false, - ); + this.xhr.open('PATCH', `${API_URL}/test_attempts/${this.context.attemptId}`, false); this.xhr.setRequestHeader('Content-Type', 'application/json'); const requestData = { cmi_datamodel: JSON.stringify(this.dataModel.dump()), @@ -202,11 +205,7 @@ export class ScormAdapterService { } const xhr = new XMLHttpRequest(); - xhr.open( - 'PATCH', - `${this.apiBaseUrl}/${this.context.taskId}/session/${this.context.attemptId}`, - true, - ); + xhr.open('PATCH', `${API_URL}/test_attempts/${this.context.attemptId}`, true); xhr.setRequestHeader('Content-Type', 'application/json'); const requestData = { cmi_datamodel: JSON.stringify(this.dataModel.dump()), diff --git a/src/app/common/scorm-player/scorm-player.component.ts b/src/app/common/scorm-player/scorm-player.component.ts index e1c68dc872..9c2ee9edb4 100644 --- a/src/app/common/scorm-player/scorm-player.component.ts +++ b/src/app/common/scorm-player/scorm-player.component.ts @@ -21,7 +21,7 @@ export class ScormPlayerComponent implements OnInit { context: ScormPlayerContext; @Input() - taskId: number; + projectId: number; @Input() taskDefId: number; @@ -41,7 +41,8 @@ export class ScormPlayerComponent implements OnInit { this.globalState.setView(ViewType.OTHER); this.globalState.hideHeader(); - this.scormAdapter.taskId = this.taskId; + this.scormAdapter.projectId = this.projectId; + this.scormAdapter.taskDefId = this.taskDefId; this.scormAdapter.mode = this.mode; window.API_1484_11 = { diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index 23b60886d6..8f48cd06fd 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -297,13 +297,13 @@ const ViewAllUnits: NgHybridStateDeclaration = { */ const ScormPlayerState: NgHybridStateDeclaration = { name: 'scorm-player', - url: '/task_def/:task_def_id/task/:task_id/scorm-player/:mode', + url: '/projects/:project_id/task_def_id/:task_definition_id/scorm-player/:mode', resolve: { - taskId: function ($stateParams) { - return $stateParams.task_id; + projectId: function ($stateParams) { + return $stateParams.project_id; }, taskDefId: function ($stateParams) { - return $stateParams.task_def_id; + return $stateParams.task_definition_id; }, mode: function ($stateParams) { return $stateParams.mode; diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts index 7d7dce6e1b..8172bcf1ff 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts @@ -22,7 +22,10 @@ export class TaskScormCardComponent implements OnInit { } launchScormPlayer(): void { - window.open(`#/task_def/${this.task.taskDefId}/task/${this.task.id}/scorm-player/normal`, '_blank'); + window.open( + `#/projects/${this.task.project.id}/task_def_id/${this.task.taskDefId}/scorm-player/normal`, + '_blank', + ); } requestMoreAttempts(): void { diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts index b584629668..b16184a042 100644 --- a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts @@ -15,6 +15,9 @@ export class ScormCommentComponent implements OnInit { ngOnInit() {} reviewScormTest() { - window.open(`#/task_def/${this.task.taskDefId}/task/${this.task.id}/scorm-player/review`, '_blank'); + window.open( + `#/projects/${this.task.project.id}/task_def_id/${this.task.taskDefId}/scorm-player/review`, + '_blank', + ); } } From 561b9241c2f44fd69d3f09c656a025f514bbaf3a Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sun, 2 Jun 2024 02:20:03 +1000 Subject: [PATCH 0083/1280] feat: enable reviewing, passing, deleting test attempts and add test attempt model and service --- src/app/api/models/doubtfire-model.ts | 3 + .../api/models/task-comment/scorm-comment.ts | 9 ++ src/app/api/models/test-attempt.ts | 20 ++++ src/app/api/services/scorm-adapter.service.ts | 29 +++++ src/app/api/services/task-comment.service.ts | 22 +++- src/app/api/services/test-attempt.service.ts | 103 ++++++++++++++++++ .../scorm-player/scorm-player.component.ts | 11 +- src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire.states.ts | 38 ++++++- .../scorm-comment.component.html | 11 +- .../scorm-comment/scorm-comment.component.ts | 29 ++++- .../task-comments-viewer.component.html | 4 +- 12 files changed, 259 insertions(+), 22 deletions(-) create mode 100644 src/app/api/models/task-comment/scorm-comment.ts create mode 100644 src/app/api/models/test-attempt.ts create mode 100644 src/app/api/services/test-attempt.service.ts diff --git a/src/app/api/models/doubtfire-model.ts b/src/app/api/models/doubtfire-model.ts index baca2f22d2..d6e4230f6e 100644 --- a/src/app/api/models/doubtfire-model.ts +++ b/src/app/api/models/doubtfire-model.ts @@ -34,6 +34,8 @@ export * from './task-similarity'; export * from './tii-action'; export * from './scorm-datamodel'; export * from './scorm-player-context'; +export * from './test-attempt'; +export * from './task-comment/scorm-comment'; // Users -- are students or staff export * from './user/user'; @@ -58,3 +60,4 @@ export * from '../services/teaching-period-break.service'; export * from '../services/learning-outcome.service'; export * from '../services/group-set.service'; export * from '../services/task-similarity.service'; +export * from '../services/test-attempt.service'; diff --git a/src/app/api/models/task-comment/scorm-comment.ts b/src/app/api/models/task-comment/scorm-comment.ts new file mode 100644 index 0000000000..3356b62b93 --- /dev/null +++ b/src/app/api/models/task-comment/scorm-comment.ts @@ -0,0 +1,9 @@ +import {Task, TaskComment, TestAttempt} from '../doubtfire-model'; + +export class ScormComment extends TaskComment { + testAttempt: TestAttempt; + + constructor(task: Task) { + super(task); + } +} diff --git a/src/app/api/models/test-attempt.ts b/src/app/api/models/test-attempt.ts new file mode 100644 index 0000000000..02bb4bb4e9 --- /dev/null +++ b/src/app/api/models/test-attempt.ts @@ -0,0 +1,20 @@ +import {Entity} from 'ngx-entity-service'; +import {Task} from './doubtfire-model'; + +export class TestAttempt extends Entity { + id: number; + attemptNumber: number; + terminated: boolean; + completionStatus: boolean; + successStatus: boolean; + scoreScaled: number; + cmiDatamodel: string; + attemptedTime: Date; + + task: Task; + + constructor(task: Task) { + super(); + this.task = task; + } +} diff --git a/src/app/api/services/scorm-adapter.service.ts b/src/app/api/services/scorm-adapter.service.ts index 233c7aed6a..b6014f14b4 100644 --- a/src/app/api/services/scorm-adapter.service.ts +++ b/src/app/api/services/scorm-adapter.service.ts @@ -29,6 +29,10 @@ export class ScormAdapterService { this.context.mode = mode; } + set testAttemptId(testAttemptId: number) { + this.context.attemptId = testAttemptId; + } + get state() { return this.context.state; } @@ -53,6 +57,31 @@ export class ScormAdapterService { break; } + if (this.context.mode === 'review') { + this.xhr.open('GET', `${API_URL}/test_attempts/${this.context.attemptId}/review`, false); + + this.xhr.onload = () => { + if (this.xhr.status >= 200 && this.xhr.status < 400) { + console.log('Retrieved the attempt.'); + } else if (this.xhr.status == 404) { + console.log('Not found.'); + noTestFound = true; + } else { + console.error('Error saving DataModel:', this.xhr.responseText); + } + }; + + this.xhr.send(); + console.log(this.xhr.responseText); + + const reviewSession = JSON.parse(this.xhr.responseText); + this.dataModel.restore(reviewSession.cmi_datamodel); + console.log(this.dataModel.dump()); + + this.context.state = 'Initialized'; + return 'true'; + } + // TODO: move this part into the player component this.xhr.open( 'GET', diff --git a/src/app/api/services/task-comment.service.ts b/src/app/api/services/task-comment.service.ts index 5f034b870d..c97ec4c3e0 100644 --- a/src/app/api/services/task-comment.service.ts +++ b/src/app/api/services/task-comment.service.ts @@ -1,4 +1,4 @@ -import { Task, TaskComment, UserService } from 'src/app/api/models/doubtfire-model'; +import { ScormComment, Task, TaskComment, TestAttemptService, UserService } from 'src/app/api/models/doubtfire-model'; import { EventEmitter, Injectable } from '@angular/core'; import { Observable } from 'rxjs'; import { tap } from 'rxjs/operators'; @@ -32,7 +32,8 @@ export class TaskCommentService extends CachedEntityService { httpClient: HttpClient, private emojiService: EmojiService, private userService: UserService, - private downloader: FileDownloaderService + private downloader: FileDownloaderService, + private testAttemptService: TestAttemptService, ) { super(httpClient, API_URL); @@ -85,7 +86,20 @@ export class TaskCommentService extends CachedEntityService { 'status', 'numberOfPrompts', 'timeDiscussionComplete', - 'timeDiscussionStarted' + 'timeDiscussionStarted', + + // Scorm Comments + { + keys: 'testAttempt', + toEntityFn: (data: object, key: string, comment: ScormComment) => { + const testAttempt = this.testAttemptService.cache.getOrCreate( + data[key].id, + testAttemptService, + data[key], + ); + return testAttempt; + }, + }, ); this.mapping.addJsonKey( @@ -103,6 +117,8 @@ export class TaskCommentService extends CachedEntityService { return new DiscussionComment(other); case 'extension': return new ExtensionComment(other); + case 'scorm': + return new ScormComment(other); default: return new TaskComment(other); } diff --git a/src/app/api/services/test-attempt.service.ts b/src/app/api/services/test-attempt.service.ts new file mode 100644 index 0000000000..7a7ac25ca2 --- /dev/null +++ b/src/app/api/services/test-attempt.service.ts @@ -0,0 +1,103 @@ +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import API_URL from 'src/app/config/constants/apiURL'; +import {Task, TestAttempt} from 'src/app/api/models/doubtfire-model'; +import {Observable} from 'rxjs'; +import {AppInjector} from 'src/app/app-injector'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {HttpClient} from '@angular/common/http'; + +@Injectable() +export class TestAttemptService extends CachedEntityService { + protected readonly endpointFormat = 'test_attempts/:id:'; + protected readonly forTaskEndpoint = + '/projects/:project_id:/task_definition_id/:task_def_id:/test_attempts'; + protected readonly latestCompletedEndpoint = + this.forTaskEndpoint + '/latest?completed=:completed:'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'attemptNumber', + 'terminated', + 'completionStatus', + 'successStatus', + 'scoreScaled', + 'cmiDatamodel', + 'attemptedTime', + ); + } + + public override createInstanceFrom(_json: object, constructorParams: Task): TestAttempt { + return new TestAttempt(constructorParams); + } + + public getAttemptsForTask(task: Task): Observable { + return this.query( + { + project_id: task.project.id, + task_def_id: task.taskDefId, + }, + { + endpointFormat: this.forTaskEndpoint, + constructorParams: task, + }, + ); + } + + public getLatestCompletedAttempt(task: Task): Observable { + return this.get( + { + project_id: task.project.id, + task_def_id: task.taskDefId, + completed: true, + }, + { + endpointFormat: this.latestCompletedEndpoint, + constructorParams: task, + }, + ); + } + + public overrideSuccessStatus(testAttemptId: number, successStatus: boolean): void { + const http = AppInjector.get(HttpClient); + + http + .patch( + `${AppInjector.get(DoubtfireConstants).API_URL}/test_attempts/${testAttemptId}?success_status=${successStatus}`, + {}, + ) + .subscribe({ + next: (_data) => { + (AppInjector.get(AlertService) as AlertService).success( + 'Attempt pass status successfully overridden.', + 6000, + ); + }, + error: (message) => { + (AppInjector.get(AlertService) as AlertService).error(message, 6000); + }, + }); + } + + public deleteAttempt(testAttemptId: number): void { + const http = AppInjector.get(HttpClient); + + http + .delete(`${AppInjector.get(DoubtfireConstants).API_URL}/test_attempts/${testAttemptId}`, {}) + .subscribe({ + next: (_data) => { + (AppInjector.get(AlertService) as AlertService).success( + 'Attempt successfully deleted.', + 6000, + ); + }, + error: (message) => { + (AppInjector.get(AlertService) as AlertService).error(message, 6000); + }, + }); + } +} diff --git a/src/app/common/scorm-player/scorm-player.component.ts b/src/app/common/scorm-player/scorm-player.component.ts index 9c2ee9edb4..4a32eb0ac7 100644 --- a/src/app/common/scorm-player/scorm-player.component.ts +++ b/src/app/common/scorm-player/scorm-player.component.ts @@ -29,6 +29,9 @@ export class ScormPlayerComponent implements OnInit { @Input() mode: 'browse' | 'normal' | 'review'; + @Input() + testAttemptId: number; + iframeSrc: SafeResourceUrl; constructor( @@ -41,9 +44,13 @@ export class ScormPlayerComponent implements OnInit { this.globalState.setView(ViewType.OTHER); this.globalState.hideHeader(); - this.scormAdapter.projectId = this.projectId; - this.scormAdapter.taskDefId = this.taskDefId; this.scormAdapter.mode = this.mode; + if (this.mode === 'normal') { + this.scormAdapter.projectId = this.projectId; + this.scormAdapter.taskDefId = this.taskDefId; + } else if (this.mode === 'review') { + this.scormAdapter.testAttemptId = this.testAttemptId; + } window.API_1484_11 = { Initialize: () => this.scormAdapter.Initialize(), diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index dabcd49145..5f6e91e775 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -229,6 +229,7 @@ import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component import {ScormAdapterService} from './api/services/scorm-adapter.service'; import {ScormCommentComponent} from './tasks/task-comments-viewer/scorm-comment/scorm-comment.component'; import {TaskScormCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component'; +import {TestAttemptService} from './api/services/test-attempt.service'; @NgModule({ // Components we declare @@ -406,6 +407,7 @@ import {TaskScormCardComponent} from './projects/states/dashboard/directives/tas IsActiveUnitRole, CreateNewUnitModal, ScormAdapterService, + TestAttemptService, provideLottieOptions({ player: () => player, }), diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index 8f48cd06fd..0338a550a9 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -295,9 +295,9 @@ const ViewAllUnits: NgHybridStateDeclaration = { /** * Define the SCORM Player state. */ -const ScormPlayerState: NgHybridStateDeclaration = { - name: 'scorm-player', - url: '/projects/:project_id/task_def_id/:task_definition_id/scorm-player/:mode', +const ScormPlayerNormalState: NgHybridStateDeclaration = { + name: 'scorm-player-normal', + url: '/projects/:project_id/task_def_id/:task_definition_id/scorm-player/normal', resolve: { projectId: function ($stateParams) { return $stateParams.project_id; @@ -305,8 +305,8 @@ const ScormPlayerState: NgHybridStateDeclaration = { taskDefId: function ($stateParams) { return $stateParams.task_definition_id; }, - mode: function ($stateParams) { - return $stateParams.mode; + mode: function () { + return 'normal'; }, }, views: { @@ -320,6 +320,31 @@ const ScormPlayerState: NgHybridStateDeclaration = { }, }; +const ScormPlayerReviewState: NgHybridStateDeclaration = { + name: 'scorm-player-review', + url: '/task_def_id/:task_definition_id/scorm-player/review/:test_attempt_id', + resolve: { + taskDefId: function ($stateParams) { + return $stateParams.task_definition_id; + }, + testAttemptId: function ($stateParams) { + return $stateParams.test_attempt_id; + }, + mode: function () { + return 'review'; + }, + }, + views: { + main: { + component: ScormPlayerComponent, + }, + }, + data: { + pageTitle: 'Review Knowledge Check', + roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin'], + }, +}; + /** * Export the list of states we have created in angular */ @@ -335,5 +360,6 @@ export const doubtfireStates = [ ViewAllProjectsState, ViewAllUnits, AdministerUnits, - ScormPlayerState, + ScormPlayerNormalState, + ScormPlayerReviewState, ]; diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html index ffe375f19d..b0536d2ce6 100644 --- a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html @@ -1,10 +1,13 @@ -
-
+
+

- -
+
+ + + +

diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts index b16184a042..201e35544a 100644 --- a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts @@ -1,23 +1,42 @@ import {Component, OnInit, Input} from '@angular/core'; -import {Task, TaskComment} from 'src/app/api/models/doubtfire-model'; +import {Task, ScormComment, User, UserService, TestAttemptService} from 'src/app/api/models/doubtfire-model'; @Component({ - selector: 'scorm-comment', + selector: 'f-scorm-comment', templateUrl: './scorm-comment.component.html', styleUrls: ['./scorm-comment.component.scss'], }) export class ScormCommentComponent implements OnInit { @Input() task: Task; - @Input() comment: TaskComment; + @Input() comment: ScormComment; - constructor() {} + user: User; + + constructor( + private userService: UserService, + private testAttemptService: TestAttemptService, + ) { + this.user = this.userService.currentUser; + } ngOnInit() {} + get canOverridePass(): boolean { + return this.user.isStaff && !this.comment.testAttempt.successStatus; + } + reviewScormTest() { window.open( - `#/projects/${this.task.project.id}/task_def_id/${this.task.taskDefId}/scorm-player/review`, + `#/task_def_id/${this.task.taskDefId}/scorm-player/review/${this.comment.testAttempt.id}`, '_blank', ); } + + passScormAttempt() { + this.testAttemptService.overrideSuccessStatus(this.comment.testAttempt.id, true); + } + + deleteScormAttempt() { + this.testAttemptService.deleteAttempt(this.comment.testAttempt.id); + } } diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html index aa20275ff6..f6228c576a 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html @@ -73,11 +73,11 @@
- + >
From e605a3cfb56f8979b6e8d3ddf16dab7a8d253c03 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sun, 2 Jun 2024 21:00:31 +1000 Subject: [PATCH 0084/1280] refactor: use new alert service for scorm editor --- .../task-definition-scorm.component.ts | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts index 8f2b72fcb9..3e41aa39d2 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts @@ -1,10 +1,10 @@ -import { Component, Inject, Input } from '@angular/core'; -import { FormControl, Validators } from '@angular/forms'; -import { alertService } from 'src/app/ajs-upgraded-providers'; -import { TaskDefinition } from 'src/app/api/models/task-definition'; -import { Unit } from 'src/app/api/models/unit'; -import { TaskDefinitionService } from 'src/app/api/services/task-definition.service'; -import { FileDownloaderService } from 'src/app/common/file-downloader/file-downloader.service'; +import {Component, Input} from '@angular/core'; +import {FormControl, Validators} from '@angular/forms'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; @Component({ selector: 'f-task-definition-scorm', @@ -16,8 +16,8 @@ export class TaskDefinitionScormComponent { constructor( private fileDownloaderService: FileDownloaderService, - @Inject(alertService) private alerts: any, - private taskDefinitionService: TaskDefinitionService + private alerts: AlertService, + private taskDefinitionService: TaskDefinitionService, ) {} public attemptLimitControl = new FormControl('', [Validators.max(100), Validators.min(0)]); @@ -41,9 +41,11 @@ export class TaskDefinitionScormComponent { } public uploadScormData(files: FileList) { - console.log(Array.from(files).map(f => f.type)); + console.log(Array.from(files).map((f) => f.type)); const validMimeTypes = ['application/zip', 'application/x-zip-compressed', 'multipart/x-zip']; - const validFiles = Array.from(files as ArrayLike).filter(f => validMimeTypes.includes(f.type)); + const validFiles = Array.from(files as ArrayLike).filter((f) => + validMimeTypes.includes(f.type), + ); if (validFiles.length > 0) { const file = validFiles[0]; this.taskDefinitionService.uploadScormData(this.taskDefinition, file).subscribe({ From 58c24c3a6760af168a918bc099e755f475eac5f0 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Mon, 3 Jun 2024 00:24:20 +1000 Subject: [PATCH 0085/1280] fix: show correct attempts left and allow tutor to review attempt always --- src/app/api/models/task.ts | 20 +++++++++++++ src/app/api/services/test-attempt.service.ts | 20 ++----------- .../task-scorm-card.component.html | 18 ++++++----- .../task-scorm-card.component.ts | 30 +++++++++++-------- .../scorm-comment.component.html | 18 ++++++++--- 5 files changed, 65 insertions(+), 41 deletions(-) diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index 556d0a7dd2..86ac445fc2 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -15,6 +15,8 @@ import { TaskCommentService, TaskSimilarity, TaskSimilarityService, + TestAttempt, + TestAttemptService, } from './doubtfire-model'; import {Grade} from './grade'; import {LOCALE_ID} from '@angular/core'; @@ -53,6 +55,7 @@ export class Task extends Entity { public readonly commentCache: EntityCache = new EntityCache(); public readonly similarityCache: EntityCache = new EntityCache(); + public readonly testAttemptCache: EntityCache = new EntityCache(); private _unit: Unit; @@ -770,4 +773,21 @@ export class Task extends Entity { }, ); } + + /** + * Fetch the SCORM test attempts for this task. + */ + public fetchTestAttempts(): Observable { + const testAttemptService: TestAttemptService = AppInjector.get(TestAttemptService); + return testAttemptService.query( + { + project_id: this.project.id, + task_def_id: this.taskDefId, + }, + { + cache: this.testAttemptCache, + constructorParams: this, + }, + ); + } } diff --git a/src/app/api/services/test-attempt.service.ts b/src/app/api/services/test-attempt.service.ts index 7a7ac25ca2..6c32ed01a8 100644 --- a/src/app/api/services/test-attempt.service.ts +++ b/src/app/api/services/test-attempt.service.ts @@ -10,11 +10,10 @@ import {HttpClient} from '@angular/common/http'; @Injectable() export class TestAttemptService extends CachedEntityService { - protected readonly endpointFormat = 'test_attempts/:id:'; - protected readonly forTaskEndpoint = - '/projects/:project_id:/task_definition_id/:task_def_id:/test_attempts'; + protected readonly endpointFormat = + '/projects/:project_id:/task_def_id/:task_def_id:/test_attempts'; protected readonly latestCompletedEndpoint = - this.forTaskEndpoint + '/latest?completed=:completed:'; + this.endpointFormat + '/latest?completed=:completed:'; constructor(httpClient: HttpClient) { super(httpClient, API_URL); @@ -35,19 +34,6 @@ export class TestAttemptService extends CachedEntityService { return new TestAttempt(constructorParams); } - public getAttemptsForTask(task: Task): Observable { - return this.query( - { - project_id: task.project.id, - task_def_id: task.taskDefId, - }, - { - endpointFormat: this.forTaskEndpoint, - constructorParams: task, - }, - ); - } - public getLatestCompletedAttempt(task: Task): Observable { return this.get( { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html index 67265461cd..9d518fb1c4 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html @@ -3,24 +3,28 @@ Knowledge Check +

You have to successfully pass this knowledge check to complete the task.

- You have to successfully pass this knowledge check to complete the task. -

-

- You have {{ (task.definition.scormAttemptLimit > 0) ? task.definition.scormAttemptLimit : 'unlimited' }} attempts to complete this test. + You have {{ attemptsLeft !== undefined ? attemptsLeft : 'unlimited' }} attempts left to + complete this test.

- There will be an increased time delay between test attempts. First 2 attempts will not have a time delay in between. + There will be an increased time delay between test attempts. First 2 attempts will not have a + time delay in between.

- - diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts index 8172bcf1ff..cdeb73df0e 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts @@ -1,23 +1,29 @@ -import {Component, Input, OnInit} from '@angular/core'; -import {Task} from 'src/app/api/models/task'; -import {TaskService} from 'src/app/api/services/task.service'; +import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; +import {Task} from 'src/app/api/models/doubtfire-model'; @Component({ selector: 'f-task-scorm-card', templateUrl: './task-scorm-card.component.html', styleUrls: ['./task-scorm-card.component.scss'], }) -export class TaskScormCardComponent implements OnInit { +export class TaskScormCardComponent implements OnChanges { @Input() task: Task; attemptsLeft: number; - constructor( - private taskService: TaskService, - ) {} - - ngOnInit(): void { - if (this.task) { + ngOnChanges(changes: SimpleChanges) { + if (changes.task && changes.task.currentValue) { + this.attemptsLeft = undefined; + this.getAttemptsLeft(); + } + } + getAttemptsLeft(): void { + if (this.task.definition.scormAttemptLimit != 0) { + this.task.fetchTestAttempts().subscribe((attempts) => { + let count = attempts.length; + if (count > 0 && attempts[0].terminated === false) count--; + this.attemptsLeft = this.task.definition.scormAttemptLimit - count; + }); } } @@ -28,7 +34,5 @@ export class TaskScormCardComponent implements OnInit { ); } - requestMoreAttempts(): void { - - } + requestMoreAttempts(): void {} } diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html index b0536d2ce6..c1dacaa788 100644 --- a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html @@ -2,11 +2,21 @@

-
+
- - - + + +

From d904ffd6fd674f6e61894d517f5aa147d1db6d29 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Wed, 5 Jun 2024 15:17:47 +1000 Subject: [PATCH 0086/1280] feat: enable students to request extra scorm attempt --- src/app/api/models/doubtfire-model.ts | 1 + .../task-comment/scorm-extension-comment.ts | 38 +++++++++++ src/app/api/models/task.ts | 1 + src/app/api/services/task-comment.service.ts | 43 ++++++++++++ src/app/api/services/task.service.ts | 1 + .../scorm-extension-modal.component.html | 45 +++++++++++++ .../scorm-extension-modal.component.ts | 67 +++++++++++++++++++ .../scorm-extension-modal.service.ts | 26 +++++++ src/app/doubtfire-angular.module.ts | 4 ++ .../task-scorm-card.component.html | 6 +- .../task-scorm-card.component.ts | 11 ++- .../scorm-extension-comment.component.html | 32 +++++++++ .../scorm-extension-comment.component.scss | 55 +++++++++++++++ .../scorm-extension-comment.component.ts | 63 +++++++++++++++++ .../task-comments-viewer.component.html | 5 ++ .../task-comments-viewer.component.scss | 4 +- .../task-comments-viewer.component.ts | 8 ++- 17 files changed, 402 insertions(+), 8 deletions(-) create mode 100644 src/app/api/models/task-comment/scorm-extension-comment.ts create mode 100644 src/app/common/modals/scorm-extension-modal/scorm-extension-modal.component.html create mode 100644 src/app/common/modals/scorm-extension-modal/scorm-extension-modal.component.ts create mode 100644 src/app/common/modals/scorm-extension-modal/scorm-extension-modal.service.ts create mode 100644 src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html create mode 100644 src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.scss create mode 100644 src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts diff --git a/src/app/api/models/doubtfire-model.ts b/src/app/api/models/doubtfire-model.ts index d6e4230f6e..fffc361a4e 100644 --- a/src/app/api/models/doubtfire-model.ts +++ b/src/app/api/models/doubtfire-model.ts @@ -36,6 +36,7 @@ export * from './scorm-datamodel'; export * from './scorm-player-context'; export * from './test-attempt'; export * from './task-comment/scorm-comment'; +export * from './task-comment/scorm-extension-comment'; // Users -- are students or staff export * from './user/user'; diff --git a/src/app/api/models/task-comment/scorm-extension-comment.ts b/src/app/api/models/task-comment/scorm-extension-comment.ts new file mode 100644 index 0000000000..3b4dfbccb6 --- /dev/null +++ b/src/app/api/models/task-comment/scorm-extension-comment.ts @@ -0,0 +1,38 @@ +import {Observable} from 'rxjs'; +import {tap} from 'rxjs/operators'; +import {AppInjector} from 'src/app/app-injector'; +import {TaskCommentService} from '../../services/task-comment.service'; +import {TaskComment, Task} from '../doubtfire-model'; + +export class ScormExtensionComment extends TaskComment { + assessed: boolean; + granted: boolean; + dateAssessed: Date; + taskScormExtensions: number; + + constructor(task: Task) { + super(task); + } + + private assessScormExtension(): Observable { + const tcs: TaskCommentService = AppInjector.get(TaskCommentService); + return tcs.assessScormExtension(this).pipe( + tap((tc: TaskComment) => { + const scormExtension: ScormExtensionComment = tc as ScormExtensionComment; + + const task = tc.task; + task.scormExtensions = scormExtension.taskScormExtensions; + }), + ); + } + + public deny(): Observable { + this.granted = false; + return this.assessScormExtension(); + } + + public grant(): Observable { + this.granted = true; + return this.assessScormExtension(); + } +} diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index 86ac445fc2..ba4bce8e04 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -32,6 +32,7 @@ export class Task extends Entity { status: TaskStatusEnum = 'not_started'; dueDate: Date; extensions: number; + scormExtensions: number; submissionDate: Date; completionDate: Date; timesAssessed: number; diff --git a/src/app/api/services/task-comment.service.ts b/src/app/api/services/task-comment.service.ts index c97ec4c3e0..e7f76d37b1 100644 --- a/src/app/api/services/task-comment.service.ts +++ b/src/app/api/services/task-comment.service.ts @@ -11,6 +11,7 @@ import API_URL from 'src/app/config/constants/apiURL'; import { EmojiService } from 'src/app/common/services/emoji.service'; import { MappingFunctions } from './mapping-fn'; import { FileDownloaderService } from 'src/app/common/file-downloader/file-downloader.service'; +import { ScormExtensionComment } from '../models/task-comment/scorm-extension-comment'; @Injectable() export class TaskCommentService extends CachedEntityService { @@ -22,6 +23,10 @@ export class TaskCommentService extends CachedEntityService { 'projects/:projectId:/task_def_id/:taskDefinitionId:/assess_extension/:id:'; private readonly requestExtensionEndpointFormat = 'projects/:projectId:/task_def_id/:taskDefinitionId:/request_extension'; + private readonly scormExtensionGrantEndpointFormat = + 'projects/:projectId:/task_def_id/:taskDefinitionId:/assess_scorm_extension/:id:'; + private readonly scormRequestExtensionEndpointFormat = + 'projects/:projectId:/task_def_id/:taskDefinitionId:/request_scorm_extension'; private readonly discussionCommentReplyEndpointFormat = "/projects/:project_id:/task_def_id/:task_definition_id:/comments/:task_comment_id:/discussion_comment/reply"; private readonly getDiscussionCommentPromptEndpointFormat = "/projects/:project_id:/task_def_id/:task_definition_id:/comments/:task_comment_id:/discussion_comment/prompt_number/:prompt_number:"; @@ -100,6 +105,9 @@ export class TaskCommentService extends CachedEntityService { return testAttempt; }, }, + + // Scorm Extension Comments + ['taskScormExtensions', 'scorm_extensions'] ); this.mapping.addJsonKey( @@ -119,6 +127,8 @@ export class TaskCommentService extends CachedEntityService { return new ExtensionComment(other); case 'scorm': return new ScormComment(other); + case 'scorm_extension': + return new ScormExtensionComment(other); default: return new TaskComment(other); } @@ -218,6 +228,39 @@ export class TaskCommentService extends CachedEntityService { ); } + public assessScormExtension(extension: ScormExtensionComment): Observable { + const opts: RequestOptions = { + endpointFormat: this.scormExtensionGrantEndpointFormat, + entity: extension, + }; + + return super.update( + { + id: extension.id, + projectId: extension.project.id, + taskDefinitionId: extension.task.definition.id, + }, + opts, + ); + } + + public requestScormExtension(reason: string, task: any): Observable { + const opts: RequestOptions = { + endpointFormat: this.scormRequestExtensionEndpointFormat, + body: { + comment: reason, + }, + cache: task.commentCache, + }; + return super.create( + { + projectId: task.project.id, + taskDefinitionId: task.definition.id, + }, + opts, + ); + } + public postDiscussionReply(comment: TaskComment, replyAudio: Blob): Observable{ const form = new FormData(); const pathIds = { diff --git a/src/app/api/services/task.service.ts b/src/app/api/services/task.service.ts index 344494c0eb..737fe1ea4c 100644 --- a/src/app/api/services/task.service.ts +++ b/src/app/api/services/task.service.ts @@ -46,6 +46,7 @@ export class TaskService extends CachedEntityService { toEntityFn: MappingFunctions.mapDateToEndOfDay, }, 'extensions', + 'scormExtensions', { keys: 'submissionDate', toEntityFn: MappingFunctions.mapDateToDay, diff --git a/src/app/common/modals/scorm-extension-modal/scorm-extension-modal.component.html b/src/app/common/modals/scorm-extension-modal/scorm-extension-modal.component.html new file mode 100644 index 0000000000..f39a9580b5 --- /dev/null +++ b/src/app/common/modals/scorm-extension-modal/scorm-extension-modal.component.html @@ -0,0 +1,45 @@ +

Extra attempt request

+
+

+ Please explain why you require an extra attempt for this knowledge check, the teaching team will + assess the request shortly. +

+ + + Reason + + {{ extensionData.controls.extensionReason.value.length }} / {{ reasonMaxLength }} + @if (extensionData.controls.extensionReason.hasError('required')) { + You must enter a reason + } + @if (extensionData.controls.extensionReason.hasError('minlength')) { + The reason must be at least {{ reasonMinLength }} characters long + } + @if (extensionData.controls.extensionReason.hasError('maxlength')) { + The reason must be less than {{ reasonMaxLength }} characters long + } + +
+ +
+ + +
diff --git a/src/app/common/modals/scorm-extension-modal/scorm-extension-modal.component.ts b/src/app/common/modals/scorm-extension-modal/scorm-extension-modal.component.ts new file mode 100644 index 0000000000..c7f5833821 --- /dev/null +++ b/src/app/common/modals/scorm-extension-modal/scorm-extension-modal.component.ts @@ -0,0 +1,67 @@ +import {Component, Inject, LOCALE_ID} from '@angular/core'; +import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {TaskComment, TaskCommentService, Task} from 'src/app/api/models/doubtfire-model'; +import {AppInjector} from 'src/app/app-injector'; +import {FormControl, Validators, FormGroup, FormGroupDirective, NgForm} from '@angular/forms'; +import {ErrorStateMatcher} from '@angular/material/core'; +import {AlertService} from '../../services/alert.service'; + +/** Error when invalid control is dirty, touched, or submitted. */ +export class ReasonErrorStateMatcher implements ErrorStateMatcher { + isErrorState(control: FormControl | null, form: FormGroupDirective | NgForm | null): boolean { + const isSubmitted = form && form.submitted; + return !!(control && control.invalid && (control.dirty || control.touched || isSubmitted)); + } +} + +@Component({ + selector: 'f-scorm-extension-modal', + templateUrl: './scorm-extension-modal.component.html', +}) +export class ScormExtensionModalComponent { + protected reasonMinLength: number = 15; + protected reasonMaxLength: number = 256; + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: {task: Task; afterApplication?: () => void}, + private alerts: AlertService, + ) {} + + matcher = new ReasonErrorStateMatcher(); + currentLocale = AppInjector.get(LOCALE_ID); + extensionData = new FormGroup({ + extensionReason: new FormControl('', [ + Validators.required, + Validators.minLength(this.reasonMinLength), + Validators.maxLength(this.reasonMaxLength), + ]), + }); + + private scrollCommentsDown(): void { + setTimeout(() => { + const objDiv = document.querySelector('div.comments-body'); + // let wrappedResult = angular.element(objDiv); + objDiv.scrollTop = objDiv.scrollHeight; + }, 50); + } + + submitApplication() { + const tcs: TaskCommentService = AppInjector.get(TaskCommentService); + tcs + .requestScormExtension(this.extensionData.controls.extensionReason.value, this.data.task) + .subscribe({ + // eslint-disable-next-line @typescript-eslint/no-unused-vars + next: ((tc: TaskComment) => { + this.alerts.success('Extra attempt requested.', 2000); + this.scrollCommentsDown(); + if (typeof this.data.afterApplication === 'function') { + this.data.afterApplication(); + } + }).bind(this), + error: ((response: never) => { + this.alerts.error('Error requesting extra attempt ' + response); + console.log(response); + }).bind(this), + }); + } +} diff --git a/src/app/common/modals/scorm-extension-modal/scorm-extension-modal.service.ts b/src/app/common/modals/scorm-extension-modal/scorm-extension-modal.service.ts new file mode 100644 index 0000000000..7e9b46f8e9 --- /dev/null +++ b/src/app/common/modals/scorm-extension-modal/scorm-extension-modal.service.ts @@ -0,0 +1,26 @@ +import {Injectable} from '@angular/core'; +import {Task} from 'src/app/api/models/task'; +import {MatDialogRef, MatDialog} from '@angular/material/dialog'; +import {ScormExtensionModalComponent} from './scorm-extension-modal.component'; + +@Injectable({ + providedIn: 'root', +}) +export class ScormExtensionModalService { + constructor(public dialog: MatDialog) {} + + public show(task: Task, afterApplication?: any) { + let dialogRef: MatDialogRef; + + dialogRef = this.dialog.open(ScormExtensionModalComponent, { + data: { + task, + afterApplication, + }, + }); + + dialogRef.afterOpened().subscribe((result: any) => {}); + + dialogRef.afterClosed().subscribe((result: any) => {}); + } +} diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 5f6e91e775..67e3c3f1dd 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -230,6 +230,8 @@ import {ScormAdapterService} from './api/services/scorm-adapter.service'; import {ScormCommentComponent} from './tasks/task-comments-viewer/scorm-comment/scorm-comment.component'; import {TaskScormCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component'; import {TestAttemptService} from './api/services/test-attempt.service'; +import {ScormExtensionCommentComponent} from './tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component'; +import {ScormExtensionModalComponent} from './common/modals/scorm-extension-modal/scorm-extension-modal.component'; @NgModule({ // Components we declare @@ -335,6 +337,8 @@ import {TestAttemptService} from './api/services/test-attempt.service'; ScormPlayerComponent, ScormCommentComponent, TaskScormCardComponent, + ScormExtensionCommentComponent, + ScormExtensionModalComponent, ], // Services we provide providers: [ diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html index 9d518fb1c4..1929afb248 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html @@ -22,10 +22,10 @@ diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts index cdeb73df0e..2713c9ee33 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts @@ -1,5 +1,6 @@ import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; import {Task} from 'src/app/api/models/doubtfire-model'; +import {ScormExtensionModalService} from 'src/app/common/modals/scorm-extension-modal/scorm-extension-modal.service'; @Component({ selector: 'f-task-scorm-card', @@ -10,6 +11,8 @@ export class TaskScormCardComponent implements OnChanges { @Input() task: Task; attemptsLeft: number; + constructor(private extensions: ScormExtensionModalService) {} + ngOnChanges(changes: SimpleChanges) { if (changes.task && changes.task.currentValue) { this.attemptsLeft = undefined; @@ -22,7 +25,7 @@ export class TaskScormCardComponent implements OnChanges { this.task.fetchTestAttempts().subscribe((attempts) => { let count = attempts.length; if (count > 0 && attempts[0].terminated === false) count--; - this.attemptsLeft = this.task.definition.scormAttemptLimit - count; + this.attemptsLeft = this.task.definition.scormAttemptLimit + this.task.scormExtensions - count; }); } } @@ -34,5 +37,9 @@ export class TaskScormCardComponent implements OnChanges { ); } - requestMoreAttempts(): void {} + requestExtraAttempt(): void { + this.extensions.show(this.task, () => { + this.task.refresh(); + }); + } } diff --git a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html new file mode 100644 index 0000000000..fa7c4cb39f --- /dev/null +++ b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html @@ -0,0 +1,32 @@ +
+ @if (comment.assessed) { +
+
+

reason: {{ comment.text }}

+
+ } + + @if (!comment.assessed) { +
+
+

+ {{ message }}
+ reason: {{ comment.text }} +

+ @if (isNotStudent) { +
+ + +
+ } +
+
+ } +
diff --git a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.scss b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.scss new file mode 100644 index 0000000000..c2917f902e --- /dev/null +++ b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.scss @@ -0,0 +1,55 @@ +div { + width: 100%; +} + +p { + color: #2c2c2c; + text-align: center; +} + +hr { + width: 100%; +} + +.hr-fade { + background: linear-gradient(to right, transparent, #9696969d, transparent); + width: 100%; +} + +.fade-text { + color: #9696969d; + opacity: 0.8; +} + +.hr-text { + margin: 0; + line-height: 1em; + position: relative; + outline: 0; + border: 0; + color: black; + text-align: center; + height: 1.5em; + opacity: 0.8; + &:before { + content: ""; + background: linear-gradient(to right, transparent, #9696969d, transparent); + position: absolute; + left: 0; + top: 50%; + width: 100%; + height: 1px; + } + &:after { + content: attr(data-content); + position: relative; + display: inline-block; + color: black; + + padding: 0 0.5em; + line-height: 1.5em; + + color: #9696969d; + background-color: #fff; + } +} diff --git a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts new file mode 100644 index 0000000000..eb1790edd4 --- /dev/null +++ b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts @@ -0,0 +1,63 @@ +import {Component, OnInit, Input} from '@angular/core'; +import {ScormExtensionComment, TaskComment, Task} from 'src/app/api/models/doubtfire-model'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-scorm-extension-comment', + templateUrl: './scorm-extension-comment.component.html', + styleUrls: ['./scorm-extension-comment.component.scss'], +}) +export class ScormExtensionCommentComponent implements OnInit { + @Input() comment: ScormExtensionComment; + @Input() task: Task; + + constructor(private alerts: AlertService) {} + + private handleError(error: any) { + this.alerts.error('Error: ' + error.data.error, 6000); + } + + ngOnInit() {} + + get message() { + const studentName = this.comment.author.name; + if (this.comment.assessed && this.comment.granted) { + return 'Extra attempt granted.'; + } else if (this.comment.assessed && !this.comment.granted) { + return 'Extra attempt request rejected.'; + } + const subject = this.isStudent ? 'You have ' : studentName + ' has '; + const message = 'requested an extra attempt for the knowledge check.'; + return subject + message; + } + + get isStudent() { + return !this.isNotStudent; + } + + get isNotStudent() { + return this.task.unit.currentUserIsStaff; + } + + denyExtension() { + this.comment.deny().subscribe({ + next: (tc: TaskComment) => { + this.alerts.success('Attempt request denied', 2000); + }, + error: (response) => { + this.handleError(response); + }, + }); + } + + grantExtension() { + this.comment.grant().subscribe({ + next: (tc: TaskComment) => { + this.alerts.success('Attempt request granted', 2000); + }, + error: (response) => { + this.handleError(response); + }, + }); + } +} diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html index f6228c576a..81b09e6011 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html @@ -95,6 +95,11 @@
+
+ + +
+
diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.scss b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.scss index d82983038f..a1b4811941 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.scss +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.scss @@ -140,7 +140,7 @@ $comment-inner-border-radius: 4px; } } - .comment-container .comment-extension { + .comment-container .comment-extension, .comment-container .comment-scorm-extension { width: 100%; } @@ -354,7 +354,7 @@ $comment-inner-border-radius: 4px; } } - .comment .extension-bubble { + .comment .extension-bubble, .comment .scorm_extension-bubble { width: 100%; background-color: transparent; } diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts index 8ad719f339..857f4581f2 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts @@ -154,7 +154,13 @@ export class TaskCommentsViewerComponent implements OnChanges, OnInit { } shouldShowAuthorIcon(commentType: string) { - return !(commentType === 'extension' || commentType === 'status' || commentType == 'assessment' || commentType == 'scorm'); + return !( + commentType === 'extension' || + commentType === 'status' || + commentType == 'assessment' || + commentType === 'scorm' || + commentType === 'scorm_extension' + ); } commentClasses(comment: TaskComment): object { From e92aac4b701035c286916eae230d9342a8f4b538 Mon Sep 17 00:00:00 2001 From: jakerenzella Date: Wed, 5 Jun 2024 17:15:02 +1000 Subject: [PATCH 0087/1280] build: upgrade packages --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 61ba8cb15a..ed19972737 100644 --- a/package.json +++ b/package.json @@ -157,4 +157,4 @@ "@nx/nx-linux-x64-gnu": "^18.0", "@nx/nx-win32-x64-msvc": "^18.0" } -} +} \ No newline at end of file From a869e7cdc00569e5101784b7d16954d0a0398a2d Mon Sep 17 00:00:00 2001 From: jakerenzella Date: Wed, 5 Jun 2024 19:40:45 +1000 Subject: [PATCH 0088/1280] refactor: (refactor) resolve data from route --- .../root-controller/root-controller.coffee | 2 +- src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire-angularjs.module.ts | 2 +- src/app/doubtfire.states.ts | 28 +++++++-- src/app/home/states/home/home.component.html | 2 +- src/app/home/states/home/home.component.ts | 4 +- .../project-dashboard.component.html | 9 ++- .../project-dashboard.component.ts | 17 ++---- src/app/projects/states/index/index.coffee | 6 +- .../task-definition-upload.component.html | 59 +++++++++++-------- src/app/units/states/edit/edit.coffee | 6 +- src/app/units/states/index/index.coffee | 8 +-- src/app/units/states/rollover/rollover.coffee | 8 +-- 13 files changed, 90 insertions(+), 63 deletions(-) diff --git a/src/app/config/root-controller/root-controller.coffee b/src/app/config/root-controller/root-controller.coffee index 4a9854fc0e..5502b2ae0e 100644 --- a/src/app/config/root-controller/root-controller.coffee +++ b/src/app/config/root-controller/root-controller.coffee @@ -3,6 +3,6 @@ angular.module('doubtfire.config.root-controller', []) # # The Doubtfire root application controller # -.controller("AppCtrl", (GlobalStateService) -> +.controller("AppCtrl", (globalStateService) -> ) diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index d2d55fa723..f5601f7d25 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -173,6 +173,7 @@ import {UnitDropdownComponent} from './common/header/unit-dropdown/unit-dropdown import {TaskDropdownComponent} from './common/header/task-dropdown/task-dropdown.component'; import {SplashScreenComponent} from './home/splash-screen/splash-screen.component'; import {HttpErrorInterceptor} from './common/services/http-error.interceptor'; +import {ProjectDashboardComponent} from './projects/states/dashboard/project-dashboard/project-dashboard.component'; import {TaskDefinitionService} from './api/services/task-definition.service'; import {NewTeachingPeriodDialogComponent} from './admin/states/teaching-periods/teaching-period-list/teaching-period-list.component'; import {MatNativeDateModule} from '@angular/material/core'; @@ -299,6 +300,7 @@ import {TasksViewerComponent} from './units/states/tasks/tasks-viewer/tasks-view UnitDropdownComponent, TaskDropdownComponent, SplashScreenComponent, + ProjectDashboardComponent, ObjectSelectComponent, WelcomeComponent, AcceptEulaComponent, diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index c102584ead..c6395115fd 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -297,7 +297,7 @@ DoubtfireAngularJSModule.factory( downgradeInjectable(TaskAssessmentModalService), ); DoubtfireAngularJSModule.factory('TaskSubmission', downgradeInjectable(TaskSubmissionService)); -DoubtfireAngularJSModule.factory('GlobalStateService', downgradeInjectable(GlobalStateService)); +DoubtfireAngularJSModule.factory('globalStateService', downgradeInjectable(GlobalStateService)); DoubtfireAngularJSModule.factory( 'TransitionHooksService', downgradeInjectable(TransitionHooksService), diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index df6102cec7..4f5b7779c3 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -11,6 +11,9 @@ import {FUnitsComponent} from './admin/states/f-units/f-units.component'; import {ProjectDashboardComponent} from './projects/states/dashboard/project-dashboard/project-dashboard.component'; import {AppInjector} from './app-injector'; import {ProjectService} from './api/services/project.service'; +import {Observable, first} from 'rxjs'; +import {GlobalStateService} from './projects/states/index/global-state.service'; +import {Project} from './api/models/project'; /* * Use this file to store any states that are sourced by angular components. @@ -277,13 +280,28 @@ const AbstractProjectState: NgHybridStateDeclaration = { name: 'projects2', url: '/projects2/:projectId', abstract: true, - // views: { - // }, + views: { + main: { + component: ProjectDashboardComponent, + }, + }, resolve: { - project: function ($stateParams) { - console.log('Getting project'); + project$: function ($stateParams) { const projectService = AppInjector.get(ProjectService); - return projectService.get({id: $stateParams.project_id}); + const globalState = AppInjector.get(GlobalStateService); + + return new Observable((observer) => { + globalState.onLoad(() => { + projectService + .get({id: $stateParams.projectId}, {cacheBehaviourOnGet: 'cacheQuery'}) + .subscribe({ + next: (project: Project) => { + observer.next(project); + observer.complete(); + }, + }); + }); + }).pipe(first()); }, }, }; diff --git a/src/app/home/states/home/home.component.html b/src/app/home/states/home/home.component.html index 43504ef9dd..034ed2791a 100644 --- a/src/app/home/states/home/home.component.html +++ b/src/app/home/states/home/home.component.html @@ -89,7 +89,7 @@

Enrolled units

diff --git a/src/app/home/states/home/home.component.ts b/src/app/home/states/home/home.component.ts index 614ef65299..b2cf5f9068 100644 --- a/src/app/home/states/home/home.component.ts +++ b/src/app/home/states/home/home.component.ts @@ -46,8 +46,8 @@ export class HomeComponent implements OnInit, OnDestroy { } ngOnInit(): void { - const last = this.router.stateRegistry.get()[this.router.stateRegistry.get().length - 1]; - this.router.stateService.go(last, {projectId: 55}); + // const last = this.router.stateRegistry.get()[this.router.stateRegistry.get().length - 1]; + // this.router.stateService.go(last, {projectId: 55}); if (this.userService.isAnonymousUser()) { this.router.stateService.go('sign_in'); } diff --git a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html index db6d335866..1fd9060d63 100644 --- a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html +++ b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html @@ -1,6 +1,11 @@ -
+
- + {{ project.activeTasks() | json }} + @if (subs$ | async) {
; subs$: Observable; @@ -34,7 +28,6 @@ export class ProjectDashboardComponent implements OnInit { private projectService: ProjectService, private globalStateService: GlobalStateService, ) { - console.log('test'); } startedDragging(event: CdkDragStart, div: HTMLDivElement) { @@ -54,8 +47,10 @@ export class ProjectDashboardComponent implements OnInit { } ngOnInit(): void { - console.log('test'); // projectTasks = this.projectService.loadProject + this.project$.subscribe((project) => { + console.log(project); + }); this.dragMoveAudited$ = this.dragMove$.pipe( withLatestFrom(this.leftComponentStartSize$), diff --git a/src/app/projects/states/index/index.coffee b/src/app/projects/states/index/index.coffee index f48cf9c356..fedb8d7608 100644 --- a/src/app/projects/states/index/index.coffee +++ b/src/app/projects/states/index/index.coffee @@ -17,12 +17,12 @@ angular.module('doubtfire.projects.states.index', []) } ) -.controller("ProjectsIndexStateCtrl", ($scope, $rootScope, $state, $stateParams, newProjectService, listenerService, GlobalStateService) -> +.controller("ProjectsIndexStateCtrl", ($scope, $rootScope, $state, $stateParams, newProjectService, listenerService, globalStateService) -> # Error - required projectId is missing! projectId = +$stateParams.projectId return $state.go('home') unless projectId - GlobalStateService.onLoad () -> + globalStateService.onLoad () -> # Load in project newProjectService.get(projectId, { # Ensure that we cache queries here... so that we get any projects we are in @@ -39,7 +39,7 @@ angular.module('doubtfire.projects.states.index', []) $scope.project = project $scope.unit = project.unit if project.unit.taskDefinitions.length > 0 && project.tasks.length == project.unit.taskDefinitions.length - GlobalStateService.setView('PROJECT', $scope.project) + globalStateService.setView('PROJECT', $scope.project) # Go home if no project was found return $state.go('home') unless project? diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html index fe96cfb2df..d53ee750f9 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html @@ -26,11 +26,11 @@ Check Similarity @if (upreq.type === 'document') { -TurnItIn -} + TurnItIn + } @if (upreq.type === 'code') { -Moss -} + Moss + } @@ -39,11 +39,11 @@ Flag At @if (upreq.type === 'document' && upreq.tiiCheck) { - - -  % - -} + + +  % + + } @@ -51,7 +51,12 @@ - @@ -63,7 +68,9 @@ - + @@ -75,19 +82,19 @@ @if (taskDefinition.needsMoss) { -
- - Language used for Moss checks - - C - C# - C++ - Python - - - - Similarity percent to flag for Moss checks - - -
+
+ + Language used for Moss checks + + C + C# + C++ + Python + + + + Similarity percent to flag for Moss checks + + +
} diff --git a/src/app/units/states/edit/edit.coffee b/src/app/units/states/edit/edit.coffee index a8a9eec6d3..5b4f368a14 100644 --- a/src/app/units/states/edit/edit.coffee +++ b/src/app/units/states/edit/edit.coffee @@ -17,11 +17,11 @@ angular.module('doubtfire.units.states.edit', [ roleWhitelist: ['Convenor', 'Admin'] } ) -.controller('EditUnitStateCtrl', ($scope, $state, $stateParams, alertService, analyticsService, newUnitService, newUserService, GlobalStateService) -> - GlobalStateService.onLoad () -> +.controller('EditUnitStateCtrl', ($scope, $state, $stateParams, alertService, analyticsService, newUnitService, newUserService, globalStateService) -> + globalStateService.onLoad () -> $scope.currentStaff = $scope.unit.staff - $scope.assessingUnitRole = GlobalStateService.loadedUnitRoles.currentValues.find((role) -> role.unit == $scope.unit) + $scope.assessingUnitRole = globalStateService.loadedUnitRoles.currentValues.find((role) -> role.unit == $scope.unit) newUserService.getTutors().subscribe( (tutors) -> $scope.staff = tutors ) diff --git a/src/app/units/states/index/index.coffee b/src/app/units/states/index/index.coffee index cd9322d791..3c0298be1c 100644 --- a/src/app/units/states/index/index.coffee +++ b/src/app/units/states/index/index.coffee @@ -17,14 +17,14 @@ angular.module('doubtfire.units.states.index', []) } ) -.controller("UnitsIndexStateCtrl", ($scope, $rootScope, $state, $stateParams, newUnitService, newProjectService, listenerService, GlobalStateService, newUserService, alertService) -> +.controller("UnitsIndexStateCtrl", ($scope, $rootScope, $state, $stateParams, newUnitService, newProjectService, listenerService, globalStateService, newUserService, alertService) -> # Error - required unitId is missing! unitId = +$stateParams.unitId return $state.go('home') unless unitId - GlobalStateService.onLoad () -> + globalStateService.onLoad () -> # Load assessing unit role - $scope.unitRole = GlobalStateService.loadedUnitRoles.currentValues.find((unitRole) -> unitRole.unit.id == unitId) + $scope.unitRole = globalStateService.loadedUnitRoles.currentValues.find((unitRole) -> unitRole.unit.id == unitId) if (! $scope.unitRole?) && ( newUserService.currentUser.role == "Admin" ) $scope.unitRole = newUserService.adminRoleFor(unitId, newUserService.currentUser) @@ -32,7 +32,7 @@ angular.module('doubtfire.units.states.index', []) # Go home if no unit role was found return $state.go('home') unless $scope.unitRole? - GlobalStateService.setView("UNIT", $scope.unitRole) + globalStateService.setView("UNIT", $scope.unitRole) newUnitService.get(unitId).subscribe({ next: (unit)-> diff --git a/src/app/units/states/rollover/rollover.coffee b/src/app/units/states/rollover/rollover.coffee index 97b958fd94..b951e166dc 100644 --- a/src/app/units/states/rollover/rollover.coffee +++ b/src/app/units/states/rollover/rollover.coffee @@ -14,13 +14,13 @@ angular.module('doubtfire.units.states.rollover', [ roleWhitelist: ['Convenor', 'Admin'] } ) -.controller("RolloverUnitState", ($scope, $state, $stateParams, newUnitService, GlobalStateService) -> +.controller("RolloverUnitState", ($scope, $state, $stateParams, newUnitService, globalStateService) -> unitId = +$stateParams.unitId return $state.go('home') unless unitId - GlobalStateService.onLoad () -> + globalStateService.onLoad () -> # Load assessing unit role - $scope.unitRole = GlobalStateService.loadedUnitRoles.currentValues.find((unitRole) -> unitRole.unit.id == unitId) + $scope.unitRole = globalStateService.loadedUnitRoles.currentValues.find((unitRole) -> unitRole.unit.id == unitId) if (! $scope.unitRole?) && ( newUserService.currentUser.role == "Admin" ) $scope.unitRole = newUserService.adminRoleFor(unitId, newUserService.currentUser) @@ -28,7 +28,7 @@ angular.module('doubtfire.units.states.rollover', [ # Go home if no unit role was found return $state.go('home') unless $scope.unitRole? - GlobalStateService.setView("UNIT", $scope.unitRole) + globalStateService.setView("UNIT", $scope.unitRole) newUnitService.get(unitId).subscribe({ next: (unit)-> $scope.unit = unit From 97e1ea187b769a51ebb66b82d76f21193bb29386 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Wed, 5 Jun 2024 23:15:15 +1000 Subject: [PATCH 0089/1280] fix: add auth headers to scorm adapter xhr requests --- src/app/api/services/scorm-adapter.service.ts | 28 +++++++++++++------ 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/src/app/api/services/scorm-adapter.service.ts b/src/app/api/services/scorm-adapter.service.ts index b6014f14b4..085d41610b 100644 --- a/src/app/api/services/scorm-adapter.service.ts +++ b/src/app/api/services/scorm-adapter.service.ts @@ -59,6 +59,8 @@ export class ScormAdapterService { if (this.context.mode === 'review') { this.xhr.open('GET', `${API_URL}/test_attempts/${this.context.attemptId}/review`, false); + this.xhr.setRequestHeader('Auth-Token', this.context.user.authenticationToken); + this.xhr.setRequestHeader('Username', this.context.user.username); this.xhr.onload = () => { if (this.xhr.status >= 200 && this.xhr.status < 400) { @@ -88,6 +90,8 @@ export class ScormAdapterService { `${API_URL}/projects/${this.context.projectId}/task_def_id/${this.context.taskDefId}/test_attempts/latest`, false, ); + this.xhr.setRequestHeader('Auth-Token', this.context.user.authenticationToken); + this.xhr.setRequestHeader('Username', this.context.user.username); let noTestFound = false; let startNewTest = false; @@ -119,6 +123,8 @@ export class ScormAdapterService { if (!startNewTest) { this.xhr.open('PATCH', `${API_URL}/test_attempts/${this.context.attemptId}`, false); + this.xhr.setRequestHeader('Auth-Token', this.context.user.authenticationToken); + this.xhr.setRequestHeader('Username', this.context.user.username); this.xhr.send(); console.log(this.xhr.responseText); @@ -133,6 +139,8 @@ export class ScormAdapterService { `${API_URL}/projects/${this.context.projectId}/task_def_id/${this.context.taskDefId}/test_attempts`, false, ); + this.xhr.setRequestHeader('Auth-Token', this.context.user.authenticationToken); + this.xhr.setRequestHeader('Username', this.context.user.username); this.xhr.send(); console.log(this.xhr.responseText); @@ -163,6 +171,8 @@ export class ScormAdapterService { } this.xhr.open('PATCH', `${API_URL}/test_attempts/${this.context.attemptId}`, false); + this.xhr.setRequestHeader('Auth-Token', this.context.user.authenticationToken); + this.xhr.setRequestHeader('Username', this.context.user.username); this.xhr.setRequestHeader('Content-Type', 'application/json'); const requestData = { cmi_datamodel: JSON.stringify(this.dataModel.dump()), @@ -233,26 +243,28 @@ export class ScormAdapterService { break; } - const xhr = new XMLHttpRequest(); - xhr.open('PATCH', `${API_URL}/test_attempts/${this.context.attemptId}`, true); - xhr.setRequestHeader('Content-Type', 'application/json'); + this.xhr.open('PATCH', `${API_URL}/test_attempts/${this.context.attemptId}`, true); + this.xhr.setRequestHeader('Auth-Token', this.context.user.authenticationToken); + this.xhr.setRequestHeader('Username', this.context.user.username); + this.xhr.setRequestHeader('Content-Type', 'application/json'); const requestData = { cmi_datamodel: JSON.stringify(this.dataModel.dump()), }; - xhr.send(JSON.stringify(requestData)); + - xhr.onload = () => { - if (xhr.status >= 200 && xhr.status < 400) { + this.xhr.onload = () => { + if (this.xhr.status >= 200 && this.xhr.status < 400) { console.log('DataModel saved successfully.'); } else { - console.error('Error saving DataModel:', xhr.responseText); + console.error('Error saving DataModel:', this.xhr.responseText); } }; - xhr.onerror = () => { + this.xhr.onerror = () => { console.error('Request failed.'); }; + this.xhr.send(JSON.stringify(requestData)); this.context.errorCode = 0; return 'true'; } From f0ff40bfd7e86b904adae94bf8cbe5d56371e011 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Wed, 5 Jun 2024 23:42:14 +1000 Subject: [PATCH 0090/1280] fix: remove attempt number field --- src/app/api/models/scorm-player-context.ts | 1 - src/app/api/models/test-attempt.ts | 1 - src/app/api/services/test-attempt.service.ts | 1 - 3 files changed, 3 deletions(-) diff --git a/src/app/api/models/scorm-player-context.ts b/src/app/api/models/scorm-player-context.ts index c065957ac0..195bc3cd4c 100644 --- a/src/app/api/models/scorm-player-context.ts +++ b/src/app/api/models/scorm-player-context.ts @@ -52,7 +52,6 @@ export class ScormPlayerContext { taskDefId: number; user: User; - attemptNumber: number; attemptId: number; learnerName: string; learnerId: number; diff --git a/src/app/api/models/test-attempt.ts b/src/app/api/models/test-attempt.ts index 02bb4bb4e9..646b9ed64f 100644 --- a/src/app/api/models/test-attempt.ts +++ b/src/app/api/models/test-attempt.ts @@ -3,7 +3,6 @@ import {Task} from './doubtfire-model'; export class TestAttempt extends Entity { id: number; - attemptNumber: number; terminated: boolean; completionStatus: boolean; successStatus: boolean; diff --git a/src/app/api/services/test-attempt.service.ts b/src/app/api/services/test-attempt.service.ts index 6c32ed01a8..df5654855f 100644 --- a/src/app/api/services/test-attempt.service.ts +++ b/src/app/api/services/test-attempt.service.ts @@ -20,7 +20,6 @@ export class TestAttemptService extends CachedEntityService { this.mapping.addKeys( 'id', - 'attemptNumber', 'terminated', 'completionStatus', 'successStatus', From 90853e93c109430669e3f80e4324649cd2d0dba6 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 6 Jun 2024 13:54:39 +1000 Subject: [PATCH 0091/1280] fix: link task list to definitions for project dashboard --- .../project-dashboard/project-dashboard.component.html | 6 ++++-- .../tasks/tasks-viewer/tasks-viewer.component.html | 4 ++-- .../f-unit-task-list/f-unit-task-list.component.html | 2 +- .../f-unit-task-list/f-unit-task-list.component.ts | 9 ++++++--- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html index 1fd9060d63..3f8d0ba1b9 100644 --- a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html +++ b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html @@ -1,9 +1,11 @@
- {{ project.activeTasks() | json }} + {{ project.activeTasks().length }} + {{ project.unit.taskDefinitions.length }} @if (subs$ | async) { diff --git a/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.html b/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.html index 04e36917e5..b9a3259c22 100644 --- a/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.html +++ b/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.html @@ -3,7 +3,7 @@
- +
@@ -23,7 +23,7 @@
- +
diff --git a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html b/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html index 1ca78334f0..d21e6003c8 100644 --- a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html +++ b/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html @@ -21,7 +21,7 @@
- + @if (filteredTasks.length === 0) {
No tasks to display
} diff --git a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.ts b/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.ts index d4dee931d5..334de8d13e 100644 --- a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.ts +++ b/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.ts @@ -11,7 +11,7 @@ import {TasksViewerService} from '../../../tasks-viewer.service'; }) export class FUnitTaskListComponent implements OnInit { @Input() mode: 'project' | 'all-tasks'; - @Input() tasks: TaskDefinition[]; + @Input() taskDefinitions: TaskDefinition[]; filteredTasks: TaskDefinition[]; // list of tasks which match the taskSearch term taskSearch: string = ''; // task search term from user input @@ -23,7 +23,10 @@ export class FUnitTaskListComponent implements OnInit { constructor(private taskViewerService: TasksViewerService) {} applyFilters() { - this.filteredTasks = this.taskDefinitionNamePipe.transform(this.tasks, this.taskSearch); + this.filteredTasks = this.taskDefinitionNamePipe.transform( + this.taskDefinitions, + this.taskSearch, + ); } ngOnInit(): void { @@ -32,7 +35,7 @@ export class FUnitTaskListComponent implements OnInit { this.taskViewerService.selectedTaskDef.subscribe((taskDef) => { this.selectedTaskDef = taskDef; }); - this.taskViewerService.selectedTaskDef.next(this.tasks[0]); + this.taskViewerService.selectedTaskDef.next(this.taskDefinitions[0]); this.taskViewerService.taskSelected.subscribe((taskSelected) => { this.taskSelected = taskSelected; From 119d7eca36b9856724b0a15e151ad32af48775d9 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 6 Jun 2024 20:23:12 +1000 Subject: [PATCH 0092/1280] chore: wire up project dashboard task list --- .../project-dashboard.component.html | 7 +++- .../project-dashboard.component.ts | 34 +++++++++++++++-- .../f-unit-task-list.component.html | 5 ++- .../f-unit-task-list.component.ts | 37 ++++++++++++++++--- 4 files changed, 70 insertions(+), 13 deletions(-) diff --git a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html index 3f8d0ba1b9..051f7edfdd 100644 --- a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html +++ b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html @@ -2,11 +2,16 @@
{{ project.activeTasks().length }} {{ project.unit.taskDefinitions.length }} +
+

Selected task definition: {{ selectedTaskDefinition.abbreviation }}

+
@if (subs$ | async) {
; + /** + * Reference to the unit task list component so that we can create an + * observer of the selected task definition. + */ + private unitTaskListPlaceholder: FUnitTaskListComponent; + + @ViewChild('unitTaskList') set unitTaskList(content: FUnitTaskListComponent) { + if (content) { + // initially setter gets called with undefined + this.unitTaskListPlaceholder = content; + this.selectedTaskDefinition$ = outputToObservable(this.unitTaskListPlaceholder.selectedTaskDefinition); + + // Triger event for first selected task? -- not a behaviour subject? How can we avoid this? + setTimeout(() => { + this.unitTaskListPlaceholder.selectedTaskDefinition.emit(this.unitTaskListPlaceholder.selectedTaskDef); + }); + } + } + + /** + * The currently selected task definition - selected in the unit task list. + */ + public selectedTaskDefinition$: Observable; + subs$: Observable; private leftComponentStartSize$ = new Subject(); private dragMove$ = new Subject<{event: CdkDragMove; div: HTMLDivElement}>(); private dragMoveAudited$; + projectTasks = []; constructor( private currentUser: UserService, private projectService: ProjectService, private globalStateService: GlobalStateService, - ) { - } + ) {} startedDragging(event: CdkDragStart, div: HTMLDivElement) { event.source.element.nativeElement.classList.add('hovering'); diff --git a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html b/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html index d21e6003c8..96f8b86b88 100644 --- a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html +++ b/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html @@ -30,9 +30,9 @@ @if (task) {
@@ -46,6 +46,7 @@

{{ task.name }}

group }
{{ gradeNames[task.targetGrade] }} Task
+

{{ taskForTaskDef(task).status }}

diff --git a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.ts b/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.ts index 334de8d13e..7d68d75f28 100644 --- a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.ts +++ b/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.ts @@ -1,6 +1,6 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {Component, Input, OnInit, output} from '@angular/core'; import {Grade} from 'src/app/api/models/grade'; -import {TaskDefinition} from 'src/app/api/models/doubtfire-model'; +import {TaskDefinition, Task} from 'src/app/api/models/doubtfire-model'; import {TaskDefinitionNamePipe} from 'src/app/common/filters/task-definition-name.pipe'; import {TasksViewerService} from '../../../tasks-viewer.service'; @@ -12,6 +12,11 @@ import {TasksViewerService} from '../../../tasks-viewer.service'; export class FUnitTaskListComponent implements OnInit { @Input() mode: 'project' | 'all-tasks'; @Input() taskDefinitions: TaskDefinition[]; + @Input() tasks: Task[]; + + selectedTaskDefinition = output(); + + // @Output() selectedTask: EventEmitter = new EventEmitter(); filteredTasks: TaskDefinition[]; // list of tasks which match the taskSearch term taskSearch: string = ''; // task search term from user input @@ -29,24 +34,44 @@ export class FUnitTaskListComponent implements OnInit { ); } + public get hasTasks(): boolean { + return this.tasks && this.tasks.length > 0; + } + + public taskForTaskDef(taskDef: TaskDefinition): Task { + return this.tasks.find((task) => task.definition.id === taskDef.id); + } + ngOnInit(): void { this.applyFilters(); + // TODO: Remove the service this.taskViewerService.selectedTaskDef.subscribe((taskDef) => { this.selectedTaskDef = taskDef; }); - this.taskViewerService.selectedTaskDef.next(this.taskDefinitions[0]); this.taskViewerService.taskSelected.subscribe((taskSelected) => { this.taskSelected = taskSelected; }); + + // Select the first task definition by default + if (this.taskDefinitions.length > 0) { + this.setSelectedTaskDefinition(this.taskDefinitions[0]); + } } - setSelectedTask(task: TaskDefinition) { - this.taskViewerService.setSelectedTaskDef(task); + setSelectedTaskDefinition(taskDef: TaskDefinition) { + this.selectedTaskDefinition.emit(taskDef); + // const selectedTask = this.taskForTaskDef(taskDef); + // if (selectedTask) { + // this.selectedTask$.next(selectedTask); + // } + + //TODO: remove + this.taskViewerService.setSelectedTaskDef(taskDef); } - isSelectedTask(task: TaskDefinition) { + isSelectedTaskDefinition(task: TaskDefinition) { return this.selectedTaskDef.id == task.id; } } From 9bc48b03905c0a839d78ea13be9817ca73ba54cf Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Thu, 6 Jun 2024 20:53:45 +1000 Subject: [PATCH 0093/1280] fix: disable launch scorm test button if user is staff --- .../task-scorm-card/task-scorm-card.component.html | 7 ++++++- .../task-scorm-card/task-scorm-card.component.ts | 10 ++++++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html index 1929afb248..ec385b4760 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html @@ -14,7 +14,12 @@

- diff --git a/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.scss b/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.scss similarity index 100% rename from src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.scss rename to src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.scss diff --git a/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.spec.ts b/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.spec.ts similarity index 100% rename from src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.spec.ts rename to src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.spec.ts diff --git a/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.ts b/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.ts new file mode 100644 index 0000000000..e079155f96 --- /dev/null +++ b/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.ts @@ -0,0 +1,34 @@ +import {Component, Input} from '@angular/core'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; +import {BehaviorSubject} from 'rxjs'; + +@Component({ + selector: 'f-tasks-viewer', + templateUrl: './f-tasks-viewer.component.html', + styleUrls: ['./f-tasks-viewer.component.scss'], +}) +export class TasksViewerComponent { + @Input() taskDefs: TaskDefinition[]; + @Input() unit: Unit; + + /** + * Monitor and publish the selected task definition for child components. + * We monitor the task definition list for changes in selected task definition. + */ + selectedTaskDefinition$: BehaviorSubject = new BehaviorSubject( + null, + ); + + public get taskSelected(): boolean { + return this.selectedTaskDef !== null; + } + + public get selectedTaskDef(): TaskDefinition { + return this.selectedTaskDefinition$.value; + } + + public clearTaskSelection(): void { + this.selectedTaskDefinition$.next(null); + } +} diff --git a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html b/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.html similarity index 98% rename from src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html rename to src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.html index 96f8b86b88..9b0adcaf33 100644 --- a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.html +++ b/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.html @@ -12,7 +12,7 @@ spellcheck="false" type="text" placeholder="Search Tasks" - [(ngModel)]="taskSearch" + [(ngModel)]="searchText" (ngModelChange)="applyFilters()" />
diff --git a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.scss b/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.scss similarity index 100% rename from src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.scss rename to src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.scss diff --git a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.spec.ts b/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.spec.ts similarity index 88% rename from src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.spec.ts rename to src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.spec.ts index dc592e52cc..3ac584b5e7 100644 --- a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.spec.ts +++ b/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FUnitTaskListComponent } from './f-unit-task-list.component'; +import { FUnitTaskListComponent } from './unit-task-list.component'; describe('FUnitTaskListComponent', () => { let component: FUnitTaskListComponent; diff --git a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.ts b/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.ts similarity index 54% rename from src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.ts rename to src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.ts index 7d68d75f28..1482c7770d 100644 --- a/src/app/units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component.ts +++ b/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.ts @@ -1,8 +1,8 @@ -import {Component, Input, OnInit, output} from '@angular/core'; +import {Component, Input, OnInit} from '@angular/core'; import {Grade} from 'src/app/api/models/grade'; import {TaskDefinition, Task} from 'src/app/api/models/doubtfire-model'; import {TaskDefinitionNamePipe} from 'src/app/common/filters/task-definition-name.pipe'; -import {TasksViewerService} from '../../../tasks-viewer.service'; +import { BehaviorSubject } from 'rxjs'; @Component({ selector: 'f-unit-task-list', @@ -14,23 +14,21 @@ export class FUnitTaskListComponent implements OnInit { @Input() taskDefinitions: TaskDefinition[]; @Input() tasks: Task[]; - selectedTaskDefinition = output(); + // What is the selected task definition + @Input() selectedTaskDefinition$: BehaviorSubject; // @Output() selectedTask: EventEmitter = new EventEmitter(); filteredTasks: TaskDefinition[]; // list of tasks which match the taskSearch term - taskSearch: string = ''; // task search term from user input + searchText: string = ''; // task search term from user input taskDefinitionNamePipe = new TaskDefinitionNamePipe(); protected gradeNames: string[] = Grade.GRADES; selectedTaskDef: TaskDefinition; - taskSelected: boolean; - - constructor(private taskViewerService: TasksViewerService) {} applyFilters() { this.filteredTasks = this.taskDefinitionNamePipe.transform( this.taskDefinitions, - this.taskSearch, + this.searchText, ); } @@ -45,33 +43,44 @@ export class FUnitTaskListComponent implements OnInit { ngOnInit(): void { this.applyFilters(); - // TODO: Remove the service - this.taskViewerService.selectedTaskDef.subscribe((taskDef) => { + // Watch for changes in the selected task definition... including from us + this.selectedTaskDefinition$.subscribe((taskDef) => { this.selectedTaskDef = taskDef; }); - this.taskViewerService.taskSelected.subscribe((taskSelected) => { - this.taskSelected = taskSelected; - }); + // // TODO: Remove the service + // this.taskViewerService.selectedTaskDef.subscribe((taskDef) => { + // this.selectedTaskDef = taskDef; + // }); - // Select the first task definition by default - if (this.taskDefinitions.length > 0) { - this.setSelectedTaskDefinition(this.taskDefinitions[0]); - } + // this.taskViewerService.taskSelected.subscribe((taskSelected) => { + // this.taskSelected = taskSelected; + // }); + + // // Select the first task definition by default + // if (this.taskDefinitions.length > 0) { + // this.setSelectedTaskDefinition(this.taskDefinitions[0]); + // } } setSelectedTaskDefinition(taskDef: TaskDefinition) { - this.selectedTaskDefinition.emit(taskDef); + if (this.isSelectedTaskDefinition(taskDef)) { + this.selectedTaskDefinition$.next(null); + } else { + this.selectedTaskDefinition$.next(taskDef); + } + + // this.selectedTaskDefinition.emit(taskDef); // const selectedTask = this.taskForTaskDef(taskDef); // if (selectedTask) { // this.selectedTask$.next(selectedTask); // } //TODO: remove - this.taskViewerService.setSelectedTaskDef(taskDef); + // this.taskViewerService.setSelectedTaskDef(taskDef); } - isSelectedTaskDefinition(task: TaskDefinition) { - return this.selectedTaskDef.id == task.id; + public isSelectedTaskDefinition(taskDef: TaskDefinition) { + return this.selectedTaskDef?.id === taskDef?.id; } } From 0e5d9de9df2eaf16e473f4f8fde920ffb59ce765 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Sat, 8 Jun 2024 17:51:01 +1000 Subject: [PATCH 0097/1280] fix: switch staff to unit roles in unit service --- src/app/api/services/unit.service.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/api/services/unit.service.ts b/src/app/api/services/unit.service.ts index 740e9b6cc1..3c97a11fed 100644 --- a/src/app/api/services/unit.service.ts +++ b/src/app/api/services/unit.service.ts @@ -50,10 +50,10 @@ export class UnitService extends CachedEntityService { toEntityFn: (data: object, jsonKey: string, entity: Unit) => { const unitRoleService = AppInjector.get(UnitRoleService); unitRoleService.cache.get(data[jsonKey]); - } + }, }, { - keys: 'staff', + keys: 'unitRoles', toEntityOp: (data, key, entity) => { const unitRoleService = AppInjector.get(UnitRoleService); // Add staff From ea710d6481157e2fecdd83d5e828b201bbe5afdf Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Sat, 8 Jun 2024 17:58:11 +1000 Subject: [PATCH 0098/1280] refactor: correct file renames to remove f- --- .../f-units.component.html => units/units.component.html} | 0 .../f-units.component.scss => units/units.component.scss} | 0 .../units.component.spec.ts} | 0 .../f-units.component.ts => units/units.component.ts} | 4 ++-- .../f-users.component.html => users/users.component.html} | 0 .../f-users.component.scss => users/users.component.scss} | 0 .../f-users.component.ts => users/users.component.ts} | 4 ++-- .../f-chip/{f-chip.component.html => chip.component.html} | 0 .../f-chip/{f-chip.component.scss => chip.component.scss} | 0 .../{f-chip.component.spec.ts => chip.component.spec.ts} | 2 +- .../f-chip/{f-chip.component.ts => chip.component.ts} | 4 ++-- src/app/doubtfire-angular.module.ts | 6 +++--- src/app/doubtfire-angularjs.module.ts | 4 ++-- src/app/doubtfire.states.ts | 4 ++-- .../task-details-view/task-details-view.component.ts | 4 ++-- .../directives/task-sheet-view/task-sheet-view.component.ts | 4 ++-- .../directives/tasks-viewer/tasks-viewer.component.ts | 4 ++-- .../directives/unit-task-list/unit-task-list.component.ts | 4 ++-- 18 files changed, 22 insertions(+), 22 deletions(-) rename src/app/admin/states/{f-units/f-units.component.html => units/units.component.html} (100%) rename src/app/admin/states/{f-units/f-units.component.scss => units/units.component.scss} (100%) rename src/app/admin/states/{f-units/f-units.component.spec.ts => units/units.component.spec.ts} (100%) rename src/app/admin/states/{f-units/f-units.component.ts => units/units.component.ts} (98%) rename src/app/admin/states/{f-users/f-users.component.html => users/users.component.html} (100%) rename src/app/admin/states/{f-users/f-users.component.scss => users/users.component.scss} (100%) rename src/app/admin/states/{f-users/f-users.component.ts => users/users.component.ts} (98%) rename src/app/common/f-chip/{f-chip.component.html => chip.component.html} (100%) rename src/app/common/f-chip/{f-chip.component.scss => chip.component.scss} (100%) rename src/app/common/f-chip/{f-chip.component.spec.ts => chip.component.spec.ts} (91%) rename src/app/common/f-chip/{f-chip.component.ts => chip.component.ts} (57%) diff --git a/src/app/admin/states/f-units/f-units.component.html b/src/app/admin/states/units/units.component.html similarity index 100% rename from src/app/admin/states/f-units/f-units.component.html rename to src/app/admin/states/units/units.component.html diff --git a/src/app/admin/states/f-units/f-units.component.scss b/src/app/admin/states/units/units.component.scss similarity index 100% rename from src/app/admin/states/f-units/f-units.component.scss rename to src/app/admin/states/units/units.component.scss diff --git a/src/app/admin/states/f-units/f-units.component.spec.ts b/src/app/admin/states/units/units.component.spec.ts similarity index 100% rename from src/app/admin/states/f-units/f-units.component.spec.ts rename to src/app/admin/states/units/units.component.spec.ts diff --git a/src/app/admin/states/f-units/f-units.component.ts b/src/app/admin/states/units/units.component.ts similarity index 98% rename from src/app/admin/states/f-units/f-units.component.ts rename to src/app/admin/states/units/units.component.ts index 03ce4ddad6..c4292152bf 100644 --- a/src/app/admin/states/f-units/f-units.component.ts +++ b/src/app/admin/states/units/units.component.ts @@ -30,8 +30,8 @@ type IUnitOrProject = { @Component({ selector: 'f-units', - templateUrl: './f-units.component.html', - styleUrls: ['./f-units.component.scss'], + templateUrl: './units.component.html', + styleUrls: ['./units.component.scss'], }) export class FUnitsComponent implements OnInit, AfterViewInit { @ViewChild(MatTable, {static: false}) table: MatTable; diff --git a/src/app/admin/states/f-users/f-users.component.html b/src/app/admin/states/users/users.component.html similarity index 100% rename from src/app/admin/states/f-users/f-users.component.html rename to src/app/admin/states/users/users.component.html diff --git a/src/app/admin/states/f-users/f-users.component.scss b/src/app/admin/states/users/users.component.scss similarity index 100% rename from src/app/admin/states/f-users/f-users.component.scss rename to src/app/admin/states/users/users.component.scss diff --git a/src/app/admin/states/f-users/f-users.component.ts b/src/app/admin/states/users/users.component.ts similarity index 98% rename from src/app/admin/states/f-users/f-users.component.ts rename to src/app/admin/states/users/users.component.ts index 7865e6801f..88c70c29e0 100644 --- a/src/app/admin/states/f-users/f-users.component.ts +++ b/src/app/admin/states/users/users.component.ts @@ -12,8 +12,8 @@ import { AlertService } from 'src/app/common/services/alert.service'; @Component({ selector: 'f-users', - templateUrl: './f-users.component.html', - styleUrls: ['./f-users.component.scss'], + templateUrl: './users.component.html', + styleUrls: ['./users.component.scss'], }) export class FUsersComponent implements OnInit, AfterViewInit, OnDestroy { @ViewChild(MatTable, { static: false }) table: MatTable; diff --git a/src/app/common/f-chip/f-chip.component.html b/src/app/common/f-chip/chip.component.html similarity index 100% rename from src/app/common/f-chip/f-chip.component.html rename to src/app/common/f-chip/chip.component.html diff --git a/src/app/common/f-chip/f-chip.component.scss b/src/app/common/f-chip/chip.component.scss similarity index 100% rename from src/app/common/f-chip/f-chip.component.scss rename to src/app/common/f-chip/chip.component.scss diff --git a/src/app/common/f-chip/f-chip.component.spec.ts b/src/app/common/f-chip/chip.component.spec.ts similarity index 91% rename from src/app/common/f-chip/f-chip.component.spec.ts rename to src/app/common/f-chip/chip.component.spec.ts index f431488a66..a08f153a40 100644 --- a/src/app/common/f-chip/f-chip.component.spec.ts +++ b/src/app/common/f-chip/chip.component.spec.ts @@ -1,6 +1,6 @@ import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { FChipComponent } from './f-chip.component'; +import { FChipComponent } from './chip.component'; describe('FChipComponent', () => { let component: FChipComponent; diff --git a/src/app/common/f-chip/f-chip.component.ts b/src/app/common/f-chip/chip.component.ts similarity index 57% rename from src/app/common/f-chip/f-chip.component.ts rename to src/app/common/f-chip/chip.component.ts index de2a1e148f..ffabb6d523 100644 --- a/src/app/common/f-chip/f-chip.component.ts +++ b/src/app/common/f-chip/chip.component.ts @@ -2,7 +2,7 @@ import { Component } from '@angular/core'; @Component({ selector: 'f-chip', - templateUrl: './f-chip.component.html', - styleUrls: ['./f-chip.component.scss'], + templateUrl: './chip.component.html', + styleUrls: ['./chip.component.scss'], }) export class FChipComponent {} diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 871204b847..ede7f5439b 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -194,7 +194,7 @@ import {TaskDashboardComponent} from './projects/states/dashboard/directives/tas import {InboxComponent} from './units/states/tasks/inbox/inbox.component'; import {ProjectProgressBarComponent} from './common/project-progress-bar/project-progress-bar.component'; import {TeachingPeriodListComponent} from './admin/states/teaching-periods/teaching-period-list/teaching-period-list.component'; -import {FChipComponent} from './common/f-chip/f-chip.component'; +import {FChipComponent} from './common/f-chip/chip.component'; import {TaskSimilarityViewComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component'; import {FileViewerComponent} from './common/file-viewer/file-viewer.component'; import {TaskDefinitionEditorComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component'; @@ -208,7 +208,7 @@ import {TaskDefinitionOverseerComponent} from './units/states/edit/directives/un import {UnitAnalyticsComponent} from './units/states/analytics/unit-analytics-route.component'; import {FileDropComponent} from './common/file-drop/file-drop.component'; import {UnitTaskEditorComponent} from './units/states/edit/directives/unit-tasks-editor/unit-task-editor.component'; -import {FUsersComponent} from './admin/states/f-users/f-users.component'; +import {FUsersComponent} from './admin/states/users/users.component'; import {ProjectProgressComponent} from './common/project-progress/project-progress.component'; import {CreateNewUnitModal} from './admin/modals/create-new-unit-modal/create-new-unit-modal.component'; import {CreateNewUnitModalContentComponent} from './admin/modals/create-new-unit-modal/create-new-unit-modal-content.component'; @@ -219,7 +219,7 @@ import { import {AcceptEulaComponent} from './eula/accept-eula/accept-eula.component'; import {TiiActionLogComponent} from './admin/tii-action-log/tii-action-log.component'; import {TiiActionService} from './api/services/tii-action.service'; -import {FUnitsComponent} from './admin/states/f-units/f-units.component'; +import {FUnitsComponent} from './admin/states/units/units.component'; import {FUnitTaskListComponent} from './units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component'; import {FTaskDetailsViewComponent} from './units/states/tasks/viewer/directives/task-details-view/task-details-view.component'; import {FTaskSheetViewComponent} from './units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component'; diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index a8aa825897..03426ebc18 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -215,13 +215,13 @@ import {UnitAnalyticsComponent} from './units/states/analytics/unit-analytics-ro import {UnitTaskEditorComponent} from './units/states/edit/directives/unit-tasks-editor/unit-task-editor.component'; import {TeachingPeriodUnitImportService} from './admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog'; import {CreateNewUnitModal} from './admin/modals/create-new-unit-modal/create-new-unit-modal.component'; -import {FUsersComponent} from './admin/states/f-users/f-users.component'; +import {FUsersComponent} from './admin/states/users/users.component'; import {FUnitTaskListComponent} from './units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component'; import {FTaskDetailsViewComponent} from './units/states/tasks/viewer/directives/task-details-view/task-details-view.component'; import {FTaskSheetViewComponent} from './units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component'; import {TasksViewerComponent} from './units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component'; -import {FUnitsComponent} from './admin/states/f-units/f-units.component'; +import {FUnitsComponent} from './admin/states/units/units.component'; import {MarkedPipe} from './common/pipes/marked.pipe'; import {AlertService} from './common/services/alert.service'; import {GradeService} from './common/services/grade.service'; diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index 8725cff1d0..fe216a6119 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -6,8 +6,8 @@ import {SignInComponent} from './sessions/states/sign-in/sign-in.component'; import {EditProfileComponent} from './account/edit-profile/edit-profile.component'; import {TeachingPeriodListComponent} from './admin/states/teaching-periods/teaching-period-list/teaching-period-list.component'; import {AcceptEulaComponent} from './eula/accept-eula/accept-eula.component'; -import {FUsersComponent} from './admin/states/f-users/f-users.component'; -import {FUnitsComponent} from './admin/states/f-units/f-units.component'; +import {FUsersComponent} from './admin/states/users/users.component'; +import {FUnitsComponent} from './admin/states/units/units.component'; import {ProjectDashboardComponent} from './projects/states/dashboard/project-dashboard/project-dashboard.component'; import {AppInjector} from './app-injector'; import {ProjectService} from './api/services/project.service'; diff --git a/src/app/units/states/tasks/viewer/directives/task-details-view/task-details-view.component.ts b/src/app/units/states/tasks/viewer/directives/task-details-view/task-details-view.component.ts index d681ebe587..932bf37db1 100644 --- a/src/app/units/states/tasks/viewer/directives/task-details-view/task-details-view.component.ts +++ b/src/app/units/states/tasks/viewer/directives/task-details-view/task-details-view.component.ts @@ -4,8 +4,8 @@ import {Unit} from 'src/app/api/models/unit'; @Component({ selector: 'f-task-details-view', - templateUrl: './f-task-details-view.component.html', - styleUrls: ['./f-task-details-view.component.scss'], + templateUrl: './task-details-view.component.html', + styleUrls: ['./task-details-view.component.scss'], }) export class FTaskDetailsViewComponent { @Input() taskDef: TaskDefinition; diff --git a/src/app/units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component.ts b/src/app/units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component.ts index 5a6171ac97..b5d71a7c52 100644 --- a/src/app/units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component.ts +++ b/src/app/units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component.ts @@ -3,8 +3,8 @@ import { TaskDefinition } from 'src/app/api/models/task-definition'; @Component({ selector: 'f-task-sheet-view', - templateUrl: './f-task-sheet-view.component.html', - styleUrls: ['./f-task-sheet-view.component.scss'], + templateUrl: './task-sheet-view.component.html', + styleUrls: ['./task-sheet-view.component.scss'], }) export class FTaskSheetViewComponent { @Input() taskDef: TaskDefinition; diff --git a/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.ts b/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.ts index e079155f96..09b21e3fa4 100644 --- a/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.ts +++ b/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.ts @@ -5,8 +5,8 @@ import {BehaviorSubject} from 'rxjs'; @Component({ selector: 'f-tasks-viewer', - templateUrl: './f-tasks-viewer.component.html', - styleUrls: ['./f-tasks-viewer.component.scss'], + templateUrl: './tasks-viewer.component.html', + styleUrls: ['./tasks-viewer.component.scss'], }) export class TasksViewerComponent { @Input() taskDefs: TaskDefinition[]; diff --git a/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.ts b/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.ts index 1482c7770d..f23c21568e 100644 --- a/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.ts +++ b/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.ts @@ -6,8 +6,8 @@ import { BehaviorSubject } from 'rxjs'; @Component({ selector: 'f-unit-task-list', - templateUrl: './f-unit-task-list.component.html', - styleUrls: ['./f-unit-task-list.component.scss'], + templateUrl: './unit-task-list.component.html', + styleUrls: ['./unit-task-list.component.scss'], }) export class FUnitTaskListComponent implements OnInit { @Input() mode: 'project' | 'all-tasks'; From dc2c0bcbe1d0562bfbe8a8babcca8a77f1fd3a87 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Sat, 8 Jun 2024 18:01:05 +1000 Subject: [PATCH 0099/1280] refactor: update project dashboard to use selected task def subject --- .../project-dashboard/project-dashboard.component.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html index 051f7edfdd..5af2305c8d 100644 --- a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html +++ b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html @@ -10,8 +10,7 @@ [mode]="'project'" [taskDefinitions]="project.unit.taskDefinitions" [tasks]="project.tasks" - (selectedTaskDefinition)="(selectedTaskDefinition$)" - #unitTaskList + [selectedTaskDefinition$]="selectedTaskDefinition$" > @if (subs$ | async) {
Date: Sat, 8 Jun 2024 22:06:21 +1000 Subject: [PATCH 0100/1280] refactor: implement unit root state and new task viewer state --- .../filters/task-definition-name.pipe.ts | 13 +-- .../unit-dropdown.component.html | 2 +- src/app/doubtfire-angular.module.ts | 12 ++- src/app/doubtfire-angularjs.module.ts | 10 +-- src/app/doubtfire.states.ts | 6 +- src/app/units/states/tasks/tasks.coffee | 1 - .../tasks/viewer/directives/directives.coffee | 5 -- .../units/states/tasks/viewer/viewer.coffee | 23 ----- src/app/units/states/tasks/viewer/viewer.scss | 4 - .../units/states/tasks/viewer/viewer.tpl.html | 1 - .../task-details-view.component.html | 0 .../task-details-view.component.scss | 0 .../task-details-view.component.ts | 0 .../task-sheet-view.component.html | 0 .../task-sheet-view.component.scss | 0 .../task-sheet-view.component.spec.ts | 0 .../task-sheet-view.component.ts | 0 .../tasks-viewer/tasks-viewer.component.html | 2 +- .../tasks-viewer/tasks-viewer.component.scss | 0 .../tasks-viewer.component.spec.ts | 0 .../tasks-viewer/tasks-viewer.component.ts | 1 - .../unit-task-list.component.html | 0 .../unit-task-list.component.scss | 0 .../unit-task-list.component.spec.ts | 0 .../unit-task-list.component.ts | 0 .../task-viewer-state.component.html | 3 + .../task-viewer-state.component.scss | 25 ++++++ .../task-viewer-state.component.ts | 44 +++++++++ src/app/units/unit-root-state.component.css | 0 src/app/units/unit-root-state.component.html | 1 + src/app/units/unit-root-state.component.ts | 90 +++++++++++++++++++ 31 files changed, 189 insertions(+), 54 deletions(-) delete mode 100644 src/app/units/states/tasks/viewer/directives/directives.coffee delete mode 100644 src/app/units/states/tasks/viewer/viewer.coffee delete mode 100644 src/app/units/states/tasks/viewer/viewer.scss delete mode 100644 src/app/units/states/tasks/viewer/viewer.tpl.html rename src/app/units/{states/tasks/viewer => task-viewer}/directives/task-details-view/task-details-view.component.html (100%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/task-details-view/task-details-view.component.scss (100%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/task-details-view/task-details-view.component.ts (100%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/task-sheet-view/task-sheet-view.component.html (100%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/task-sheet-view/task-sheet-view.component.scss (100%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/task-sheet-view/task-sheet-view.component.spec.ts (100%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/task-sheet-view/task-sheet-view.component.ts (100%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/tasks-viewer/tasks-viewer.component.html (97%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/tasks-viewer/tasks-viewer.component.scss (100%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/tasks-viewer/tasks-viewer.component.spec.ts (100%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/tasks-viewer/tasks-viewer.component.ts (96%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/unit-task-list/unit-task-list.component.html (100%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/unit-task-list/unit-task-list.component.scss (100%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/unit-task-list/unit-task-list.component.spec.ts (100%) rename src/app/units/{states/tasks/viewer => task-viewer}/directives/unit-task-list/unit-task-list.component.ts (100%) create mode 100644 src/app/units/task-viewer/task-viewer-state.component.html create mode 100644 src/app/units/task-viewer/task-viewer-state.component.scss create mode 100644 src/app/units/task-viewer/task-viewer-state.component.ts create mode 100644 src/app/units/unit-root-state.component.css create mode 100644 src/app/units/unit-root-state.component.html create mode 100644 src/app/units/unit-root-state.component.ts diff --git a/src/app/common/filters/task-definition-name.pipe.ts b/src/app/common/filters/task-definition-name.pipe.ts index 155595d2ff..ad9ccdce18 100644 --- a/src/app/common/filters/task-definition-name.pipe.ts +++ b/src/app/common/filters/task-definition-name.pipe.ts @@ -1,4 +1,3 @@ - import { Pipe, PipeTransform } from '@angular/core'; import { Task, TaskDefinition } from '../../api/models/doubtfire-model'; @@ -10,10 +9,12 @@ export class TaskDefinitionNamePipe implements PipeTransform { searchName = searchName.toLowerCase(); return taskDefinitions.filter( // use lodash filter? (td) => { - return td.name.toLowerCase().includes(searchName) || - td.abbreviation.toLowerCase().includes(searchName) || - td.targetGradeText.toLowerCase().includes(searchName) - } - ) + return ( + td?.name.toLowerCase().includes(searchName) || + td?.abbreviation.toLowerCase().includes(searchName) || + td?.targetGradeText.toLowerCase().includes(searchName) + ); + }, + ); } } diff --git a/src/app/common/header/unit-dropdown/unit-dropdown.component.html b/src/app/common/header/unit-dropdown/unit-dropdown.component.html index 8ac2a35e17..60b67ece95 100644 --- a/src/app/common/header/unit-dropdown/unit-dropdown.component.html +++ b/src/app/common/header/unit-dropdown/unit-dropdown.component.html @@ -5,7 +5,7 @@ [shiftBetweenBadges]="false" [width]="80" [unit_code]="unit?.code" - matTooltip="{{ unit.name }}" + matTooltip="{{ unit?.name }}" [matMenuTriggerFor]="menu" #menuState="matMenuTrigger" > diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index ede7f5439b..9582928c63 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -220,12 +220,14 @@ import {AcceptEulaComponent} from './eula/accept-eula/accept-eula.component'; import {TiiActionLogComponent} from './admin/tii-action-log/tii-action-log.component'; import {TiiActionService} from './api/services/tii-action.service'; import {FUnitsComponent} from './admin/states/units/units.component'; -import {FUnitTaskListComponent} from './units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component'; -import {FTaskDetailsViewComponent} from './units/states/tasks/viewer/directives/task-details-view/task-details-view.component'; -import {FTaskSheetViewComponent} from './units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component'; -import {TasksViewerComponent} from './units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component'; +import {FUnitTaskListComponent} from './units/task-viewer/directives/unit-task-list/unit-task-list.component'; +import {FTaskDetailsViewComponent} from './units/task-viewer/directives/task-details-view/task-details-view.component'; +import {FTaskSheetViewComponent} from './units/task-viewer/directives/task-sheet-view/task-sheet-view.component'; +import {TasksViewerComponent} from './units/task-viewer/directives/tasks-viewer/tasks-viewer.component'; import {UnitCodeComponent} from './common/unit-code/unit-code.component'; import {GradeService} from './common/services/grade.service'; +import { UnitRootStateComponent } from './units/unit-root-state.component'; +import { TaskViewerStateComponent } from './units/task-viewer/task-viewer-state.component'; @NgModule({ // Components we declare @@ -325,6 +327,8 @@ import {GradeService} from './common/services/grade.service'; FTaskDetailsViewComponent, FTaskSheetViewComponent, TasksViewerComponent, + UnitRootStateComponent, + TaskViewerStateComponent, FUsersComponent, ProjectProgressComponent, FTaskBadgeComponent, diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 03426ebc18..7f77443a7e 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -98,8 +98,6 @@ import 'build/src/app/units/modals/modals.js'; import 'build/src/app/units/units.js'; import 'build/src/app/units/states/tasks/inbox/inbox.js'; import 'build/src/app/units/states/tasks/tasks.js'; -import 'build/src/app/units/states/tasks/viewer/directives/directives.js'; -import 'build/src/app/units/states/tasks/viewer/viewer.js'; import 'build/src/app/units/states/tasks/definition/definition.js'; import 'build/src/app/units/states/portfolios/portfolios.js'; import 'build/src/app/units/states/groups/groups.js'; @@ -216,10 +214,10 @@ import {UnitTaskEditorComponent} from './units/states/edit/directives/unit-tasks import {TeachingPeriodUnitImportService} from './admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog'; import {CreateNewUnitModal} from './admin/modals/create-new-unit-modal/create-new-unit-modal.component'; import {FUsersComponent} from './admin/states/users/users.component'; -import {FUnitTaskListComponent} from './units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component'; -import {FTaskDetailsViewComponent} from './units/states/tasks/viewer/directives/task-details-view/task-details-view.component'; -import {FTaskSheetViewComponent} from './units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component'; -import {TasksViewerComponent} from './units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component'; +import {FUnitTaskListComponent} from './units/task-viewer/directives/unit-task-list/unit-task-list.component'; +import {FTaskDetailsViewComponent} from './units/task-viewer/directives/task-details-view/task-details-view.component'; +import {FTaskSheetViewComponent} from './units/task-viewer/directives/task-sheet-view/task-sheet-view.component'; +import {TasksViewerComponent} from './units/task-viewer/directives/tasks-viewer/tasks-viewer.component'; import {FUnitsComponent} from './admin/states/units/units.component'; import {MarkedPipe} from './common/pipes/marked.pipe'; diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index fe216a6119..f9330cac67 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -14,6 +14,8 @@ import {ProjectService} from './api/services/project.service'; import {Observable, first} from 'rxjs'; import {GlobalStateService} from './projects/states/index/global-state.service'; import {Project} from './api/models/project'; +import {UnitRootState} from './units/unit-root-state.component'; +import { TaskViewerState } from './units/task-viewer/task-viewer-state.component'; /* * Use this file to store any states that are sourced by angular components. @@ -289,7 +291,7 @@ const AbstractProjectState: NgHybridStateDeclaration = { const projectService = AppInjector.get(ProjectService); const globalState = AppInjector.get(GlobalStateService); - return new Observable((observer) => { + return new Observable((observer) => { globalState.onLoad(() => { projectService .get({id: $stateParams.projectId}, {cacheBehaviourOnGet: 'cacheQuery'}) @@ -359,4 +361,6 @@ export const doubtfireStates = [ AdministerUnits, AbstractProjectState, ProjectDashboardState, + UnitRootState, + TaskViewerState, ]; diff --git a/src/app/units/states/tasks/tasks.coffee b/src/app/units/states/tasks/tasks.coffee index 141e0364c6..eba3810469 100644 --- a/src/app/units/states/tasks/tasks.coffee +++ b/src/app/units/states/tasks/tasks.coffee @@ -1,7 +1,6 @@ angular.module('doubtfire.units.states.tasks', [ 'doubtfire.units.states.tasks.inbox' 'doubtfire.units.states.tasks.definition' - 'doubtfire.units.states.tasks.viewer' ]) # diff --git a/src/app/units/states/tasks/viewer/directives/directives.coffee b/src/app/units/states/tasks/viewer/directives/directives.coffee deleted file mode 100644 index 1624d23757..0000000000 --- a/src/app/units/states/tasks/viewer/directives/directives.coffee +++ /dev/null @@ -1,5 +0,0 @@ -angular.module('doubtfire.units.states.tasks.viewer.directives', [ - # 'doubtfire.units.states.tasks.viewer.directives.unit-task-list' - # 'doubtfire.units.states.tasks.viewer.directives.task-sheet-view' - # 'doubtfire.units.states.tasks.viewer.directives.task-details-view' -]) diff --git a/src/app/units/states/tasks/viewer/viewer.coffee b/src/app/units/states/tasks/viewer/viewer.coffee deleted file mode 100644 index 0dde935439..0000000000 --- a/src/app/units/states/tasks/viewer/viewer.coffee +++ /dev/null @@ -1,23 +0,0 @@ -angular.module('doubtfire.units.states.tasks.viewer', [ - 'doubtfire.units.states.tasks.viewer.directives' -]) - -# -# Give feedback when on one-to-one for students (i.e., tasksRequiringFeedback) -# -.config(($stateProvider) -> - $stateProvider.state 'units/tasks/viewer', { - parent: 'units/tasks' - url: '/viewer' - templateUrl: "units/states/tasks/viewer/viewer.tpl.html" - controller: "TaskViewerStateCtrl" - data: - task: "Task List" - pageTitle: "_Home_" - roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Auditor'] - } -) - -.controller('TaskViewerStateCtrl', ($scope) -> - $scope.taskDefs = $scope.unit.taskDefinitions -) diff --git a/src/app/units/states/tasks/viewer/viewer.scss b/src/app/units/states/tasks/viewer/viewer.scss deleted file mode 100644 index 382bfdc247..0000000000 --- a/src/app/units/states/tasks/viewer/viewer.scss +++ /dev/null @@ -1,4 +0,0 @@ -f-tasks-viewer { - height: calc($main-view-max-height + 70px); // temporary fix to reclaim the footer region for this specific page - display: flex; -} diff --git a/src/app/units/states/tasks/viewer/viewer.tpl.html b/src/app/units/states/tasks/viewer/viewer.tpl.html deleted file mode 100644 index 358d6f33a2..0000000000 --- a/src/app/units/states/tasks/viewer/viewer.tpl.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/app/units/states/tasks/viewer/directives/task-details-view/task-details-view.component.html b/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.html similarity index 100% rename from src/app/units/states/tasks/viewer/directives/task-details-view/task-details-view.component.html rename to src/app/units/task-viewer/directives/task-details-view/task-details-view.component.html diff --git a/src/app/units/states/tasks/viewer/directives/task-details-view/task-details-view.component.scss b/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.scss similarity index 100% rename from src/app/units/states/tasks/viewer/directives/task-details-view/task-details-view.component.scss rename to src/app/units/task-viewer/directives/task-details-view/task-details-view.component.scss diff --git a/src/app/units/states/tasks/viewer/directives/task-details-view/task-details-view.component.ts b/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.ts similarity index 100% rename from src/app/units/states/tasks/viewer/directives/task-details-view/task-details-view.component.ts rename to src/app/units/task-viewer/directives/task-details-view/task-details-view.component.ts diff --git a/src/app/units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component.html b/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.html similarity index 100% rename from src/app/units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component.html rename to src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.html diff --git a/src/app/units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component.scss b/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.scss similarity index 100% rename from src/app/units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component.scss rename to src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.scss diff --git a/src/app/units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component.spec.ts b/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.spec.ts similarity index 100% rename from src/app/units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component.spec.ts rename to src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.spec.ts diff --git a/src/app/units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component.ts b/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.ts similarity index 100% rename from src/app/units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.component.ts rename to src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.ts diff --git a/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.html b/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.html similarity index 97% rename from src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.html rename to src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.html index 383bd28d2d..c752c41c84 100644 --- a/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.html +++ b/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.html @@ -29,7 +29,7 @@
diff --git a/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.scss b/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.scss similarity index 100% rename from src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.scss rename to src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.scss diff --git a/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.spec.ts b/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.spec.ts similarity index 100% rename from src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.spec.ts rename to src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.spec.ts diff --git a/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.ts b/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.ts similarity index 96% rename from src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.ts rename to src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.ts index 09b21e3fa4..059d881eef 100644 --- a/src/app/units/states/tasks/viewer/directives/tasks-viewer/tasks-viewer.component.ts +++ b/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.ts @@ -9,7 +9,6 @@ import {BehaviorSubject} from 'rxjs'; styleUrls: ['./tasks-viewer.component.scss'], }) export class TasksViewerComponent { - @Input() taskDefs: TaskDefinition[]; @Input() unit: Unit; /** diff --git a/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.html b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html similarity index 100% rename from src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.html rename to src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html diff --git a/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.scss b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss similarity index 100% rename from src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.scss rename to src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss diff --git a/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.spec.ts b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.spec.ts similarity index 100% rename from src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.spec.ts rename to src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.spec.ts diff --git a/src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.ts b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts similarity index 100% rename from src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.component.ts rename to src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts diff --git a/src/app/units/task-viewer/task-viewer-state.component.html b/src/app/units/task-viewer/task-viewer-state.component.html new file mode 100644 index 0000000000..ab9fe5dd31 --- /dev/null +++ b/src/app/units/task-viewer/task-viewer-state.component.html @@ -0,0 +1,3 @@ +
+ +
diff --git a/src/app/units/task-viewer/task-viewer-state.component.scss b/src/app/units/task-viewer/task-viewer-state.component.scss new file mode 100644 index 0000000000..f3720d4d50 --- /dev/null +++ b/src/app/units/task-viewer/task-viewer-state.component.scss @@ -0,0 +1,25 @@ +.vertical-panel { + border-radius: 10px; + background-color: white; + padding: 8px; + min-width: 60px; + width: 450px; + height: 100%; + + &.mobile { + max-width: 100%; + width: 100%; + padding: 0px; + } +} + +.vertical-spacer { + background-color: #f5f5f5; + z-index: 200; + width: 10px +} + +f-tasks-viewer { + height: calc($main-view-max-height + 70px); // temporary fix to reclaim the footer region for this specific page + display: flex; +} diff --git a/src/app/units/task-viewer/task-viewer-state.component.ts b/src/app/units/task-viewer/task-viewer-state.component.ts new file mode 100644 index 0000000000..26628829c7 --- /dev/null +++ b/src/app/units/task-viewer/task-viewer-state.component.ts @@ -0,0 +1,44 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import {CdkDragEnd, CdkDragMove, CdkDragStart} from '@angular/cdk/drag-drop'; +import {Component, Input, OnInit} from '@angular/core'; +import { + BehaviorSubject, + Observable, + Subject, + auditTime, + first, + merge, + of, + tap, + withLatestFrom, +} from 'rxjs'; +import {TaskDefinition, Unit, UnitService, UserService} from 'src/app/api/models/doubtfire-model'; +import { AppInjector } from '../../app-injector'; +import { NgHybridStateDeclaration } from '@uirouter/angular-hybrid'; +import { GlobalStateService, ViewType } from '../../projects/states/index/global-state.service'; +import { StateService } from '@uirouter/core'; +import { AlertService } from '../../common/services/alert.service'; + +@Component({ + selector: 'f-task-viewer-state', + templateUrl: './task-viewer-state.component.html', + styleUrl: './task-viewer-state.component.scss', +}) +export class TaskViewerStateComponent { + @Input() public unit$: Observable; +} + +export const TaskViewerState: NgHybridStateDeclaration = { + name: 'units2/tasks', + url: '/tasks/:taskDefId', + parent: 'unit-root-state', + data: { + pageTitle: 'Unit Tasks', + roleWhiteList: ['Tutor', 'Convenor', 'Admin', 'Auditor'], + }, + views: { + unitView: { + component: TaskViewerStateComponent, + }, + }, +}; diff --git a/src/app/units/unit-root-state.component.css b/src/app/units/unit-root-state.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/unit-root-state.component.html b/src/app/units/unit-root-state.component.html new file mode 100644 index 0000000000..7261f3fdc6 --- /dev/null +++ b/src/app/units/unit-root-state.component.html @@ -0,0 +1 @@ +
diff --git a/src/app/units/unit-root-state.component.ts b/src/app/units/unit-root-state.component.ts new file mode 100644 index 0000000000..8a6109121f --- /dev/null +++ b/src/app/units/unit-root-state.component.ts @@ -0,0 +1,90 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import {CdkDragEnd, CdkDragMove, CdkDragStart} from '@angular/cdk/drag-drop'; +import {Component, Input, OnInit} from '@angular/core'; +import { + BehaviorSubject, + Observable, + Subject, + auditTime, + first, + merge, + of, + tap, + withLatestFrom, +} from 'rxjs'; +import {Unit, UnitService, UserService} from 'src/app/api/models/doubtfire-model'; +import { AppInjector } from '../app-injector'; +import { NgHybridStateDeclaration } from '@uirouter/angular-hybrid'; +import { GlobalStateService, ViewType } from '../projects/states/index/global-state.service'; +import { StateService } from '@uirouter/core'; +import { AlertService } from '../common/services/alert.service'; + +@Component({ + selector: 'f-unit-root-state', + templateUrl: './unit-root-state.component.html', + styleUrl: './unit-root-state.component.css', +}) +export class UnitRootStateComponent { + @Input() public unit$: Observable; +} + +export const UnitRootState: NgHybridStateDeclaration = { + name: 'unit-root-state', + url: '/units2/:unitId', + abstract: true, + data: { + pageTitle: 'Unit Root State', + roleWhiteList: ['Tutor', 'Convenor', 'Admin', 'Auditor'], + }, + views: { + main: { + component: UnitRootStateComponent, + }, + }, + resolve: { + unit$: function ($stateParams) { + const unitService = AppInjector.get(UnitService); + const globalState = AppInjector.get(GlobalStateService); + const userService = AppInjector.get(UserService); + const stateService = AppInjector.get(StateService); + + return new Observable((observer) => { + globalState.onLoad(() => { + const unitId: number = parseInt($stateParams.unitId); + let unitRole = globalState.loadedUnitRoles.currentValues.find( + (unitRole) => unitRole.unit.id === unitId, + ); + + if ( + !unitRole && + (userService.currentUser.role == 'Admin' || userService.currentUser.role == 'Auditor') + ) { + unitRole = userService.adminOrAuditorRoleFor( + userService.currentUser.role, + unitId, + userService.currentUser, + ); + } + + // Go home if no unit role was found + if (!unitRole) { + console.log('No unit role found for unit', unitId); + return stateService.go('home'); + } + + unitService.get(unitId).subscribe({ + next: (unit: Unit) => { + observer.next(unit); + globalState.setView(ViewType.UNIT, unitRole); + observer.complete(); + }, + error: (err) => { + AppInjector.get(AlertService).error('Error loading unit: ' + err, 8000); + setTimeout(() => stateService.go('home'), 5000); + } + }); + }); + }).pipe(first()); + }, + }, +}; From 3ed44798f86860cac8b1fc8636818d9f5d1aeb6a Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Sun, 9 Jun 2024 09:58:00 +1000 Subject: [PATCH 0101/1280] refactor: move task viewer into state component --- src/app/doubtfire-angular.module.ts | 2 - src/app/doubtfire-angularjs.module.ts | 5 -- .../task-details-view.component.scss | 2 +- .../tasks-viewer/tasks-viewer.component.html | 53 ------------------ .../tasks-viewer/tasks-viewer.component.scss | 20 ------- .../tasks-viewer.component.spec.ts | 20 ------- .../tasks-viewer/tasks-viewer.component.ts | 33 ------------ .../unit-task-list.component.scss | 2 +- .../task-viewer-state.component.html | 54 ++++++++++++++++++- .../task-viewer-state.component.scss | 2 +- .../task-viewer-state.component.ts | 43 ++++++++------- 11 files changed, 80 insertions(+), 156 deletions(-) delete mode 100644 src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.html delete mode 100644 src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.scss delete mode 100644 src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.spec.ts delete mode 100644 src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.ts diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 9582928c63..a7851ca5b5 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -223,7 +223,6 @@ import {FUnitsComponent} from './admin/states/units/units.component'; import {FUnitTaskListComponent} from './units/task-viewer/directives/unit-task-list/unit-task-list.component'; import {FTaskDetailsViewComponent} from './units/task-viewer/directives/task-details-view/task-details-view.component'; import {FTaskSheetViewComponent} from './units/task-viewer/directives/task-sheet-view/task-sheet-view.component'; -import {TasksViewerComponent} from './units/task-viewer/directives/tasks-viewer/tasks-viewer.component'; import {UnitCodeComponent} from './common/unit-code/unit-code.component'; import {GradeService} from './common/services/grade.service'; import { UnitRootStateComponent } from './units/unit-root-state.component'; @@ -326,7 +325,6 @@ import { TaskViewerStateComponent } from './units/task-viewer/task-viewer-state. FUnitTaskListComponent, FTaskDetailsViewComponent, FTaskSheetViewComponent, - TasksViewerComponent, UnitRootStateComponent, TaskViewerStateComponent, FUsersComponent, diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 7f77443a7e..1920adebdc 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -217,7 +217,6 @@ import {FUsersComponent} from './admin/states/users/users.component'; import {FUnitTaskListComponent} from './units/task-viewer/directives/unit-task-list/unit-task-list.component'; import {FTaskDetailsViewComponent} from './units/task-viewer/directives/task-details-view/task-details-view.component'; import {FTaskSheetViewComponent} from './units/task-viewer/directives/task-sheet-view/task-sheet-view.component'; -import {TasksViewerComponent} from './units/task-viewer/directives/tasks-viewer/tasks-viewer.component'; import {FUnitsComponent} from './admin/states/units/units.component'; import {MarkedPipe} from './common/pipes/marked.pipe'; @@ -365,10 +364,6 @@ DoubtfireAngularJSModule.directive( 'fTaskStatusCard', downgradeComponent({component: TaskStatusCardComponent}), ); -DoubtfireAngularJSModule.directive( - 'fTasksViewer', - downgradeComponent({component: TasksViewerComponent}), -); DoubtfireAngularJSModule.directive('fInbox', downgradeComponent({component: InboxComponent})); DoubtfireAngularJSModule.directive( 'fTaskDueCard', diff --git a/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.scss b/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.scss index dda643e643..b06c626b5a 100644 --- a/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.scss +++ b/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.scss @@ -1,6 +1,6 @@ @use '@angular/material' as mat; -@import '../../../../../../../theme.scss'; +@import '/src/theme.scssr'; $my-palette: mat.define-palette($md-formatif); diff --git a/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.html b/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.html deleted file mode 100644 index c752c41c84..0000000000 --- a/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.html +++ /dev/null @@ -1,53 +0,0 @@ - -
-
- -
- -
- -
- - -
-
-
- -
- -
-
-
-
- - -
-
- -
- -
-
- -
- -
- -
-
-
diff --git a/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.scss b/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.scss deleted file mode 100644 index cddaf52b1d..0000000000 --- a/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.scss +++ /dev/null @@ -1,20 +0,0 @@ -.vertical-panel { - border-radius: 10px; - background-color: white; - padding: 8px; - min-width: 60px; - width: 450px; - height: 100%; - - &.mobile { - max-width: 100%; - width: 100%; - padding: 0px; - } -} - -.vertical-spacer { - background-color: #f5f5f5; - z-index: 200; - width: 10px -} diff --git a/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.spec.ts b/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.spec.ts deleted file mode 100644 index bc7a35f057..0000000000 --- a/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.spec.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { TasksViewerComponent } from './tasks-viewer.component'; - -describe('TasksViewerComponent', () => { - let component: TasksViewerComponent; - let fixture: ComponentFixture; - - beforeEach(() => { - TestBed.configureTestingModule({ - declarations: [TasksViewerComponent], - }); - fixture = TestBed.createComponent(TasksViewerComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.ts b/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.ts deleted file mode 100644 index 059d881eef..0000000000 --- a/src/app/units/task-viewer/directives/tasks-viewer/tasks-viewer.component.ts +++ /dev/null @@ -1,33 +0,0 @@ -import {Component, Input} from '@angular/core'; -import {TaskDefinition} from 'src/app/api/models/task-definition'; -import {Unit} from 'src/app/api/models/unit'; -import {BehaviorSubject} from 'rxjs'; - -@Component({ - selector: 'f-tasks-viewer', - templateUrl: './tasks-viewer.component.html', - styleUrls: ['./tasks-viewer.component.scss'], -}) -export class TasksViewerComponent { - @Input() unit: Unit; - - /** - * Monitor and publish the selected task definition for child components. - * We monitor the task definition list for changes in selected task definition. - */ - selectedTaskDefinition$: BehaviorSubject = new BehaviorSubject( - null, - ); - - public get taskSelected(): boolean { - return this.selectedTaskDef !== null; - } - - public get selectedTaskDef(): TaskDefinition { - return this.selectedTaskDefinition$.value; - } - - public clearTaskSelection(): void { - this.selectedTaskDefinition$.next(null); - } -} diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss index 0d460d0ffd..f6aed93b2c 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss @@ -1,6 +1,6 @@ @use '@angular/material' as mat; -@import '../../../../../../../theme.scss'; +@import '/src/theme.scss'; @import '../../../../../../../styles/mixins/scrollable.scss'; $my-palette: mat.define-palette($md-formatif); diff --git a/src/app/units/task-viewer/task-viewer-state.component.html b/src/app/units/task-viewer/task-viewer-state.component.html index ab9fe5dd31..8d19bd1bef 100644 --- a/src/app/units/task-viewer/task-viewer-state.component.html +++ b/src/app/units/task-viewer/task-viewer-state.component.html @@ -1,3 +1,55 @@
- + +
+
+ +
+ +
+ +
+ + +
+
+
+ +
+ +
+
+
+
+ + +
+
+ +
+ +
+
+ +
+ +
+ +
+
+
diff --git a/src/app/units/task-viewer/task-viewer-state.component.scss b/src/app/units/task-viewer/task-viewer-state.component.scss index f3720d4d50..39bcc3f728 100644 --- a/src/app/units/task-viewer/task-viewer-state.component.scss +++ b/src/app/units/task-viewer/task-viewer-state.component.scss @@ -19,7 +19,7 @@ width: 10px } -f-tasks-viewer { +f-task-viewer-state { height: calc($main-view-max-height + 70px); // temporary fix to reclaim the footer region for this specific page display: flex; } diff --git a/src/app/units/task-viewer/task-viewer-state.component.ts b/src/app/units/task-viewer/task-viewer-state.component.ts index 26628829c7..833647f4cb 100644 --- a/src/app/units/task-viewer/task-viewer-state.component.ts +++ b/src/app/units/task-viewer/task-viewer-state.component.ts @@ -1,23 +1,8 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import {CdkDragEnd, CdkDragMove, CdkDragStart} from '@angular/cdk/drag-drop'; -import {Component, Input, OnInit} from '@angular/core'; -import { - BehaviorSubject, - Observable, - Subject, - auditTime, - first, - merge, - of, - tap, - withLatestFrom, -} from 'rxjs'; -import {TaskDefinition, Unit, UnitService, UserService} from 'src/app/api/models/doubtfire-model'; -import { AppInjector } from '../../app-injector'; -import { NgHybridStateDeclaration } from '@uirouter/angular-hybrid'; -import { GlobalStateService, ViewType } from '../../projects/states/index/global-state.service'; -import { StateService } from '@uirouter/core'; -import { AlertService } from '../../common/services/alert.service'; +import {Component, Input} from '@angular/core'; +import {BehaviorSubject, Observable} from 'rxjs'; +import {TaskDefinition, Unit} from 'src/app/api/models/doubtfire-model'; +import {NgHybridStateDeclaration} from '@uirouter/angular-hybrid'; @Component({ selector: 'f-task-viewer-state', @@ -26,6 +11,26 @@ import { AlertService } from '../../common/services/alert.service'; }) export class TaskViewerStateComponent { @Input() public unit$: Observable; + + /** + * Monitor and publish the selected task definition for child components. + * We monitor the task definition list for changes in selected task definition. + */ + selectedTaskDefinition$: BehaviorSubject = new BehaviorSubject( + null, + ); + + public get taskSelected(): boolean { + return this.selectedTaskDef !== null; + } + + public get selectedTaskDef(): TaskDefinition { + return this.selectedTaskDefinition$.value; + } + + public clearTaskSelection(): void { + this.selectedTaskDefinition$.next(null); + } } export const TaskViewerState: NgHybridStateDeclaration = { From 7d0092b8fc4d28f71884f16cc76bbd4332bdd610 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Sun, 9 Jun 2024 10:15:18 +1000 Subject: [PATCH 0102/1280] refactor: introduce project root state --- src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire.states.ts | 35 ++----------- .../states/project-root-state.component.css | 0 .../states/project-root-state.component.html | 1 + .../states/project-root-state.component.ts | 50 +++++++++++++++++++ 5 files changed, 56 insertions(+), 32 deletions(-) create mode 100644 src/app/projects/states/project-root-state.component.css create mode 100644 src/app/projects/states/project-root-state.component.html create mode 100644 src/app/projects/states/project-root-state.component.ts diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index a7851ca5b5..9991e9cb33 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -227,6 +227,7 @@ import {UnitCodeComponent} from './common/unit-code/unit-code.component'; import {GradeService} from './common/services/grade.service'; import { UnitRootStateComponent } from './units/unit-root-state.component'; import { TaskViewerStateComponent } from './units/task-viewer/task-viewer-state.component'; +import { ProjectRootStateComponent } from './projects/states/project-root-state.component'; @NgModule({ // Components we declare @@ -326,6 +327,7 @@ import { TaskViewerStateComponent } from './units/task-viewer/task-viewer-state. FTaskDetailsViewComponent, FTaskSheetViewComponent, UnitRootStateComponent, + ProjectRootStateComponent, TaskViewerStateComponent, FUsersComponent, ProjectProgressComponent, diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index f9330cac67..3e4ea5e853 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -15,6 +15,7 @@ import {Observable, first} from 'rxjs'; import {GlobalStateService} from './projects/states/index/global-state.service'; import {Project} from './api/models/project'; import {UnitRootState} from './units/unit-root-state.component'; +import {ProjectRootState} from './projects/states/project-root-state.component'; import { TaskViewerState } from './units/task-viewer/task-viewer-state.component'; /* @@ -277,43 +278,13 @@ const AdministerUnits: NgHybridStateDeclaration = { }, }; -const AbstractProjectState: NgHybridStateDeclaration = { - name: 'projects2', - url: '/projects2/:projectId', - abstract: true, - views: { - main: { - component: ProjectDashboardComponent, - }, - }, - resolve: { - project$: function ($stateParams) { - const projectService = AppInjector.get(ProjectService); - const globalState = AppInjector.get(GlobalStateService); - - return new Observable((observer) => { - globalState.onLoad(() => { - projectService - .get({id: $stateParams.projectId}, {cacheBehaviourOnGet: 'cacheQuery'}) - .subscribe({ - next: (project: Project) => { - observer.next(project); - observer.complete(); - }, - }); - }); - }).pipe(first()); - }, - }, -}; - // projectDashboardState which gets the project from the abstract state above const ProjectDashboardState: NgHybridStateDeclaration = { name: 'dashboard2', parent: 'projects2', url: '/dashboard2', views: { - main: { + projectView: { component: ProjectDashboardComponent, }, }, @@ -359,7 +330,7 @@ export const doubtfireStates = [ ViewAllProjectsState, ViewAllUnits, AdministerUnits, - AbstractProjectState, + ProjectRootState, ProjectDashboardState, UnitRootState, TaskViewerState, diff --git a/src/app/projects/states/project-root-state.component.css b/src/app/projects/states/project-root-state.component.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/project-root-state.component.html b/src/app/projects/states/project-root-state.component.html new file mode 100644 index 0000000000..62b885d8dc --- /dev/null +++ b/src/app/projects/states/project-root-state.component.html @@ -0,0 +1 @@ +
diff --git a/src/app/projects/states/project-root-state.component.ts b/src/app/projects/states/project-root-state.component.ts new file mode 100644 index 0000000000..53de8a52b5 --- /dev/null +++ b/src/app/projects/states/project-root-state.component.ts @@ -0,0 +1,50 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import {Component, Input} from '@angular/core'; +import {Observable, first} from 'rxjs'; +import {Project, ProjectService} from 'src/app/api/models/doubtfire-model'; +import {AppInjector} from 'src/app/app-injector'; +import {NgHybridStateDeclaration} from '@uirouter/angular-hybrid'; +import {GlobalStateService} from 'src/app/projects/states/index/global-state.service'; + +@Component({ + selector: 'f-project-root-state', + templateUrl: './project-root-state.component.html', + styleUrl: './project-root-state.component.css', +}) +export class ProjectRootStateComponent { + @Input() public project$: Observable; +} + +export const ProjectRootState: NgHybridStateDeclaration = { + name: 'projects2', + url: '/projects2/:projectId', + abstract: true, + data: { + pageTitle: 'Unit Studied', + roleWhiteList: ['Student', 'Tutor', 'Convenor', 'Admin', 'Auditor'], + }, + views: { + main: { + component: ProjectRootStateComponent, + }, + }, + resolve: { + project$: function ($stateParams) { + const projectService = AppInjector.get(ProjectService); + const globalState = AppInjector.get(GlobalStateService); + + return new Observable((observer) => { + const projectId = parseInt($stateParams.projectId); + + globalState.onLoad(() => { + projectService.get({id: projectId}, {cacheBehaviourOnGet: 'cacheQuery'}).subscribe({ + next: (project: Project) => { + observer.next(project); + observer.complete(); + }, + }); + }); + }).pipe(first()); + }, + }, +}; From 4fc36705223ee8567f86632feb6c30ec830e3fe3 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Sun, 9 Jun 2024 10:43:34 +1000 Subject: [PATCH 0103/1280] refactor: ensure tasks selectable in unit task list --- .../unit-task-list.component.html | 23 +++++++++++-------- .../unit-task-list.component.scss | 4 ++-- .../unit-task-list.component.ts | 17 +++++++++----- 3 files changed, 26 insertions(+), 18 deletions(-) diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html index 9b0adcaf33..8231b77aa8 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html @@ -22,31 +22,34 @@
- @if (filteredTasks.length === 0) { + @if (filteredTaskDefinitions.length === 0) {
No tasks to display
} - @for (task of filteredTasks; track task) { + @for (taskDef of filteredTaskDefinitions; track taskDef) { - @if (task) { + @if (taskDef) {
- + Selected: {{taskDef.abbreviation}} {{isSelectedTaskDefinition(taskDef)}} +
-

{{ task.name }}

+

{{ taskDef.name }}

- @if (task.isGroupTask()) { + @if (taskDef.isGroupTask()) { group } -
{{ gradeNames[task.targetGrade] }} Task
-

{{ taskForTaskDef(task).status }}

+
{{ gradeNames[taskDef.targetGrade] }} Task
+ @if (hasTasks && taskForTaskDef(taskDef)) { +

{{ taskForTaskDef(taskDef).status }}

+ }
diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss index f6aed93b2c..61c49678b4 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss @@ -1,7 +1,7 @@ @use '@angular/material' as mat; -@import '/src/theme.scss'; -@import '../../../../../../../styles/mixins/scrollable.scss'; +@import 'src/theme.scss'; +@import 'src/styles/mixins/scrollable.scss'; $my-palette: mat.define-palette($md-formatif); diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts index f23c21568e..94e1d13fca 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts @@ -16,17 +16,17 @@ export class FUnitTaskListComponent implements OnInit { // What is the selected task definition @Input() selectedTaskDefinition$: BehaviorSubject; + selectedTaskDef: TaskDefinition; // @Output() selectedTask: EventEmitter = new EventEmitter(); - filteredTasks: TaskDefinition[]; // list of tasks which match the taskSearch term + filteredTaskDefinitions: TaskDefinition[]; // list of tasks which match the taskSearch term searchText: string = ''; // task search term from user input taskDefinitionNamePipe = new TaskDefinitionNamePipe(); protected gradeNames: string[] = Grade.GRADES; - selectedTaskDef: TaskDefinition; applyFilters() { - this.filteredTasks = this.taskDefinitionNamePipe.transform( + this.filteredTaskDefinitions = this.taskDefinitionNamePipe.transform( this.taskDefinitions, this.searchText, ); @@ -37,7 +37,11 @@ export class FUnitTaskListComponent implements OnInit { } public taskForTaskDef(taskDef: TaskDefinition): Task { - return this.tasks.find((task) => task.definition.id === taskDef.id); + if (!this.hasTasks || !taskDef) { + return null; + } + + return this.tasks.find((task) => task.definition.id === taskDef?.id); } ngOnInit(): void { @@ -80,7 +84,8 @@ export class FUnitTaskListComponent implements OnInit { // this.taskViewerService.setSelectedTaskDef(taskDef); } - public isSelectedTaskDefinition(taskDef: TaskDefinition) { - return this.selectedTaskDef?.id === taskDef?.id; + public isSelectedTaskDefinition(taskDef: TaskDefinition) : boolean { + console.log(taskDef?.abbreviation); + return this.selectedTaskDef?.id === taskDef?.id; } } From c97509f77e8651af89e16a3a6db0562b64ffc5f8 Mon Sep 17 00:00:00 2001 From: jakerenzella Date: Mon, 10 Jun 2024 01:27:20 +1000 Subject: [PATCH 0104/1280] refactor: (wip) add new student experience skeleton --- angular.json | 8 +- src/app/api/models/project.ts | 75 +++-- src/app/common/footer/footer.component.html | 92 ++++-- ...s => project-progress-gauge.component.css} | 3 +- .../project-progress-gauge.component.html | 17 + ...ts => project-progress-gauge.component.ts} | 41 +-- .../project-progress.component.html | 33 -- src/app/common/services/grade.service.ts | 6 +- src/app/doubtfire-angular.module.ts | 15 +- .../project-progress-dashboard.component.html | 57 ++++ .../project-progress-dashboard.component.scss | 11 + .../project-progress-dashboard.component.ts | 48 +++ .../task-dashboard.component.html | 2 +- .../project-dashboard.component.html | 51 +-- .../staff-task-list.component.html | 302 ++++++++++-------- .../task-details-view.component.scss | 2 +- .../unit-task-list.component.html | 5 +- .../unit-task-list.component.ts | 5 +- 18 files changed, 463 insertions(+), 310 deletions(-) rename src/app/common/project-progress/{project-progress.component.css => project-progress-gauge.component.css} (96%) create mode 100644 src/app/common/project-progress/project-progress-gauge.component.html rename src/app/common/project-progress/{project-progress.component.ts => project-progress-gauge.component.ts} (65%) delete mode 100644 src/app/common/project-progress/project-progress.component.html create mode 100644 src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html create mode 100644 src/app/projects/project-progress-dashboard/project-progress-dashboard.component.scss create mode 100644 src/app/projects/project-progress-dashboard/project-progress-dashboard.component.ts diff --git a/angular.json b/angular.json index 2c0b1f0b92..a70e1e5845 100644 --- a/angular.json +++ b/angular.json @@ -10,7 +10,10 @@ "prefix": "f", "schematics": { "@schematics/angular:application": { - "strict": false + "strict": false, + "standalone": false, + "style": "scss", + "skipTests": true } }, "architect": { @@ -167,9 +170,6 @@ } }, "schematics": { - "@schematics/angular:component": { - "style": "scss" - }, "@angular-eslint/schematics:application": { "setParserOptionsProject": true }, diff --git a/src/app/api/models/project.ts b/src/app/api/models/project.ts index ca469e1698..380c62d199 100644 --- a/src/app/api/models/project.ts +++ b/src/app/api/models/project.ts @@ -1,10 +1,10 @@ -import { HttpClient } from '@angular/common/http'; -import { Entity, EntityCache, RequestOptions } from 'ngx-entity-service'; -import { Observable, tap } from 'rxjs'; -import { visualisations } from 'src/app/ajs-upgraded-providers'; -import { AppInjector } from 'src/app/app-injector'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; -import { MappingFunctions } from '../services/mapping-fn'; +import {HttpClient} from '@angular/common/http'; +import {Entity, EntityCache, RequestOptions} from 'ngx-entity-service'; +import {Observable, tap} from 'rxjs'; +import {visualisations} from 'src/app/ajs-upgraded-providers'; +import {AppInjector} from 'src/app/app-injector'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {MappingFunctions} from '../services/mapping-fn'; import { Campus, Grade, @@ -21,8 +21,8 @@ import { Unit, User, } from './doubtfire-model'; -import { TaskOutcomeAlignment } from './task-outcome-alignment'; -import { AlertService } from 'src/app/common/services/alert.service'; +import {TaskOutcomeAlignment} from './task-outcome-alignment'; +import {AlertService} from 'src/app/common/services/alert.service'; export class Project extends Entity { public id: number; @@ -40,7 +40,7 @@ export class Project extends Entity { public hasPortfolio: boolean; public portfolioStatus: number; - public portfolioFiles: { kind: string; name: string; idx: number }[]; + public portfolioFiles: {kind: string; name: string; idx: number}[]; public taskStats: { key: TaskStatusEnum; @@ -48,7 +48,7 @@ export class Project extends Entity { }[]; public orderScale: number; - public burndownChartData: { key: string; values: number[] }[]; + public burndownChartData: {key: string; values: number[]}[]; public readonly taskCache: EntityCache = new EntityCache(); public readonly tutorialEnrolmentsCache: EntityCache = new EntityCache(); public readonly groupCache: EntityCache = new EntityCache(); @@ -172,7 +172,9 @@ export class Project extends Entity { } public activeTasks(): Task[] { - return this.taskCache.currentValues.filter((task) => task.definition.targetGrade <= this.targetGrade); + return this.taskCache.currentValues.filter( + (task) => task.definition.targetGrade <= this.targetGrade, + ); } public calcTopTasks() { @@ -275,16 +277,19 @@ export class Project extends Entity { return httpClient.delete(this.portfolioUrl(false)); } - public deleteFileFromPortfolio(file: { idx: any; kind: any; name: any }) { + public deleteFileFromPortfolio(file: {idx: any; kind: any; name: any}) { const httpClient = AppInjector.get(HttpClient); return httpClient - .delete(`${AppInjector.get(DoubtfireConstants).API_URL}/submission/project/${this.id}/portfolio`, { - body: { - idx: file.idx, - kind: file.kind, - name: file.name, + .delete( + `${AppInjector.get(DoubtfireConstants).API_URL}/submission/project/${this.id}/portfolio`, + { + body: { + idx: file.idx, + kind: file.kind, + name: file.name, + }, }, - }) + ) .pipe( tap(() => { this.portfolioFiles = this.portfolioFiles.filter((value) => value != file); @@ -369,7 +374,7 @@ export class Project extends Entity { tutorialService.switchTutorial(this, tutorial, !this.isEnrolledIn(tutorial)); } - public getProgressStats(): {} { + public get progressStats() { const stats = {}; this.taskStats.forEach((stat) => { @@ -380,15 +385,15 @@ export class Project extends Entity { } public refreshBurndownChartData(): void { - const result: { key: string; values: number[] }[] = []; + const result: {key: string; values: number[]}[] = []; // Setup the dictionaries to contain the keys and values // key = series name // values = array of [ x, y ] values - const projectedResults = { key: 'Projected', values: [] }; - const targetTaskResults = { key: 'Target', values: [] }; - const doneTaskResults = { key: 'To Submit', values: [] }; - const completeTaskResults = { key: 'To Complete', values: [] }; + const projectedResults = {key: 'Projected', values: []}; + const targetTaskResults = {key: 'Target', values: []}; + const doneTaskResults = {key: 'To Submit', values: []}; + const completeTaskResults = {key: 'To Complete', values: []}; result.push(targetTaskResults); result.push(projectedResults); @@ -398,15 +403,19 @@ export class Project extends Entity { // Get the weeks between start and end date as an array // dates = unit.start_date.to_date.step(unit.end_date.to_date + 1.week, step=7).to_a const endDateValue = this.unit.endDate.getTime() + MappingFunctions.weeksMs(3); - const dates = MappingFunctions.step(this.unit.startDate.getTime(), endDateValue, MappingFunctions.weeksMs(1)).map( - (val) => new Date(val), - ); + const dates = MappingFunctions.step( + this.unit.startDate.getTime(), + endDateValue, + MappingFunctions.weeksMs(1), + ).map((val) => new Date(val)); // Get the target task from the unit's task definitions const targetTasks = this.unit.taskDefinitionsForGrade(this.targetGrade); // get total value of all tasks assigned to this project - const total = targetTasks.map((td) => td.weighting).reduce((prev, current, idx, array) => prev + current, 0); + const total = targetTasks + .map((td) => td.weighting) + .reduce((prev, current, idx, array) => prev + current, 0); // exit if no tasks or no weights if (targetTasks.length === 0 || total === 0) { @@ -425,7 +434,10 @@ export class Project extends Entity { // Get the tasks currently marked as done (or ready to mark) const doneTasks = tasks.filter( - (t) => !['working_on_it', 'not_started', 'fix_and_resubmit', 'redo', 'need_help'].includes(t.status), + (t) => + !['working_on_it', 'not_started', 'fix_and_resubmit', 'redo', 'need_help'].includes( + t.status, + ), ); // last done task date) @@ -438,7 +450,8 @@ export class Project extends Entity { } // today is used to determine when to stop adding done tasks - const today = new Date().getTime() > this.unit.endDate.getTime() ? this.unit.endDate : new Date(); + const today = + new Date().getTime() > this.unit.endDate.getTime() ? this.unit.endDate : new Date(); // use weekly completion rate to determine projected progress let completionRate: number = 0; diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index 7e28c72b32..ef45ad43ec 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -1,21 +1,21 @@ @if (selectedTask?.similaritiesDetected) { -
-
-

- Similarities flagged for {{ selectedTask?.project.student.name }} -

-
+
+
+

+ Similarities flagged for {{ selectedTask?.project.student.name }} +

+
}
@@ -71,17 +71,17 @@
@if (selectedTask?.similaritiesDetected) { - + } - - @@ -141,12 +159,16 @@ file_download - {{ selectedTask?.project.targetGradeAcronym }} + {{ + selectedTask?.project.targetGradeAcronym + }}
diff --git a/src/app/common/project-progress/project-progress.component.css b/src/app/common/project-progress/project-progress-gauge.component.css similarity index 96% rename from src/app/common/project-progress/project-progress.component.css rename to src/app/common/project-progress/project-progress-gauge.component.css index db89229c2c..0755ce7a39 100644 --- a/src/app/common/project-progress/project-progress.component.css +++ b/src/app/common/project-progress/project-progress-gauge.component.css @@ -1,4 +1,5 @@ :host { display: block; -} + +} diff --git a/src/app/common/project-progress/project-progress-gauge.component.html b/src/app/common/project-progress/project-progress-gauge.component.html new file mode 100644 index 0000000000..4ccf5a81a5 --- /dev/null +++ b/src/app/common/project-progress/project-progress-gauge.component.html @@ -0,0 +1,17 @@ + + diff --git a/src/app/common/project-progress/project-progress.component.ts b/src/app/common/project-progress/project-progress-gauge.component.ts similarity index 65% rename from src/app/common/project-progress/project-progress.component.ts rename to src/app/common/project-progress/project-progress-gauge.component.ts index 025bced4f7..1cb5acfd27 100644 --- a/src/app/common/project-progress/project-progress.component.ts +++ b/src/app/common/project-progress/project-progress-gauge.component.ts @@ -1,28 +1,19 @@ -import {Component, Injector, OnInit, ViewContainerRef} from '@angular/core'; +import {Component, Injector, Input, OnInit, ViewContainerRef} from '@angular/core'; import {TooltipService} from '@swimlane/ngx-charts'; +import {Project} from 'src/app/api/models/project'; @Component({ - selector: 'f-project-progress', - templateUrl: './project-progress.component.html', - styleUrl: './project-progress.component.css', + selector: 'f-project-progress-gauge', + templateUrl: './project-progress-gauge.component.html', + styleUrl: './project-progress-gauge.component.css', }) -export class ProjectProgressComponent implements OnInit { - ngOnInit(): void { - this.chartToolTipService.injectionService.setRootViewContainer(this.viewContainerRef); - } - - constructor(private injectorObj: Injector) { - this.chartToolTipService = this.injectorObj.get(TooltipService); - this.viewContainerRef = this.injectorObj.get(ViewContainerRef); - } - private chartToolTipService: TooltipService; - readonly viewContainerRef: ViewContainerRef; +export class ProjectProgressGaugeComponent implements OnInit { + @Input() project: Project; - data = [ + protected gaugeData = [ { 'name': 'Pass', 'value': 100, - 'label': '100%', }, { 'name': 'Credit', @@ -37,8 +28,22 @@ export class ProjectProgressComponent implements OnInit { 'value': 19, }, ]; + + ngOnInit(): void { + this.chartToolTipService.injectionService.setRootViewContainer(this.viewContainerRef); + + console.log(this.project.taskStats); + } + + constructor(private injectorObj: Injector) { + this.chartToolTipService = this.injectorObj.get(TooltipService); + this.viewContainerRef = this.injectorObj.get(ViewContainerRef); + } + private chartToolTipService: TooltipService; + readonly viewContainerRef: ViewContainerRef; + smallView = [90, 90]; - view = [400, 250]; + view = [500, 500]; legend: boolean = true; legendPosition: string = 'below'; diff --git a/src/app/common/project-progress/project-progress.component.html b/src/app/common/project-progress/project-progress.component.html deleted file mode 100644 index 50fe53dbeb..0000000000 --- a/src/app/common/project-progress/project-progress.component.html +++ /dev/null @@ -1,33 +0,0 @@ - - - - - diff --git a/src/app/common/services/grade.service.ts b/src/app/common/services/grade.service.ts index d2c0ee6213..6a76e5e25c 100644 --- a/src/app/common/services/grade.service.ts +++ b/src/app/common/services/grade.service.ts @@ -8,7 +8,7 @@ export class GradeService { allGradeValues = [-1, 0, 1, 2, 3]; gradeValues = [0, 1, 2, 3]; - grades = { + public grades = { '-1': 'Fail', 0: 'Pass', 1: 'Credit', @@ -16,7 +16,7 @@ export class GradeService { 3: 'High Distinction', }; - gradeIndex = { + public gradeIndex = { Fail: -1, Pass: 0, Credit: 1, @@ -24,7 +24,7 @@ export class GradeService { 'High Distinction': 3, }; - gradeViewData = [ + public gradeViewData = [ {value: -1, viewValue: 'Fail'}, {value: 0, viewValue: 'Pass'}, {value: 1, viewValue: 'Credit'}, diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 9991e9cb33..d71e9cc731 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -15,6 +15,7 @@ import player from 'lottie-web'; import {ClipboardModule} from '@angular/cdk/clipboard'; import {DragDropModule} from '@angular/cdk/drag-drop'; import {MatToolbarModule} from '@angular/material/toolbar'; +import {MatSidenavModule} from '@angular/material/sidenav'; import {MatSelectModule} from '@angular/material/select'; import {MatButtonModule} from '@angular/material/button'; import {MatMenuModule} from '@angular/material/menu'; @@ -209,7 +210,7 @@ import {UnitAnalyticsComponent} from './units/states/analytics/unit-analytics-ro import {FileDropComponent} from './common/file-drop/file-drop.component'; import {UnitTaskEditorComponent} from './units/states/edit/directives/unit-tasks-editor/unit-task-editor.component'; import {FUsersComponent} from './admin/states/users/users.component'; -import {ProjectProgressComponent} from './common/project-progress/project-progress.component'; +import {ProjectProgressGaugeComponent} from './common/project-progress/project-progress-gauge.component'; import {CreateNewUnitModal} from './admin/modals/create-new-unit-modal/create-new-unit-modal.component'; import {CreateNewUnitModalContentComponent} from './admin/modals/create-new-unit-modal/create-new-unit-modal-content.component'; import { @@ -225,9 +226,10 @@ import {FTaskDetailsViewComponent} from './units/task-viewer/directives/task-det import {FTaskSheetViewComponent} from './units/task-viewer/directives/task-sheet-view/task-sheet-view.component'; import {UnitCodeComponent} from './common/unit-code/unit-code.component'; import {GradeService} from './common/services/grade.service'; -import { UnitRootStateComponent } from './units/unit-root-state.component'; -import { TaskViewerStateComponent } from './units/task-viewer/task-viewer-state.component'; -import { ProjectRootStateComponent } from './projects/states/project-root-state.component'; +import {UnitRootStateComponent} from './units/unit-root-state.component'; +import {TaskViewerStateComponent} from './units/task-viewer/task-viewer-state.component'; +import {ProjectRootStateComponent} from './projects/states/project-root-state.component'; +import {ProjectProgressDashboardComponent} from './projects/project-progress-dashboard/project-progress-dashboard.component'; @NgModule({ // Components we declare @@ -276,6 +278,7 @@ import { ProjectRootStateComponent } from './projects/states/project-root-state. TaskCommentsViewerComponent, UserIconComponent, AudioPlayerComponent, + ProjectProgressDashboardComponent, MarkedPipe, HumanizedDatePipe, IsActiveUnitRole, @@ -330,7 +333,7 @@ import { ProjectRootStateComponent } from './projects/states/project-root-state. ProjectRootStateComponent, TaskViewerStateComponent, FUsersComponent, - ProjectProgressComponent, + ProjectProgressGaugeComponent, FTaskBadgeComponent, FUnitsComponent, ], @@ -418,6 +421,7 @@ import { ProjectRootStateComponent } from './projects/states/project-root-state. DragDropModule, ScrollingModule, MatToolbarModule, + MatSidenavModule, MatFormFieldModule, MatAutocompleteModule, MatInputModule, @@ -447,7 +451,6 @@ import { ProjectRootStateComponent } from './projects/states/project-root-state. MatExpansionModule, MatCardModule, MatGridListModule, - MatSelectModule, MatToolbarModule, MatTabsModule, UpgradeModule, diff --git a/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html new file mode 100644 index 0000000000..d1c272e131 --- /dev/null +++ b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html @@ -0,0 +1,57 @@ +
+ +
+ + + +

{{ project.unit.name }}

+

{{ project.unit.description }}

+
+
+
+
+ + + +

Targetting

+ + info +
+ + + Target grade + + @for (grade of grades; track grade) { + {{ + grade.viewValue + }} + } + + + +

+
+
+
+ + +
+ + +

Your progress

+ +
+ +
+
+
+
+ + + +
diff --git a/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.scss b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.scss new file mode 100644 index 0000000000..3a2b24d37b --- /dev/null +++ b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.scss @@ -0,0 +1,11 @@ +:host { + display: block; +} + +h1, +h2, +h3, +h4, +p { + color: black; +} diff --git a/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.ts b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.ts new file mode 100644 index 0000000000..c9132c5209 --- /dev/null +++ b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.ts @@ -0,0 +1,48 @@ +import {Component, Input, type OnInit} from '@angular/core'; +import {BehaviorSubject, Observable} from 'rxjs'; +import {Project} from 'src/app/api/models/project'; +import {ProjectService} from 'src/app/api/services/project.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {GradeService} from 'src/app/common/services/grade.service'; + +@Component({ + selector: 'f-project-progress-dashboard', + templateUrl: './project-progress-dashboard.component.html', + styleUrl: './project-progress-dashboard.component.scss', +}) +export class ProjectProgressDashboardComponent implements OnInit { + @Input() project$: Observable; + private project: Project; + protected grades; + + constructor( + private gradeService: GradeService, + private projectService: ProjectService, + private alertService: AlertService, + ) {} + + ngOnInit(): void { + this.project$.subscribe((project) => { + this.project = project; + }); + + this.grades = this.gradeService.gradeViewData.slice(1); + + setTimeout(() => { + console.log(this.project.taskStats); + }, 3000); + } + + protected targetGradeClicked(grade: number): void { + this.project.targetGrade = grade; + this.projectService.update(this.project).subscribe({ + next: (project) => { + this.alertService.success('Target grade updated'); + }, + error: (error) => { + console.error(error); + this.alertService.error('Error updating target grade', error); + }, + }); + } +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html index a76c3feab4..fa43b725b3 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html @@ -1,5 +1,5 @@
- + diff --git a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html index 5af2305c8d..5207f2c725 100644 --- a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html +++ b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html @@ -1,17 +1,14 @@ -
-
- {{ project.activeTasks().length }} - {{ project.unit.taskDefinitions.length }} -
-

Selected task definition: {{ selectedTaskDefinition.abbreviation }}

-
+
+
+ @if (subs$ | async) {
} -
- - - -
- -
- -
- - - -
-
-
+ + + -
+
@if (collapsable) { - - } @if (!isTaskDefMode) { - - } @if (isTaskDefMode) { - + + } + @if (!isTaskDefMode) { + + } + @if (isTaskDefMode) { + }
@@ -140,14 +154,19 @@ - +
-
+
@if (!isNarrow) { -
- -
+
+ +
}
@@ -170,44 +191,45 @@ @if (filteredTasks) { - - - - @if (task) { -
+ + -
- - -
-

{{ task.project.student.name }}

-
- {{ task.definition.abbreviation }} - - {{ task.definition.name }} -
- -
- @if (task.hasGrade()) { -
- {{ task.gradeDesc() }} -
- } - - @if (!isTaskDefMode) { -
- - - - - + + @if (!isTaskDefMode) { +
+ + + + + +
+ } +
+
- } -
- -
- } - + } + - - - + + + }
diff --git a/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.scss b/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.scss index b06c626b5a..4d2e096ff0 100644 --- a/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.scss +++ b/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.scss @@ -1,6 +1,6 @@ @use '@angular/material' as mat; -@import '/src/theme.scssr'; +@import '/src/theme.scss'; $my-palette: mat.define-palette($md-formatif); diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html index 8231b77aa8..0723fe581e 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html @@ -21,7 +21,7 @@
- + @if (filteredTaskDefinitions.length === 0) {
No tasks to display
} @@ -37,7 +37,6 @@ >
- Selected: {{taskDef.abbreviation}} {{isSelectedTaskDefinition(taskDef)}}

{{ taskDef.name }}

@@ -60,6 +59,6 @@

{{ taskDef.name }}

} } - +
diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts index 94e1d13fca..9ff21d0c78 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts @@ -2,7 +2,7 @@ import {Component, Input, OnInit} from '@angular/core'; import {Grade} from 'src/app/api/models/grade'; import {TaskDefinition, Task} from 'src/app/api/models/doubtfire-model'; import {TaskDefinitionNamePipe} from 'src/app/common/filters/task-definition-name.pipe'; -import { BehaviorSubject } from 'rxjs'; +import {BehaviorSubject} from 'rxjs'; @Component({ selector: 'f-unit-task-list', @@ -84,8 +84,7 @@ export class FUnitTaskListComponent implements OnInit { // this.taskViewerService.setSelectedTaskDef(taskDef); } - public isSelectedTaskDefinition(taskDef: TaskDefinition) : boolean { - console.log(taskDef?.abbreviation); + public isSelectedTaskDefinition(taskDef: TaskDefinition): boolean { return this.selectedTaskDef?.id === taskDef?.id; } } From 7b9ace47132f0237bc621d3d0e45c3031e7fac05 Mon Sep 17 00:00:00 2001 From: jakerenzella Date: Mon, 10 Jun 2024 11:25:10 +1000 Subject: [PATCH 0105/1280] feat: (wip) add name to new student experience skeleton --- .../project-progress-dashboard.component.html | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html index d1c272e131..af172d96d9 100644 --- a/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html +++ b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html @@ -4,7 +4,9 @@ -

{{ project.unit.name }}

+

+ {{ project.student.nickname || project.student.firstName }}'s {{ project.unit.name }} +

{{ project.unit.description }}

@@ -38,9 +40,10 @@

Targetting

+ + Your progress + -

Your progress

-
From 2e0eb7742a1bdd69e6cda7a85fd2f6e2e92968fc Mon Sep 17 00:00:00 2001 From: jakerenzella Date: Mon, 10 Jun 2024 12:03:05 +1000 Subject: [PATCH 0106/1280] refactor: (wip) prepare for m3 --- package-lock.json | 42 +++++++++++++++++++++--------------------- package.json | 38 +++++++++++++++++++------------------- src/styles.scss | 13 ++++++++----- 3 files changed, 48 insertions(+), 45 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9fc1598ad6..4b21a6feb9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,19 +9,19 @@ "version": "8.0.9", "license": "AGPL-3.0", "dependencies": { - "@angular/animations": "^18.0.1", - "@angular/cdk": "^18.0.1", - "@angular/common": "^18.0.1", - "@angular/compiler": "^18.0.1", - "@angular/core": "^18.0.1", - "@angular/forms": "^18.0.1", - "@angular/material": "^18.0.1", - "@angular/material-moment-adapter": "^18.0.1", - "@angular/platform-browser": "^18.0.1", - "@angular/platform-browser-dynamic": "^18.0.1", - "@angular/router": "^18.0.1", - "@angular/service-worker": "^18.0.1", - "@angular/upgrade": "^18.0.1", + "@angular/animations": "^18.0.2", + "@angular/cdk": "^18.0.2", + "@angular/common": "^18.0.2", + "@angular/compiler": "^18.0.2", + "@angular/core": "^18.0.2", + "@angular/forms": "^18.0.2", + "@angular/material": "^18.0.2", + "@angular/material-moment-adapter": "^18.0.2", + "@angular/platform-browser": "^18.0.2", + "@angular/platform-browser-dynamic": "^18.0.2", + "@angular/router": "^18.0.2", + "@angular/service-worker": "^18.0.2", + "@angular/upgrade": "^18.0.2", "@ctrl/ngx-emoji-mart": "^9.2.0", "@ngneat/hotkeys": "^4.0.0", "@swimlane/ngx-charts": "^20.5.0", @@ -48,7 +48,7 @@ "angulartics-google-analytics": "0.1.4", "bootstrap": "~3.4", "bootstrap-sass": "~3.4", - "canvas-confetti": "^1.6.0", + "canvas-confetti": "^1.9", "codemirror": "5.65.0", "core-js": "^3.21.1", "d3": "3.5.17", @@ -58,8 +58,8 @@ "jquery": "2.1.4", "lodash": "~4.17", "lottie-web": "^5.12.2", - "marked": "^11.1.0", - "moment": "^2.29.4", + "marked": "^12", + "moment": "^2.30", "ng-csv": "0.2.3", "ng-file-upload": "~5.0.9", "ng-flex-layout": "^17.3.7-beta.1", @@ -77,8 +77,8 @@ "devDependencies": { "@angular-devkit/build-angular": "^18.0.2", "@angular/cli": "^18.0.2", - "@angular/compiler-cli": "^18.0.1", - "@angular/language-service": "^18.0.1", + "@angular/compiler-cli": "^18.0.2", + "@angular/language-service": "^18.0.2", "@commitlint/cli": "^16.0.1", "@commitlint/config-conventional": "^17", "@types/angular": "1.5.11", @@ -16789,9 +16789,9 @@ } }, "node_modules/marked": { - "version": "11.2.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-11.2.0.tgz", - "integrity": "sha512-HR0m3bvu0jAPYiIvLUUQtdg1g6D247//lvcekpHO1WMvbwDlwSkZAX9Lw4F4YHE1T0HaaNve0tuAWuV1UJ6vtw==", + "version": "12.0.2", + "resolved": "https://registry.npmjs.org/marked/-/marked-12.0.2.tgz", + "integrity": "sha512-qXUm7e/YKFoqFPYPa3Ukg9xlI5cyAtGmyEIzMfW//m6kXwCy2Ps9DYf5ioijFKQ8qyuscrHoY04iJGctu2Kg0Q==", "bin": { "marked": "bin/marked.js" }, diff --git a/package.json b/package.json index fd8cc0068b..4aa54a248f 100644 --- a/package.json +++ b/package.json @@ -26,19 +26,19 @@ "keywords": [], "author": "", "dependencies": { - "@angular/animations": "^18.0.1", - "@angular/cdk": "^18.0.1", - "@angular/common": "^18.0.1", - "@angular/compiler": "^18.0.1", - "@angular/core": "^18.0.1", - "@angular/forms": "^18.0.1", - "@angular/material": "^18.0.1", - "@angular/material-moment-adapter": "^18.0.1", - "@angular/platform-browser": "^18.0.1", - "@angular/platform-browser-dynamic": "^18.0.1", - "@angular/router": "^18.0.1", - "@angular/service-worker": "^18.0.1", - "@angular/upgrade": "^18.0.1", + "@angular/animations": "^18.0.2", + "@angular/cdk": "^18.0.2", + "@angular/common": "^18.0.2", + "@angular/compiler": "^18.0.2", + "@angular/core": "^18.0.2", + "@angular/forms": "^18.0.2", + "@angular/material": "^18.0.2", + "@angular/material-moment-adapter": "^18.0.2", + "@angular/platform-browser": "^18.0.2", + "@angular/platform-browser-dynamic": "^18.0.2", + "@angular/router": "^18.0.2", + "@angular/service-worker": "^18.0.2", + "@angular/upgrade": "^18.0.2", "@ctrl/ngx-emoji-mart": "^9.2.0", "@ngneat/hotkeys": "^4.0.0", "@swimlane/ngx-charts": "^20.5.0", @@ -65,7 +65,7 @@ "angulartics-google-analytics": "0.1.4", "bootstrap": "~3.4", "bootstrap-sass": "~3.4", - "canvas-confetti": "^1.6.0", + "canvas-confetti": "^1.9", "codemirror": "5.65.0", "core-js": "^3.21.1", "d3": "3.5.17", @@ -75,8 +75,8 @@ "jquery": "2.1.4", "lodash": "~4.17", "lottie-web": "^5.12.2", - "marked": "^11.1.0", - "moment": "^2.29.4", + "marked": "^12", + "moment": "^2.30", "ng-csv": "0.2.3", "ng-file-upload": "~5.0.9", "ng-flex-layout": "^17.3.7-beta.1", @@ -93,9 +93,9 @@ }, "devDependencies": { "@angular-devkit/build-angular": "^18.0.2", - "@angular/compiler-cli": "^18.0.1", + "@angular/compiler-cli": "^18.0.2", "@angular/cli": "^18.0.2", - "@angular/language-service": "^18.0.1", + "@angular/language-service": "^18.0.2", "@commitlint/cli": "^16.0.1", "@commitlint/config-conventional": "^17", "@types/angular": "1.5.11", @@ -158,4 +158,4 @@ "@nx/nx-linux-x64-gnu": "^18.0", "@nx/nx-win32-x64-msvc": "^18.0" } -} \ No newline at end of file +} diff --git a/src/styles.scss b/src/styles.scss index e04a119ea4..f8ab056beb 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,7 +1,5 @@ // For more information: https://material.angular.io/guide/theming @use '@angular/material' as mat; -// @use './styles/m3-theme.scss'; - @include mat.core(); @import './theme.scss'; @@ -10,11 +8,15 @@ @tailwind components; @tailwind utilities; -// $main-view-top-padding: 30px; -// $main-view-bottom-padding: $main-view-top-padding; +$main-view-top-padding: 30px; +$main-view-bottom-padding: $main-view-top-padding; -// $main-view-max-height: calc((var(--vh, 1vh) * (100)) - 85px); +$main-view-max-height: calc((var(--vh, 1vh) * (100)) - 85px); +// This is the new Angular Material 3 theme file which we will migrate to +// @use './styles/m3-theme.scss'; + +// this is a pre-defined green palette for testing. // $theme: mat.define-theme(( // color: ( // theme-type: light, @@ -34,6 +36,7 @@ // @include mat.all-component-themes($theme); // } + .mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field.mat-mdc-form-field .mdc-notched-outline__notch { border-right-style: hidden; From 6954ac62627e058b6a73c0e83dc8dc8a1740698d Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 11 Jun 2024 20:50:37 +1000 Subject: [PATCH 0107/1280] fix: ensure loading screen removed in sign in component --- src/app/projects/states/index/global-state.service.ts | 7 ++++++- src/app/sessions/states/sign-in/sign-in.component.ts | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/app/projects/states/index/global-state.service.ts b/src/app/projects/states/index/global-state.service.ts index bb730a37c8..18d77561ac 100644 --- a/src/app/projects/states/index/global-state.service.ts +++ b/src/app/projects/states/index/global-state.service.ts @@ -251,7 +251,6 @@ export class GlobalStateService implements OnDestroy { * Query the API for the units taught and studied by the current user. */ private loadUnitsAndProjects() { - this.isLoadingSubject.next(true); this.unitRoleService.query().subscribe({ next: (_unitRoles: UnitRole[]) => { // unit roles are now in the cache @@ -264,8 +263,14 @@ export class GlobalStateService implements OnDestroy { this.isLoadingSubject.next(false); }, 800); }, + error: (_response) => { + this.alerts.error('Unable to access the units you study.', 6000); + }, }); }, + error: (_response) => { + this.alerts.error('Unable to access your units.', 6000); + } }); } diff --git a/src/app/sessions/states/sign-in/sign-in.component.ts b/src/app/sessions/states/sign-in/sign-in.component.ts index f41b944018..1ac97cca73 100644 --- a/src/app/sessions/states/sign-in/sign-in.component.ts +++ b/src/app/sessions/states/sign-in/sign-in.component.ts @@ -79,11 +79,13 @@ export class SignInComponent implements OnInit { } }); } else { + this.globalState.isLoadingSubject.next(false); // We are SSO and no credentials this.showCredentials = false; return wait.then(); } } else { + this.globalState.isLoadingSubject.next(false); this.authMethodLoaded = true; this.showCredentials = true; return wait.then(); From 729c438f7f6a988f5ff2fa4035493b5cae1c98f7 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 11 Jun 2024 20:50:37 +1000 Subject: [PATCH 0108/1280] fix: ensure loading screen removed in sign in component --- src/app/projects/states/index/global-state.service.ts | 7 ++++++- src/app/sessions/states/sign-in/sign-in.component.ts | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/app/projects/states/index/global-state.service.ts b/src/app/projects/states/index/global-state.service.ts index bb730a37c8..18d77561ac 100644 --- a/src/app/projects/states/index/global-state.service.ts +++ b/src/app/projects/states/index/global-state.service.ts @@ -251,7 +251,6 @@ export class GlobalStateService implements OnDestroy { * Query the API for the units taught and studied by the current user. */ private loadUnitsAndProjects() { - this.isLoadingSubject.next(true); this.unitRoleService.query().subscribe({ next: (_unitRoles: UnitRole[]) => { // unit roles are now in the cache @@ -264,8 +263,14 @@ export class GlobalStateService implements OnDestroy { this.isLoadingSubject.next(false); }, 800); }, + error: (_response) => { + this.alerts.error('Unable to access the units you study.', 6000); + }, }); }, + error: (_response) => { + this.alerts.error('Unable to access your units.', 6000); + } }); } diff --git a/src/app/sessions/states/sign-in/sign-in.component.ts b/src/app/sessions/states/sign-in/sign-in.component.ts index f41b944018..1ac97cca73 100644 --- a/src/app/sessions/states/sign-in/sign-in.component.ts +++ b/src/app/sessions/states/sign-in/sign-in.component.ts @@ -79,11 +79,13 @@ export class SignInComponent implements OnInit { } }); } else { + this.globalState.isLoadingSubject.next(false); // We are SSO and no credentials this.showCredentials = false; return wait.then(); } } else { + this.globalState.isLoadingSubject.next(false); this.authMethodLoaded = true; this.showCredentials = true; return wait.then(); From 5def11c81fd1c1adb9a705b126e6d81cc9510c88 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 11 Jun 2024 21:55:37 +1000 Subject: [PATCH 0109/1280] refactor: remove scorm extension deny button --- .../task-comment/scorm-extension-comment.ts | 5 ----- .../scorm-extension-comment.component.html | 19 ++++++++----------- .../scorm-extension-comment.component.ts | 11 ----------- 3 files changed, 8 insertions(+), 27 deletions(-) diff --git a/src/app/api/models/task-comment/scorm-extension-comment.ts b/src/app/api/models/task-comment/scorm-extension-comment.ts index 3b4dfbccb6..b8aac7909b 100644 --- a/src/app/api/models/task-comment/scorm-extension-comment.ts +++ b/src/app/api/models/task-comment/scorm-extension-comment.ts @@ -26,11 +26,6 @@ export class ScormExtensionComment extends TaskComment { ); } - public deny(): Observable { - this.granted = false; - return this.assessScormExtension(); - } - public grant(): Observable { this.granted = true; return this.assessScormExtension(); diff --git a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html index fa7c4cb39f..b0a74a991e 100644 --- a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html +++ b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html @@ -14,17 +14,14 @@ reason: {{ comment.text }}

@if (isNotStudent) { -
- - -
+ }
diff --git a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts index eb1790edd4..7585e8d7c9 100644 --- a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts @@ -39,17 +39,6 @@ export class ScormExtensionCommentComponent implements OnInit { return this.task.unit.currentUserIsStaff; } - denyExtension() { - this.comment.deny().subscribe({ - next: (tc: TaskComment) => { - this.alerts.success('Attempt request denied', 2000); - }, - error: (response) => { - this.handleError(response); - }, - }); - } - grantExtension() { this.comment.grant().subscribe({ next: (tc: TaskComment) => { From 703563c86253c60ad30d451ee2d8e0fa7ebbfabb Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 11 Jun 2024 22:20:39 +1000 Subject: [PATCH 0110/1280] feat: disable attempt button if passed and add button to review latest attempt in card --- .../task-scorm-card.component.html | 9 +++- .../task-scorm-card.component.ts | 49 ++++++++++++++++--- 2 files changed, 50 insertions(+), 8 deletions(-) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html index ec385b4760..4781d88f2f 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html @@ -18,13 +18,20 @@ mat-stroked-button (click)="launchScormPlayer()" [hidden]="attemptsLeft === 0" - [disabled]="user.isStaff" + [disabled]="user.isStaff || checkIfPassed()" > launch Attempt test + - - - - +@if (isPassed) { + + @if (latestCompletedAttempt.scoreScaled === 1) { + + check + Knowledge Check Passed + + } + @if (latestCompletedAttempt.scoreScaled !== 1) { + + check + Knowledge Check Passed With Mistakes + + } + +

+ You have successfully completed this knowledge check. You can now proceed to submitting task + files. +

+
+ + + +
+} +@if (!isPassed) { + + @if (isPassed === false) { + + close + Knowledge Check Failed + + } + @if (isPassed === undefined) { + + Knowledge Check + + } + +

You have to successfully pass this knowledge check to complete the task.

+

+ You have {{ attemptsLeft !== undefined ? attemptsLeft : 'unlimited' }} attempts left to + complete this test. +

+

+ There will be an increased time delay between test attempts. First 2 attempts will not have + a time delay in between. +

+
+ + + + + +
+} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts index 80744b104a..25fc9e479a 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts @@ -16,6 +16,7 @@ import {ScormExtensionModalService} from 'src/app/common/modals/scorm-extension- export class TaskScormCardComponent implements OnInit, OnChanges { @Input() task: Task; attemptsLeft: number; + isPassed: boolean; latestCompletedAttempt: TestAttempt; user: User; @@ -39,10 +40,13 @@ export class TaskScormCardComponent implements OnInit, OnChanges { refreshAttemptData(): void { this.attemptsLeft = undefined; - this.getAttemptsLeft(); + this.isPassed = undefined; this.latestCompletedAttempt = undefined; + + this.getAttemptsLeft(); this.testAttemptService.getLatestCompletedAttempt(this.task).subscribe((attempt) => { this.latestCompletedAttempt = attempt; + this.isPassed = attempt.successStatus; }); } @@ -57,13 +61,6 @@ export class TaskScormCardComponent implements OnInit, OnChanges { } } - checkIfPassed(): boolean { - if (this.latestCompletedAttempt) { - return this.latestCompletedAttempt.successStatus; - } - return false; - } - launchScormPlayer(): void { window.open( `#/projects/${this.task.project.id}/task_def_id/${this.task.taskDefId}/scorm-player/normal`, From eea5ac5bec09106045573c964dc373585f17777b Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 14 Jun 2024 11:02:10 +1000 Subject: [PATCH 0112/1280] chore: ensure lf file endings --- .gitattributes | 2 ++ .gitignore | 1 - .vscode/settings.json | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 .vscode/settings.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..d56abbf304 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore index 9abc43ca67..c5c729aef4 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ vendor/ .sass-cache* .bundle* tmp.scss -.vscode .tscache a.env dist/ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..8582900e71 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "files.eol": "\n" +} From 0fcb649a0346d78c04d179d2feccee7d920b6b53 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 14 Jun 2024 11:02:10 +1000 Subject: [PATCH 0113/1280] chore: ensure lf file endings --- .gitattributes | 2 ++ .gitignore | 1 - .vscode/settings.json | 3 +++ 3 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 .gitattributes create mode 100644 .vscode/settings.json diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..d56abbf304 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,2 @@ +# Set the default behavior, in case people don't have core.autocrlf set. +* text=auto eol=lf diff --git a/.gitignore b/.gitignore index 9abc43ca67..c5c729aef4 100644 --- a/.gitignore +++ b/.gitignore @@ -11,7 +11,6 @@ vendor/ .sass-cache* .bundle* tmp.scss -.vscode .tscache a.env dist/ diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..8582900e71 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "files.eol": "\n" +} From c5dd45c57fd34e8373f11d065a0cd08edef0a794 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 14 Jun 2024 11:27:05 +1000 Subject: [PATCH 0114/1280] fix: ensure tii open report alerts errors --- .../task-similarity-view.component.ts | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.ts index 2a6739207a..c407d28b4c 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.ts @@ -18,7 +18,7 @@ export class TaskSimilarityViewComponent implements OnChanges { constructor( private taskSimilarityService: TaskSimilarityService, - private alertsService: AlertService, + private alertService: AlertService, private selectedTaskService: SelectedTaskService ) {} @@ -37,7 +37,7 @@ export class TaskSimilarityViewComponent implements OnChanges { this.taskSimilarityService .update({ taskId: similarity.task.id, id: similarity.id }, { entity: similarity }) .subscribe((_) => { - this.alertsService.success('Similarity flag updated'); + this.alertService.success('Similarity flag updated'); similarity.task.similarityFlag = similarity.task.similarityCache.currentValues .map((s) => { return s.flagged; @@ -50,8 +50,13 @@ export class TaskSimilarityViewComponent implements OnChanges { openReport(e: Event, similarity: TaskSimilarity) { e.stopPropagation(); // Open similarity report in new tab - similarity.fetchSimilarityReportUrl().subscribe((url) => { - window.open(url, '_blank'); + similarity.fetchSimilarityReportUrl().subscribe({ + next: (url) => { + window.open(url, '_blank'); + }, + error: (err) => { + this.alertService.error(`Error accessing TurnItIn: ${err}`); + }, }); } } From 456cf466bf49b86467b269ec3d6fb4e63f6a059f Mon Sep 17 00:00:00 2001 From: jakerenzella Date: Sat, 15 Jun 2024 00:10:27 +1000 Subject: [PATCH 0115/1280] fix: fix pdf viewer for portfolios --- .../pdf-viewer/pdf-viewer.component.html | 41 +++++++--- .../common/pdf-viewer/pdf-viewer.component.ts | 11 ++- .../units/states/portfolios/portfolios.coffee | 4 +- .../states/portfolios/portfolios.tpl.html | 82 +++++++++++++++---- 4 files changed, 108 insertions(+), 30 deletions(-) diff --git a/src/app/common/pdf-viewer/pdf-viewer.component.html b/src/app/common/pdf-viewer/pdf-viewer.component.html index 232c89d5ed..87dc97c996 100644 --- a/src/app/common/pdf-viewer/pdf-viewer.component.html +++ b/src/app/common/pdf-viewer/pdf-viewer.component.html @@ -3,25 +3,44 @@
search - + - -
@if (pdfBlobUrl) { - + }
diff --git a/src/app/common/pdf-viewer/pdf-viewer.component.ts b/src/app/common/pdf-viewer/pdf-viewer.component.ts index bb2a85514e..5cd893b5a9 100644 --- a/src/app/common/pdf-viewer/pdf-viewer.component.ts +++ b/src/app/common/pdf-viewer/pdf-viewer.component.ts @@ -1,4 +1,4 @@ -import { HttpResponse } from '@angular/common/http'; +import {HttpResponse} from '@angular/common/http'; import { Component, Input, @@ -7,6 +7,8 @@ import { SimpleChanges, OnChanges, ViewChild, + OnInit, + AfterViewInit, } from '@angular/core'; import {PdfViewerComponent} from 'ng2-pdf-viewer'; import {FileDownloaderService} from '../file-downloader/file-downloader.service'; @@ -17,7 +19,7 @@ import {AlertService} from '../services/alert.service'; templateUrl: './pdf-viewer.component.html', styleUrls: ['./pdf-viewer.component.scss'], }) -export class fPdfViewerComponent implements OnDestroy, OnChanges { +export class fPdfViewerComponent implements OnDestroy, OnChanges, AfterViewInit { private _pdfUrl: string; public pdfBlobUrl: string; @Input() pdfUrl: string; @@ -38,6 +40,11 @@ export class fPdfViewerComponent implements OnDestroy, OnChanges { } } + ngAfterViewInit(): void { + console.log("pdfUrl"); + console.log(this.pdfUrl); + } + ngOnChanges(changes: SimpleChanges): void { this.pdfUrlChanges(changes.pdfUrl.currentValue); } diff --git a/src/app/units/states/portfolios/portfolios.coffee b/src/app/units/states/portfolios/portfolios.coffee index 7e745b33d1..41d0b60797 100644 --- a/src/app/units/states/portfolios/portfolios.coffee +++ b/src/app/units/states/portfolios/portfolios.coffee @@ -122,7 +122,9 @@ angular.module('doubtfire.units.states.portfolios', []) $scope.selectedStudent = student $scope.project = null newProjectService.loadProject(student, $scope.unit).subscribe({ - next: (project) -> $scope.project = project + next: (project) -> + $scope.project = project + $scope.project.preloadedUrl = $scope.project.portfolioUrl() error: (message) -> alertService.error( message, 6000) }) ) diff --git a/src/app/units/states/portfolios/portfolios.tpl.html b/src/app/units/states/portfolios/portfolios.tpl.html index 075680654c..2974d0719a 100644 --- a/src/app/units/states/portfolios/portfolios.tpl.html +++ b/src/app/units/states/portfolios/portfolios.tpl.html @@ -27,7 +27,11 @@

Mark Portfolios

>
@@ -39,7 +43,11 @@

Mark Portfolios

-

No portfolios found

- +
@@ -172,7 +210,9 @@

Mark Portfolios

- + @@ -237,7 +277,13 @@

Review Portfolio of {{selectedStudent.student.name}}

No Portfolio Submitted

- +
+ + +
@@ -260,8 +306,12 @@

Grade for {{selectedStudent.student.name}}

ng-class="{'no-rationale': project.gradeRationale == null}" ng-hide="editingRationale" > - -
+ +
Click to add one
From 93b0017c40823038807d0a555983f5c3bfe78ce8 Mon Sep 17 00:00:00 2001 From: jakerenzella Date: Sat, 15 Jun 2024 00:25:41 +1000 Subject: [PATCH 0116/1280] Angular CLI update for packages - @angular/core@18, @angular/cli@18 --- package-lock.json | 811 +++++++++++++++++++++++++++++----------------- package.json | 28 +- 2 files changed, 535 insertions(+), 304 deletions(-) diff --git a/package-lock.json b/package-lock.json index 93bb789c23..085f5d6307 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,20 +9,20 @@ "version": "8.0.9", "license": "AGPL-3.0", "dependencies": { - "@angular/animations": "^18.0.1", + "@angular/animations": "^18.0.3", "@angular/cdk": "^18.0.1", - "@angular/cli": "^18.0.2", - "@angular/common": "^18.0.1", - "@angular/compiler": "^18.0.1", - "@angular/core": "^18.0.1", - "@angular/forms": "^18.0.1", + "@angular/cli": "^18.0.4", + "@angular/common": "^18.0.3", + "@angular/compiler": "^18.0.3", + "@angular/core": "^18.0.3", + "@angular/forms": "^18.0.3", "@angular/material": "^18.0.1", "@angular/material-moment-adapter": "^18.0.1", - "@angular/platform-browser": "^18.0.1", - "@angular/platform-browser-dynamic": "^18.0.1", - "@angular/router": "^18.0.1", - "@angular/service-worker": "^18.0.1", - "@angular/upgrade": "^18.0.1", + "@angular/platform-browser": "^18.0.3", + "@angular/platform-browser-dynamic": "^18.0.3", + "@angular/router": "^18.0.3", + "@angular/service-worker": "^18.0.3", + "@angular/upgrade": "^18.0.3", "@ctrl/ngx-emoji-mart": "^9.2.0", "@ngneat/hotkeys": "^4.0.0", "@uirouter/angular": "^13.0", @@ -75,14 +75,14 @@ "zone.js": "~0.14" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.0.2", + "@angular-devkit/build-angular": "^18.0.4", "@angular-eslint/builder": "^17.3.0", "@angular-eslint/eslint-plugin": "^17.3.0", "@angular-eslint/eslint-plugin-template": "^17.3.0", "@angular-eslint/schematics": "^17.3.0", "@angular-eslint/template-parser": "^17.3.0", - "@angular/compiler-cli": "^18.0.1", - "@angular/language-service": "^18.0.1", + "@angular/compiler-cli": "^18.0.3", + "@angular/language-service": "^18.0.3", "@commitlint/cli": "^16.0.1", "@commitlint/config-conventional": "^17", "@types/angular": "1.5.11", @@ -180,11 +180,11 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.1800.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1800.2.tgz", - "integrity": "sha512-PX7lCTAqWe9C40+fie+DAc8vhpGA+JgZKWWrMHUTV/iZx8RXx2X4xGQsqYu36p4i3MSfQdbn+0xLWGmjScPVOQ==", + "version": "0.1800.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1800.4.tgz", + "integrity": "sha512-82TKhYnSO8aGIBo5TxPtyUQnZFcbV+qB2bIIYOAKsJgxAVxLeFD6QA6gTmHOZPXw5pBEPUO/+PUwq+Uk5xesgw==", "dependencies": { - "@angular-devkit/core": "18.0.2", + "@angular-devkit/core": "18.0.4", "rxjs": "7.8.1" }, "engines": { @@ -202,16 +202,16 @@ } }, "node_modules/@angular-devkit/build-angular": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.0.2.tgz", - "integrity": "sha512-cQkTx7XaIPj6+DXo6wZmO4iY0hOOfPDnSN/+m84XpBW0tuPGxH7Z9B6wV+Uwcpm9HGPqzRA7VZyPsqbK860b0Q==", + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-18.0.4.tgz", + "integrity": "sha512-lFu1NDEUPIUxY+CmZJ3JspqVZDesrvdae5RbqQXCl87RfSy+ZDIa7rOtQxyBQtt2BuQIB9pWQSzCMii5kTHd6w==", "dev": true, "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1800.2", - "@angular-devkit/build-webpack": "0.1800.2", - "@angular-devkit/core": "18.0.2", - "@angular/build": "18.0.2", + "@angular-devkit/architect": "0.1800.4", + "@angular-devkit/build-webpack": "0.1800.4", + "@angular-devkit/core": "18.0.4", + "@angular/build": "18.0.4", "@babel/core": "7.24.5", "@babel/generator": "7.24.5", "@babel/helper-annotate-as-pure": "7.22.5", @@ -222,7 +222,7 @@ "@babel/preset-env": "7.24.5", "@babel/runtime": "7.24.5", "@discoveryjs/json-ext": "0.5.7", - "@ngtools/webpack": "18.0.2", + "@ngtools/webpack": "18.0.4", "@vitejs/plugin-basic-ssl": "1.1.0", "ansi-colors": "4.1.3", "autoprefixer": "10.4.19", @@ -441,12 +441,12 @@ } }, "node_modules/@angular-devkit/build-webpack": { - "version": "0.1800.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1800.2.tgz", - "integrity": "sha512-CbTURBhZWzx+5KewS2Nkqy2rwBTFgDCvUwONGWuy1K68+85vOWUKqjkfvriHA+JkWN03w7FzWEtTfcOg0EzYkw==", + "version": "0.1800.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1800.4.tgz", + "integrity": "sha512-EtWyWH3Hb7Rh8u0Jb4cWJKRxlqiUo4qhHKjU+62E8XplWlajbuld3ltL50a3t8lkZQYYgl7nPt53E5kM/zFVrw==", "dev": true, "dependencies": { - "@angular-devkit/architect": "0.1800.2", + "@angular-devkit/architect": "0.1800.4", "rxjs": "7.8.1" }, "engines": { @@ -469,9 +469,9 @@ } }, "node_modules/@angular-devkit/core": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.0.2.tgz", - "integrity": "sha512-QXcEdfmODc0rKblBerk30yw70fypIkFm6gQBLJgsshpwc+TMA+fuMLcPQebOTzKLtD2tNUkk/7SrWPQIGqeXaA==", + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-18.0.4.tgz", + "integrity": "sha512-8vYvJ5FF2NjFUia00hv8KWakOjOZ+09PbnNqd+lntJBekIg1lHDOF/vNMlVHtU5LiE1aNi9P/69/VXTckPfU9g==", "dependencies": { "ajv": "8.13.0", "ajv-formats": "3.0.1", @@ -519,11 +519,11 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.0.2.tgz", - "integrity": "sha512-G9yGcoB67sH0eRNWoiQWNn2KwiI7sDasVscYPGKf1yo7JRiXmzX/LpfKRPsZTl+Bs0FItnwDInsqgMisK89/6g==", + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-18.0.4.tgz", + "integrity": "sha512-hCHmuu/Z1teOQPx1AMJa/gcK6depk+XgU5dIpEvflC+ApW3hglNe2QKaqajDZ+34s+PKAVWa86M8IOV7o/mHuA==", "dependencies": { - "@angular-devkit/core": "18.0.2", + "@angular-devkit/core": "18.0.4", "jsonc-parser": "3.2.1", "magic-string": "0.30.10", "ora": "5.4.1", @@ -643,27 +643,27 @@ } }, "node_modules/@angular/animations": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.0.1.tgz", - "integrity": "sha512-QAY/oxfuFY2Bjr3foniWlLAiddXHu8879lZvXHt1NVOsiav+vD15IEEQsnuQbJPy/EHEnAlUh9UptB4zQIBp/Q==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-18.0.3.tgz", + "integrity": "sha512-Wlll6y7euIXYsOHpTh0hvVTBs7lVnbKDHiyd4Dz7kAMSeE2zyQo6OcRN+FFH3GH9BUi5UooAICNX8dJDfps6Mw==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.0.1" + "@angular/core": "18.0.3" } }, "node_modules/@angular/build": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.0.2.tgz", - "integrity": "sha512-iPPHdAJ3LiR8t/+39xjvrqMWcTmRrfphzKxXoIVDcswQjVQIk00EYuxinC6EVa7dSKDl1thk1MeCNZ9DIjaAvQ==", + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-18.0.4.tgz", + "integrity": "sha512-70HQQnbCOXFT5F3ROyWNNfS9A63Fzts5ANJKJY1MJLrn+dgNEG7jdIWjTtvohL3RZz97rlzSq3qRZnfxqf1lsQ==", "dev": true, "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.1800.2", + "@angular-devkit/architect": "0.1800.4", "@babel/core": "7.24.5", "@babel/helper-annotate-as-pure": "7.22.5", "@babel/helper-split-export-declaration": "7.24.5", @@ -798,14 +798,14 @@ } }, "node_modules/@angular/cli": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.0.2.tgz", - "integrity": "sha512-shrxMD1bcWWh7WpBN3KTV+Lt8E62gURSUFhs6kdGLepMDif8LPAv45+hpt8SBU9VfQuL6AHa4cW8uDL9BKGlYA==", - "dependencies": { - "@angular-devkit/architect": "0.1800.2", - "@angular-devkit/core": "18.0.2", - "@angular-devkit/schematics": "18.0.2", - "@schematics/angular": "18.0.2", + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-18.0.4.tgz", + "integrity": "sha512-i7DLVIc4HN0CFZZKbEeVeQSADRG1Dt2CwXh/wTUzglRLu/tE7Q+WMrqJ2+lGTT2edZp2KKysM4Gxp+ATAzP8AQ==", + "dependencies": { + "@angular-devkit/architect": "0.1800.4", + "@angular-devkit/core": "18.0.4", + "@angular-devkit/schematics": "18.0.4", + "@schematics/angular": "18.0.4", "@yarnpkg/lockfile": "1.1.0", "ansi-colors": "4.1.3", "ini": "4.1.2", @@ -841,32 +841,32 @@ } }, "node_modules/@angular/common": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.0.1.tgz", - "integrity": "sha512-iADQC5m4fvk+VNXEoU1KR93b0eG218/GuNdzUNVJHcjxdFxPshKk5fiaGSosUCxXPRQOxDKzmS9EDang87E/Ew==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.0.3.tgz", + "integrity": "sha512-lmT9QbWHduqzpsB0osQFHeSwvQB1iUeNwTVUyMtcs6i46l4qOPtAt2/9DvHUWEUp01EBDxyi385ZI3vD+FHH/w==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.0.1", + "@angular/core": "18.0.3", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.0.1.tgz", - "integrity": "sha512-zyG/ifCtN0drAuwz0oV6LtzTiDREsM1Ay7eJW9wTvp3NCv06goHLtHXX12eFfZQWJViBv924lyRDSWdZN7r3GQ==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-18.0.3.tgz", + "integrity": "sha512-wrXxgBsZX4yTrj/oZ8PDGmvhqj9S2TZfcuivaUitprNC2uBWTVb1UcOS45Qw9YlLB0sYa2AmBudICDqYpb8lfw==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/core": "18.0.1" + "@angular/core": "18.0.3" }, "peerDependenciesMeta": { "@angular/core": { @@ -875,12 +875,12 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.0.1.tgz", - "integrity": "sha512-Aoz70+/o8R2lG2EGDAYbj6yu2B7kqa/9loYEwG0fECJTtXoRBP+bEGpUxMmxOb59tMDnbIhBHmNPPEQVTXvgSQ==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-18.0.3.tgz", + "integrity": "sha512-mxwQEeP94YBM6C9A2YfkV7ug1sHgh0fU/TSBpQcm5ni4cZiVPu6q/+Ft7hyFTKe2p3tKQme33+xVjsWhtOCx0A==", "dev": true, "dependencies": { - "@babel/core": "7.24.4", + "@babel/core": "7.24.7", "@jridgewell/sourcemap-codec": "^1.4.14", "chokidar": "^3.0.0", "convert-source-map": "^1.5.1", @@ -895,22 +895,22 @@ "ngcc": "bundles/ngcc/index.js" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "18.0.1", + "@angular/compiler": "18.0.3", "typescript": ">=5.4 <5.5" } }, "node_modules/@angular/core": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.0.1.tgz", - "integrity": "sha512-Db1livvugoLdLsWww5IqUS5v+yUN7/5Rj0trZv9BgxIuoNtoipfLqKHwZWpumH3yI5Ucu+UH9zZ1mlGyF0Kexw==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-18.0.3.tgz", + "integrity": "sha512-376hijhEqNpeA+qKncpVTIaZXRdBT6RctEBnFhJ2l57aHPH5S3oaSBQu1k3TEi07FlKOD4XF1+NzX9dvdup1eg==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { "rxjs": "^6.5.3 || ^7.4.0", @@ -918,29 +918,29 @@ } }, "node_modules/@angular/forms": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.0.1.tgz", - "integrity": "sha512-j1nUzwnZHO/BRXK0joQbAV10JWxeRVKmPzIaDulY2o28Er1jVKyw2T8EwI+xSvBbAqyJyaAd+ysWUhm3FfH+GA==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-18.0.3.tgz", + "integrity": "sha512-+CjDiooUi5FkTP3YQmdO8YRbjZicgLGZonvCdz3mSucLrTY6w3oBocNs6+Kc7fLuO1NKSkFmAfYApBwK3fKBMg==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.0.1", - "@angular/core": "18.0.1", - "@angular/platform-browser": "18.0.1", + "@angular/common": "18.0.3", + "@angular/core": "18.0.3", + "@angular/platform-browser": "18.0.3", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.0.1.tgz", - "integrity": "sha512-T4ILrLJTnredemIDxkKiL0pD0OZFzXwX6tn/nem2RG9aV5UQWqitOjw1RNuWDbsNXX6vRZsL/nw9cwDpeZhebQ==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-18.0.3.tgz", + "integrity": "sha512-urENnMjhSO4Jia7CnbchqN236dOIU6TC3CazwsQoj1Odch9x+iSFkx9Y0jXsiR5r/suK4uqKpK5N8MJ1PxDG1g==", "dev": true, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" } }, "node_modules/@angular/material": { @@ -1022,19 +1022,19 @@ } }, "node_modules/@angular/platform-browser": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.0.1.tgz", - "integrity": "sha512-rQUsOxZxiwSPvyHdne60IKIGsvFoVc1rO4mDyXU+9sCCLmPKHzNyEzp7vybTZeiqa3k6v3sV/bfHWwrRzmvenw==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-18.0.3.tgz", + "integrity": "sha512-1fl/oJOca8BLxLxN0EjwxQZ3xzn3PCCN96ytM54bjdEMiELz+0AcQe5GNKcVjXlwMkibRLl1BP5GIdvnQYqJRA==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/animations": "18.0.1", - "@angular/common": "18.0.1", - "@angular/core": "18.0.1" + "@angular/animations": "18.0.3", + "@angular/common": "18.0.3", + "@angular/core": "18.0.3" }, "peerDependenciesMeta": { "@angular/animations": { @@ -1043,43 +1043,43 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.0.1.tgz", - "integrity": "sha512-lzjq7HjigGxO5oh5Sw0Vxa3mAVidYHpHFQr46/OSl9T5jLpStcjEqK0xcfQz9bf2hV+0qFfMqmd2k0XQl7feqg==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-18.0.3.tgz", + "integrity": "sha512-+kHMn7P552YKk1gkVQNO1QXzHVaIeFiVa1rV1MNvX4DvumKT3puknx1SzcmtxZTX+9ee22OuPuyLNSAKREDAQQ==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.0.1", - "@angular/compiler": "18.0.1", - "@angular/core": "18.0.1", - "@angular/platform-browser": "18.0.1" + "@angular/common": "18.0.3", + "@angular/compiler": "18.0.3", + "@angular/core": "18.0.3", + "@angular/platform-browser": "18.0.3" } }, "node_modules/@angular/router": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.0.1.tgz", - "integrity": "sha512-PapdvfATjRZI0cJ/RH8n/ixHDHa4HIBaOMwhgU73InU9t6NIhBXg6aRECYV2qGt7NtpLYSHmG5Z1Ws86rm5Tyw==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-18.0.3.tgz", + "integrity": "sha512-/cglLev0USxUNMc4M+EBFGrqw1EpKq87LUJL3+0Ztr012sVSeOU38ad41fs6pPcMBePBDZIw7KmSXypvUJJFMA==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.0.1", - "@angular/core": "18.0.1", - "@angular/platform-browser": "18.0.1", + "@angular/common": "18.0.3", + "@angular/core": "18.0.3", + "@angular/platform-browser": "18.0.3", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.0.1.tgz", - "integrity": "sha512-jTYAeBUg1/4RtQgYerETn3EmOjZnjlhoJ4tXwk25LDEbqzA1HoNjL1R1ifC6sEX3zyOL1SEXp7sMSB1mqq3fJw==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-18.0.3.tgz", + "integrity": "sha512-/8BXh8VxkIAmdl6ftBUh2may6GRGANesvQor9yqH0ddCUpYeIafqqbwIMgHqxe4PJ3ApSkO2zcnXgoUZHL0a/A==", "dependencies": { "tslib": "^2.3.0" }, @@ -1087,37 +1087,37 @@ "ngsw-config": "ngsw-config.js" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/common": "18.0.1", - "@angular/core": "18.0.1" + "@angular/common": "18.0.3", + "@angular/core": "18.0.3" } }, "node_modules/@angular/upgrade": { - "version": "18.0.1", - "resolved": "https://registry.npmjs.org/@angular/upgrade/-/upgrade-18.0.1.tgz", - "integrity": "sha512-xNd97cvtT6o6bGqBeYuoywaBTejPU7iVUS+WhNwUCvsaTnbFD4i6ySNtn3ZBThCaBxfa6+TKq9v/va4Tp8yUCA==", + "version": "18.0.3", + "resolved": "https://registry.npmjs.org/@angular/upgrade/-/upgrade-18.0.3.tgz", + "integrity": "sha512-zGTzS945PO/PmHNfTziFAMyPjMHkO2D5Ip8RRPTSAk0n30qgr9BCvf6Rm1OXcbwgmns2vRLsvvytRV/XD7FN2g==", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^18.13.0 || >=20.9.0" + "node": "^18.19.1 || ^20.11.1 || >=22.0.0" }, "peerDependencies": { - "@angular/compiler": "18.0.1", - "@angular/core": "18.0.1", - "@angular/platform-browser": "18.0.1", - "@angular/platform-browser-dynamic": "18.0.1" + "@angular/compiler": "18.0.3", + "@angular/core": "18.0.3", + "@angular/platform-browser": "18.0.3", + "@angular/platform-browser-dynamic": "18.0.3" } }, "node_modules/@babel/code-frame": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.6.tgz", - "integrity": "sha512-ZJhac6FkEd1yhG2AHOmfcXG4ceoLltoCVJjN5XsWN9BifBQr+cHJbWi0h68HZuSORq+3WtJ2z0hwF2NG1b5kcA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", "dev": true, "dependencies": { - "@babel/highlight": "^7.24.6", + "@babel/highlight": "^7.24.7", "picocolors": "^1.0.0" }, "engines": { @@ -1125,30 +1125,30 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.6.tgz", - "integrity": "sha512-aC2DGhBq5eEdyXWqrDInSqQjO0k8xtPRf5YylULqx8MCd6jBtzqfta/3ETMRpuKIc5hyswfO80ObyA1MvkCcUQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", + "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/core": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.4.tgz", - "integrity": "sha512-MBVlMXP+kkl5394RBLSxxk/iLTeVGuXTV3cIDXavPpMMqnSnt6apKgan/U8O3USWZCWZT/TbgfEpKa4uMgN4Dg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", + "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.4", - "@babel/helper-compilation-targets": "^7.23.6", - "@babel/helper-module-transforms": "^7.23.3", - "@babel/helpers": "^7.24.4", - "@babel/parser": "^7.24.4", - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.1", - "@babel/types": "^7.24.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helpers": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7", "convert-source-map": "^2.0.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -1163,6 +1163,21 @@ "url": "https://opencollective.com/babel" } }, + "node_modules/@babel/core/node_modules/@babel/generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", + "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/core/node_modules/convert-source-map": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", @@ -1218,13 +1233,13 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.6.tgz", - "integrity": "sha512-VZQ57UsDGlX/5fFA7GkVPplZhHsVc+vuErWgdOiysI9Ksnw0Pbbd6pnPiR/mmJyKHgyIW0c7KT32gmhiF+cirg==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", + "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", "dev": true, "dependencies": { - "@babel/compat-data": "^7.24.6", - "@babel/helper-validator-option": "^7.24.6", + "@babel/compat-data": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", "browserslist": "^4.22.2", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -1353,34 +1368,37 @@ } }, "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.6.tgz", - "integrity": "sha512-Y50Cg3k0LKLMjxdPjIl40SdJgMB85iXn27Vk/qbHZCFx/o5XO3PSnpi675h1KEmmDb6OFArfd5SCQEQ5Q4H88g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-function-name": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.6.tgz", - "integrity": "sha512-xpeLqeeRkbxhnYimfr2PC+iA0Q7ljX/d1eZ9/inYbmfG2jpl8Lu3DyXvpOAnrS5kxkfOWJjioIMQsaMBXFI05w==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", "dev": true, "dependencies": { - "@babel/template": "^7.24.6", - "@babel/types": "^7.24.6" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.6.tgz", - "integrity": "sha512-SF/EMrC3OD7dSta1bLJIlrsVxwtd0UpjRJqLno6125epQMJ/kyFmpTT4pbvPbdQHzCHg+biQ7Syo8lnDtbR+uA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1399,28 +1417,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.6.tgz", - "integrity": "sha512-a26dmxFJBF62rRO9mmpgrfTLsAuyHk4e1hKTUkD/fcMfynt8gvEKwQPQDVxWhca8dHoDck+55DFt42zV0QMw5g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.6.tgz", - "integrity": "sha512-Y/YMPm83mV2HJTbX1Qh2sjgjqcacvOlhbzdCCsSlblOKjSYmQqEbO6rUniWQyRo9ncyfjT8hnUjlG06RXDEmcA==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", + "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", "dev": true, "dependencies": { - "@babel/helper-environment-visitor": "^7.24.6", - "@babel/helper-module-imports": "^7.24.6", - "@babel/helper-simple-access": "^7.24.6", - "@babel/helper-split-export-declaration": "^7.24.6", - "@babel/helper-validator-identifier": "^7.24.6" + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1430,12 +1449,12 @@ } }, "node_modules/@babel/helper-module-transforms/node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.6.tgz", - "integrity": "sha512-CvLSkwXGWnYlF9+J3iZUvwgAxKiYzK3BWuo+mLzD/MDGOZDj7Gq8+hqaOkMxmJwmlv0iu86uH5fdADd9Hxkymw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1509,12 +1528,13 @@ } }, "node_modules/@babel/helper-simple-access": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.6.tgz", - "integrity": "sha512-nZzcMMD4ZhmB35MOOzQuiGO5RzL6tJbsT37Zx8M5L/i9KSrukGXWTjLe1knIbb/RmxoJE9GON9soq0c0VEMM5g==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", "dev": true, "dependencies": { - "@babel/types": "^7.24.6" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" @@ -1545,27 +1565,27 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.6.tgz", - "integrity": "sha512-WdJjwMEkmBicq5T9fm/cHND3+UlFa2Yj8ALLgmoSQAJZysYbBjw+azChSGPN4DSPLXOcooGRvDwZWMcF/mLO2Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", + "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.6.tgz", - "integrity": "sha512-4yA7s865JHaqUdRbnaxarZREuPTHrjpDT+pXoAZ1yhyo6uFnIEpS8VMu16siFOHDpZNKYv5BObhsB//ycbICyw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", "dev": true, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-validator-option": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.6.tgz", - "integrity": "sha512-Jktc8KkF3zIkePb48QO+IapbXlSapOW9S+ogZZkcO6bABgYAxtZcjZ/O005111YLf+j4M84uEgwYoidDkXbCkQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", + "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", "dev": true, "engines": { "node": ">=6.9.0" @@ -1586,26 +1606,25 @@ } }, "node_modules/@babel/helpers": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.5.tgz", - "integrity": "sha512-CiQmBMMpMQHwM5m01YnrM6imUG1ebgYJ+fAIW4FZe6m4qHTPaRHti+R8cggAwkdz4oXhtO4/K9JWlh+8hIfR2Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", + "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", "dev": true, "dependencies": { - "@babel/template": "^7.24.0", - "@babel/traverse": "^7.24.5", - "@babel/types": "^7.24.5" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/highlight": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.6.tgz", - "integrity": "sha512-2YnuOp4HAk2BsBrJJvYCbItHx0zWscI1C3zgWkz+wDyD9I7GIVrfnLyrR4Y1VR+7p+chAEcrgRQYZAGIKMV7vQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", "dev": true, "dependencies": { - "@babel/helper-validator-identifier": "^7.24.6", + "@babel/helper-validator-identifier": "^7.24.7", "chalk": "^2.4.2", "js-tokens": "^4.0.0", "picocolors": "^1.0.0" @@ -1615,9 +1634,9 @@ } }, "node_modules/@babel/parser": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.6.tgz", - "integrity": "sha512-eNZXdfU35nJC2h24RznROuOpO94h6x8sg9ju0tT9biNtLZ2vuP8SduLqqV+/8+cebSLV9SJEAN5Z3zQbJG/M+Q==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", "dev": true, "bin": { "parser": "bin/babel-parser.js" @@ -2910,33 +2929,33 @@ } }, "node_modules/@babel/template": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.6.tgz", - "integrity": "sha512-3vgazJlLwNXi9jhrR1ef8qiB65L1RK90+lEQwv4OxveHnqC3BfmnHdgySwRLzf6akhlOYenT+b7AfWq+a//AHw==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", "dev": true, "dependencies": { - "@babel/code-frame": "^7.24.6", - "@babel/parser": "^7.24.6", - "@babel/types": "^7.24.6" + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.24.5", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.5.tgz", - "integrity": "sha512-7aaBLeDQ4zYcUFDUD41lJc1fG8+5IU9DaNSJAgal866FGvmD5EbWQgnEC6kO1gGLsX0esNkfnJSndbTXA3r7UA==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.24.2", - "@babel/generator": "^7.24.5", - "@babel/helper-environment-visitor": "^7.22.20", - "@babel/helper-function-name": "^7.23.0", - "@babel/helper-hoist-variables": "^7.22.5", - "@babel/helper-split-export-declaration": "^7.24.5", - "@babel/parser": "^7.24.5", - "@babel/types": "^7.24.5", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", + "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7", "debug": "^4.3.1", "globals": "^11.1.0" }, @@ -2944,14 +2963,41 @@ "node": ">=6.9.0" } }, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", + "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dev": true, + "dependencies": { + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.6.tgz", - "integrity": "sha512-WaMsgi6Q8zMgMth93GvWPXkhAIEobfsIkLTacoVZoK1J0CevIPGYY2Vo5YvJGqyHqXM6P4ppOYGsIRU8MM9pFQ==", + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", + "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", "dev": true, "dependencies": { - "@babel/helper-string-parser": "^7.24.6", - "@babel/helper-validator-identifier": "^7.24.6", + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", "to-fast-properties": "^2.0.0" }, "engines": { @@ -5335,9 +5381,9 @@ } }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.2.tgz", - "integrity": "sha512-9bfjwDxIDWmmOKusUcqdS4Rw+SETlp9Dy39Xui9BEGEk19dDwH0jhipwFzEff/pFg95NKymc6TOTbRKcWeRqyQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", + "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", "cpu": [ "arm64" ], @@ -5348,9 +5394,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.2.tgz", - "integrity": "sha512-lwriRAHm1Yg4iDf23Oxm9n/t5Zpw1lVnxYU3HnJPTi2lJRkKTrps1KVgvL6m7WvmhYVt/FIsssWay+k45QHeuw==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", + "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", "cpu": [ "x64" ], @@ -5361,9 +5407,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.2.tgz", - "integrity": "sha512-MOI9Dlfrpi2Cuc7i5dXdxPbFIgbDBGgKR5F2yWEa6FVEtSWncfVNKW5AKjImAQ6CZlBK9tympdsZJ2xThBiWWA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", + "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", "cpu": [ "arm" ], @@ -5374,9 +5420,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.2.tgz", - "integrity": "sha512-FU20Bo66/f7He9Fp9sP2zaJ1Q8L9uLPZQDub/WlUip78JlPeMbVL8546HbZfcW9LNciEXc8d+tThSJjSC+tmsg==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", "cpu": [ "arm64" ], @@ -5387,9 +5433,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.2.tgz", - "integrity": "sha512-gsWNDCklNy7Ajk0vBBf9jEx04RUxuDQfBse918Ww+Qb9HCPoGzS+XJTLe96iN3BVK7grnLiYghP/M4L8VsaHeA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", + "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", "cpu": [ "x64" ], @@ -5400,9 +5446,9 @@ ] }, "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.2.tgz", - "integrity": "sha512-O+6Gs8UeDbyFpbSh2CPEz/UOrrdWPTBYNblZK5CxxLisYt4kGX3Sc+czffFonyjiGSq3jWLwJS/CCJc7tBr4sQ==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", + "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", "cpu": [ "x64" ], @@ -5421,9 +5467,9 @@ } }, "node_modules/@ngtools/webpack": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.0.2.tgz", - "integrity": "sha512-I+ZNFGBnykUWBwGPCXy6m9R2fIX/ovnAUHylvThYd/M+FUfc+Z/3DpKEUBYIOLVCLNZR5nuK0t9QLlazYhWFgg==", + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-18.0.4.tgz", + "integrity": "sha512-eWQkAuHEnLme01Ey4Z0FoG6upJHYhnJfsCTBnyEB2LTfdyBUk+PC0gwPXInK8oltWjFfiMnCwxrUQvQsvPW7Hg==", "dev": true, "engines": { "node": "^18.19.1 || ^20.11.1 || >=22.0.0", @@ -5897,10 +5943,88 @@ "url": "https://opencollective.com/unts" } }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", + "integrity": "sha512-Tya6xypR10giZV1XzxmH5wr25VcZSncG0pZIjfePT0OVBvqNEurzValetGNarVrGiq66EBVAFn15iYX4w6FKgQ==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.18.0.tgz", + "integrity": "sha512-avCea0RAP03lTsDhEyfy+hpfr85KfyTctMADqHVhLAF3MlIkq83CP8UfAHUssgXTYd+6er6PaAhx/QGv4L1EiA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.18.0.tgz", + "integrity": "sha512-IWfdwU7KDSm07Ty0PuA/W2JYoZ4iTj3TUQjkVsO/6U+4I1jN5lcR71ZEvRh52sDOERdnNhhHU57UITXz5jC1/w==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.18.0.tgz", + "integrity": "sha512-n2LMsUz7Ynu7DoQrSQkBf8iNrjOGyPLrdSg802vk6XT3FtsgX6JbE8IHRvposskFm9SNxzkLYGSq9QdpLYpRNA==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.18.0.tgz", + "integrity": "sha512-C/zbRYRXFjWvz9Z4haRxcTdnkPt1BtCkz+7RtBSuNmKzMzp3ZxdM28Mpccn6pt28/UWUCTXa+b0Mx1k3g6NOMA==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.18.0.tgz", + "integrity": "sha512-l3m9ewPgjQSXrUMHg93vt0hYCGnrMOcUpTz6FLtbwljo2HluS4zTXFy2571YQbisTnfTKPZ01u/ukJdQTLGh9A==", + "cpu": [ + "arm" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.17.2.tgz", - "integrity": "sha512-EMMPHkiCRtE8Wdk3Qhtciq6BndLtstqZIroHiiGzB3C5LDJmIZcSzVtLRbwuXuUft1Cnv+9fxuDtDxz3k3EW2A==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.18.0.tgz", + "integrity": "sha512-rJ5D47d8WD7J+7STKdCUAgmQk49xuFrRi9pZkWoRD1UeSMakbcepWXPF8ycChBoAqs1pb2wzvbY6Q33WmN2ftw==", "cpu": [ "arm64" ], @@ -5911,9 +6035,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.17.2.tgz", - "integrity": "sha512-NMPylUUZ1i0z/xJUIx6VUhISZDRT+uTWpBcjdv0/zkp7b/bQDF+NfnfdzuTiB1G6HTodgoFa93hp0O1xl+/UbA==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.18.0.tgz", + "integrity": "sha512-be6Yx37b24ZwxQ+wOQXXLZqpq4jTckJhtGlWGZs68TgdKXJgw54lUUoFYrg6Zs/kjzAQwEwYbp8JxZVzZLRepQ==", "cpu": [ "arm64" ], @@ -5923,6 +6047,110 @@ "linux" ] }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.18.0.tgz", + "integrity": "sha512-hNVMQK+qrA9Todu9+wqrXOHxFiD5YmdEi3paj6vP02Kx1hjd2LLYR2eaN7DsEshg09+9uzWi2W18MJDlG0cxJA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.18.0.tgz", + "integrity": "sha512-ROCM7i+m1NfdrsmvwSzoxp9HFtmKGHEqu5NNDiZWQtXLA8S5HBCkVvKAxJ8U+CVctHwV2Gb5VUaK7UAkzhDjlg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.18.0.tgz", + "integrity": "sha512-0UyyRHyDN42QL+NbqevXIIUnKA47A+45WyasO+y2bGJ1mhQrfrtXUpTxCOrfxCR4esV3/RLYyucGVPiUsO8xjg==", + "cpu": [ + "s390x" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.18.0.tgz", + "integrity": "sha512-xuglR2rBVHA5UsI8h8UbX4VJ470PtGCf5Vpswh7p2ukaqBGFTnsfzxUBetoWBWymHMxbIG0Cmx7Y9qDZzr648w==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.18.0.tgz", + "integrity": "sha512-LKaqQL9osY/ir2geuLVvRRs+utWUNilzdE90TpyoX0eNqPzWjRm14oMEE+YLve4k/NAqCdPkGYDaDF5Sw+xBfg==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.18.0.tgz", + "integrity": "sha512-7J6TkZQFGo9qBKH0pk2cEVSRhJbL6MtfWxth7Y5YmZs57Pi+4x6c2dStAUvaQkHQLnEQv1jzBUW43GvZW8OFqA==", + "cpu": [ + "arm64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.18.0.tgz", + "integrity": "sha512-Txjh+IxBPbkUB9+SXZMpv+b/vnTEtFyfWZgJ6iyCmt2tdx0OF5WhFowLmnh8ENGNpfUlUZkdI//4IEmhwPieNg==", + "cpu": [ + "ia32" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.18.0.tgz", + "integrity": "sha512-UOo5FdvOL0+eIVTgS4tIdbW+TtnBLWg1YBCcU2KWM7nuNwRz9bksDX1bekJJCpu25N1DVWaCwnT39dVQxzqS8g==", + "cpu": [ + "x64" + ], + "dev": true, + "optional": true, + "os": [ + "win32" + ] + }, "node_modules/@scarf/scarf": { "version": "1.3.0", "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.3.0.tgz", @@ -5930,12 +6158,12 @@ "hasInstallScript": true }, "node_modules/@schematics/angular": { - "version": "18.0.2", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.0.2.tgz", - "integrity": "sha512-qkJs1oxHtneJ6QxDKpxNyneXGDM9SKVj+Bgi8xUAU3FEzpsYmE/aW3MfwYHOZl0pDBO8c2raqLvlyl3dGP6/Gg==", + "version": "18.0.4", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-18.0.4.tgz", + "integrity": "sha512-fN4whuym9ZmcQFdTfwLZr4j+NcZ4LzbdLk8XYrYdxt1z8c9ujs5LqJYn0LYc3UWiYl7z2RVc9NOxzNrkiXdwlw==", "dependencies": { - "@angular-devkit/core": "18.0.2", - "@angular-devkit/schematics": "18.0.2", + "@angular-devkit/core": "18.0.4", + "@angular-devkit/schematics": "18.0.4", "jsonc-parser": "3.2.1" }, "engines": { @@ -18010,33 +18238,36 @@ } }, "node_modules/msgpackr-extract": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.2.tgz", - "integrity": "sha512-SdzXp4kD/Qf8agZ9+iTu6eql0m3kWm1A2y1hkpTeVNENutaB0BwHlSvAIaMxwntmRUAUjon2V4L8Z/njd0Ct8A==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", + "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", "dev": true, "hasInstallScript": true, "optional": true, "dependencies": { - "node-gyp-build-optional-packages": "5.0.7" + "node-gyp-build-optional-packages": "5.2.2" }, "bin": { "download-msgpackr-prebuilds": "bin/download-prebuilds.js" }, "optionalDependencies": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.2", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.2", - "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.2", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.2", - "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.2", - "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.2" + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" } }, "node_modules/msgpackr-extract/node_modules/node-gyp-build-optional-packages": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.0.7.tgz", - "integrity": "sha512-YlCCc6Wffkx0kHkmam79GKvDQ6x+QZkMjFGrIMxgFNILFvGSbCp2fCBC55pGTT9gVaz8Na5CLmxt/urtzRv36w==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/node-gyp-build-optional-packages/-/node-gyp-build-optional-packages-5.2.2.tgz", + "integrity": "sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==", "dev": true, "optional": true, + "dependencies": { + "detect-libc": "^2.0.1" + }, "bin": { "node-gyp-build-optional-packages": "bin.js", "node-gyp-build-optional-packages-optional": "optional.js", @@ -22052,9 +22283,9 @@ } }, "node_modules/rollup": { - "version": "4.17.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.17.2.tgz", - "integrity": "sha512-/9ClTJPByC0U4zNLowV1tMBe8yMEAxewtR3cUNX5BoEpGH3dQEWpJLr6CLp0fPdYRF/fzVOgvDb1zXuakwF5kQ==", + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.18.0.tgz", + "integrity": "sha512-QmJz14PX3rzbJCN1SG4Xe/bAAX2a6NpCP8ab2vfu2GiUr8AQcr2nCV/oEO3yneFarB67zk8ShlIyWb2LGTb3Sg==", "dev": true, "dependencies": { "@types/estree": "1.0.5" @@ -22067,22 +22298,22 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.17.2", - "@rollup/rollup-android-arm64": "4.17.2", - "@rollup/rollup-darwin-arm64": "4.17.2", - "@rollup/rollup-darwin-x64": "4.17.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.17.2", - "@rollup/rollup-linux-arm-musleabihf": "4.17.2", - "@rollup/rollup-linux-arm64-gnu": "4.17.2", - "@rollup/rollup-linux-arm64-musl": "4.17.2", - "@rollup/rollup-linux-powerpc64le-gnu": "4.17.2", - "@rollup/rollup-linux-riscv64-gnu": "4.17.2", - "@rollup/rollup-linux-s390x-gnu": "4.17.2", - "@rollup/rollup-linux-x64-gnu": "4.17.2", - "@rollup/rollup-linux-x64-musl": "4.17.2", - "@rollup/rollup-win32-arm64-msvc": "4.17.2", - "@rollup/rollup-win32-ia32-msvc": "4.17.2", - "@rollup/rollup-win32-x64-msvc": "4.17.2", + "@rollup/rollup-android-arm-eabi": "4.18.0", + "@rollup/rollup-android-arm64": "4.18.0", + "@rollup/rollup-darwin-arm64": "4.18.0", + "@rollup/rollup-darwin-x64": "4.18.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.18.0", + "@rollup/rollup-linux-arm-musleabihf": "4.18.0", + "@rollup/rollup-linux-arm64-gnu": "4.18.0", + "@rollup/rollup-linux-arm64-musl": "4.18.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.18.0", + "@rollup/rollup-linux-riscv64-gnu": "4.18.0", + "@rollup/rollup-linux-s390x-gnu": "4.18.0", + "@rollup/rollup-linux-x64-gnu": "4.18.0", + "@rollup/rollup-linux-x64-musl": "4.18.0", + "@rollup/rollup-win32-arm64-msvc": "4.18.0", + "@rollup/rollup-win32-ia32-msvc": "4.18.0", + "@rollup/rollup-win32-x64-msvc": "4.18.0", "fsevents": "~2.3.2" } }, @@ -25962,9 +26193,9 @@ } }, "node_modules/webpack-dev-server/node_modules/jackspeak": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.1.2.tgz", - "integrity": "sha512-kWmLKn2tRtfYMF/BakihVVRzBKOxz4gJMiL2Rj91WnAB5TPZumSH99R/Yf1qE1u4uRimvCSJfm6hnxohXeEXjQ==", + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-3.4.0.tgz", + "integrity": "sha512-JVYhQnN59LVPFCEcVa2C3CrEKYacvjRfqIQl+h8oi91aLYQVWRYbxjPcv1bUiUy/kLmQaANrYfNMCO3kuEDHfw==", "dev": true, "dependencies": { "@isaacs/cliui": "^8.0.2" diff --git a/package.json b/package.json index cefc596960..7431b2a58c 100644 --- a/package.json +++ b/package.json @@ -26,20 +26,20 @@ "keywords": [], "author": "", "dependencies": { - "@angular/animations": "^18.0.1", + "@angular/animations": "^18.0.3", "@angular/cdk": "^18.0.1", - "@angular/cli": "^18.0.2", - "@angular/common": "^18.0.1", - "@angular/compiler": "^18.0.1", - "@angular/core": "^18.0.1", - "@angular/forms": "^18.0.1", + "@angular/cli": "^18.0.4", + "@angular/common": "^18.0.3", + "@angular/compiler": "^18.0.3", + "@angular/core": "^18.0.3", + "@angular/forms": "^18.0.3", "@angular/material": "^18.0.1", "@angular/material-moment-adapter": "^18.0.1", - "@angular/platform-browser": "^18.0.1", - "@angular/platform-browser-dynamic": "^18.0.1", - "@angular/router": "^18.0.1", - "@angular/service-worker": "^18.0.1", - "@angular/upgrade": "^18.0.1", + "@angular/platform-browser": "^18.0.3", + "@angular/platform-browser-dynamic": "^18.0.3", + "@angular/router": "^18.0.3", + "@angular/service-worker": "^18.0.3", + "@angular/upgrade": "^18.0.3", "@ctrl/ngx-emoji-mart": "^9.2.0", "@ngneat/hotkeys": "^4.0.0", "@uirouter/angular": "^13.0", @@ -92,14 +92,14 @@ "zone.js": "~0.14" }, "devDependencies": { - "@angular-devkit/build-angular": "^18.0.2", + "@angular-devkit/build-angular": "^18.0.4", "@angular-eslint/builder": "^17.3.0", "@angular-eslint/eslint-plugin": "^17.3.0", "@angular-eslint/eslint-plugin-template": "^17.3.0", "@angular-eslint/schematics": "^17.3.0", "@angular-eslint/template-parser": "^17.3.0", - "@angular/compiler-cli": "^18.0.1", - "@angular/language-service": "^18.0.1", + "@angular/compiler-cli": "^18.0.3", + "@angular/language-service": "^18.0.3", "@commitlint/cli": "^16.0.1", "@commitlint/config-conventional": "^17", "@types/angular": "1.5.11", From e1094bcf2468a939d6186dc769621a8dba5cfa0f Mon Sep 17 00:00:00 2001 From: jakerenzella Date: Sat, 15 Jun 2024 00:57:06 +1000 Subject: [PATCH 0117/1280] build: upgrade eslint packages and flow --- .eslintrc.json | 91 - angular.json | 6 +- eslint.config.js | 62 + package-lock.json | 1812 ++++++++--------- package.json | 33 +- .../task-definition-upload.component.html | 59 +- .../task-definition-upload.component.ts | 12 +- .../states/portfolios/portfolios.tpl.html | 8 +- 8 files changed, 984 insertions(+), 1099 deletions(-) delete mode 100644 .eslintrc.json create mode 100644 eslint.config.js diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 9bf5e49a86..0000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,91 +0,0 @@ -{ - "root": true, - "overrides": [ - { - "files": ["*.ts"], - "parserOptions": { - "project": ["tsconfig.*?.json"], - "createDefaultProgram": true - }, - "plugins": ["@typescript-eslint"], - "extends": [ - "plugin:@angular-eslint/recommended", - "plugin:@typescript-eslint/recommended", - "plugin:prettier/recommended" - ], - "env": { - "browser": true, - "jasmine": true - }, - "rules": { - "@typescript-eslint/no-unused-vars": [ - "warn", - { - "args": "all", - "argsIgnorePattern": "^_", - "caughtErrors": "all", - "caughtErrorsIgnorePattern": "^_", - "destructuredArrayIgnorePattern": "^_", - "varsIgnorePattern": "^_", - "ignoreRestSiblings": true - } - ], - "@angular-eslint/no-empty-lifecycle-method": "warn", - "@angular-eslint/component-class-suffix": "warn", - "@angular-eslint/no-output-on-prefix": "warn", - "@typescript-eslint/no-inferrable-types": "off", - "@angular-eslint/directive-selector": [ - "warn", - { - "type": "attribute", - "prefix": "f", - "style": "camelCase" - } - ], - "@angular-eslint/component-selector": [ - "warn", - { - "type": "element", - "prefix": "f", - "style": "kebab-case" - } - ], - "@typescript-eslint/ban-types": "warn", - "@typescript-eslint/no-empty-function": "warn", - "@typescript-eslint/no-inferrable-types": "off", - "@typescript-eslint/no-this-alias": "warn", - "no-dupe-class-members": "warn", - "no-prototype-builtins": "warn", - "no-unused-vars": "off", - "no-useless-escape": "warn", - "no-var": "warn", - "quotes": [ - "warn", - "single", - { - "allowTemplateLiterals": true - } - ], - "prefer-const": "warn", - "prettier/prettier": "warn" - } - }, - { - "files": ["*.component.html"], - "extends": ["plugin:@angular-eslint/template/recommended", "plugin:prettier/recommended"], - "rules": { - "max-len": [ - "warn", - { - "code": 140 - } - ], - "prettier/prettier": "warn" - } - }, - { - "files": ["*.component.ts"], - "extends": ["plugin:@angular-eslint/template/process-inline-templates"] - } - ] -} diff --git a/angular.json b/angular.json index 2c0b1f0b92..278de25b84 100644 --- a/angular.json +++ b/angular.json @@ -20,7 +20,9 @@ "outputPath": "dist", "index": "build/index.html", "browser": "src/main.ts", - "polyfills": ["src/polyfills.ts"], + "polyfills": [ + "src/polyfills.ts" + ], "tsConfig": "src/tsconfig.app.json", "assets": [ "src/assets", @@ -150,7 +152,7 @@ "options": { "lintFilePatterns": [ "src/**/*.ts", - "src/**/*.component.html" + "src/**/*.html" ] } }, diff --git a/eslint.config.js b/eslint.config.js new file mode 100644 index 0000000000..a327c5d852 --- /dev/null +++ b/eslint.config.js @@ -0,0 +1,62 @@ +// @ts-check + +// Allows us to bring in the recommended core rules from eslint itself +const eslint = require('@eslint/js'); + +// Allows us to use the typed utility for our config, and to bring in the recommended rules for TypeScript projects from typescript-eslint +const tseslint = require('typescript-eslint'); + +// Allows us to bring in the recommended rules for Angular projects from angular-eslint +const angular = require('angular-eslint'); + +// Export our config array, which is composed together thanks to the typed utility function from typescript-eslint +module.exports = tseslint.config( + { + // Everything in this config object targets our TypeScript files (Components, Directives, Pipes etc) + files: ['**/*.ts'], + extends: [ + // Apply the recommended core rules + eslint.configs.recommended, + // Apply the recommended TypeScript rules + ...tseslint.configs.recommended, + // Optionally apply stylistic rules from typescript-eslint that improve code consistency + ...tseslint.configs.stylistic, + // Apply the recommended Angular rules + ...angular.configs.tsRecommended, + ], + // Set the custom processor which will allow us to have our inline Component templates extracted + // and treated as if they are HTML files (and therefore have the .html config below applied to them) + processor: angular.processInlineTemplates, + // Override specific rules for TypeScript files (these will take priority over the extended configs above) + rules: { + '@angular-eslint/directive-selector': [ + 'error', + { + type: 'attribute', + prefix: 'f', + style: 'camelCase', + }, + ], + '@angular-eslint/component-selector': [ + 'error', + { + type: 'element', + prefix: 'f', + style: 'kebab-case', + }, + ], + }, + }, + { + // Everything in this config object targets our HTML files (external templates, + // and inline templates as long as we have the `processor` set on our TypeScript config above) + files: ['**/*component.html'], + extends: [ + // Apply the recommended Angular template rules + ...angular.configs.templateRecommended, + // Apply the Angular template rules which focus on accessibility of our apps + ...angular.configs.templateAccessibility, + ], + rules: {}, + }, +); diff --git a/package-lock.json b/package-lock.json index 085f5d6307..8702239d8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,13 +25,9 @@ "@angular/upgrade": "^18.0.3", "@ctrl/ngx-emoji-mart": "^9.2.0", "@ngneat/hotkeys": "^4.0.0", - "@uirouter/angular": "^13.0", - "@uirouter/angular-hybrid": "^17.1.0", - "@uirouter/angularjs": "^1.0.30", - "@uirouter/core": "^6.1.0", - "@uirouter/rx": "^1.0.0", "angular": "1.5.11", "angular-cookies": "1.5.11", + "angular-eslint": "^18.0.1", "angular-file-upload": "~1", "angular-filter": "0.5.17", "angular-local-storage": "0.7.1", @@ -65,22 +61,23 @@ "ng-flex-layout": "^17.3.7-beta.1", "ng2-pdf-viewer": "^10.2", "ngx-bootstrap": "^6.1.0", - "ngx-entity-service": "^0.0.38", + "ngx-entity-service": "^0.0.39", "ngx-lottie": "^11.0.2", "nvd3": "1.8.6", "rxjs": "~7.4.0", "ts-md5": "^1.3.1", "tslib": "^2.6.2", + "typescript-eslint": "^7.13.0", "underscore.string": "2.3.3", "zone.js": "~0.14" }, "devDependencies": { "@angular-devkit/build-angular": "^18.0.4", - "@angular-eslint/builder": "^17.3.0", - "@angular-eslint/eslint-plugin": "^17.3.0", - "@angular-eslint/eslint-plugin-template": "^17.3.0", - "@angular-eslint/schematics": "^17.3.0", - "@angular-eslint/template-parser": "^17.3.0", + "@angular-eslint/builder": "18.0.1", + "@angular-eslint/eslint-plugin": "18.0.1", + "@angular-eslint/eslint-plugin-template": "18.0.1", + "@angular-eslint/schematics": "18.0.1", + "@angular-eslint/template-parser": "18.0.1", "@angular/compiler-cli": "^18.0.3", "@angular/language-service": "^18.0.3", "@commitlint/cli": "^16.0.1", @@ -93,17 +90,12 @@ "@types/jasminewd2": "~2.0.3", "@types/lodash": "^4.14.115", "@types/node": "^20.9.0", - "@typescript-eslint/eslint-plugin": "^7.2.0", - "@typescript-eslint/parser": "^7.2.0", + "@typescript-eslint/eslint-plugin": "7.11.0", + "@typescript-eslint/parser": "7.11.0", "autoprefixer": "~6", "canonical-path": "0.0.2", "concurrently": "^3.2.0", - "eslint": "^8.57.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "2.26.0", - "eslint-plugin-jsdoc": "39.3.6", - "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-prettier": "^5.0.1", + "eslint": "8.57.0", "grunt": "^1.0.4", "grunt-bump": "0.8.0", "grunt-coffeelint": "0.0.16", @@ -137,7 +129,6 @@ "postcss": "^8.4.27", "postcss-scss": "^0.1.7", "prettier": "^3.1.0", - "protractor": "~7.0.0", "sass": "^1.48.0", "tailwindcss": "~3.3", "ts-node": "~10.9", @@ -428,18 +419,6 @@ "tslib": "^2.1.0" } }, - "node_modules/@angular-devkit/build-angular/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@angular-devkit/build-webpack": { "version": "0.1800.4", "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1800.4.tgz", @@ -544,101 +523,94 @@ } }, "node_modules/@angular-eslint/builder": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-17.4.0.tgz", - "integrity": "sha512-+3ujbi+ar/iqAAwnJ2bTdWzQpHh9iVEPgjHUOeQhrEM8gcaOLnZXMlUyZL7D+NlXg7aDoEIxETb73dgbIBm55A==", - "dev": true, + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-18.0.1.tgz", + "integrity": "sha512-b/VUeTQznAmGdwP4OyPWyegqSRWub7E8/WXBqojrSFyLkFhpTiHpk/3/5G3LsgTb0zBfyAsqkA0yaadsHu9pjA==", "dependencies": { - "@nx/devkit": "^17.2.8 || ^18.0.0", - "nx": "^17.2.8 || ^18.0.0" + "@nx/devkit": "^19.0.6", + "nx": "^19.0.6" }, "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-17.4.0.tgz", - "integrity": "sha512-cYEJs4PO+QLDt1wfgWh9q8OjOphnoe1OTTFtMqm9lHl0AkBynPnFA6ghiiG5NaT03l7HXi2TQ23rLFlXl3JOBg==", - "dev": true + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-18.0.1.tgz", + "integrity": "sha512-lr4Ysoo28FBOKcJFQUGTMpbWDcak+gyuYvyggp37ERvazE6EDomPFxzEHNqVT9EI9sZ+GDBOoPR+EdFh0ALGNw==" }, "node_modules/@angular-eslint/eslint-plugin": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-17.4.0.tgz", - "integrity": "sha512-E+/O83PXttQUACurGEskLDU+wboBqMMVqvo4T8C/iMcpLx+01M5UBzqpCmfz6ri609G96Au7uDbUEedU1hwqmQ==", - "dev": true, + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-18.0.1.tgz", + "integrity": "sha512-pS3SYLa9DA+ENklGxEUlcw6/xCxgDk9fgjyaheuSjDxL3TIh1pTa4V2TptODdcPh7XCYXiVmy+e/w79mXlGzOw==", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.4.0", - "@angular-eslint/utils": "17.4.0", - "@typescript-eslint/utils": "7.8.0" + "@angular-eslint/bundled-angular-compiler": "18.0.1", + "@angular-eslint/utils": "18.0.1" }, "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0-alpha.20", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-17.4.0.tgz", - "integrity": "sha512-o1Vb7rt3TpPChVzaxswOKBDWRboMcpC4qUUyoHfeSYa7sDuQHMeIQlCS5QXuykR/RYnIQJSKd89FOd28nGmmRw==", - "dev": true, + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-18.0.1.tgz", + "integrity": "sha512-u/eov/CFBb8l35D8dW78Dx5fBLd8FZFibKN9XQknhzXnDMpISuUOMny5g5/wvYYjqLgqEySXMiHKEAxEup7xtA==", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.4.0", - "@angular-eslint/utils": "17.4.0", - "@typescript-eslint/type-utils": "7.8.0", - "@typescript-eslint/utils": "7.8.0", + "@angular-eslint/bundled-angular-compiler": "18.0.1", + "@angular-eslint/utils": "18.0.1", "aria-query": "5.3.0", "axobject-query": "4.0.0" }, "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0-alpha.20", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/schematics": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-17.4.0.tgz", - "integrity": "sha512-3WQQbwwBD1N3dZbbx1a1KY/jRujUQgz5778Ac21LU+AdCtvbjnmSpxRfsE3HH8MAreqr8Lv1kjLyiRzPTS5GQQ==", - "dev": true, + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-18.0.1.tgz", + "integrity": "sha512-G9PgFrjyvBaQR8enMnP2scnQDLk99GMpifh3voiOmdEkxaQHRWqhCWncV7GATwpXDzeyj9J9XT9iHGJjnZTpJQ==", "dependencies": { - "@angular-eslint/eslint-plugin": "17.4.0", - "@angular-eslint/eslint-plugin-template": "17.4.0", - "@nx/devkit": "^17.2.8 || ^18.0.0", + "@angular-eslint/eslint-plugin": "18.0.1", + "@angular-eslint/eslint-plugin-template": "18.0.1", + "@nx/devkit": "^19.0.6", "ignore": "5.3.1", - "nx": "^17.2.8 || ^18.0.0", - "strip-json-comments": "3.1.1", - "tmp": "0.2.3" + "nx": "^19.0.6", + "semver": "7.6.2", + "strip-json-comments": "3.1.1" }, "peerDependencies": { - "@angular/cli": ">= 17.0.0 < 18.0.0" + "@angular-devkit/core": ">= 18.0.0 < 19.0.0", + "@angular-devkit/schematics": ">= 18.0.0 < 19.0.0" } }, "node_modules/@angular-eslint/template-parser": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-17.4.0.tgz", - "integrity": "sha512-vT/Tg8dl6Uy++MS9lPS0l37SynH3EaMcggDiTJqn15pIb4ePO65fafOIIKKYG+BN6R6iFe/g9mH/9nb8ohlzdQ==", - "dev": true, + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-18.0.1.tgz", + "integrity": "sha512-22fKzkWo9Ts8aY/WHL1A6seS2tpltgRRXVfnZnnqvQRyRiuPnx1FC0ly7+QPZkThh8vdLwxU+BvtLq9Uiqh9OQ==", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.4.0", + "@angular-eslint/bundled-angular-compiler": "18.0.1", "eslint-scope": "^8.0.0" }, "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/utils": { - "version": "17.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-17.4.0.tgz", - "integrity": "sha512-lHgRXyT878fauDITygraICDM6RHLb51QAJ3gWNZLr7SXcywsZg5d3rxRPCjrCnjgdxNPU0fJ+VJZ5AMt5Ibn7w==", - "dev": true, + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-18.0.1.tgz", + "integrity": "sha512-Q9lCySqg+9h2cz08+SoWj48cY1i04tL1k3bsQJmF2TsylAw2mSsNGX2X3h9WkdxY7sUoY0mP7MVW1iU54Gobcg==", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "17.4.0", - "@typescript-eslint/utils": "7.8.0" + "@angular-eslint/bundled-angular-compiler": "18.0.1" }, "peerDependencies": { - "eslint": "^7.20.0 || ^8.0.0", + "@typescript-eslint/utils": "^7.11.0 || ^8.0.0-alpha.20", + "eslint": "^8.57.0 || ^9.0.0", "typescript": "*" } }, @@ -769,18 +741,6 @@ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", "dev": true }, - "node_modules/@angular/build/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "dev": true, - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@angular/cdk": { "version": "18.0.1", "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-18.0.1.tgz", @@ -829,17 +789,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular/cli/node_modules/semver": { - "version": "7.6.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", - "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/@angular/common": { "version": "18.0.3", "resolved": "https://registry.npmjs.org/@angular/common/-/common-18.0.3.tgz", @@ -3570,20 +3519,6 @@ "node": ">=10.0.0" } }, - "node_modules/@es-joy/jsdoccomment": { - "version": "0.31.0", - "resolved": "https://registry.npmjs.org/@es-joy/jsdoccomment/-/jsdoccomment-0.31.0.tgz", - "integrity": "sha512-tc1/iuQcnaiSIUVad72PBierDFpsxdUHtEF/OrfqvM1CBAsIoMP51j52jTMb3dXriwhieTo289InzZj72jL3EQ==", - "dev": true, - "dependencies": { - "comment-parser": "1.3.1", - "esquery": "^1.4.0", - "jsdoc-type-pratt-parser": "~3.1.0" - }, - "engines": { - "node": "^14 || ^16 || ^17 || ^18" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.21.3", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.3.tgz", @@ -3956,7 +3891,6 @@ "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, "dependencies": { "eslint-visitor-keys": "^3.3.0" }, @@ -3971,7 +3905,6 @@ "version": "4.10.0", "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true, "engines": { "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } @@ -3980,7 +3913,6 @@ "version": "2.1.4", "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", - "dev": true, "dependencies": { "ajv": "^6.12.4", "debug": "^4.3.2", @@ -4003,7 +3935,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -4018,14 +3949,12 @@ "node_modules/@eslint/eslintrc/node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4035,7 +3964,6 @@ "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -4050,7 +3978,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -4061,14 +3988,12 @@ "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -4080,7 +4005,6 @@ "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, "engines": { "node": ">=10" }, @@ -4092,7 +4016,6 @@ "version": "8.57.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", - "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } @@ -4101,7 +4024,6 @@ "version": "0.11.14", "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", - "dev": true, "dependencies": { "@humanwhocodes/object-schema": "^2.0.2", "debug": "^4.3.1", @@ -4115,7 +4037,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4125,7 +4046,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -4137,7 +4057,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, "engines": { "node": ">=12.22" }, @@ -4149,8 +4068,7 @@ "node_modules/@humanwhocodes/object-schema": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "dev": true + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==" }, "node_modules/@inquirer/figures": { "version": "1.0.3", @@ -4330,7 +4248,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, "dependencies": { "@sinclair/typebox": "^0.27.8" }, @@ -5486,7 +5403,6 @@ "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "2.0.5", "run-parallel": "^1.1.9" @@ -5499,7 +5415,6 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, "engines": { "node": ">= 8" } @@ -5508,7 +5423,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, "dependencies": { "@nodelib/fs.scandir": "2.1.5", "fastq": "^1.6.0" @@ -5790,21 +5704,19 @@ } }, "node_modules/@nrwl/devkit": { - "version": "18.3.4", - "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-18.3.4.tgz", - "integrity": "sha512-Fty9Huqm12OYueU3uLJl3uvBUl5BvEyPfvw8+rLiNx9iftdEattM8C+268eAbIRRSLSOVXlWsJH4brlc6QZYYw==", - "dev": true, + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@nrwl/devkit/-/devkit-19.3.0.tgz", + "integrity": "sha512-WRcph/7U37HkTLIRzQ2oburZVfEFkPHJUn7vmo46gCq+N2cAKy3qwONO0RbthhjFIsG94YPXqFWFlV6k4nXpxA==", "dependencies": { - "@nx/devkit": "18.3.4" + "@nx/devkit": "19.3.0" } }, "node_modules/@nrwl/tao": { - "version": "18.3.4", - "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-18.3.4.tgz", - "integrity": "sha512-+7KsDYmGj1cvNaXZcjSYOPN1h17hsGFBtVX7MqnpJLLkQTUhKg2rQxqyluzshJ+RoDUVtYPGyHg1AizlB66RIA==", - "dev": true, + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@nrwl/tao/-/tao-19.3.0.tgz", + "integrity": "sha512-MyGYeHbh9O4Tv9xmz3Du+/leY5sKUHaPy4ancfNyShHgYi21hemX0/YYjzzoYHi44D8GzSc1XG2rAuwba7Kilw==", "dependencies": { - "nx": "18.3.4", + "nx": "19.3.0", "tslib": "^2.3.0" }, "bin": { @@ -5812,22 +5724,36 @@ } }, "node_modules/@nx/devkit": { - "version": "18.3.4", - "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-18.3.4.tgz", - "integrity": "sha512-M3htxl5WvlNKK5KNOndCAApbyBCZNTFFs+rtdwvudNZk5+84zAAPaWzSoX9C4XLAW78/f98LzF68/ch05aN12A==", - "dev": true, + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@nx/devkit/-/devkit-19.3.0.tgz", + "integrity": "sha512-Natya5nzvHH0qTOIL1w/EZtwMgDx87Dgz0LgeY7te2fULaNFcj5fVrP+mUKEJZR+NccO7GPumT2RPhuEl9rPnQ==", "dependencies": { - "@nrwl/devkit": "18.3.4", + "@nrwl/devkit": "19.3.0", "ejs": "^3.1.7", "enquirer": "~2.3.6", "ignore": "^5.0.4", + "minimatch": "9.0.3", "semver": "^7.5.3", "tmp": "~0.2.1", "tslib": "^2.3.0", "yargs-parser": "21.1.1" }, "peerDependencies": { - "nx": ">= 16 <= 19" + "nx": ">= 17 <= 20" + } + }, + "node_modules/@nx/devkit/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/@nx/nx-darwin-arm64": { @@ -5860,14 +5786,43 @@ "node": ">= 10" } }, + "node_modules/@nx/nx-freebsd-x64": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@nx/nx-freebsd-x64/-/nx-freebsd-x64-19.3.0.tgz", + "integrity": "sha512-1ow7Xku1yyjHviCKsWiuHCAnTd3fD+5O5c+e4DXHVthT8wnadKSotvBIWf38DMbMthl7na82e72OzxcdSbrVqQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-linux-arm-gnueabihf": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm-gnueabihf/-/nx-linux-arm-gnueabihf-19.3.0.tgz", + "integrity": "sha512-mYQMIUvNr2gww8vbg766uk/C1RxoC1fwioeP87bmV5NRUKSzJ8WEJVxAsqc9RGhAOUaNXOgEuKYrMcVhKyIKJQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "18.3.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-18.3.4.tgz", - "integrity": "sha512-g/2IaB2bZTKaBNPEf9LxtIXb1XHdhh3VO9PnePIrwkkixPMLN0dTxT5Sttt75lvLP3EU1AUR5w3Aaz2Q1mYtWA==", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-19.3.0.tgz", + "integrity": "sha512-rHL3eQ0RHkeAXnhHHu/NIyouN/ykiXvgyNU3TuCd50+2MZcAbjB+Xq3mwL0MwiP+BQuptiE+snTuxFUJp4ZH6A==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5877,13 +5832,12 @@ } }, "node_modules/@nx/nx-linux-arm64-musl": { - "version": "18.3.4", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-18.3.4.tgz", - "integrity": "sha512-MgfKLoEF6I1cCS+0ooFLEjJSSVdCYyCT9Q96IHRJntAEL8u/0GR2OUoBoLC+q1lnbIkJr/uqTJxA2Jh+sJTIbA==", + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-musl/-/nx-linux-arm64-musl-19.3.0.tgz", + "integrity": "sha512-im0+OgOD6ShpTkI9ZRz7BjzxhQ/Lk3xjYmmCu+PFGmaybEnkNNDFwsgS0iEVKMdWZ/EQoQvJrqOYsX125iIBuQ==", "cpu": [ "arm64" ], - "dev": true, "optional": true, "os": [ "linux" @@ -5907,6 +5861,36 @@ "node": ">= 10" } }, + "node_modules/@nx/nx-linux-x64-musl": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-musl/-/nx-linux-x64-musl-19.3.0.tgz", + "integrity": "sha512-sahEV99glBlpGKG1TIQ5PkJ0QvpHp69wWsBFK2DKtCETxOtsWqwvIjemxTCXRirTqeHiP7BiR6VWsf2YqqqBdw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-win32-arm64-msvc": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-arm64-msvc/-/nx-win32-arm64-msvc-19.3.0.tgz", + "integrity": "sha512-w03gFwLijStmhUji70QJHYo/U16ovybNczxGO7+5TT330X8/y+ihw9FCGHiIcujAjTAE88h0DKGn05WlNqRmfg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/@nx/nx-win32-x64-msvc": { "version": "18.3.4", "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-18.3.4.tgz", @@ -5931,18 +5915,6 @@ "node": ">=14" } }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.18.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.18.0.tgz", @@ -6243,8 +6215,7 @@ "node_modules/@sinclair/typebox": { "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", - "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true + "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==" }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", @@ -6485,12 +6456,6 @@ "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", "dev": true }, - "node_modules/@types/json5": { - "version": "0.0.29", - "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", - "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", - "dev": true - }, "node_modules/@types/lodash": { "version": "4.17.1", "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.1.tgz", @@ -6549,7 +6514,9 @@ "version": "0.0.32", "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", "integrity": "sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/@types/qs": { "version": "6.9.15", @@ -6573,13 +6540,9 @@ "version": "3.0.26", "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz", "integrity": "sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==", - "dev": true - }, - "node_modules/@types/semver": { - "version": "7.5.8", - "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", - "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/@types/send": { "version": "0.17.4", @@ -6630,21 +6593,19 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.8.0.tgz", - "integrity": "sha512-gFTT+ezJmkwutUPmB0skOj3GZJtlEGnlssems4AjkVweUPGj7jRwwqg0Hhg7++kPGJqKtTYx+R05Ftww372aIg==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz", + "integrity": "sha512-P+qEahbgeHW4JQ/87FuItjBj8O3MYv5gELDzr8QaQ7fsll1gSMTYb6j87MYyxwf3DtD7uGFB9ShwgmCJB5KmaQ==", "dev": true, "dependencies": { "@eslint-community/regexpp": "^4.10.0", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/type-utils": "7.8.0", - "@typescript-eslint/utils": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", - "debug": "^4.3.4", + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/type-utils": "7.11.0", + "@typescript-eslint/utils": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", "graphemer": "^1.4.0", "ignore": "^5.3.1", "natural-compare": "^1.4.0", - "semver": "^7.6.0", "ts-api-utils": "^1.3.0" }, "engines": { @@ -6664,16 +6625,38 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/utils": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz", + "integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/typescript-estree": "7.11.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, "node_modules/@typescript-eslint/parser": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.8.0.tgz", - "integrity": "sha512-KgKQly1pv0l4ltcftP59uQZCi4HUYswCLbTqVZEJu7uLX8CTLyswqMLqLN+2QFz4jCptqWVV4SB7vdxcH2+0kQ==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.11.0.tgz", + "integrity": "sha512-yimw99teuaXVWsBcPO1Ais02kwJ1jmNA1KxE7ng0aT7ndr1pT1wqj0OJnsYVGKKlc4QJai86l/025L6z8CljOg==", "dev": true, "dependencies": { - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/typescript-estree": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", "debug": "^4.3.4" }, "engines": { @@ -6693,13 +6676,13 @@ } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.8.0.tgz", - "integrity": "sha512-viEmZ1LmwsGcnr85gIq+FCYI7nO90DVbE37/ll51hjv9aG+YZMb4WDE2fyWpUR4O/UrhGRpYXK/XajcGTk2B8g==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.11.0.tgz", + "integrity": "sha512-27tGdVEiutD4POirLZX4YzT180vevUURJl4wJGmm6TrQoiYwuxTIY98PBp6L2oN+JQxzE0URvYlzJaBHIekXAw==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0" + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6710,13 +6693,13 @@ } }, "node_modules/@typescript-eslint/type-utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.8.0.tgz", - "integrity": "sha512-H70R3AefQDQpz9mGv13Uhi121FNMh+WEaRqcXTX09YEDky21km4dV1ZXJIp8QjXc4ZaVkXVdohvWDzbnbHDS+A==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.11.0.tgz", + "integrity": "sha512-WmppUEgYy+y1NTseNMJ6mCFxt03/7jTOy08bcg7bxJJdsM4nuhnchyBbE8vryveaJUf62noH7LodPSo5Z0WUCg==", "dev": true, "dependencies": { - "@typescript-eslint/typescript-estree": "7.8.0", - "@typescript-eslint/utils": "7.8.0", + "@typescript-eslint/typescript-estree": "7.11.0", + "@typescript-eslint/utils": "7.11.0", "debug": "^4.3.4", "ts-api-utils": "^1.3.0" }, @@ -6736,10 +6719,32 @@ } } }, + "node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/utils": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.11.0.tgz", + "integrity": "sha512-xlAWwPleNRHwF37AhrZurOxA1wyXowW4PqVXZVUNCLjB48CqdPJoJWkrpH2nij9Q3Lb7rtWindtoXwxjxlKKCA==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "7.11.0", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/typescript-estree": "7.11.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, "node_modules/@typescript-eslint/types": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.8.0.tgz", - "integrity": "sha512-wf0peJ+ZGlcH+2ZS23aJbOv+ztjeeP8uQ9GgwMJGVLx/Nj9CJt17GWgWWoSmoRVKAX2X+7fzEnAjxdvK2gqCLw==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.11.0.tgz", + "integrity": "sha512-MPEsDRZTyCiXkD4vd3zywDCifi7tatc4K37KqTprCvaXptP7Xlpdw0NR2hRJTetG5TxbWDB79Ys4kLmHliEo/w==", "dev": true, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6750,13 +6755,13 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.8.0.tgz", - "integrity": "sha512-5pfUCOwK5yjPaJQNy44prjCwtr981dO8Qo9J9PwYXZ0MosgAbfEMB008dJ5sNo3+/BN6ytBPuSvXUg9SAqB0dg==", + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.11.0.tgz", + "integrity": "sha512-cxkhZ2C/iyi3/6U9EPc5y+a6csqHItndvN/CzbNXTNrsC3/ASoYQZEt9uMaEp+xFNjasqQyszp5TumAVKKvJeQ==", "dev": true, "dependencies": { - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/visitor-keys": "7.8.0", + "@typescript-eslint/types": "7.11.0", + "@typescript-eslint/visitor-keys": "7.11.0", "debug": "^4.3.4", "globby": "^11.1.0", "is-glob": "^4.0.3", @@ -6778,18 +6783,14 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.8.0.tgz", - "integrity": "sha512-L0yFqOCflVqXxiZyXrDr80lnahQfSOfc9ELAAZ75sqicqp2i36kEZZGuUymHNFoYOqxRT05up760b4iGsl02nQ==", - "dev": true, + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.0.tgz", + "integrity": "sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==", "dependencies": { "@eslint-community/eslint-utils": "^4.4.0", - "@types/json-schema": "^7.0.15", - "@types/semver": "^7.5.8", - "@typescript-eslint/scope-manager": "7.8.0", - "@typescript-eslint/types": "7.8.0", - "@typescript-eslint/typescript-estree": "7.8.0", - "semver": "^7.6.0" + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/typescript-estree": "7.13.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6802,14 +6803,13 @@ "eslint": "^8.56.0" } }, - "node_modules/@typescript-eslint/visitor-keys": { - "version": "7.8.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.8.0.tgz", - "integrity": "sha512-q4/gibTNBQNA0lGyYQCmWRS5D15n8rXh4QjK3KV+MBPlTYHpfBUT3D3PaPR/HeNiI9W6R7FvlkcGhNyAoP+caA==", - "dev": true, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", + "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", "dependencies": { - "@typescript-eslint/types": "7.8.0", - "eslint-visitor-keys": "^3.4.3" + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0" }, "engines": { "node": "^18.18.0 || >=20.0.0" @@ -6819,73 +6819,82 @@ "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@uirouter/angular": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/@uirouter/angular/-/angular-13.0.0.tgz", - "integrity": "sha512-T2aizSXzW+7eiXUmc0LiLH+I8ZBJvDr7OQmm/5WCcxVL2NfuIse7B1kpvfdh9PmBAqw8AY7S0NhrJgABfFJUnw==", - "dependencies": { - "tslib": "^2.3.0" - }, + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", + "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", "engines": { - "node": ">=6.0.0" + "node": "^18.18.0 || >=20.0.0" }, - "peerDependencies": { - "@angular/common": "^17.0.0", - "@angular/core": "^17.0.0", - "@uirouter/core": "^6.0.8", - "@uirouter/rx": "^1.0.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@uirouter/angular-hybrid": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/@uirouter/angular-hybrid/-/angular-hybrid-17.1.0.tgz", - "integrity": "sha512-zUQ/b2BaEuODPOtDtxp2SpEifm/VHoLauPTXtZAfcHpDoty6DFbLyGCrA4ZI9lqyoACVxpOuUKjhTHLNE9SXTw==", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", + "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", "dependencies": { - "tslib": "^2.3.0" + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" }, - "peerDependencies": { - "@angular/core": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", - "@angular/upgrade": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", - "@uirouter/angular": "^13.0.0", - "@uirouter/angularjs": "^1.0.30", - "@uirouter/core": "^6.1.0", - "angular": "^1.5.0" - } - }, - "node_modules/@uirouter/angularjs": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.1.0.tgz", - "integrity": "sha512-AhgxXhMfN6FU2HxDQqwDPbzmd6kTgvYCgV/kgoCAXfxAH6cFQrifViToC90Wdg6djBynHwA3L/KYP+iOYHkw6A==", "engines": { - "node": ">=4.0.0" + "node": "^18.18.0 || >=20.0.0" }, - "peerDependencies": { - "@uirouter/core": "^6.0.8", - "angular": ">=1.2.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/@uirouter/core": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@uirouter/core/-/core-6.1.0.tgz", - "integrity": "sha512-WFYh5NPAqRX4L2qlI4k62tgR6pxoqOBSW1CM1uBWCau4mAmgasYd5etJ9RoSJrSnCpCQ2km2Jltf0n5ql684MQ==", + "node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", + "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", + "dependencies": { + "@typescript-eslint/types": "7.13.0", + "eslint-visitor-keys": "^3.4.3" + }, "engines": { - "node": ">=4.0.0" + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, - "node_modules/@uirouter/rx": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/@uirouter/rx/-/rx-1.0.0.tgz", - "integrity": "sha512-dqPmLFC+qqF6RIdJVKktXSON6WILy2oyLhADDk74F3GAUZ/VvOu3QSPLDtZEP3LMSo6vkGQvwcUdjgNVWL3YJA==", - "peerDependencies": { - "@uirouter/core": ">=6.0.1", - "rxjs": "^6.5.3 || ^7.4.0" + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.11.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.11.0.tgz", + "integrity": "sha512-7syYk4MzjxTEk0g/w3iqtgxnFQspDJfn6QKD36xMuuhTzjcxY7F8EmBLnALjVyaOF1/bVocu3bS/2/F7rXrveQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.11.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" } }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", - "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", - "dev": true + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==" }, "node_modules/@vitejs/plugin-basic-ssl": { "version": "1.1.0", @@ -7066,7 +7075,6 @@ "version": "3.0.0-rc.46", "resolved": "https://registry.npmjs.org/@yarnpkg/parsers/-/parsers-3.0.0-rc.46.tgz", "integrity": "sha512-aiATs7pSutzda/rq8fnuPwTglyVwjM22bNnK2ZgjrpAjQHSSl3lztd2f9evst1W/qnC58DRz7T7QndUDumAR4Q==", - "dev": true, "dependencies": { "js-yaml": "^3.10.0", "tslib": "^2.4.0" @@ -7076,10 +7084,9 @@ } }, "node_modules/@zkochan/js-yaml": { - "version": "0.0.6", - "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.6.tgz", - "integrity": "sha512-nzvgl3VfhcELQ8LyVrYOru+UtAy1nrygk2+AGbTm8a5YcO6o8lSjAT+pfg3vJWxIoZKOUhrK6UU7xW/+00kQrg==", - "dev": true, + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@zkochan/js-yaml/-/js-yaml-0.0.7.tgz", + "integrity": "sha512-nrUSn7hzt7J6JWgWGz78ZYI8wj+gdIJdk0Ynjpp8l+trkn58Uqsf6RYrYkEK+3X18EX+TNdtJI0WxAtc+L84SQ==", "dependencies": { "argparse": "^2.0.1" }, @@ -7090,8 +7097,7 @@ "node_modules/@zkochan/js-yaml/node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/abbrev": { "version": "1.1.1", @@ -7115,7 +7121,6 @@ "version": "8.11.3", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, "bin": { "acorn": "bin/acorn" }, @@ -7159,7 +7164,6 @@ "version": "5.3.2", "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", - "dev": true, "peerDependencies": { "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } @@ -7205,6 +7209,8 @@ "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.12.tgz", "integrity": "sha512-6TVU49mK6KZb4qG6xWaaM4C7sA/sgUMLy/JYMOzkcp3BvVLpW0fXDFQiIzAuxFCt/2+xD7fNIiPFAoLZPhVNLQ==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=6.0" } @@ -7333,6 +7339,23 @@ "integrity": "sha512-WyUrigFcnxLZnzaupIAqOLrGXMCOcGz0L5O7OoaWKYGvEx2yNvGSNAGJCmOggGmaPEfIt6YMGTcbc4uwS6Srdw==", "deprecated": "For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward." }, + "node_modules/angular-eslint": { + "version": "18.0.1", + "resolved": "https://registry.npmjs.org/angular-eslint/-/angular-eslint-18.0.1.tgz", + "integrity": "sha512-wZMLDDHLSWKce8uB4BXln2Rnfk8jxgj9WXcRNcPwS0IJhA2YgcGp4u4GIqqPc6y+U+5LmQc9pzBpETWUBDyfEw==", + "dependencies": { + "@angular-eslint/builder": "18.0.1", + "@angular-eslint/eslint-plugin": "18.0.1", + "@angular-eslint/eslint-plugin-template": "18.0.1", + "@angular-eslint/schematics": "18.0.1", + "@angular-eslint/template-parser": "18.0.1" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": "*", + "typescript-eslint": "^8.0.0-alpha.20" + } + }, "node_modules/angular-file-upload": { "version": "1.1.6", "resolved": "https://registry.npmjs.org/angular-file-upload/-/angular-file-upload-1.1.6.tgz", @@ -8003,7 +8026,6 @@ "version": "1.0.10", "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, "dependencies": { "sprintf-js": "~1.0.2" } @@ -8012,7 +8034,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "dev": true, "dependencies": { "dequal": "^2.0.3" } @@ -8090,26 +8111,6 @@ "integrity": "sha512-c5AMf34bKdvPhQ7tBGhqkgKNUzMr4WUs+WDtC2ZUGOUncbxKMTvqxYctiseW3+L4bA8ec+GcZ6/A/FW4m8ukng==", "dev": true }, - "node_modules/array-includes": { - "version": "3.1.8", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.8.tgz", - "integrity": "sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.4", - "is-string": "^1.0.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/array-slice": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", @@ -8123,7 +8124,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true, "engines": { "node": ">=8" } @@ -8133,6 +8133,8 @@ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -8146,24 +8148,6 @@ "node": ">=0.10.0" } }, - "node_modules/array.prototype.flat": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", - "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "es-shim-unscopables": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/arraybuffer.prototype.slice": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", @@ -8207,6 +8191,8 @@ "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "safer-buffer": "~2.1.0" } @@ -8216,6 +8202,8 @@ "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.8" } @@ -8250,8 +8238,7 @@ "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" }, "node_modules/atob": { "version": "2.1.2", @@ -8413,6 +8400,8 @@ "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": "*" } @@ -8421,13 +8410,14 @@ "version": "1.12.0", "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/axios": { "version": "1.6.8", "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.8.tgz", "integrity": "sha512-v/ZHtJDU39mDpyBoFVkETcd/uNdxrWRrg3bKpOKzXFA6Bvqopts6ALSMU3y6ijYxbw2B+wPrIv46egTzJXCLGQ==", - "dev": true, "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -8438,7 +8428,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz", "integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==", - "dev": true, "dependencies": { "dequal": "^2.0.3" } @@ -8683,6 +8672,8 @@ "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "tweetnacl": "^0.14.3" } @@ -8733,6 +8724,8 @@ "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "minimist": "^1.2.0" }, @@ -8884,7 +8877,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", - "devOptional": true, "dependencies": { "fill-range": "^7.0.1" }, @@ -8929,6 +8921,8 @@ "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "https-proxy-agent": "^2.2.1" } @@ -8938,6 +8932,8 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "es6-promisify": "^5.0.0" }, @@ -8950,6 +8946,8 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -8959,6 +8957,8 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -9130,7 +9130,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, "engines": { "node": ">=6" } @@ -9239,7 +9238,9 @@ "version": "0.12.0", "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/center-align": { "version": "0.1.3", @@ -9693,7 +9694,6 @@ "version": "1.0.8", "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, "dependencies": { "delayed-stream": "~1.0.0" }, @@ -9710,15 +9710,6 @@ "node": ">= 0.6.x" } }, - "node_modules/comment-parser": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.3.1.tgz", - "integrity": "sha512-B52sN2VNghyq5ofvUsqZjmk6YkihBX5vMSChmSK9v4ShjKf3Vk5Xcmgpw4o+iIgtrnM/u5FiMpz9VKb8lpBveA==", - "dev": true, - "engines": { - "node": ">= 12.0.0" - } - }, "node_modules/common-path-prefix": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", @@ -9801,8 +9792,7 @@ "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "devOptional": true + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" }, "node_modules/concurrently": { "version": "3.6.1", @@ -10413,6 +10403,8 @@ "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "assert-plus": "^1.0.0" }, @@ -10574,8 +10566,7 @@ "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", - "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", - "dev": true + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==" }, "node_modules/default-browser": { "version": "5.2.1", @@ -10648,7 +10639,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", - "dev": true, "engines": { "node": ">=8" } @@ -10687,6 +10677,8 @@ "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", "integrity": "sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "globby": "^5.0.0", "is-path-cwd": "^1.0.0", @@ -10705,6 +10697,8 @@ "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "array-uniq": "^1.0.1" }, @@ -10717,6 +10711,8 @@ "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -10726,6 +10722,8 @@ "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", "integrity": "sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "array-union": "^1.0.1", "arrify": "^1.0.0", @@ -10743,6 +10741,8 @@ "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -10752,6 +10752,8 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -10763,7 +10765,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, "engines": { "node": ">=0.4.0" } @@ -10787,7 +10788,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "dev": true, "engines": { "node": ">=6" } @@ -10851,7 +10851,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", - "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -10860,7 +10859,6 @@ "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", - "dev": true, "dependencies": { "path-type": "^4.0.0" }, @@ -10890,7 +10888,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", - "dev": true, "dependencies": { "esutils": "^2.0.2" }, @@ -10988,7 +10985,6 @@ "version": "16.3.2", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.3.2.tgz", "integrity": "sha512-HTlk5nmhkm8F6JcdXvHIzaorzCoziNQT9mGxLPVXW8wJF1TiGSL60ZGB4gHWabHOaMmWmhvk2/lPHfnBiT78AQ==", - "dev": true, "engines": { "node": ">=12" }, @@ -11000,7 +10996,6 @@ "version": "10.0.0", "resolved": "https://registry.npmjs.org/dotenv-expand/-/dotenv-expand-10.0.0.tgz", "integrity": "sha512-GopVGCpVS1UKH75VKHGuQFqS1Gusej0z4FyQkPdwjil2gNIv+LNsqBlboOzpJFZKVT95GkCyWJbBSdFEFUWI2A==", - "dev": true, "engines": { "node": ">=12" } @@ -11008,8 +11003,7 @@ "node_modules/duplexer": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", - "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==", - "dev": true + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" }, "node_modules/eastasianwidth": { "version": "0.2.0", @@ -11021,6 +11015,8 @@ "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "jsbn": "~0.1.0", "safer-buffer": "^2.1.0" @@ -11030,7 +11026,9 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/ee-first": { "version": "1.1.1", @@ -11042,7 +11040,6 @@ "version": "3.1.10", "resolved": "https://registry.npmjs.org/ejs/-/ejs-3.1.10.tgz", "integrity": "sha512-UeJmFfOrAQS8OJWPZ4qtgHyWExa088/MtK5UEyoJGFH67cDEXkZSviOiKRCZ4Xij0zxI3JECgYs3oKx+AizQBA==", - "dev": true, "dependencies": { "jake": "^10.8.5" }, @@ -11095,7 +11092,6 @@ "version": "1.4.4", "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, "dependencies": { "once": "^1.4.0" } @@ -11147,7 +11143,6 @@ "version": "2.3.6", "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", - "dev": true, "dependencies": { "ansi-colors": "^4.1.1" }, @@ -11328,15 +11323,6 @@ "node": ">= 0.4" } }, - "node_modules/es-shim-unscopables": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", - "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", - "dev": true, - "dependencies": { - "hasown": "^2.0.0" - } - }, "node_modules/es-to-primitive": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", @@ -11366,13 +11352,17 @@ "version": "4.2.8", "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/es6-promisify": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "es6-promise": "^4.0.3" } @@ -11445,7 +11435,6 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, "engines": { "node": ">=0.8.0" } @@ -11454,7 +11443,6 @@ "version": "8.57.0", "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", - "dev": true, "dependencies": { "@eslint-community/eslint-utils": "^4.2.0", "@eslint-community/regexpp": "^4.6.1", @@ -11505,217 +11493,10 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint-config-prettier": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz", - "integrity": "sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-import-resolver-node": { - "version": "0.3.9", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", - "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", - "dev": true, - "dependencies": { - "debug": "^3.2.7", - "is-core-module": "^2.13.0", - "resolve": "^1.22.4" - } - }, - "node_modules/eslint-import-resolver-node/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-module-utils": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.1.tgz", - "integrity": "sha512-rXDXR3h7cs7dy9RNpUlQf80nX31XWJEyGq1tRMo+6GsO5VmTe4UTwtmonAD4ZkAsrfMVDA2wlGJ3790Ys+D49Q==", - "dev": true, - "dependencies": { - "debug": "^3.2.7" - }, - "engines": { - "node": ">=4" - }, - "peerDependenciesMeta": { - "eslint": { - "optional": true - } - } - }, - "node_modules/eslint-module-utils/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/eslint-plugin-import": { - "version": "2.26.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.26.0.tgz", - "integrity": "sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==", - "dev": true, - "dependencies": { - "array-includes": "^3.1.4", - "array.prototype.flat": "^1.2.5", - "debug": "^2.6.9", - "doctrine": "^2.1.0", - "eslint-import-resolver-node": "^0.3.6", - "eslint-module-utils": "^2.7.3", - "has": "^1.0.3", - "is-core-module": "^2.8.1", - "is-glob": "^4.0.3", - "minimatch": "^3.1.2", - "object.values": "^1.1.5", - "resolve": "^1.22.0", - "tsconfig-paths": "^3.14.1" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" - } - }, - "node_modules/eslint-plugin-import/node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/eslint-plugin-import/node_modules/debug": { - "version": "2.6.9", - "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", - "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", - "dev": true, - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/eslint-plugin-import/node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/eslint-plugin-import/node_modules/ms": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", - "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", - "dev": true - }, - "node_modules/eslint-plugin-jsdoc": { - "version": "39.3.6", - "resolved": "https://registry.npmjs.org/eslint-plugin-jsdoc/-/eslint-plugin-jsdoc-39.3.6.tgz", - "integrity": "sha512-R6dZ4t83qPdMhIOGr7g2QII2pwCjYyKP+z0tPOfO1bbAbQyKC20Y2Rd6z1te86Lq3T7uM8bNo+VD9YFpE8HU/g==", - "dev": true, - "dependencies": { - "@es-joy/jsdoccomment": "~0.31.0", - "comment-parser": "1.3.1", - "debug": "^4.3.4", - "escape-string-regexp": "^4.0.0", - "esquery": "^1.4.0", - "semver": "^7.3.7", - "spdx-expression-parse": "^3.0.1" - }, - "engines": { - "node": "^14 || ^16 || ^17 || ^18" - }, - "peerDependencies": { - "eslint": "^7.0.0 || ^8.0.0" - } - }, - "node_modules/eslint-plugin-jsdoc/node_modules/escape-string-regexp": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", - "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/eslint-plugin-prefer-arrow": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prefer-arrow/-/eslint-plugin-prefer-arrow-1.2.3.tgz", - "integrity": "sha512-J9I5PKCOJretVuiZRGvPQxCbllxGAV/viI20JO3LYblAodofBxyMnZAJ+WGeClHgANnSJberTNoFWWjrWKBuXQ==", - "dev": true, - "peerDependencies": { - "eslint": ">=2.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.1.3", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", - "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.8.6" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, "node_modules/eslint-scope": { "version": "8.0.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.0.1.tgz", "integrity": "sha512-pL8XjgP4ZOmmwfFE8mEhSxA7ZY4C+LWyqjQ3o4yWkkmD0qcMT9kkW3zWHOczhWcjTSgqycYAgwSlXvZltv65og==", - "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -11731,7 +11512,6 @@ "version": "3.4.3", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, @@ -11743,7 +11523,6 @@ "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", - "dev": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -11759,7 +11538,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -11773,14 +11551,12 @@ "node_modules/eslint/node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -11790,7 +11566,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -11806,7 +11581,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -11817,14 +11591,12 @@ "node_modules/eslint/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/eslint/node_modules/escape-string-regexp": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "engines": { "node": ">=10" }, @@ -11836,7 +11608,6 @@ "version": "7.2.2", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", - "dev": true, "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" @@ -11852,7 +11623,6 @@ "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", - "dev": true, "dependencies": { "is-glob": "^4.0.3" }, @@ -11864,7 +11634,6 @@ "version": "13.24.0", "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", - "dev": true, "dependencies": { "type-fest": "^0.20.2" }, @@ -11879,7 +11648,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -11888,7 +11656,6 @@ "version": "4.1.0", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, "dependencies": { "argparse": "^2.0.1" }, @@ -11899,14 +11666,12 @@ "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, "node_modules/eslint/node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -11918,7 +11683,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -11930,7 +11694,6 @@ "version": "0.20.2", "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", - "dev": true, "engines": { "node": ">=10" }, @@ -11942,7 +11705,6 @@ "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", - "dev": true, "dependencies": { "acorn": "^8.9.0", "acorn-jsx": "^5.3.2", @@ -11959,7 +11721,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" @@ -11972,7 +11733,6 @@ "version": "1.5.0", "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", - "dev": true, "dependencies": { "estraverse": "^5.1.0" }, @@ -11984,7 +11744,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", - "dev": true, "dependencies": { "estraverse": "^5.2.0" }, @@ -11996,7 +11755,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", - "dev": true, "engines": { "node": ">=4.0" } @@ -12005,7 +11763,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -12349,24 +12106,19 @@ "dev": true, "engines": [ "node >=0.6.0" - ] + ], + "optional": true, + "peer": true }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, "node_modules/fast-glob": { "version": "3.3.2", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", - "dev": true, "dependencies": { "@nodelib/fs.stat": "^2.0.2", "@nodelib/fs.walk": "^1.2.3", @@ -12381,20 +12133,17 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, "node_modules/fast-levenshtein": { "version": "2.0.6", "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==" }, "node_modules/fastq": { "version": "1.17.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", - "dev": true, "dependencies": { "reusify": "^1.0.4" } @@ -12415,7 +12164,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, "dependencies": { "escape-string-regexp": "^1.0.5" }, @@ -12430,7 +12178,6 @@ "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", - "dev": true, "dependencies": { "flat-cache": "^3.0.4" }, @@ -12460,7 +12207,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/filelist/-/filelist-1.0.4.tgz", "integrity": "sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==", - "dev": true, "dependencies": { "minimatch": "^5.0.1" } @@ -12469,7 +12215,6 @@ "version": "5.1.6", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -12481,7 +12226,6 @@ "version": "7.0.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", - "devOptional": true, "dependencies": { "to-regex-range": "^5.0.1" }, @@ -12542,7 +12286,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", - "dev": true, "dependencies": { "locate-path": "^6.0.0", "path-exists": "^4.0.0" @@ -12598,7 +12341,6 @@ "version": "5.0.2", "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", - "dev": true, "bin": { "flat": "cli.js" } @@ -12607,7 +12349,6 @@ "version": "3.2.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", - "dev": true, "dependencies": { "flatted": "^3.2.9", "keyv": "^4.5.3", @@ -12620,14 +12361,12 @@ "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" }, "node_modules/follow-redirects": { "version": "1.15.6", "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", - "dev": true, "funding": [ { "type": "individual", @@ -12712,6 +12451,8 @@ "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": "*" } @@ -12720,7 +12461,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", - "dev": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.8", @@ -12773,11 +12513,18 @@ "node": ">= 0.6" } }, + "node_modules/front-matter": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/front-matter/-/front-matter-4.0.2.tgz", + "integrity": "sha512-I8ZuJ/qG92NWX8i5x1Y8qyj3vizhXS31OxjKDu3LKP+7/qBgfIKValiZIEwoVoJKUHlhWtYrktkxV1XsX+pPlg==", + "dependencies": { + "js-yaml": "^3.13.1" + } + }, "node_modules/fs-constants": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", - "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", - "dev": true + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, "node_modules/fs-extra": { "version": "10.1.0", @@ -12807,8 +12554,7 @@ "node_modules/fs.realpath": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "devOptional": true + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" }, "node_modules/fsevents": { "version": "2.3.3", @@ -12997,6 +12743,8 @@ "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "assert-plus": "^1.0.0" } @@ -13024,7 +12772,6 @@ "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "devOptional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -13044,7 +12791,6 @@ "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "devOptional": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -13062,7 +12808,6 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "devOptional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -13072,7 +12817,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "devOptional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -13175,7 +12919,6 @@ "version": "11.1.0", "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", - "dev": true, "dependencies": { "array-union": "^2.1.0", "dir-glob": "^3.0.1", @@ -13246,8 +12989,7 @@ "node_modules/graphemer": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", - "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", - "dev": true + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==" }, "node_modules/grunt": { "version": "1.6.1", @@ -14523,6 +14265,8 @@ "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=4" } @@ -14533,6 +14277,8 @@ "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", "deprecated": "this library is no longer supported", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ajv": "^6.12.3", "har-schema": "^2.0.0" @@ -14546,6 +14292,8 @@ "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", @@ -14561,7 +14309,9 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/hard-rejection": { "version": "2.1.0", @@ -14572,15 +14322,6 @@ "node": ">=6" } }, - "node_modules/has": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.4.tgz", - "integrity": "sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==", - "dev": true, - "engines": { - "node": ">= 0.4.0" - } - }, "node_modules/has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -15007,6 +14748,8 @@ "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "assert-plus": "^1.0.0", "jsprim": "^1.2.2", @@ -15119,7 +14862,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, "engines": { "node": ">= 4" } @@ -15152,7 +14894,9 @@ "version": "3.0.6", "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/immutable": { "version": "4.3.5", @@ -15164,7 +14908,6 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" @@ -15180,7 +14923,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, "engines": { "node": ">=4" } @@ -15205,7 +14947,6 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "devOptional": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -15495,7 +15236,6 @@ "version": "2.2.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", - "dev": true, "bin": { "is-docker": "cli.js" }, @@ -15543,7 +15283,6 @@ "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -15560,7 +15299,6 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "devOptional": true, "dependencies": { "is-extglob": "^2.1.1" }, @@ -15642,7 +15380,6 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "devOptional": true, "engines": { "node": ">=0.12.0" } @@ -15676,6 +15413,8 @@ "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -15685,6 +15424,8 @@ "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "is-path-inside": "^1.0.0" }, @@ -15697,6 +15438,8 @@ "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "path-is-inside": "^1.0.1" }, @@ -15708,7 +15451,6 @@ "version": "3.0.3", "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -15860,7 +15602,9 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/is-unc-path": { "version": "1.0.0", @@ -15916,7 +15660,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", - "dev": true, "dependencies": { "is-docker": "^2.0.0" }, @@ -15960,7 +15703,9 @@ "version": "0.1.2", "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", @@ -16143,7 +15888,6 @@ "version": "10.9.1", "resolved": "https://registry.npmjs.org/jake/-/jake-10.9.1.tgz", "integrity": "sha512-61btcOHNnLnsOdtLgA5efqQWjnSi/vow5HbI7HMdKKWqvrKR1bLK3BPlJn9gcSaP2ewuamUSMB5XEy76KUIS2w==", - "dev": true, "dependencies": { "async": "^3.2.3", "chalk": "^4.0.2", @@ -16161,7 +15905,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -16175,14 +15918,12 @@ "node_modules/jake/node_modules/async": { "version": "3.2.5", "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", - "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==", - "dev": true + "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, "node_modules/jake/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -16192,7 +15933,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -16208,7 +15948,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -16219,14 +15958,12 @@ "node_modules/jake/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jake/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -16235,7 +15972,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -16247,7 +15983,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -16260,6 +15995,8 @@ "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", "integrity": "sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "exit": "^0.1.2", "glob": "^7.0.6", @@ -16297,13 +16034,17 @@ "version": "2.8.0", "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", "integrity": "sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/jasminewd2": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", "integrity": "sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">= 6.9.x" } @@ -16312,7 +16053,6 @@ "version": "29.7.0", "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.7.0.tgz", "integrity": "sha512-LMIgiIrhigmPrs03JHpxUh2yISK3vLFPkAodPeo0+BuF7wA2FoQbkEg1u8gBYBThncu7e1oEDUfIXVuTqLRUjw==", - "dev": true, "dependencies": { "chalk": "^4.0.0", "diff-sequences": "^29.6.3", @@ -16327,7 +16067,6 @@ "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -16342,7 +16081,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -16358,7 +16096,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -16369,14 +16106,12 @@ "node_modules/jest-diff/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/jest-diff/node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } @@ -16385,7 +16120,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -16397,7 +16131,6 @@ "version": "29.6.3", "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", - "dev": true, "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -16477,7 +16210,6 @@ "version": "3.14.1", "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, "dependencies": { "argparse": "^1.0.7", "esprima": "^4.0.0" @@ -16491,15 +16223,6 @@ "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" }, - "node_modules/jsdoc-type-pratt-parser": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/jsdoc-type-pratt-parser/-/jsdoc-type-pratt-parser-3.1.0.tgz", - "integrity": "sha512-MgtD0ZiCDk9B+eI73BextfRrVQl0oyzRG8B2BjORts6jbunj4ScKPcyXGTbB6eXL4y9TzxCm6hyeLq/2ASzNdw==", - "dev": true, - "engines": { - "node": ">=12.0.0" - } - }, "node_modules/jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -16667,8 +16390,7 @@ "node_modules/json-buffer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" }, "node_modules/json-parse-better-errors": { "version": "1.0.2", @@ -16688,7 +16410,9 @@ "version": "0.4.0", "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/json-schema-traverse": { "version": "1.0.0", @@ -16698,20 +16422,20 @@ "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==" }, "node_modules/json-stringify-safe": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", - "dev": true, "bin": { "json5": "lib/cli.js" }, @@ -16728,7 +16452,6 @@ "version": "6.1.0", "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dev": true, "dependencies": { "universalify": "^2.0.0" }, @@ -16765,6 +16488,8 @@ "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "assert-plus": "1.0.0", "extsprintf": "1.3.0", @@ -16791,6 +16516,8 @@ "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "lie": "~3.3.0", "pako": "~1.0.2", @@ -16802,13 +16529,17 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/jszip/node_modules/readable-stream": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "core-util-is": "~1.0.0", "inherits": "~2.0.3", @@ -16824,6 +16555,8 @@ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "safe-buffer": "~5.1.0" } @@ -17089,7 +16822,6 @@ "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", - "dev": true, "dependencies": { "json-buffer": "3.0.1" } @@ -17236,7 +16968,6 @@ "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", - "dev": true, "dependencies": { "prelude-ls": "^1.2.1", "type-check": "~0.4.0" @@ -17267,6 +16998,8 @@ "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "immediate": "~3.0.5" } @@ -17318,7 +17051,6 @@ "version": "2.0.4", "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", - "dev": true, "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } @@ -17422,7 +17154,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", - "dev": true, "dependencies": { "p-locate": "^5.0.0" }, @@ -17453,8 +17184,7 @@ "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "dev": true + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==" }, "node_modules/log-symbols": { "version": "4.1.0", @@ -17787,7 +17517,6 @@ "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", - "dev": true, "engines": { "node": ">= 8" } @@ -17805,7 +17534,6 @@ "version": "4.0.5", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", - "dev": true, "dependencies": { "braces": "^3.0.2", "picomatch": "^2.3.1" @@ -17818,7 +17546,6 @@ "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", - "dev": true, "engines": { "node": ">=8.6" }, @@ -17842,7 +17569,6 @@ "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, "engines": { "node": ">= 0.6" } @@ -17851,7 +17577,6 @@ "version": "2.1.35", "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, "dependencies": { "mime-db": "1.52.0" }, @@ -17932,7 +17657,6 @@ "version": "1.2.8", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", - "dev": true, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -18444,8 +18168,7 @@ "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", - "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", - "dev": true + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==" }, "node_modules/needle": { "version": "3.3.1", @@ -18575,15 +18298,15 @@ } }, "node_modules/ngx-entity-service": { - "version": "0.0.38", - "resolved": "https://registry.npmjs.org/ngx-entity-service/-/ngx-entity-service-0.0.38.tgz", - "integrity": "sha512-QmzXwn2aAv+cMrp7qBFBAhf8eR9cjljPneJ2qXIYa5l/TUNH91RnlF60BKKj4c4uD66tesokUqXZEPVaes92Tg==", + "version": "0.0.39", + "resolved": "https://registry.npmjs.org/ngx-entity-service/-/ngx-entity-service-0.0.39.tgz", + "integrity": "sha512-81DdRQxN7R2lELTiZkB5FkjeK147C8AUmyl52sxZgtYw/WiFay7iWk9KTSsZAJ8OhKKkmllXfMkOpQzvoYTafw==", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/common": "^13.0 || ^14.0 || ^15.0 || ^16.0 || ^17", - "@angular/core": "^13.0 || ^14.0 || ^15.0 || ^16.0 || ^17" + "@angular/common": "^13.0 || ^14.0 || ^15.0 || ^16.0 || ^17 || ^18", + "@angular/core": "^13.0 || ^14.0 || ^15.0 || ^16.0 || ^17 || ^18" } }, "node_modules/ngx-lottie": { @@ -18813,8 +18536,7 @@ "node_modules/node-machine-id": { "version": "1.1.12", "resolved": "https://registry.npmjs.org/node-machine-id/-/node-machine-id-1.1.12.tgz", - "integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==", - "dev": true + "integrity": "sha512-QNABxbrPa3qEIfrE6GOJ7BYIuignnJw7iQ2YPbc3Nla1HzRJjXzZOiikfF8m7eAMfichLt3M4VgLOetqgDmgGQ==" }, "node_modules/node-releases": { "version": "2.0.14", @@ -19091,7 +18813,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, "dependencies": { "path-key": "^3.0.0" }, @@ -19139,16 +18860,15 @@ } }, "node_modules/nx": { - "version": "18.3.4", - "resolved": "https://registry.npmjs.org/nx/-/nx-18.3.4.tgz", - "integrity": "sha512-7rOHRyxpnZGJ3pHnwmpoAMHt9hNuwibWhOhPBJDhJVcbQJtGfwcWWyV/iSEnVXwKZ2lfHVE3TwE+gXFdT/GFiw==", - "dev": true, + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/nx/-/nx-19.3.0.tgz", + "integrity": "sha512-WILWiROUkZWwuPJ12tP24Z0NULPEhxFN9i55/fECuVXYaFtkg6FvEne9C4d4bRqhZPcbrz6WhHnzE3NhdjH7XQ==", "hasInstallScript": true, "dependencies": { - "@nrwl/tao": "18.3.4", + "@nrwl/tao": "19.3.0", "@yarnpkg/lockfile": "^1.1.0", "@yarnpkg/parsers": "3.0.0-rc.46", - "@zkochan/js-yaml": "0.0.6", + "@zkochan/js-yaml": "0.0.7", "axios": "^1.6.0", "chalk": "^4.1.0", "cli-cursor": "3.1.0", @@ -19159,10 +18879,10 @@ "enquirer": "~2.3.6", "figures": "3.2.0", "flat": "^5.0.2", + "front-matter": "^4.0.2", "fs-extra": "^11.1.0", "ignore": "^5.0.4", "jest-diff": "^29.4.1", - "js-yaml": "4.1.0", "jsonc-parser": "3.2.0", "lines-and-columns": "~2.0.3", "minimatch": "9.0.3", @@ -19185,16 +18905,16 @@ "nx-cloud": "bin/nx-cloud.js" }, "optionalDependencies": { - "@nx/nx-darwin-arm64": "18.3.4", - "@nx/nx-darwin-x64": "18.3.4", - "@nx/nx-freebsd-x64": "18.3.4", - "@nx/nx-linux-arm-gnueabihf": "18.3.4", - "@nx/nx-linux-arm64-gnu": "18.3.4", - "@nx/nx-linux-arm64-musl": "18.3.4", - "@nx/nx-linux-x64-gnu": "18.3.4", - "@nx/nx-linux-x64-musl": "18.3.4", - "@nx/nx-win32-arm64-msvc": "18.3.4", - "@nx/nx-win32-x64-msvc": "18.3.4" + "@nx/nx-darwin-arm64": "19.3.0", + "@nx/nx-darwin-x64": "19.3.0", + "@nx/nx-freebsd-x64": "19.3.0", + "@nx/nx-linux-arm-gnueabihf": "19.3.0", + "@nx/nx-linux-arm64-gnu": "19.3.0", + "@nx/nx-linux-arm64-musl": "19.3.0", + "@nx/nx-linux-x64-gnu": "19.3.0", + "@nx/nx-linux-x64-musl": "19.3.0", + "@nx/nx-win32-arm64-msvc": "19.3.0", + "@nx/nx-win32-x64-msvc": "19.3.0" }, "peerDependencies": { "@swc-node/register": "^1.8.0", @@ -19209,11 +18929,70 @@ } } }, + "node_modules/nx/node_modules/@nx/nx-darwin-arm64": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-19.3.0.tgz", + "integrity": "sha512-TMTxjrN7Y/UsKFjmz0YfhVItLTGWqvud8cmQchw5NEjdNakfjXk0mREufO5/5PwoiRIsen6MbThoTprLpjOUiQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/nx/node_modules/@nx/nx-darwin-x64": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-19.3.0.tgz", + "integrity": "sha512-GH2L6ftnzdIs7JEdv7ZPCdbpAdB5sW6NijK07riYZSONzq5fEruD1yDWDkyZbYBb8RTxsparUWJnq8q1qxEPHQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/nx/node_modules/@nx/nx-linux-x64-gnu": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-19.3.0.tgz", + "integrity": "sha512-k8q/d6WBSXOeUpBq6Mw69yMKL4n9LaX3o4LBNwBkVCEZ8p6s0njwKefLtjwnKlai0g/k5f0NcilU2zTwP/Ex8g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/nx/node_modules/@nx/nx-win32-x64-msvc": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-19.3.0.tgz", + "integrity": "sha512-M7e2zXGfTjH8NLiwqKLdWC9VlfMSQDYlI4/SM4OSpPqhUTfPlRPa+wNKNTG7perKfDXxE9ei8yjocujknXJk/A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, "node_modules/nx/node_modules/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -19224,17 +19003,10 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/nx/node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true - }, "node_modules/nx/node_modules/chalk": { "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" @@ -19250,7 +19022,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, "dependencies": { "color-name": "~1.1.4" }, @@ -19261,14 +19032,12 @@ "node_modules/nx/node_modules/color-name": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" }, "node_modules/nx/node_modules/fs-extra": { "version": "11.2.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.2.0.tgz", "integrity": "sha512-PmDi3uwK5nFuXh7XDTlVnS17xJS7vW36is2+w3xcv8SVxiB4NyATf4ctkVY5bkSjX0Y4nbvZCq1/EjtEyr9ktw==", - "dev": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^6.0.1", @@ -19282,34 +19051,19 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "engines": { "node": ">=8" } }, - "node_modules/nx/node_modules/js-yaml": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", - "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, "node_modules/nx/node_modules/jsonc-parser": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.0.tgz", - "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==", - "dev": true + "integrity": "sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==" }, "node_modules/nx/node_modules/minimatch": { "version": "9.0.3", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", - "dev": true, "dependencies": { "brace-expansion": "^2.0.1" }, @@ -19324,7 +19078,6 @@ "version": "5.3.0", "resolved": "https://registry.npmjs.org/ora/-/ora-5.3.0.tgz", "integrity": "sha512-zAKMgGXUim0Jyd6CXK9lraBnD3H5yPGBPPOkC23a2BG6hsm4Zu6OQSjQuEtV0BHDf4aKHcUFvJiGRrFuW3MG8g==", - "dev": true, "dependencies": { "bl": "^4.0.3", "chalk": "^4.1.0", @@ -19346,7 +19099,6 @@ "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "dependencies": { "has-flag": "^4.0.0" }, @@ -19354,25 +19106,13 @@ "node": ">=8" } }, - "node_modules/nx/node_modules/tsconfig-paths": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", - "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", - "dev": true, - "dependencies": { - "json5": "^2.2.2", - "minimist": "^1.2.6", - "strip-bom": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/oauth-sign": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": "*" } @@ -19509,23 +19249,6 @@ "node": ">=0.10.0" } }, - "node_modules/object.values": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.0.tgz", - "integrity": "sha512-yBYjY9QX2hnRmZHAjG/f13MzmBzxzYgQhFrke06TTyKY5zSTEqkOeukBzIdVA3j3ulu8Qa3MbVFShV7T2RmGtQ==", - "dev": true, - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/obuf": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", @@ -19557,7 +19280,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "devOptional": true, "dependencies": { "wrappy": "1" } @@ -19580,7 +19302,6 @@ "version": "8.4.2", "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", - "dev": true, "dependencies": { "define-lazy-prop": "^2.0.0", "is-docker": "^2.1.1", @@ -19626,7 +19347,6 @@ "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", - "dev": true, "dependencies": { "deep-is": "^0.1.3", "fast-levenshtein": "^2.0.6", @@ -19777,7 +19497,6 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", - "dev": true, "dependencies": { "yocto-queue": "^0.1.0" }, @@ -19792,7 +19511,6 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", - "dev": true, "dependencies": { "p-limit": "^3.0.2" }, @@ -19885,7 +19603,9 @@ "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/param-case": { "version": "2.1.1", @@ -19900,7 +19620,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, "dependencies": { "callsites": "^3.0.0" }, @@ -20036,7 +19755,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "engines": { "node": ">=8" } @@ -20045,7 +19763,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -20054,7 +19771,9 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/path-key": { "version": "3.1.1", @@ -20123,7 +19842,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, "engines": { "node": ">=8" } @@ -20153,7 +19871,9 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/picocolors": { "version": "1.0.0", @@ -20859,7 +20579,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", - "dev": true, "engines": { "node": ">= 0.8.0" } @@ -20891,23 +20610,10 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/pretty-format": { "version": "29.7.0", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, "dependencies": { "@jest/schemas": "^29.6.3", "ansi-styles": "^5.0.0", @@ -20921,7 +20627,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, "engines": { "node": ">=10" }, @@ -20976,6 +20681,8 @@ "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", "dev": true, + "optional": true, + "peer": true, "dependencies": { "@types/q": "^0.0.32", "@types/selenium-webdriver": "^3.0.0", @@ -21006,6 +20713,8 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -21015,6 +20724,8 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -21024,6 +20735,8 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -21040,6 +20753,8 @@ "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -21051,6 +20766,8 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -21060,6 +20777,8 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -21072,6 +20791,8 @@ "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "locate-path": "^5.0.0", "path-exists": "^4.0.0" @@ -21085,6 +20806,8 @@ "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "p-locate": "^4.1.0" }, @@ -21097,6 +20820,8 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "p-try": "^2.0.0" }, @@ -21112,6 +20837,8 @@ "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "p-limit": "^2.2.0" }, @@ -21124,6 +20851,8 @@ "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", "integrity": "sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.6.0", "teleport": ">=0.2.0" @@ -21134,6 +20863,8 @@ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -21143,6 +20874,8 @@ "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "source-map": "^0.5.6" } @@ -21152,6 +20885,8 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ansi-regex": "^2.0.0" }, @@ -21164,6 +20899,8 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.8.0" } @@ -21172,13 +20909,17 @@ "version": "4.0.3", "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/protractor/node_modules/yargs": { "version": "15.4.1", "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "cliui": "^6.0.0", "decamelize": "^1.2.0", @@ -21201,6 +20942,8 @@ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "camelcase": "^5.0.0", "decamelize": "^1.2.0" @@ -21234,8 +20977,7 @@ "node_modules/proxy-from-env": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", - "dev": true + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" }, "node_modules/prr": { "version": "1.0.1", @@ -21248,7 +20990,9 @@ "version": "1.9.0", "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/pug": { "version": "2.0.4", @@ -21509,7 +21253,6 @@ "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", - "dev": true, "funding": [ { "type": "github", @@ -21582,8 +21325,7 @@ "node_modules/react-is": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", - "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==" }, "node_modules/read-cache": { "version": "1.0.0", @@ -22025,6 +21767,8 @@ "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", "dev": true, + "optional": true, + "peer": true, "dependencies": { "aws-sign2": "~0.7.0", "aws4": "^1.8.0", @@ -22056,6 +21800,8 @@ "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "asynckit": "^0.4.0", "combined-stream": "^1.0.6", @@ -22070,6 +21816,8 @@ "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.3.tgz", "integrity": "sha512-qxXIEh4pCGfHICj1mAJQ2/2XVZkjCDTcEgfoSQxc/fYivUZxTkk7L3bDBJSoNrEzXI17oUO5Dp07ktqE5KzczA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.6" } @@ -22242,7 +21990,6 @@ "version": "1.0.4", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, "engines": { "iojs": ">=1.0.0", "node": ">=0.10.0" @@ -22271,7 +22018,6 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "devOptional": true, "dependencies": { "glob": "^7.1.3" }, @@ -22341,7 +22087,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", - "dev": true, "funding": [ { "type": "github", @@ -22507,6 +22252,8 @@ "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "https-proxy-agent": "^2.2.1" }, @@ -22519,6 +22266,8 @@ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "es6-promisify": "^5.0.0" }, @@ -22531,6 +22280,8 @@ "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ms": "^2.1.1" } @@ -22540,6 +22291,8 @@ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "agent-base": "^4.3.0", "debug": "^3.1.0" @@ -22552,7 +22305,8 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz", "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA==", - "dev": true + "dev": true, + "optional": true }, "node_modules/schema-utils": { "version": "4.2.0", @@ -22584,6 +22338,8 @@ "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "jszip": "^3.1.3", "rimraf": "^2.5.4", @@ -22599,6 +22355,8 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -22611,6 +22369,8 @@ "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "os-tmpdir": "~1.0.1" }, @@ -22632,12 +22392,9 @@ } }, "node_modules/semver": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", - "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", - "dependencies": { - "lru-cache": "^6.0.0" - }, + "version": "7.6.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz", + "integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==", "bin": { "semver": "bin/semver.js" }, @@ -22645,22 +22402,6 @@ "node": ">=10" } }, - "node_modules/semver/node_modules/lru-cache": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", - "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/semver/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - }, "node_modules/send": { "version": "0.18.0", "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", @@ -22887,7 +22628,9 @@ "version": "1.0.5", "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/setprototypeof": { "version": "1.2.0", @@ -23205,7 +22948,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true, "engines": { "node": ">=8" } @@ -23633,14 +23375,15 @@ "node_modules/sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", - "dev": true + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "node_modules/sshpk": { "version": "1.18.0", "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "asn1": "~0.2.3", "assert-plus": "^1.0.0", @@ -23665,7 +23408,9 @@ "version": "0.1.1", "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/ssri": { "version": "10.0.6", @@ -23919,7 +23664,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", - "dev": true, "engines": { "node": ">=4" } @@ -23949,7 +23693,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "dev": true, "engines": { "node": ">=8" }, @@ -23961,7 +23704,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz", "integrity": "sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA==", - "dev": true, "dependencies": { "duplexer": "^0.1.1", "minimist": "^1.2.0", @@ -24064,22 +23806,6 @@ "node": ">=0.10" } }, - "node_modules/synckit": { - "version": "0.8.8", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", - "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, "node_modules/tailwindcss": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.3.7.tgz", @@ -24158,7 +23884,6 @@ "version": "2.2.0", "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", - "dev": true, "dependencies": { "bl": "^4.0.3", "end-of-stream": "^1.4.1", @@ -24371,8 +24096,7 @@ "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", - "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", - "dev": true + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==" }, "node_modules/thenify": { "version": "3.3.1", @@ -24410,8 +24134,7 @@ "node_modules/through": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==", - "dev": true + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" }, "node_modules/through2": { "version": "4.0.2", @@ -24455,7 +24178,6 @@ "version": "0.2.3", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", - "dev": true, "engines": { "node": ">=14.14" } @@ -24512,7 +24234,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "devOptional": true, "dependencies": { "is-number": "^7.0.0" }, @@ -24592,6 +24313,8 @@ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "psl": "^1.1.28", "punycode": "^2.1.1" @@ -24650,7 +24373,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", - "dev": true, "engines": { "node": ">=16" }, @@ -24731,27 +24453,16 @@ } }, "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", - "dev": true, + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", + "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" - } - }, - "node_modules/tsconfig-paths/node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", - "dev": true, - "dependencies": { - "minimist": "^1.2.0" }, - "bin": { - "json5": "lib/cli.js" + "engines": { + "node": ">=6" } }, "node_modules/tslib": { @@ -24777,6 +24488,8 @@ "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "safe-buffer": "^5.0.1" }, @@ -24788,13 +24501,14 @@ "version": "0.14.5", "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", - "dev": true, "dependencies": { "prelude-ls": "^1.2.1" }, @@ -24909,7 +24623,6 @@ "version": "5.4.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.5.tgz", "integrity": "sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==", - "dev": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -24918,6 +24631,187 @@ "node": ">=14.17" } }, + "node_modules/typescript-eslint": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-7.13.0.tgz", + "integrity": "sha512-upO0AXxyBwJ4BbiC6CRgAJKtGYha2zw4m1g7TIVPSonwYEuf7vCicw3syjS1OxdDMTz96sZIXl3Jx3vWJLLKFw==", + "dependencies": { + "@typescript-eslint/eslint-plugin": "7.13.0", + "@typescript-eslint/parser": "7.13.0", + "@typescript-eslint/utils": "7.13.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.0.tgz", + "integrity": "sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/type-utils": "7.13.0", + "@typescript-eslint/utils": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.0.tgz", + "integrity": "sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==", + "dependencies": { + "@typescript-eslint/scope-manager": "7.13.0", + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/typescript-estree": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.0.tgz", + "integrity": "sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==", + "dependencies": { + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.0.tgz", + "integrity": "sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==", + "dependencies": { + "@typescript-eslint/typescript-estree": "7.13.0", + "@typescript-eslint/utils": "7.13.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.0.tgz", + "integrity": "sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==", + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.0.tgz", + "integrity": "sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==", + "dependencies": { + "@typescript-eslint/types": "7.13.0", + "@typescript-eslint/visitor-keys": "7.13.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^1.3.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.0.tgz", + "integrity": "sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==", + "dependencies": { + "@typescript-eslint/types": "7.13.0", + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/ua-parser-js": { "version": "0.7.37", "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.37.tgz", @@ -25111,7 +25005,6 @@ "version": "2.0.1", "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "dev": true, "engines": { "node": ">= 10.0.0" } @@ -25278,6 +25171,8 @@ "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", "deprecated": "Please upgrade to version 7 or higher. Older versions may use Math.random() in certain circumstances, which is known to be problematic. See https://v8.dev/blog/math-random for details.", "dev": true, + "optional": true, + "peer": true, "bin": { "uuid": "bin/uuid" } @@ -25334,6 +25229,8 @@ "engines": [ "node >=0.6.0" ], + "optional": true, + "peer": true, "dependencies": { "assert-plus": "^1.0.0", "core-util-is": "1.0.2", @@ -25851,6 +25748,8 @@ "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "@types/selenium-webdriver": "^3.0.0", "selenium-webdriver": "^3.0.1" @@ -25864,6 +25763,8 @@ "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz", "integrity": "sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "adm-zip": "^0.5.2", "chalk": "^1.1.1", @@ -25889,6 +25790,8 @@ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -25898,6 +25801,8 @@ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -25907,6 +25812,8 @@ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ansi-styles": "^2.2.1", "escape-string-regexp": "^1.0.2", @@ -25922,13 +25829,17 @@ "version": "1.3.8", "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true + "dev": true, + "optional": true, + "peer": true }, "node_modules/webdriver-manager/node_modules/rimraf": { "version": "2.7.1", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "glob": "^7.1.3" }, @@ -25941,6 +25852,8 @@ "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, + "optional": true, + "peer": true, "bin": { "semver": "bin/semver" } @@ -25950,6 +25863,8 @@ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "ansi-regex": "^2.0.0" }, @@ -25962,6 +25877,8 @@ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=0.8.0" } @@ -26526,7 +26443,6 @@ "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -26633,8 +26549,7 @@ "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "devOptional": true + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" }, "node_modules/ws": { "version": "8.11.0", @@ -26662,6 +26577,8 @@ "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", "dev": true, + "optional": true, + "peer": true, "dependencies": { "sax": ">=0.6.0", "xmlbuilder": "~11.0.0" @@ -26675,6 +26592,8 @@ "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true, + "optional": true, + "peer": true, "engines": { "node": ">=4.0" } @@ -26746,7 +26665,6 @@ "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", - "dev": true, "engines": { "node": ">=10" }, diff --git a/package.json b/package.json index 7431b2a58c..467afeb38c 100644 --- a/package.json +++ b/package.json @@ -42,13 +42,9 @@ "@angular/upgrade": "^18.0.3", "@ctrl/ngx-emoji-mart": "^9.2.0", "@ngneat/hotkeys": "^4.0.0", - "@uirouter/angular": "^13.0", - "@uirouter/angular-hybrid": "^17.1.0", - "@uirouter/angularjs": "^1.0.30", - "@uirouter/core": "^6.1.0", - "@uirouter/rx": "^1.0.0", "angular": "1.5.11", "angular-cookies": "1.5.11", + "angular-eslint": "^18.0.1", "angular-file-upload": "~1", "angular-filter": "0.5.17", "angular-local-storage": "0.7.1", @@ -82,22 +78,23 @@ "ng-flex-layout": "^17.3.7-beta.1", "ng2-pdf-viewer": "^10.2", "ngx-bootstrap": "^6.1.0", - "ngx-entity-service": "^0.0.38", + "ngx-entity-service": "^0.0.39", "ngx-lottie": "^11.0.2", "nvd3": "1.8.6", "rxjs": "~7.4.0", "ts-md5": "^1.3.1", "tslib": "^2.6.2", + "typescript-eslint": "^7.13.0", "underscore.string": "2.3.3", "zone.js": "~0.14" }, "devDependencies": { "@angular-devkit/build-angular": "^18.0.4", - "@angular-eslint/builder": "^17.3.0", - "@angular-eslint/eslint-plugin": "^17.3.0", - "@angular-eslint/eslint-plugin-template": "^17.3.0", - "@angular-eslint/schematics": "^17.3.0", - "@angular-eslint/template-parser": "^17.3.0", + "@angular-eslint/builder": "18.0.1", + "@angular-eslint/eslint-plugin": "18.0.1", + "@angular-eslint/eslint-plugin-template": "18.0.1", + "@angular-eslint/schematics": "18.0.1", + "@angular-eslint/template-parser": "18.0.1", "@angular/compiler-cli": "^18.0.3", "@angular/language-service": "^18.0.3", "@commitlint/cli": "^16.0.1", @@ -110,17 +107,12 @@ "@types/jasminewd2": "~2.0.3", "@types/lodash": "^4.14.115", "@types/node": "^20.9.0", - "@typescript-eslint/eslint-plugin": "^7.2.0", - "@typescript-eslint/parser": "^7.2.0", + "@typescript-eslint/eslint-plugin": "7.11.0", + "@typescript-eslint/parser": "7.11.0", "autoprefixer": "~6", "canonical-path": "0.0.2", "concurrently": "^3.2.0", - "eslint": "^8.57.0", - "eslint-config-prettier": "^8.5.0", - "eslint-plugin-import": "2.26.0", - "eslint-plugin-jsdoc": "39.3.6", - "eslint-plugin-prefer-arrow": "1.2.3", - "eslint-plugin-prettier": "^5.0.1", + "eslint": "8.57.0", "grunt": "^1.0.4", "grunt-bump": "0.8.0", "grunt-coffeelint": "0.0.16", @@ -154,7 +146,6 @@ "postcss": "^8.4.27", "postcss-scss": "^0.1.7", "prettier": "^3.1.0", - "protractor": "~7.0.0", "sass": "^1.48.0", "tailwindcss": "~3.3", "ts-node": "~10.9", @@ -167,4 +158,4 @@ "@nx/nx-linux-x64-gnu": "^18.0", "@nx/nx-win32-x64-msvc": "^18.0" } -} \ No newline at end of file +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html index fe96cfb2df..d53ee750f9 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html @@ -26,11 +26,11 @@
@@ -39,11 +39,11 @@ @@ -51,7 +51,12 @@ @@ -63,7 +68,9 @@ - + @@ -75,19 +82,19 @@
- Student + Student + - Name + Name + - Tutor + Tutor + Tutorial - + - Target + Target + Submitted as - + - Stats + Stats - Portfolio? + Portfolio? + - Grade + Grade +
{{student.hasPortfolio ? "Yes" : "No"}} + {{student.hasPortfolio ? "Yes" : "No"}} + {{student.grade}}
Check Similarity @if (upreq.type === 'document') { -TurnItIn -} + TurnItIn + } @if (upreq.type === 'code') { -Moss -} + Moss + } Flag At @if (upreq.type === 'document' && upreq.tiiCheck) { - - -  % - -} + + +  % + + } -
@if (taskDefinition.needsMoss) { -
- - Language used for Moss checks - - C - C# - C++ - Python - - - - Similarity percent to flag for Moss checks - - -
+
+ + Language used for Moss checks + + C + C# + C++ + Python + + + + Similarity percent to flag for Moss checks + + +
} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts index a8915d843b..3e949c507a 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts @@ -1,7 +1,7 @@ -import { Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/core'; -import { MatTable, MatTableDataSource } from '@angular/material/table'; -import { TaskDefinition, UploadRequirement } from 'src/app/api/models/task-definition'; -import { Unit } from 'src/app/api/models/unit'; +import {Component, Input, OnChanges, SimpleChanges, ViewChild} from '@angular/core'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; +import {TaskDefinition, UploadRequirement} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; @Component({ selector: 'f-task-definition-upload', @@ -10,7 +10,7 @@ import { Unit } from 'src/app/api/models/unit'; }) export class TaskDefinitionUploadComponent { @Input() public taskDefinition: TaskDefinition; - @ViewChild('upreqTable', { static: true }) table: MatTable; + @ViewChild('upreqTable', {static: true}) table: MatTable; public columns: string[] = ['file-name', 'file-type', 'tii-check', 'flag-pct', 'row-actions']; @@ -32,7 +32,7 @@ export class TaskDefinitionUploadComponent { public removeUpReq(upreq: UploadRequirement) { this.taskDefinition.uploadRequirements = this.taskDefinition.uploadRequirements.filter( - (anUpReq) => anUpReq.key != upreq.key + (anUpReq) => anUpReq.key != upreq.key, ); } } diff --git a/src/app/units/states/portfolios/portfolios.tpl.html b/src/app/units/states/portfolios/portfolios.tpl.html index 2974d0719a..ef8d12efaa 100644 --- a/src/app/units/states/portfolios/portfolios.tpl.html +++ b/src/app/units/states/portfolios/portfolios.tpl.html @@ -51,7 +51,7 @@

Mark Portfolios

All @@ -278,11 +278,7 @@

Review Portfolio of {{selectedStudent.student.name}}

No Portfolio Submitted

- - +
From 59c769c1305cbc3b94fc3e50f105fc57d42ec185 Mon Sep 17 00:00:00 2001 From: jakerenzella Date: Sat, 15 Jun 2024 19:30:07 +1000 Subject: [PATCH 0118/1280] build: upgrade packages --- package-lock.json | 67 +++++++++++++++++++++++++++++++++++++++++++++++ package.json | 13 ++++++--- 2 files changed, 76 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 8702239d8b..d96368f91a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,6 +25,11 @@ "@angular/upgrade": "^18.0.3", "@ctrl/ngx-emoji-mart": "^9.2.0", "@ngneat/hotkeys": "^4.0.0", + "@uirouter/angular": "^13.0", + "@uirouter/angular-hybrid": "^17.1.0", + "@uirouter/angularjs": "^1.0.30", + "@uirouter/core": "^6.1.0", + "@uirouter/rx": "^1.0.0", "angular": "1.5.11", "angular-cookies": "1.5.11", "angular-eslint": "^18.0.1", @@ -6891,6 +6896,68 @@ "url": "https://opencollective.com/typescript-eslint" } }, + "node_modules/@uirouter/angular": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/@uirouter/angular/-/angular-13.0.0.tgz", + "integrity": "sha512-T2aizSXzW+7eiXUmc0LiLH+I8ZBJvDr7OQmm/5WCcxVL2NfuIse7B1kpvfdh9PmBAqw8AY7S0NhrJgABfFJUnw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "@angular/common": "^17.0.0", + "@angular/core": "^17.0.0", + "@uirouter/core": "^6.0.8", + "@uirouter/rx": "^1.0.0" + } + }, + "node_modules/@uirouter/angular-hybrid": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/@uirouter/angular-hybrid/-/angular-hybrid-17.1.0.tgz", + "integrity": "sha512-zUQ/b2BaEuODPOtDtxp2SpEifm/VHoLauPTXtZAfcHpDoty6DFbLyGCrA4ZI9lqyoACVxpOuUKjhTHLNE9SXTw==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", + "@angular/upgrade": "^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", + "@uirouter/angular": "^13.0.0", + "@uirouter/angularjs": "^1.0.30", + "@uirouter/core": "^6.1.0", + "angular": "^1.5.0" + } + }, + "node_modules/@uirouter/angularjs": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@uirouter/angularjs/-/angularjs-1.1.0.tgz", + "integrity": "sha512-AhgxXhMfN6FU2HxDQqwDPbzmd6kTgvYCgV/kgoCAXfxAH6cFQrifViToC90Wdg6djBynHwA3L/KYP+iOYHkw6A==", + "engines": { + "node": ">=4.0.0" + }, + "peerDependencies": { + "@uirouter/core": "^6.0.8", + "angular": ">=1.2.0" + } + }, + "node_modules/@uirouter/core": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@uirouter/core/-/core-6.1.0.tgz", + "integrity": "sha512-WFYh5NPAqRX4L2qlI4k62tgR6pxoqOBSW1CM1uBWCau4mAmgasYd5etJ9RoSJrSnCpCQ2km2Jltf0n5ql684MQ==", + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/@uirouter/rx": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@uirouter/rx/-/rx-1.0.0.tgz", + "integrity": "sha512-dqPmLFC+qqF6RIdJVKktXSON6WILy2oyLhADDk74F3GAUZ/VvOu3QSPLDtZEP3LMSo6vkGQvwcUdjgNVWL3YJA==", + "peerDependencies": { + "@uirouter/core": ">=6.0.1", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, "node_modules/@ungap/structured-clone": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", diff --git a/package.json b/package.json index 467afeb38c..d92388b974 100644 --- a/package.json +++ b/package.json @@ -9,13 +9,13 @@ "node": ">=20.9.0" }, "scripts": { - "build": "run-s -l build:angular1 build:angular17", + "build": "run-s -l build:angular1 build:angular18", "build:angular1": "grunt build", - "build:angular17": "ng build", + "build:angular18": "ng build", "lint:fix": "ng lint --fix", "lint": "ng lint", - "serve:angular17": "export NODE_OPTIONS=--max_old_space_size=4096 && ng serve --configuration $NODE_ENV", - "start": "npm-run-all -l -s build:angular1 -p watch:angular1 serve:angular17", + "serve:angular18": "export NODE_OPTIONS=--max_old_space_size=4096 && ng serve --configuration $NODE_ENV", + "start": "npm-run-all -l -s build:angular1 -p watch:angular1 serve:angular18", "watch:angular1": "grunt delta", "deploy:build2api": "ng build --delete-output-path=true --optimization=true --configuration production --output-path dist", "deploy": "run-s -l build:angular1 deploy:build2api", @@ -42,6 +42,11 @@ "@angular/upgrade": "^18.0.3", "@ctrl/ngx-emoji-mart": "^9.2.0", "@ngneat/hotkeys": "^4.0.0", + "@uirouter/angular": "^13.0", + "@uirouter/angular-hybrid": "^17.1.0", + "@uirouter/angularjs": "^1.0.30", + "@uirouter/core": "^6.1.0", + "@uirouter/rx": "^1.0.0", "angular": "1.5.11", "angular-cookies": "1.5.11", "angular-eslint": "^18.0.1", From 110271cd7140a31e8dcfca377092ce46181164fc Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sat, 15 Jun 2024 20:23:14 +1000 Subject: [PATCH 0119/1280] refactor: fix spacing in task scorm card --- .../task-scorm-card.component.html | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html index cec59fc939..81e11cf43c 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html @@ -17,17 +17,16 @@ } -

+

You have successfully completed this knowledge check. You can now proceed to submitting task files.

- - @@ -54,7 +53,7 @@ You have {{ attemptsLeft !== undefined ? attemptsLeft : 'unlimited' }} attempts left to complete this test.

-

+

There will be an increased time delay between test attempts. First 2 attempts will not have a time delay in between.

From 3b7576570394dc0122db73c7052dd5ed97bf0152 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sat, 15 Jun 2024 20:25:41 +1000 Subject: [PATCH 0120/1280] refactor: add description for scorm time delay --- .../task-definition-scorm.component.html | 21 +++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html index 5b3b54c111..5321600cf5 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html @@ -24,10 +24,7 @@
-
- - Enable incremental time delays between test attempts - +
Allow students to review completed test attempt @@ -44,5 +41,21 @@ />
+ +
+ + Enable incremental time delays between test attempts + + If enabled, first 2 attempts can be completed immediately. Subsequently, a time delay will + be added, increasing by 2 hours every attempt made. +
}
From ec86e4eca8e9c50ebdaf54c34c302da88dd44b31 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Sat, 15 Jun 2024 21:21:17 +1000 Subject: [PATCH 0121/1280] feat: prevent uploading files until scorm passed --- src/app/api/models/task-definition.ts | 1 + src/app/api/models/task.ts | 24 +++++++-- .../api/services/task-definition.service.ts | 1 + src/app/api/services/test-attempt.service.ts | 2 +- .../task-scorm-card.component.html | 9 ++-- .../task-scorm-card.component.ts | 54 +++++++------------ .../task-definition-scorm.component.html | 3 ++ 7 files changed, 50 insertions(+), 44 deletions(-) diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index ca2d188eb6..050466d740 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -34,6 +34,7 @@ export class TaskDefinition extends Entity { scormEnabled: boolean; hasScormData: boolean; scormAllowReview: boolean; + scormBypassTest: boolean; scormTimeDelayEnabled: boolean; scormAttemptLimit: number = 0; hasTaskAssessmentResources: boolean; diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index ba4bce8e04..2cadc79d72 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -512,9 +512,22 @@ export class Task extends Entity { } public get scormEnabled(): boolean { - return ( - this.definition.scormEnabled && this.definition.hasScormData - ); + return this.definition.scormEnabled && this.definition.hasScormData; + } + + public get scormPassed(): boolean { + if (this.latestCompletedTestAttempt) { + return this.latestCompletedTestAttempt.successStatus; + } + return false; + } + + public get isReadyForUpload(): boolean { + return !this.scormEnabled || this.definition.scormBypassTest || this.scormPassed; + } + + public get latestCompletedTestAttempt(): TestAttempt { + return this.testAttemptCache.currentValues.find((attempt) => attempt.terminated); } public submissionUrl(asAttachment: boolean = false): string { @@ -669,12 +682,15 @@ export class Task extends Entity { public triggerTransition(status: TaskStatusEnum): void { if (this.status === status) return; + const alerts: AlertService = AppInjector.get(AlertService); const requiresFileUpload = ['ready_for_feedback', 'need_help'].includes(status) && this.requiresFileUpload(); - if (requiresFileUpload) { + if (requiresFileUpload && this.isReadyForUpload) { this.presentTaskSubmissionModal(status); + } else if (requiresFileUpload && !this.isReadyForUpload) { + alerts.error('Complete Knowledge Check first to submit files', 6000); } else { this.updateTaskStatus(status); } diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index 3776432fd8..9a4a1eeb59 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -96,6 +96,7 @@ export class TaskDefinitionService extends CachedEntityService { 'scormEnabled', 'hasScormData', 'scormAllowReview', + 'scormBypassTest', 'scormTimeDelayEnabled', 'scormAttemptLimit', 'isGraded', diff --git a/src/app/api/services/test-attempt.service.ts b/src/app/api/services/test-attempt.service.ts index df5654855f..3e2c461619 100644 --- a/src/app/api/services/test-attempt.service.ts +++ b/src/app/api/services/test-attempt.service.ts @@ -11,7 +11,7 @@ import {HttpClient} from '@angular/common/http'; @Injectable() export class TestAttemptService extends CachedEntityService { protected readonly endpointFormat = - '/projects/:project_id:/task_def_id/:task_def_id:/test_attempts'; + 'projects/:project_id:/task_def_id/:task_def_id:/test_attempts'; protected readonly latestCompletedEndpoint = this.endpointFormat + '/latest?completed=:completed:'; diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html index 81e11cf43c..12df6a4936 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html @@ -1,6 +1,6 @@ @if (isPassed) { - @if (latestCompletedAttempt.scoreScaled === 1) { + @if (this.task.latestCompletedTestAttempt.scoreScaled === 1) { check @@ -8,7 +8,7 @@ > } - @if (latestCompletedAttempt.scoreScaled !== 1) { + @if (this.task.latestCompletedTestAttempt.scoreScaled !== 1) { check @@ -73,7 +73,10 @@ diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts index 25fc9e479a..9860d47741 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts @@ -1,11 +1,5 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; -import { - Task, - TestAttempt, - TestAttemptService, - User, - UserService, -} from 'src/app/api/models/doubtfire-model'; +import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; +import {Task, User, UserService} from 'src/app/api/models/doubtfire-model'; import {ScormExtensionModalService} from 'src/app/common/modals/scorm-extension-modal/scorm-extension-modal.service'; @Component({ @@ -13,51 +7,39 @@ import {ScormExtensionModalService} from 'src/app/common/modals/scorm-extension- templateUrl: './task-scorm-card.component.html', styleUrls: ['./task-scorm-card.component.scss'], }) -export class TaskScormCardComponent implements OnInit, OnChanges { +export class TaskScormCardComponent implements OnChanges { @Input() task: Task; attemptsLeft: number; isPassed: boolean; - latestCompletedAttempt: TestAttempt; user: User; constructor( private extensions: ScormExtensionModalService, - private testAttemptService: TestAttemptService, private userService: UserService, ) { this.user = this.userService.currentUser; } - ngOnInit() { - this.refreshAttemptData(); - } - ngOnChanges(changes: SimpleChanges) { - if (changes.task && changes.task.currentValue) { - this.refreshAttemptData(); - } - } - - refreshAttemptData(): void { - this.attemptsLeft = undefined; - this.isPassed = undefined; - this.latestCompletedAttempt = undefined; + if (changes.task && changes.task.currentValue && changes.task.currentValue.scormEnabled) { + this.attemptsLeft = undefined; + this.isPassed = undefined; - this.getAttemptsLeft(); - this.testAttemptService.getLatestCompletedAttempt(this.task).subscribe((attempt) => { - this.latestCompletedAttempt = attempt; - this.isPassed = attempt.successStatus; - }); + // eslint-disable-next-line @typescript-eslint/no-unused-vars + this.task?.fetchTestAttempts().subscribe((_) => { + this.getAttemptsLeft(); + if (this.task.latestCompletedTestAttempt) this.isPassed = this.task.scormPassed; + }); + } } getAttemptsLeft(): void { if (this.task.definition.scormAttemptLimit != 0) { - this.task.fetchTestAttempts().subscribe((attempts) => { - let count = attempts.length; - if (count > 0 && attempts[0].terminated === false) count--; - this.attemptsLeft = - this.task.definition.scormAttemptLimit + this.task.scormExtensions - count; - }); + const attempts = this.task.testAttemptCache.currentValues; + let count = attempts.length; + if (count > 0 && attempts[0].terminated === false) count--; + this.attemptsLeft = + this.task.definition.scormAttemptLimit + this.task.scormExtensions - count; } } @@ -70,7 +52,7 @@ export class TaskScormCardComponent implements OnInit, OnChanges { reviewLatestCompletedAttempt(): void { window.open( - `#/task_def_id/${this.task.taskDefId}/scorm-player/review/${this.latestCompletedAttempt.id}`, + `#/task_def_id/${this.task.taskDefId}/scorm-player/review/${this.task.latestCompletedTestAttempt.id}`, '_blank', ); } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html index 5321600cf5..c2b89f9d7b 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html @@ -28,6 +28,9 @@ Allow students to review completed test attempt + + Allow file upload regardless of test pass status +
Attempt limit From 20da0423450fe3b9b8006660bf6f5e06670f520c Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 18 Jun 2024 19:04:03 +1000 Subject: [PATCH 0122/1280] fix: change success status descriptions --- .../task-scorm-card/task-scorm-card.component.html | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html index 12df6a4936..ac1221f87f 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html @@ -4,7 +4,7 @@ check - Knowledge Check PassedKnowledge Check Passed Without Mistakes
} @@ -12,7 +12,7 @@ check - Knowledge Check Passed With MistakesKnowledge Check Passed } @@ -38,7 +38,7 @@ close - Knowledge Check FailedKnowledge Check Unsuccessful } From 14c66a7bc8c1d75f1736d4e1682e78dca1e365de Mon Sep 17 00:00:00 2001 From: jakerenzella Date: Mon, 3 Jun 2024 23:20:12 +1000 Subject: [PATCH 0123/1280] build: upgrade pdf viewer --- package-lock.json | 388 ++++++++++++++++++++++++++++++++++++++++------ package.json | 4 +- 2 files changed, 340 insertions(+), 52 deletions(-) diff --git a/package-lock.json b/package-lock.json index f1bfcafa3d..92e5cafe0c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -62,8 +62,8 @@ "moment": "^2.29.4", "ng-csv": "0.2.3", "ng-file-upload": "~5.0.9", - "ng-flex-layout": "^17.3.4-beta.1", - "ng2-pdf-viewer": "^10.0", + "ng-flex-layout": "^17.3.7-beta.1", + "ng2-pdf-viewer": "^10.2", "ngx-bootstrap": "^6.1.0", "ngx-entity-service": "^0.0.38", "ngx-lottie": "^11.0.2", @@ -3836,6 +3836,90 @@ "node": ">= 0.4" } }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "optional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "optional": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@material/animation": { "version": "15.0.0-canary.7f224ddd4.0", "resolved": "https://registry.npmjs.org/@material/animation/-/animation-15.0.0-canary.7f224ddd4.0.tgz", @@ -6926,6 +7010,26 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/aproba": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.0.0.tgz", + "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -8134,6 +8238,21 @@ "integrity": "sha512-y8EIEvL+IW81S4hRQWCRFtly+g1cc1G+wxHpjhYR9jI2+JJjWiaKnkH8mmvNHOMOAd9fzgARDO3AEzjuR51qaA==", "dev": true }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/canvas-confetti": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.3.tgz", @@ -8573,6 +8692,15 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -8701,7 +8829,7 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true + "devOptional": true }, "node_modules/concurrently": { "version": "3.6.1", @@ -8805,6 +8933,12 @@ "date-now": "^0.1.4" } }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "optional": true + }, "node_modules/constantinople": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/constantinople/-/constantinople-3.1.2.tgz", @@ -9452,6 +9586,18 @@ "node": ">=0.10" } }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -9620,6 +9766,12 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "optional": true + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -9657,6 +9809,15 @@ "node": ">=0.10.0" } }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/detect-node": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", @@ -9795,12 +9956,6 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/dommatrix": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/dommatrix/-/dommatrix-1.0.3.tgz", - "integrity": "sha512-l32Xp/TLgWb8ReqbVJAFIvXmY7go4nTxxlWiAFyhoQw9RKEOHBZNnyGvJWqDVSPmq3Y9HlM4npqF/T6VMOXhww==", - "deprecated": "dommatrix is no longer maintained. Please use @thednp/dommatrix." - }, "node_modules/domutils": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", @@ -11649,7 +11804,7 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "dev": true + "devOptional": true }, "node_modules/function-bind": { "version": "1.1.2", @@ -11686,6 +11841,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/gaze": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", @@ -11830,7 +12006,7 @@ "version": "7.1.7", "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz", "integrity": "sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ==", - "dev": true, + "devOptional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -11868,7 +12044,7 @@ "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "devOptional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -11878,7 +12054,7 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "devOptional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -13455,6 +13631,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "optional": true + }, "node_modules/has-value": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", @@ -13984,7 +14166,7 @@ "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "dev": true, + "devOptional": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -16580,6 +16762,18 @@ "node": ">=6" } }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/min-indent": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", @@ -16999,6 +17193,12 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.19.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.19.0.tgz", + "integrity": "sha512-nO1xXxfh/RWNxfd/XPfbIfFk5vgLsAxUR9y5O0cHMJu/AW9U95JLXqthYHjEp+8gQ5p96K9jUp8nbVOxCdRbtw==", + "optional": true + }, "node_modules/nanoid": { "version": "3.3.7", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", @@ -17191,9 +17391,9 @@ "integrity": "sha512-298k/s42+cyHLFAWCtgmXHGOUFqAh5VviSbMuQAPfqAavK1h9ADU/A+gN7OLmgNhW9PM94bWSt22LpjO/cvKwA==" }, "node_modules/ng-flex-layout": { - "version": "17.3.4-beta.1", - "resolved": "https://registry.npmjs.org/ng-flex-layout/-/ng-flex-layout-17.3.4-beta.1.tgz", - "integrity": "sha512-MmXj7Cq9cBSDgJKT3vOok2YCq3OcUD4zhPaKup9V5lVJLZ38sHPgfPf5fFBjDZO7R6AD66wYPod0i4zW5LrrgA==", + "version": "17.3.7-beta.1", + "resolved": "https://registry.npmjs.org/ng-flex-layout/-/ng-flex-layout-17.3.7-beta.1.tgz", + "integrity": "sha512-MTjlQUldB/hEsn0DY/RoY2SKBQoyaKltlOOFjCjH2OfcYA3COHhkJS3PZe9NAjR7TBDb9Ve989m18bSucRzACQ==", "dependencies": { "tslib": "^2.3.0" }, @@ -17206,15 +17406,12 @@ } }, "node_modules/ng2-pdf-viewer": { - "version": "10.0.0", - "resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-10.0.0.tgz", - "integrity": "sha512-zEefcAsTpDoxFceQYs3ycPMaUAkt5UX4OcTstVQoNqRK6w+vOY+V8z8aFCuBwnt+7iN1EHaIpquOf4S9mWc04g==", + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-10.2.2.tgz", + "integrity": "sha512-GaKAvF0nXAiR9U4LFWuT54MM9nzp0ie8GGscp34W+lFsSOXdlwS0iFx5UPuVlODRm3YEUKx6xcK5oaJeBq0SAw==", "dependencies": { - "pdfjs-dist": "~2.16.105", + "pdfjs-dist": "^3.11.174", "tslib": "^2.3.0" - }, - "peerDependencies": { - "pdfjs-dist": "~2.16.105" } }, "node_modules/ngx-bootstrap": { @@ -17288,6 +17485,26 @@ "dev": true, "optional": true }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "optional": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-forge": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", @@ -17694,6 +17911,19 @@ "node": ">=8" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "optional": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -17963,7 +18193,7 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -18139,7 +18369,7 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dev": true, + "devOptional": true, "dependencies": { "wrappy": "1" } @@ -18617,7 +18847,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "dev": true, + "devOptional": true, "engines": { "node": ">=0.10.0" } @@ -18700,21 +18930,25 @@ "node": ">=8" } }, + "node_modules/path2d-polyfill": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", + "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", + "optional": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pdfjs-dist": { - "version": "2.16.105", - "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-2.16.105.tgz", - "integrity": "sha512-J4dn41spsAwUxCpEoVf6GVoz908IAA3mYiLmNxg8J9kfRXc2jxpbUepcP0ocp0alVNLFthTAM8DZ1RaHh8sU0A==", - "dependencies": { - "dommatrix": "^1.0.3", - "web-streams-polyfill": "^3.2.1" - }, - "peerDependencies": { - "worker-loader": "^3.0.8" + "version": "3.11.174", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", + "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", + "engines": { + "node": ">=18" }, - "peerDependenciesMeta": { - "worker-loader": { - "optional": true - } + "optionalDependencies": { + "canvas": "^2.11.2", + "path2d-polyfill": "^2.0.1" } }, "node_modules/performance-now": { @@ -20919,7 +21153,7 @@ "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "dev": true, + "devOptional": true, "dependencies": { "glob": "^7.1.3" }, @@ -21794,12 +22028,43 @@ "node": "^16.14.0 || >=18.0.0" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, "node_modules/simple-fmt": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/simple-fmt/-/simple-fmt-0.1.0.tgz", "integrity": "sha512-9a3zTDDh9LXbTR37qBhACWIQ/mP/ry5xtmbE98BJM8GR02sanCkfMzp7AdCTqYhkBZggK/w7hJtc8Pb9nmo16A==", "dev": true }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/simple-is": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/simple-is/-/simple-is-0.2.0.tgz", @@ -23174,6 +23439,12 @@ "node": ">=0.8" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "optional": true + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -24040,14 +24311,6 @@ "defaults": "^1.0.3" } }, - "node_modules/web-streams-polyfill": { - "version": "3.3.3", - "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", - "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", - "engines": { - "node": ">= 8" - } - }, "node_modules/webdriver-js-extender": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", @@ -24168,6 +24431,12 @@ "node": ">=0.8.0" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "optional": true + }, "node_modules/webpack": { "version": "5.90.3", "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", @@ -24490,6 +24759,16 @@ "node": ">=0.8.0" } }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "optional": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -24544,6 +24823,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "node_modules/wildcard": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", @@ -24694,7 +24982,7 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", - "dev": true + "devOptional": true }, "node_modules/ws": { "version": "8.11.0", diff --git a/package.json b/package.json index 272c6019b9..3f95891a81 100644 --- a/package.json +++ b/package.json @@ -79,8 +79,8 @@ "moment": "^2.29.4", "ng-csv": "0.2.3", "ng-file-upload": "~5.0.9", - "ng-flex-layout": "^17.3.4-beta.1", - "ng2-pdf-viewer": "^10.0", + "ng-flex-layout": "^17.3.7-beta.1", + "ng2-pdf-viewer": "^10.2", "ngx-bootstrap": "^6.1.0", "ngx-entity-service": "^0.0.38", "ngx-lottie": "^11.0.2", From da376b9bc7905aadeb4d234cbb4f595e4c4424a1 Mon Sep 17 00:00:00 2001 From: jakerenzella Date: Sat, 15 Jun 2024 00:10:27 +1000 Subject: [PATCH 0124/1280] fix: fix pdf viewer for portfolios --- .../pdf-viewer/pdf-viewer.component.html | 41 +++++++--- .../common/pdf-viewer/pdf-viewer.component.ts | 9 +- .../units/states/portfolios/portfolios.coffee | 4 +- .../states/portfolios/portfolios.tpl.html | 82 +++++++++++++++---- 4 files changed, 107 insertions(+), 29 deletions(-) diff --git a/src/app/common/pdf-viewer/pdf-viewer.component.html b/src/app/common/pdf-viewer/pdf-viewer.component.html index 232c89d5ed..87dc97c996 100644 --- a/src/app/common/pdf-viewer/pdf-viewer.component.html +++ b/src/app/common/pdf-viewer/pdf-viewer.component.html @@ -3,25 +3,44 @@
search - + - -
@if (pdfBlobUrl) { - + } diff --git a/src/app/common/pdf-viewer/pdf-viewer.component.ts b/src/app/common/pdf-viewer/pdf-viewer.component.ts index 23d5029b2f..5cd893b5a9 100644 --- a/src/app/common/pdf-viewer/pdf-viewer.component.ts +++ b/src/app/common/pdf-viewer/pdf-viewer.component.ts @@ -7,6 +7,8 @@ import { SimpleChanges, OnChanges, ViewChild, + OnInit, + AfterViewInit, } from '@angular/core'; import {PdfViewerComponent} from 'ng2-pdf-viewer'; import {FileDownloaderService} from '../file-downloader/file-downloader.service'; @@ -17,7 +19,7 @@ import {AlertService} from '../services/alert.service'; templateUrl: './pdf-viewer.component.html', styleUrls: ['./pdf-viewer.component.scss'], }) -export class fPdfViewerComponent implements OnDestroy, OnChanges { +export class fPdfViewerComponent implements OnDestroy, OnChanges, AfterViewInit { private _pdfUrl: string; public pdfBlobUrl: string; @Input() pdfUrl: string; @@ -38,6 +40,11 @@ export class fPdfViewerComponent implements OnDestroy, OnChanges { } } + ngAfterViewInit(): void { + console.log("pdfUrl"); + console.log(this.pdfUrl); + } + ngOnChanges(changes: SimpleChanges): void { this.pdfUrlChanges(changes.pdfUrl.currentValue); } diff --git a/src/app/units/states/portfolios/portfolios.coffee b/src/app/units/states/portfolios/portfolios.coffee index 7e745b33d1..41d0b60797 100644 --- a/src/app/units/states/portfolios/portfolios.coffee +++ b/src/app/units/states/portfolios/portfolios.coffee @@ -122,7 +122,9 @@ angular.module('doubtfire.units.states.portfolios', []) $scope.selectedStudent = student $scope.project = null newProjectService.loadProject(student, $scope.unit).subscribe({ - next: (project) -> $scope.project = project + next: (project) -> + $scope.project = project + $scope.project.preloadedUrl = $scope.project.portfolioUrl() error: (message) -> alertService.error( message, 6000) }) ) diff --git a/src/app/units/states/portfolios/portfolios.tpl.html b/src/app/units/states/portfolios/portfolios.tpl.html index 075680654c..2974d0719a 100644 --- a/src/app/units/states/portfolios/portfolios.tpl.html +++ b/src/app/units/states/portfolios/portfolios.tpl.html @@ -27,7 +27,11 @@

Mark Portfolios

>
@@ -39,7 +43,11 @@

Mark Portfolios

-
- +
@@ -172,7 +210,9 @@

Mark Portfolios

- + @@ -237,7 +277,13 @@

Review Portfolio of {{selectedStudent.student.name}}

No Portfolio Submitted

- +
+ + +
@@ -260,8 +306,12 @@

Grade for {{selectedStudent.student.name}}

ng-class="{'no-rationale': project.gradeRationale == null}" ng-hide="editingRationale" > - -
+ +
Click to add one
From a2e8a9c1bef2f2cbf3a32683ee84302c061b90ef Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 18 Jun 2024 20:24:39 +1000 Subject: [PATCH 0125/1280] refactor: show consecutive scorm comments together --- .../api/models/task-comment/scorm-comment.ts | 3 ++ src/app/api/models/task.ts | 9 ++++ .../scorm-comment.component.html | 54 +++++++++++-------- .../scorm-comment.component.scss | 6 +-- .../scorm-comment/scorm-comment.component.ts | 4 -- 5 files changed, 44 insertions(+), 32 deletions(-) diff --git a/src/app/api/models/task-comment/scorm-comment.ts b/src/app/api/models/task-comment/scorm-comment.ts index 3356b62b93..b15a2c50c8 100644 --- a/src/app/api/models/task-comment/scorm-comment.ts +++ b/src/app/api/models/task-comment/scorm-comment.ts @@ -3,6 +3,9 @@ import {Task, TaskComment, TestAttempt} from '../doubtfire-model'; export class ScormComment extends TaskComment { testAttempt: TestAttempt; + // UI rendering data + lastInScormSeries: boolean = false; + constructor(task: Task) { super(task); } diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index 2cadc79d72..0643f99732 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -17,6 +17,7 @@ import { TaskSimilarityService, TestAttempt, TestAttemptService, + ScormComment, } from './doubtfire-model'; import {Grade} from './grade'; import {LOCALE_ID} from '@angular/core'; @@ -385,6 +386,14 @@ export class Task extends Entity { if (comments[i].replyToId) { comments[i].originalComment = comments.find((tc) => tc.id === comments[i].replyToId); } + + // Scorm series + if (comments[i].commentType === 'scorm') { + comments[i].firstInSeries = i === 0 || comments[i - 1].commentType !== 'scorm'; + (comments[i] as ScormComment).lastInScormSeries = + i + 1 === comments.length || comments[i + 1]?.commentType !== 'scorm'; + if (!comments[i].firstInSeries) comments[i].shouldShowTimestamp = false; + } } comments[comments.length - 1].shouldShowAvatar = true; diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html index c1dacaa788..edde1e057c 100644 --- a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html @@ -1,24 +1,32 @@ -
-
-
-
-
-
- - - -
-
-
-
+
+
+ +
+ + + + +
+
diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.scss b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.scss index 31df73023a..7bc5f74d91 100644 --- a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.scss +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.scss @@ -1,7 +1,3 @@ -div { - width: 100%; -} - p { color: #2c2c2c; text-align: center; @@ -14,7 +10,7 @@ hr { .hr-fade { background: linear-gradient(to right, transparent, #9696969d, transparent); width: 100%; - margin-top: 1px; + margin-top: 6px; } .hr-text { diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts index 87daf5b6ca..a16e397ad6 100644 --- a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts @@ -27,10 +27,6 @@ export class ScormCommentComponent { this.user = this.userService.currentUser; } - get canOverridePass(): boolean { - return this.user.isStaff && !this.comment.testAttempt.successStatus; - } - reviewScormTest() { window.open( `#/task_def_id/${this.task.taskDefId}/scorm-player/review/${this.comment.testAttempt.id}`, From b6887e85b7a06b166519924dd682ef57650a4e32 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 18 Jun 2024 20:46:43 +1000 Subject: [PATCH 0126/1280] fix: delete comment as well as test attempt --- .../scorm-comment/scorm-comment.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts index a16e397ad6..d26b914f7e 100644 --- a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts @@ -50,6 +50,7 @@ export class ScormCommentComponent { 'Are you sure you want to delete this test attempt? This action is final and will delete information associated with this test attempt.', () => { this.testAttemptService.deleteAttempt(this.comment.testAttempt.id); + this.comment.delete(); }, ); } From fd916b94e9012c0909c5880f377f93d326c18e4d Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 20 Jun 2024 22:09:57 +1000 Subject: [PATCH 0127/1280] fix: ensure portfolio can get grades from strings --- src/app/common/grade-icon/grade-icon.coffee | 2 +- src/app/common/services/grade.service.ts | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/common/grade-icon/grade-icon.coffee b/src/app/common/grade-icon/grade-icon.coffee index be0ed0b0c3..54480aff9f 100644 --- a/src/app/common/grade-icon/grade-icon.coffee +++ b/src/app/common/grade-icon/grade-icon.coffee @@ -9,7 +9,7 @@ angular.module('doubtfire.common.grade-icon', []) colorful: '=?' controller: ($scope, gradeService) -> $scope.$watch 'inputGrade', (newGrade) -> - $scope.grade = if _.isString($scope.inputGrade) then gradeService.grades.indexOf($scope.inputGrade) else $scope.inputGrade + $scope.grade = if _.isString($scope.inputGrade) then gradeService.stringToGrade($scope.inputGrade) else $scope.inputGrade $scope.gradeText = (grade) -> if $scope.grade? then gradeService.grades[$scope.grade] or "Grade" $scope.gradeLetter = (grade) -> diff --git a/src/app/common/services/grade.service.ts b/src/app/common/services/grade.service.ts index 619bad36f5..35e0f24f2a 100644 --- a/src/app/common/services/grade.service.ts +++ b/src/app/common/services/grade.service.ts @@ -16,6 +16,10 @@ export class GradeService { 3: 'High Distinction', }; + public stringToGrade(value: string): number { + return this.gradeViewData.find((grade) => grade.viewValue === value)?.value; + } + gradeViewData = [ {value: -1, viewValue: 'Fail'}, {value: 0, viewValue: 'Pass'}, From ce970f5fdc4f42708edc71c98dc9d869056e9e2c Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 21 Jun 2024 21:21:07 +1000 Subject: [PATCH 0128/1280] fix: ensure portfolio only shown when it exists --- src/app/units/states/portfolios/portfolios.tpl.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/units/states/portfolios/portfolios.tpl.html b/src/app/units/states/portfolios/portfolios.tpl.html index a51934b9a5..2b8a2277eb 100644 --- a/src/app/units/states/portfolios/portfolios.tpl.html +++ b/src/app/units/states/portfolios/portfolios.tpl.html @@ -277,7 +277,7 @@

Review Portfolio of {{selectedStudent.student.name}}

No Portfolio Submitted

-
+
Date: Fri, 21 Jun 2024 21:21:27 +1000 Subject: [PATCH 0129/1280] chore(release): 8.0.10 --- CHANGELOG.md | 326 ++++++++++++++++++++++++++++++++++++++++++++++ package-lock.json | 4 +- package.json | 2 +- 3 files changed, 329 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1ca7d64128..887dcb3746 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,332 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.10](https://github.com/macite/doubtfire-deploy/compare/v7.0.23...v8.0.10) (2024-06-21) + + +### Bug Fixes + +* ensure loading screen removed in sign in component ([729c438](https://github.com/macite/doubtfire-deploy/commit/729c438f7f6a988f5ff2fa4035493b5cae1c98f7)) +* ensure portfolio can get grades from strings ([fd916b9](https://github.com/macite/doubtfire-deploy/commit/fd916b94e9012c0909c5880f377f93d326c18e4d)) +* ensure portfolio only shown when it exists ([ce970f5](https://github.com/macite/doubtfire-deploy/commit/ce970f5fdc4f42708edc71c98dc9d869056e9e2c)) +* ensure tii open report alerts errors ([c5dd45c](https://github.com/macite/doubtfire-deploy/commit/c5dd45c57fd34e8373f11d065a0cd08edef0a794)) +* fix pdf viewer for portfolios ([da376b9](https://github.com/macite/doubtfire-deploy/commit/da376b9bc7905aadeb4d234cbb4f595e4c4424a1)) +* grade icon for portfolio page ([aab1b9c](https://github.com/macite/doubtfire-deploy/commit/aab1b9c3e7365cdf7dd64d767fdb6e5a9a2436a3)) +* show burndown and pie chart on portfolio page ([e70f4c7](https://github.com/macite/doubtfire-deploy/commit/e70f4c7cd1395eaab942ee389788f75f92e985c9)) + +### [8.0.9](https://github.com/macite/doubtfire-deploy/compare/v7.0.22...v8.0.9) (2024-05-31) + + +### Bug Fixes + +* comment out fix and complete hotkeys temporarily ([c1f623d](https://github.com/macite/doubtfire-deploy/commit/c1f623d17432f3563366ef32fc3da3b54dbef0b7)) + +### [8.0.8](https://github.com/macite/doubtfire-deploy/compare/v8.0.7...v8.0.8) (2024-05-30) + + +### Features + +* added percentage to tooltip when hovering student's task progress ([69ed613](https://github.com/macite/doubtfire-deploy/commit/69ed61380bd7681d4496cb109e628111873b6e82)) + + +### Bug Fixes + +* change from hiding element to not loading ([414da65](https://github.com/macite/doubtfire-deploy/commit/414da65fcef9b10367f53112239a60e1b271d475)) +* change grade values, change grade display ([081c35b](https://github.com/macite/doubtfire-deploy/commit/081c35ba0fbc7ab4ddb2fba3c58892d0e66f325c)) +* fix task inbox shortcuts ([9bc949f](https://github.com/macite/doubtfire-deploy/commit/9bc949fd6dcb71ea165e89de9a4ec9d9347e6562)) +* inbox search box width ([02a99a8](https://github.com/macite/doubtfire-deploy/commit/02a99a8f71033014b26260d3b0dbfca075ca7273)) +* remove pdf viewer on task view when no sheet ([f3e973d](https://github.com/macite/doubtfire-deploy/commit/f3e973dacc5b079ab58da239194d802c5586ca07)) +* revert index changes, html changes for grade ([8f41cd1](https://github.com/macite/doubtfire-deploy/commit/8f41cd1656971963c2035a9249acdde0a257766e)) +* task list scrolling ([0088e9e](https://github.com/macite/doubtfire-deploy/commit/0088e9e245dbd326dea4032239b53eee88754179)) +* use tailwind classes instead of css styling ([42434a5](https://github.com/macite/doubtfire-deploy/commit/42434a5fd4b866781da5d23ecdb0b9b4369aace1)) + +### [8.0.7](https://github.com/macite/doubtfire-deploy/compare/v8.0.6...v8.0.7) (2024-05-26) + + +### Bug Fixes + +* add task description editing ([ee0cfbf](https://github.com/macite/doubtfire-deploy/commit/ee0cfbf7ce804a1806ca5810bad138b97703ebfe)) + +### [8.0.6](https://github.com/macite/doubtfire-deploy/compare/v8.0.5...v8.0.6) (2024-05-25) + + +### Bug Fixes + +* ensure all admin units are fully loaded ([917325e](https://github.com/macite/doubtfire-deploy/commit/917325ed08b89690a7eea0716438673732ba1ec9)) + +### [8.0.5](https://github.com/macite/doubtfire-deploy/compare/v8.0.4...v8.0.5) (2024-05-25) + + +### Bug Fixes + +* ensure (click) is on button, not mat-icon ([99c717d](https://github.com/macite/doubtfire-deploy/commit/99c717d2333de0975da1b3f282195a0b3577a3f6)) + +### [8.0.4](https://github.com/macite/doubtfire-deploy/compare/v8.0.3...v8.0.4) (2024-05-25) + + +### Bug Fixes + +* fix various issues with admin unit list ([3720666](https://github.com/macite/doubtfire-deploy/commit/3720666fb4105bac274449eb468ce34e0f68bae7)) + +### [8.0.3](https://github.com/macite/doubtfire-deploy/compare/v8.0.2...v8.0.3) (2024-05-25) + + +### Features + +* add 4-character abbreviations ([eb62dfc](https://github.com/macite/doubtfire-deploy/commit/eb62dfc90db836870d6c396727fc43c149808e9d)) + +### [8.0.2](https://github.com/macite/doubtfire-deploy/compare/v8.0.1...v8.0.2) (2024-05-25) + + +### Bug Fixes + +* gradeservice bugs ([fd6eb1c](https://github.com/macite/doubtfire-deploy/commit/fd6eb1cd152b72cf297cbd6bd529579858afc543)) +* gradeservice bugs ([7545eb9](https://github.com/macite/doubtfire-deploy/commit/7545eb92b9353d99ac8d8d7d89982cdadf9688b1)) + +### [8.0.1](https://github.com/macite/doubtfire-deploy/compare/v8.0.0...v8.0.1) (2024-05-24) + + +### Features + +* implement live PDF search that updates dynamically as you type ([b9b9945](https://github.com/macite/doubtfire-deploy/commit/b9b9945346d55392e5ee9a6431d85ae92de1bde5)) + + +### Bug Fixes + +* fix critical bugs ([356846e](https://github.com/macite/doubtfire-deploy/commit/356846e5c385c484a6034553366965cde95ec78b)) +* fix splashscreen ([2692b7f](https://github.com/macite/doubtfire-deploy/commit/2692b7f4a3e1ca2a5bc4df3b82a9dfd4aa2ec68a)) + +## [8.0.0](https://github.com/macite/doubtfire-deploy/compare/v8.0.0-6...v8.0.0) (2024-05-23) + + +### Features + +* add multi-badge support ([44c1473](https://github.com/macite/doubtfire-deploy/commit/44c1473700a3d7a4a025d68acac5aa61189d8b52)) +* add synchronised multi-badge ([f70ebdc](https://github.com/macite/doubtfire-deploy/commit/f70ebdca92a05e5ca350d4062a8dc8efba9fd681)) +* add working unit-badge ([dd30247](https://github.com/macite/doubtfire-deploy/commit/dd302478e97228e6bfbfdbee0134abb3eabf2587)) +* add working unit-badge ([c7338ff](https://github.com/macite/doubtfire-deploy/commit/c7338ffd88edb457a3443b43ea21706c43231973)) +* qol improvements for unit codes ([f7f928e](https://github.com/macite/doubtfire-deploy/commit/f7f928e485448a69b054dca94f07d623f84e328f)) +* small fixes to home and unit code ([918e804](https://github.com/macite/doubtfire-deploy/commit/918e8047745b489aae1fafdc67720568dd8d829e)) + + +### Bug Fixes + +* add missing imports ([659b52c](https://github.com/macite/doubtfire-deploy/commit/659b52c82a26b9496a3dba81401b5147d05248ae)) +* change time exceeded to feedback exceeded ([673619d](https://github.com/macite/doubtfire-deploy/commit/673619d99f177d834fba3643171426092e0d05e0)) +* correct task resource upload actions ([5e9c9b1](https://github.com/macite/doubtfire-deploy/commit/5e9c9b1d05d6d6975fd4ba3a3176314ddd7d8514)) +* ensure loading state changed after projects and unit roles load ([9171d0c](https://github.com/macite/doubtfire-deploy/commit/9171d0c2c37c17d26f464f6aa0ba7c479851e6eb)) +* ensure staff task list checks unit exists ([dbb312d](https://github.com/macite/doubtfire-deploy/commit/dbb312dc3c5c9e2be24161914e8d95e1a5c1bc53)) +* ensure unit load updates unit object if it already exists ([e48ffad](https://github.com/macite/doubtfire-deploy/commit/e48ffadf63891212c3e40ab696d54a3935485b08)) +* hide overseer settings if automation disabled ([0c08fe3](https://github.com/macite/doubtfire-deploy/commit/0c08fe3e82a78dd1e91fb44ce6008fb5298c46ee)) +* slide unit code off left side ([8cd57b5](https://github.com/macite/doubtfire-deploy/commit/8cd57b589812fd59c6da4de02246791fb4410959)) +* sort units desc by start date ([9b78856](https://github.com/macite/doubtfire-deploy/commit/9b788561372a3ddf065d3b28e547a2194ef29655)) +* zip upload for overseer ([5ad2085](https://github.com/macite/doubtfire-deploy/commit/5ad2085b2d730235f61e7b7c603727d8b6736cf2)) + +## [8.0.0-6](https://github.com/macite/doubtfire-deploy/compare/v8.0.0-5...v8.0.0-6) (2024-05-13) + +## [8.0.0-5](https://github.com/macite/doubtfire-deploy/compare/v8.0.0-4...v8.0.0-5) (2024-05-13) + +## [8.0.0-4](https://github.com/macite/doubtfire-deploy/compare/v8.0.0-3...v8.0.0-4) (2024-05-11) + + +### Features + +* add task badge ([b48cd4c](https://github.com/macite/doubtfire-deploy/commit/b48cd4c99333e41c0c1d32531e571d32bb482a81)) + + +### Bug Fixes + +* (WIP) fix alert service migration ([3d9f4dc](https://github.com/macite/doubtfire-deploy/commit/3d9f4dc05e7a45884dc383e0f5ed4bdb09b0558d)) +* add max length validator and change reason field to text-area ([6227200](https://github.com/macite/doubtfire-deploy/commit/6227200566c3f608c279e92a3f255a7e94148c1d)) +* address linter issues in task.ts ([14e9699](https://github.com/macite/doubtfire-deploy/commit/14e9699bdfe336f1e3f3cce3d722c835d58f3cdb)) +* copy dist browser to nginx html ([08fa919](https://github.com/macite/doubtfire-deploy/commit/08fa91937e028cb3ee093709e5a31f94da44fc33)) +* correct filenames for grotesk fonts ([9bedd81](https://github.com/macite/doubtfire-deploy/commit/9bedd812b12628df9cb32e48cb91a88b5cdf69b1)) +* ensure eula state remains visible ([131540c](https://github.com/macite/doubtfire-deploy/commit/131540ca4b934773afd9f72aa2578579048ed6a2)) +* ensure unit admin shows all units ([02b7a15](https://github.com/macite/doubtfire-deploy/commit/02b7a15bbbd2306a61e344f995dffb72a3915498)) +* fix course progress bar on firefox ([ae5c1e0](https://github.com/macite/doubtfire-deploy/commit/ae5c1e0b5901bae0411cf7bbaa32ee8f340b908a)) +* fix incorrect projcets listed in dropdown ([6a7e478](https://github.com/macite/doubtfire-deploy/commit/6a7e4788b522e5af6331a82ed33e9c9137d2ca86)) +* fix margin issue on dropdown ([c8145f0](https://github.com/macite/doubtfire-deploy/commit/c8145f0972a03e52377e0203cabb2cf6353db8b3)) +* grade and quality point display on task-assessment-card ([7cba502](https://github.com/macite/doubtfire-deploy/commit/7cba502e002143e8255bf0d786551bd270f73f0e)) +* indicate mandatory fields in upload-submission-modal ([e8801e2](https://github.com/macite/doubtfire-deploy/commit/e8801e2a64fe15ad423d9017d10e5e23f6e00eda)) +* only check grade if it exists ([1c213c5](https://github.com/macite/doubtfire-deploy/commit/1c213c53571f79563e9a071e2dd9645598382522)) +* remove unused imports in extension-modal.service ([8081f51](https://github.com/macite/doubtfire-deploy/commit/8081f51b5f28ea511b9f76d026ae63f16153ae2c)) +* use tailwindcss classes ([8d7e160](https://github.com/macite/doubtfire-deploy/commit/8d7e160e2d40c42284ee0c1fc85d6d9e01166cda)) + +## [8.0.0-3](https://github.com/macite/doubtfire-deploy/compare/v8.0.0-2...v8.0.0-3) (2024-05-02) + + +### Bug Fixes + +* reenable eula html fetch ([cda9e52](https://github.com/macite/doubtfire-deploy/commit/cda9e52a259bfaa27e8252f40e579d11d1af280c)) + +## [8.0.0-2](https://github.com/macite/doubtfire-deploy/compare/v7.0.21...v8.0.0-2) (2024-05-01) + + +### Features + +* accept promela files ([df93a69](https://github.com/macite/doubtfire-deploy/commit/df93a69e45d2d9e41b9cf0802d521a3663d7a36c)) +* migrate unit list in all locations ([6651d00](https://github.com/macite/doubtfire-deploy/commit/6651d0011446fdde7179c5173f902ce2e4ea7545)) +* remove misleading progress statement ([63e276c](https://github.com/macite/doubtfire-deploy/commit/63e276c041f77d8b401d24a4f49896cfa2095442)) + + +### Bug Fixes + +* correct change detection on task def ([55daff2](https://github.com/macite/doubtfire-deploy/commit/55daff234441a242d96de097c2b2912df0c6c9a8)) +* correct npm install for dev container image ([5126c3b](https://github.com/macite/doubtfire-deploy/commit/5126c3ba7fed55217e88c54c25dc70595ec4c666)) +* ensure npm will force install ([f91751e](https://github.com/macite/doubtfire-deploy/commit/f91751eae788bc3f65d33b610ed80c96d3978974)) +* fix firefox-specific bug ([6b6054b](https://github.com/macite/doubtfire-deploy/commit/6b6054bd5c1104a96ccac413a7115009eeba8d2f)) +* remove ngClass ([d1d8c72](https://github.com/macite/doubtfire-deploy/commit/d1d8c72ace21551a68bd4d0a8ba88eabb2ebdb9d)) +* remove plagiarism checks ([21b02fb](https://github.com/macite/doubtfire-deploy/commit/21b02fb7cc616090f1fb2d26f65b336072f9105b)) +* remove the incorrect option from for scrollIntoView() ([9e752fe](https://github.com/macite/doubtfire-deploy/commit/9e752fe9d49df786ceb3e7007cbf0aad57809604)) +* remove unused loading from f-units ([c4c38fa](https://github.com/macite/doubtfire-deploy/commit/c4c38fad4fbdfe248e383cf247f949197ad0a047)) +* typo ([820c56f](https://github.com/macite/doubtfire-deploy/commit/820c56f3a1bc30b7637b98e6f80b406ca350b5b8)) + +## [8.0.0-1](https://github.com/macite/doubtfire-deploy/compare/v8.0.0-0...v8.0.0-1) (2024-03-21) + + +### Bug Fixes + +* update deploy dockerfile ([41a5161](https://github.com/macite/doubtfire-deploy/commit/41a5161b356931eafd8e4caf256f311f10bc8bb4)) + +## [8.0.0-0](https://github.com/macite/doubtfire-deploy/compare/v7.0.18...v8.0.0-0) (2024-03-21) + + +### Features + +* (wip) add similarities notification ([8e4a198](https://github.com/macite/doubtfire-deploy/commit/8e4a198a037de832bbebe96e309c4c8485d076cc)) +* add ability to accept tii eula to model ([0106b01](https://github.com/macite/doubtfire-deploy/commit/0106b01ed249139cbe06096f95a36b5d11bcd0ac)) +* add ability to accept turn it in eula ([380ad1e](https://github.com/macite/doubtfire-deploy/commit/380ad1e93252f8f928893626b65f4dab01813524)) +* add ability to open turnitin viewer ([5248e80](https://github.com/macite/doubtfire-deploy/commit/5248e80622e55b79ce4d7b35f8202ee8099c2dce)) +* add ability to update similarity flag ([de005ee](https://github.com/macite/doubtfire-deploy/commit/de005ee98a270998e2175109783cab72b92e36f3)) +* add dynamic footer ([3c62fe0](https://github.com/macite/doubtfire-deploy/commit/3c62fe06d009c3b752259f50887c625c98a371cd)) +* add empty pdf view to new task dashboard ([9c3cdfb](https://github.com/macite/doubtfire-deploy/commit/9c3cdfbb93711a6ae911ed461651200d8c75db48)) +* add file drop component ([c211003](https://github.com/macite/doubtfire-deploy/commit/c211003004ae6c7505158a65ce2006b219920827)) +* add footer content ([735c43b](https://github.com/macite/doubtfire-deploy/commit/735c43b5c2df7e8f367310ad92ef716fd5140375)) +* add link to student task from inbox ([d4301e0](https://github.com/macite/doubtfire-deploy/commit/d4301e0d1f2f6ec4c563801a7f0d1132884f9989)) +* add mobile inbox view ([56ded70](https://github.com/macite/doubtfire-deploy/commit/56ded707e638ae769665a863ce65acffea5a588a)) +* add multi-file support to f-upload ([d181969](https://github.com/macite/doubtfire-deploy/commit/d181969198e2b7611e3f0e330577b825e99a248f)) +* add new file upload component ([891ab20](https://github.com/macite/doubtfire-deploy/commit/891ab20eb6f1d545ff58d0157fdd9912b9546c9f)) +* add new inbox component ([ec0f62c](https://github.com/macite/doubtfire-deploy/commit/ec0f62c488ae3e99e9487ea1ab87f5bb2f1fbed7)) +* add new pdf-viewer ([617fbd2](https://github.com/macite/doubtfire-deploy/commit/617fbd24f8424541aeb87b16651f06737b570633)) +* add new similarity component ([48ba01c](https://github.com/macite/doubtfire-deploy/commit/48ba01c8d780a04a1f526f89fcd9bc63ef5d4aec)) +* add new task assessment card ([ac3b50f](https://github.com/macite/doubtfire-deploy/commit/ac3b50f29b8a2722d09ad94a2f82bb54c1c32da7)) +* add new task dashboard component ([dc841f9](https://github.com/macite/doubtfire-deploy/commit/dc841f9e7af811a3a56a0c21fd3b3968ec7aead9)) +* add new task due card ([3ade5ea](https://github.com/macite/doubtfire-deploy/commit/3ade5ea34eb3c2c756d7df0f7a6c250fa50290bb)) +* add new task due card content ([c43ea3e](https://github.com/macite/doubtfire-deploy/commit/c43ea3e27abdf253596bfedd5112f5ef7a7b929d)) +* add new task submission card ([6d27690](https://github.com/macite/doubtfire-deploy/commit/6d2769029413f84b73c7c825d16e9a3366142177)) +* add pdf search and zoom ([f83ce57](https://github.com/macite/doubtfire-deploy/commit/f83ce570e80dc20d118288c6d32c2d2a9ca263b5)) +* add resizable inbox panels ([4920e31](https://github.com/macite/doubtfire-deploy/commit/4920e31ce366c3dfb4340ab4da159b176381cf49)) +* add resizable panels to inbox ([5abda03](https://github.com/macite/doubtfire-deploy/commit/5abda039af5b2d3b5e2589c4864b2e1715c5e8c0)) +* add rest of layout to footer ([3b9de7c](https://github.com/macite/doubtfire-deploy/commit/3b9de7cc6d923a0e6431524f2967b5e3bc360a6f)) +* add selected task sheet url ([00a7fb5](https://github.com/macite/doubtfire-deploy/commit/00a7fb516d362d3725b915d012878a9ccf8ef009)) +* add selectedTask service ([02aa41a](https://github.com/macite/doubtfire-deploy/commit/02aa41a34232359d1366d841d1236a068a837ae5)) +* add similarities staff dashboard switch ([1ec0b72](https://github.com/macite/doubtfire-deploy/commit/1ec0b72c26cc27bd4d17376af5b47650d28bbc10)) +* add similarity flags to view ([8c7975c](https://github.com/macite/doubtfire-deploy/commit/8c7975cadd14e6d3390cfa9917983cd01498a69c)) +* add simple project progress bar ([73fda77](https://github.com/macite/doubtfire-deploy/commit/73fda776ee36c6574c1ddc0dc09b958d61de3000)) +* add start of new similarity view ([a1e51b6](https://github.com/macite/doubtfire-deploy/commit/a1e51b6bc7030086a1d7a4d715f23b3e76f7ddb3)) +* add task plagairism warning on inbox ([6bd8620](https://github.com/macite/doubtfire-deploy/commit/6bd8620f5473db4517e38fd0487ab5876f921a36)) +* add teaching period remove break function ([90c6a37](https://github.com/macite/doubtfire-deploy/commit/90c6a3730f84da9e64abec676bcdf66c10b7fc60)) +* add tii action log ([96d982d](https://github.com/macite/doubtfire-deploy/commit/96d982d5fb945bdbf9ea8b6d534a5dd18ab64ad7)) +* add unselected user icon badge in inbox ([794697b](https://github.com/macite/doubtfire-deploy/commit/794697b53d6ee81f57b37b173d03a0688c6993b5)) +* complete mobile task inbox view ([00a4b3f](https://github.com/macite/doubtfire-deploy/commit/00a4b3f1e8f52364a83b6affae34295da4a7af34)) +* disable hover on task inbox for mobile ([a59fd01](https://github.com/macite/doubtfire-deploy/commit/a59fd0153de8b1f9e9b9022d0f6df1032c92f8d1)) +* downgrade task due card ([c342ac2](https://github.com/macite/doubtfire-deploy/commit/c342ac2e3cc4213c2b92499bc4a191485184af37)) +* enhance task search with similarity flags ([65ad918](https://github.com/macite/doubtfire-deploy/commit/65ad91842882e76379033350f90b966d874c6ba4)) +* enhance ui/ux of task inbox screen ([6b275c3](https://github.com/macite/doubtfire-deploy/commit/6b275c3cd5d575a399e901d52a62808238c6d0e4)) +* expand new file uplaoder ([11d798d](https://github.com/macite/doubtfire-deploy/commit/11d798d6a6e5eca4555a7d141e1d11d2a862fcfe)) +* finish new alerts service ([3beb059](https://github.com/macite/doubtfire-deploy/commit/3beb05987e605c9f4270fc0d7bdd95f82bf64007)) +* make all datetime in aus format ([7a0f749](https://github.com/macite/doubtfire-deploy/commit/7a0f749a4328a44c1ffb5692017dfa39a061e1d5)) +* migrate new unit dialog ([0a2a1e9](https://github.com/macite/doubtfire-deploy/commit/0a2a1e9baca6b0553730c1a939b246bf1be178a3)) +* minor improvements to file-drop ([73139be](https://github.com/macite/doubtfire-deploy/commit/73139be83449f50036eedb3520ed2d8daa5da09c)) +* new footer component ([c3b4c18](https://github.com/macite/doubtfire-deploy/commit/c3b4c182921079d6ebc0851ec7e6515e65f1c15b)) +* new grade service ([31073e1](https://github.com/macite/doubtfire-deploy/commit/31073e1dbe963c1e0f2c84139a2c3f746cc31bbb)) +* new student user badge ([97c84d3](https://github.com/macite/doubtfire-deploy/commit/97c84d3016b0e322d54062fae0d46da112146d5d)) +* new task status card ([78218cf](https://github.com/macite/doubtfire-deploy/commit/78218cf6d45f5cac50203f96109d27400fa37686)) +* only download similarity resource on view ([563d102](https://github.com/macite/doubtfire-deploy/commit/563d1024ee7023e4228a9ceef9f556e48e7127d1)) +* progress redesigned inbox ([f1b672b](https://github.com/macite/doubtfire-deploy/commit/f1b672b7495a9086abb88f5e1991cb4c4f7b60c1)) +* register new inbox component ([3d79baa](https://github.com/macite/doubtfire-deploy/commit/3d79baae505e44c401179ae34de4804e8d90b7ba)) +* show TII accepted status in profile ([7b5c3e2](https://github.com/macite/doubtfire-deploy/commit/7b5c3e2c0fe9fcc30f9fffc73d9a942714db7cb2)) +* small change to task view ([f640920](https://github.com/macite/doubtfire-deploy/commit/f6409201e9d4af4f075b4db8559fc1e26f4a374f)) +* small changes to user table ([18957ac](https://github.com/macite/doubtfire-deploy/commit/18957acfc700e941ebb161d9ddb8f5e1ebe1beff)) +* trigger window resize when pdf loads ([044c170](https://github.com/macite/doubtfire-deploy/commit/044c170ebe05e7e3a368df2e8041884d2e23c752)) +* update file viewer to use file download and blobs ([8751123](https://github.com/macite/doubtfire-deploy/commit/87511232ca384a355ddfc5eb396186babd676f92)) +* wip add file uploader component ([48c73f5](https://github.com/macite/doubtfire-deploy/commit/48c73f547892ae3ce12fdac416bf93c3a2c72006)) + + +### Bug Fixes + +* add activeUntil date mapping to tps ([2cae20a](https://github.com/macite/doubtfire-deploy/commit/2cae20a6b3fa3e5ea8a001ffa40a87263c438b68)) +* add arbitrary task argument to `togglePin` in task inbox ([6e1784f](https://github.com/macite/doubtfire-deploy/commit/6e1784ff52a745330e57f2ccc2a55b3206d535d0)) +* add seperator to naviation on mobile ([fc4f052](https://github.com/macite/doubtfire-deploy/commit/fc4f0527b144fd8f3b6e98b335e629f85fe1bb3b)) +* add the correct enterkeyhint to the comment composer ([569db05](https://github.com/macite/doubtfire-deploy/commit/569db059fc9786363b1b62d7be72e44f711faba3)) +* add unloaded state to progressbar ([2c3a28e](https://github.com/macite/doubtfire-deploy/commit/2c3a28e9718879f55596221517db35bda8c09450)) +* adjust due card layout ([0360a6e](https://github.com/macite/doubtfire-deploy/commit/0360a6e0868e995d7ba5c9091be556dad4bfd474)) +* always display shortened task name in header ([a05c8ff](https://github.com/macite/doubtfire-deploy/commit/a05c8ffd9aef9c865f72458157b465f9de1e07f3)) +* center pins along items in new task inbox ([6b3c0d2](https://github.com/macite/doubtfire-deploy/commit/6b3c0d2b1d5541fe36c6fbd03dfc752f43d03e18)) +* center placeholder text in task inbox search bar & reduce padding on far-right ([ffec9b6](https://github.com/macite/doubtfire-deploy/commit/ffec9b6f4bfc9d2aee6aa762c41bcce1ed1823ba)) +* center student and task name on bottom left screen ([e986199](https://github.com/macite/doubtfire-deploy/commit/e9861992e9e5a40076973a2215bcc919c1777b5d)) +* center view all units button on home page ([9807dfd](https://github.com/macite/doubtfire-deploy/commit/9807dfd1f18e1efc9f882a67ef99f1d198a03ff7)) +* centering of Administration icons on home page ([1043f74](https://github.com/macite/doubtfire-deploy/commit/1043f74e2ca5d23cad8c4d890a202b20ddb4bc37)) +* change display name of student on bottom left screen from being nickname to full name ([5fe7790](https://github.com/macite/doubtfire-deploy/commit/5fe7790e23aec709f8be5a444bf84ebdf77c9ce5)) +* change shown name on messages in chat to be student's full name ([93636c4](https://github.com/macite/doubtfire-deploy/commit/93636c400c1850e20320a57be010347541c5137c)) +* chatbox spacing, placement of messages <> photos, distance between message & name ([dd9cb2a](https://github.com/macite/doubtfire-deploy/commit/dd9cb2ab3bdde886c2f297d8044986427febd366)) +* ensure accepted TII eula details are retained ([e60ae54](https://github.com/macite/doubtfire-deploy/commit/e60ae547121f33edd7cc8d8c5d4afd27a1f90e8c)) +* ensure blobs are freed on destroy ([ee017eb](https://github.com/macite/doubtfire-deploy/commit/ee017eb00a506c81a108ce6dec52f7f91064d350)) +* ensure font is set to roboto ([a6ff4ce](https://github.com/macite/doubtfire-deploy/commit/a6ff4cee9794e37a208af28d7d085182441fa555)) +* ensure loadedUnitRoles is public in global ([b92159f](https://github.com/macite/doubtfire-deploy/commit/b92159ff33cf9537c0ccec50d57a54636315bec4)) +* ensure logout in timeout always signs out ([3380075](https://github.com/macite/doubtfire-deploy/commit/33800759083156682014f0f63bc83a0283ae96fa)) +* ensure mat menu icons have correct tags ([f971ad1](https://github.com/macite/doubtfire-deploy/commit/f971ad1cf7fa56de0f4e97e9533a0567db897da4)) +* ensure only staff need to accept turn it in EULA ([029c40b](https://github.com/macite/doubtfire-deploy/commit/029c40b556bb1709e75547615b2d1a1109997a74)) +* ensure pdf actions loads after pdf loaded ([0425c54](https://github.com/macite/doubtfire-deploy/commit/0425c5465a678509e1a8d719fef39975c4d8e9e5)) +* ensure similarities without files still view ([5794e2f](https://github.com/macite/doubtfire-deploy/commit/5794e2fb345328396517a7d2f945cfabb1c37173)) +* ensure task pdf viewer works ([d3d1bf8](https://github.com/macite/doubtfire-deploy/commit/d3d1bf8564c6e6134130b44df90bef42430f4654)) +* ensure task submission status updated on init ([ca77c92](https://github.com/macite/doubtfire-deploy/commit/ca77c92d251bf4087964886579de642f6f300b9a)) +* ensure that timeout state not re-routed ([c16ee90](https://github.com/macite/doubtfire-deploy/commit/c16ee90c2c372ea1889d3470e2be510aefd2245f)) +* ensure welcome page still can go to timeout ([5253f2e](https://github.com/macite/doubtfire-deploy/commit/5253f2eb6fce1de1b6df585589f1cc2594ac87a8)) +* excessive spacing below unit tags on home page ([1bfaa21](https://github.com/macite/doubtfire-deploy/commit/1bfaa216440d880d82875f519e9b3f0f59ddcc23)) +* fix few type errors ([8a96e5b](https://github.com/macite/doubtfire-deploy/commit/8a96e5b33a095cd70222719b33d7dc853d67f347)) +* fix file drop to support click to upload ([599cd9e](https://github.com/macite/doubtfire-deploy/commit/599cd9e82c1518113374f0675fc54dd1483fcc85)) +* fix footer height not resetting on similarity ([19c43d7](https://github.com/macite/doubtfire-deploy/commit/19c43d7945c5848d1ca511e146fefdfa9735c49b)) +* fix incorrect closing tag ([ad28818](https://github.com/macite/doubtfire-deploy/commit/ad28818fba9dac552a2adf14785c5bbf98b4e206)) +* fix page height recalculation trigger ([8f219c3](https://github.com/macite/doubtfire-deploy/commit/8f219c31e9a3461626a9344352c4d7aa68c57c43)) +* fix various build issues ([8b947ae](https://github.com/macite/doubtfire-deploy/commit/8b947aeea1cb0dfa4bac8e22ff5bdb2a9a82ec49)) +* fix various task comment composer/display issues ([5670bf1](https://github.com/macite/doubtfire-deploy/commit/5670bf1dcd77e8010fe88bf24662ec96e4e29847)) +* hide extension for staff if can't apply ([1699e50](https://github.com/macite/doubtfire-deploy/commit/1699e50f2d7424361e0f7d5a173bdd9fffd87c24)) +* initialise inbox on return ([1249e96](https://github.com/macite/doubtfire-deploy/commit/1249e96f53ef9544cd81e3f2c3f1d5acf4a628f3)) +* initialise inbox view ([1ae4ac9](https://github.com/macite/doubtfire-deploy/commit/1ae4ac9b304348f5528368d87ded3c26e8e5cf40)) +* issues with UI in photo spacing and text alignment ([716ead3](https://github.com/macite/doubtfire-deploy/commit/716ead3497a8a2ecd1050484bd289c003a47dffa)) +* make photo in chatbox fall to bottom ([aa4e814](https://github.com/macite/doubtfire-deploy/commit/aa4e81446546f1e62b08fd74ba8ac1e563e5efc8)) +* make read receipt smaller to fix message alignment ([c869458](https://github.com/macite/doubtfire-deploy/commit/c869458cd45334e009ae83ab3c911033bc1987b9)) +* null input checks on migrated cards ([7a192af](https://github.com/macite/doubtfire-deploy/commit/7a192af22bf1eef026d05a16edcc3a97c6abbebf)) +* pass selected task to footer's user icon ([28782b1](https://github.com/macite/doubtfire-deploy/commit/28782b134cb03f5c334df48e8887f81393661bda)) +* photo from below message to being inline ([0e97a03](https://github.com/macite/doubtfire-deploy/commit/0e97a03a491f4137ec301dd18a42130a845ebe37)) +* reduce user badge clickable region ([7305f86](https://github.com/macite/doubtfire-deploy/commit/7305f866a9582e10dd870fad1861de4ce209a4e0)) +* regenerate user icons on input changes ([257ab4e](https://github.com/macite/doubtfire-deploy/commit/257ab4eb63ec15de545193f8b60176ac33e17b01)) +* remove call to teaching period name ([1e2e019](https://github.com/macite/doubtfire-deploy/commit/1e2e0198a32acd59c11932fde2a2f14a5bacf48f)) +* remove dupe case in transition hook ([9808798](https://github.com/macite/doubtfire-deploy/commit/98087981e06296a1eb9a17f527c49ab9b27caef3)) +* remove incorrect aria hidden tags ([46bfe21](https://github.com/macite/doubtfire-deploy/commit/46bfe2109e4b912a146201572671ff759fc02226)) +* remove no PDF text from overlapping with icon ([c6543cf](https://github.com/macite/doubtfire-deploy/commit/c6543cf2f9be9644b7382eeb64699e15e461447a)) +* remove old teaching periods from home ([4f4a617](https://github.com/macite/doubtfire-deploy/commit/4f4a6175f39ac9df75c7efe920ffcc15576cc98e)) +* remove pct copy data ([6bb96b4](https://github.com/macite/doubtfire-deploy/commit/6bb96b49f436a7d4bd6f5e587b30a8528e6d75b7)) +* remove user badge from old task panel ([9129956](https://github.com/macite/doubtfire-deploy/commit/9129956f41b78a8e3e84ffe9a124a7941d8905c1)) +* require eula for any user ([daf7ba9](https://github.com/macite/doubtfire-deploy/commit/daf7ba9d9056c262cafc871b623c59a0ef837274)) +* resolved issue with intelligent discussion ([18cd1fc](https://github.com/macite/doubtfire-deploy/commit/18cd1fc6f0443c353fc5f49c81dafd2428901cbc)) +* resolved issue with intelligent-discussion-dialog component rendering ([1efa758](https://github.com/macite/doubtfire-deploy/commit/1efa758fd813751788cc79fe30e01ca8a09013d8)) +* shrink header menu on small screens ([580445d](https://github.com/macite/doubtfire-deploy/commit/580445d25573bf00671246269c61685917c34867)) +* spacing (of own/person messaging) is now right/left aligned respectively ([7d10aa0](https://github.com/macite/doubtfire-deploy/commit/7d10aa0f58e2d7c8e8fd45439d8c464fabe3508c)) +* split header onto seperate lines on small screens ([d8a9016](https://github.com/macite/doubtfire-deploy/commit/d8a90168e58ef8d71f31f76d999d4f6a59232987)) +* switch max pct to similarity flag in project ([094b418](https://github.com/macite/doubtfire-deploy/commit/094b418c1bff709e755bf7c61207ebf22bfc6106)) +* task explorer 405 error ([7ea516c](https://github.com/macite/doubtfire-deploy/commit/7ea516ce8e346d46e8acf68c8b41fa81485515ba)) +* task submission pdf downloading ([b0becb4](https://github.com/macite/doubtfire-deploy/commit/b0becb4c76e4e45f10782561a6b53a322eb43665)) +* tweak theme.scss file ([393770b](https://github.com/macite/doubtfire-deploy/commit/393770b35d1688d27bce47e1d6b94735a1822494)) +* update package lock ([674f3c7](https://github.com/macite/doubtfire-deploy/commit/674f3c70bd0a4c8c33e25d34beeab76c29f56325)) +* use angular 15 ([d0104cc](https://github.com/macite/doubtfire-deploy/commit/d0104cc57edda68a1a165bdf1fd7cf75bd74ec68)) +* use correct task object in task pinning ([a5fceb0](https://github.com/macite/doubtfire-deploy/commit/a5fceb048b931dbd5ccc3ad5d4fd898b146284fb)) +* use correct theming import ([b0d3232](https://github.com/macite/doubtfire-deploy/commit/b0d3232eaed2096296cf025437dda26ddcd595e0)) +* use disabled blinding ([628ca55](https://github.com/macite/doubtfire-deploy/commit/628ca55b4e8f569f751b78ead7a50fa9e086ccec)) +* use new state name in task dropdown ([3c2fe44](https://github.com/macite/doubtfire-deploy/commit/3c2fe444d398bcedb5c998a47683d04279996680)) +* use onChanges rather than input setter ([8069c21](https://github.com/macite/doubtfire-deploy/commit/8069c21d9ecfc412dea37cade8e8a37e79730f01)) + ### [8.0.9](https://github.com/doubtfire-lms/doubtfire-deploy/compare/v8.0.8...v8.0.9) (2024-05-31) diff --git a/package-lock.json b/package-lock.json index 396f5fee98..5ec5842fc2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "8.0.9", + "version": "8.0.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "8.0.9", + "version": "8.0.10", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 13d95e9bc7..a6af7f3bba 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "8.0.9", + "version": "8.0.10", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 2f91e8fbba7902e1e22871cc82c87f4ff797b058 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 24 Jun 2024 13:28:40 +1000 Subject: [PATCH 0130/1280] fix: task date picker allows direct entry --- src/app/api/services/mapping-fn.ts | 39 ++++++++++++++++++----------- src/app/doubtfire-angular.module.ts | 18 ++++++++++++- 2 files changed, 42 insertions(+), 15 deletions(-) diff --git a/src/app/api/services/mapping-fn.ts b/src/app/api/services/mapping-fn.ts index 7302bb387f..9124152095 100644 --- a/src/app/api/services/mapping-fn.ts +++ b/src/app/api/services/mapping-fn.ts @@ -1,23 +1,34 @@ +import moment from 'moment'; + export class MappingFunctions { - public static mapDateToEndOfDay(data, key, entity, params?) { + public static mapDateToEndOfDay(data, key, _entity, _params?) { const jsonDate = new Date(data[key]); - return new Date(jsonDate.getFullYear(), jsonDate.getMonth(), jsonDate.getDate(), 23, 59, 59, 999); + return new Date( + jsonDate.getFullYear(), + jsonDate.getMonth(), + jsonDate.getDate(), + 23, // all dates map to end of day + 59, + 59, + 999, + ); } - public static mapDateToDay(data, key, entity, params?) { + public static mapDateToDay(data, key: string, _entity, _params?) { const jsonDate = new Date(data[key]); return new Date(jsonDate.getFullYear(), jsonDate.getMonth(), jsonDate.getDate()); } - public static mapDate(data, key, entity, params?) { + public static mapDate(data, key: string, _entity, _params?) { return new Date(data[key]); } public static mapDayToJson(entity: T, key: string): string { if (entity[key]) { - const month = entity[key].getMonth() + 1; - const day = entity[key].getDate(); - return `${entity[key].getFullYear()}-${month < 10 ? '0' : ''}${month}-${day < 10 ? '0' : ''}${day}`; + const dateValue = moment.isMoment(entity[key]) ? entity[key].toDate() : entity[key]; + const month = dateValue.getMonth() + 1; + const day = dateValue.getDate(); + return `${dateValue.getFullYear()}-${month < 10 ? '0' : ''}${month}-${day < 10 ? '0' : ''}${day}`; } else { return undefined; } @@ -50,12 +61,12 @@ export class MappingFunctions { } /** - * Calculate the time between two dates - * - * @param date1 days from this date - * @param date2 to this date - * @returns the time from date1 to date2 - */ + * Calculate the time between two dates + * + * @param date1 days from this date + * @param date2 to this date + * @returns the time from date1 to date2 + */ public static timeBetween(date1: Date, date2: Date): number { return date2.getTime() - date1.getTime(); } @@ -67,7 +78,7 @@ export class MappingFunctions { * @param date2 to this date * @returns the days from date1 to date2 */ - public static daysBetween(date1: Date, date2: Date): number { + public static daysBetween(date1: Date, date2: Date): number { const diff = this.timeBetween(date1, date2); return Math.ceil(diff / (1000 * 3600 * 24)); } diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 9284745988..9be5408ace 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -95,8 +95,9 @@ import {ExtensionModalComponent} from './common/modals/extension-modal/extension import {CalendarModalComponent} from './common/modals/calendar-modal/calendar-modal.component'; import {MatRadioModule} from '@angular/material/radio'; import {MatButtonToggleModule} from '@angular/material/button-toggle'; -import {MAT_DATE_LOCALE, MatOptionModule} from '@angular/material/core'; +import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatOptionModule} from '@angular/material/core'; import {MatDatepickerModule} from '@angular/material/datepicker'; +import {MomentDateAdapter} from '@angular/material-moment-adapter'; import {doubtfireStates} from './doubtfire.states'; import {MatTableModule} from '@angular/material/table'; import {MatTabsModule} from '@angular/material/tabs'; @@ -225,6 +226,19 @@ import {TasksViewerComponent} from './units/states/tasks/tasks-viewer/tasks-view import {UnitCodeComponent} from './common/unit-code/unit-code.component'; import {GradeService} from './common/services/grade.service'; +// See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 +const MY_DATE_FORMAT = { + parse: { + dateInput: 'DD/MM/YYYY', // this is how your date will be parsed from Input + }, + display: { + dateInput: 'DD/MM/YYYY', // this is how your date will get displayed on the Input + monthYearLabel: 'MMMM YYYY', + dateA11yLabel: 'LL', + monthYearA11yLabel: 'MMMM YYYY', + }, +}; + @NgModule({ // Components we declare declarations: [ @@ -369,6 +383,8 @@ import {GradeService} from './common/services/grade.service'; CsvUploadModalProvider, CsvResultModalProvider, {provide: MAT_DATE_LOCALE, useValue: 'en-AU'}, + {provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE]}, + {provide: MAT_DATE_FORMATS, useValue: MY_DATE_FORMAT}, UnitStudentEnrolmentModalProvider, TaskCommentService, AudioRecorderProvider, From 8a6424b6eecc08c4625e8fb36a85c79bc3a023dc Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 24 Jun 2024 13:30:10 +1000 Subject: [PATCH 0131/1280] chore: tidy up file downloader --- .../file-downloader/file-downloader.service.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/app/common/file-downloader/file-downloader.service.ts b/src/app/common/file-downloader/file-downloader.service.ts index 0ec8b90e34..681e4bde8e 100644 --- a/src/app/common/file-downloader/file-downloader.service.ts +++ b/src/app/common/file-downloader/file-downloader.service.ts @@ -3,13 +3,13 @@ import {Injectable} from '@angular/core'; import {AlertService} from '../services/alert.service'; interface FileDownloaderData { - url: string, - response: HttpResponse, - success: (url: string, response: HttpResponse) => void, + url: string; + response: HttpResponse; + success: (url: string, response: HttpResponse) => void; // eslint-disable-next-line @typescript-eslint/no-explicit-any - failure: (error: any) => void, + failure: (error: any) => void; // eslint-disable-next-line @typescript-eslint/no-explicit-any - binaryData: Blob[], + binaryData: Blob[]; } @Injectable({ @@ -100,7 +100,7 @@ export class FileDownloaderService { public downloadBlob( url: string, success: (url: string, response: HttpResponse) => void, - failure: (error: any) => void, + failure: (error) => void, ) { // Declare binary data outside of the subscription so that it can be accessed in the second requests when partial content is returned const binaryData = []; @@ -146,7 +146,7 @@ export class FileDownloaderService { downloadLink.click(); downloadLink.parentNode.removeChild(downloadLink); }, - (error: any) => { + (error) => { this.alerts.error(`Error downloading file - ${error}`); }, ); From 3a81688904159c8c9e3efdde8f3605aa5677630f Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 24 Jun 2024 13:39:53 +1000 Subject: [PATCH 0132/1280] fix: ensure turn it in only appears to task editor when enabled --- .../task-definition-upload.component.html | 10 +++++----- .../task-definition-upload.component.ts | 11 +++++++++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html index fe96cfb2df..8607e6c719 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html @@ -25,12 +25,12 @@
diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts index a8915d843b..a6d049446a 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts @@ -2,6 +2,7 @@ import { Component, Input, OnChanges, SimpleChanges, ViewChild } from '@angular/ import { MatTable, MatTableDataSource } from '@angular/material/table'; import { TaskDefinition, UploadRequirement } from 'src/app/api/models/task-definition'; import { Unit } from 'src/app/api/models/unit'; +import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; @Component({ selector: 'f-task-definition-upload', @@ -10,10 +11,12 @@ import { Unit } from 'src/app/api/models/unit'; }) export class TaskDefinitionUploadComponent { @Input() public taskDefinition: TaskDefinition; - @ViewChild('upreqTable', { static: true }) table: MatTable; + @ViewChild('upreqTable', {static: true}) table: MatTable; public columns: string[] = ['file-name', 'file-type', 'tii-check', 'flag-pct', 'row-actions']; + constructor(private constants: DoubtfireConstants) {} + public get unit(): Unit { return this.taskDefinition?.unit; } @@ -30,9 +33,13 @@ export class TaskDefinitionUploadComponent { this.table.renderRows(); } + public tiiEnabled(): boolean { + return this.constants.IsTiiEnabled.value; + } + public removeUpReq(upreq: UploadRequirement) { this.taskDefinition.uploadRequirements = this.taskDefinition.uploadRequirements.filter( - (anUpReq) => anUpReq.key != upreq.key + (anUpReq) => anUpReq.key != upreq.key, ); } } From c7ae09170fdc43c21452e8b2665f0f36e480dd4d Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 24 Jun 2024 13:40:07 +1000 Subject: [PATCH 0133/1280] chore(release): 8.0.11 --- CHANGELOG.md | 15 +++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 76d7c600ff..54ea56c57d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.11](https://github.com/macite/doubtfire-deploy/compare/v8.0.10...v8.0.11) (2024-06-24) + + +### Bug Fixes + +* ensure turn it in only appears to task editor when enabled ([3a81688](https://github.com/macite/doubtfire-deploy/commit/3a81688904159c8c9e3efdde8f3605aa5677630f)) +* task date picker allows direct entry ([2f91e8f](https://github.com/macite/doubtfire-deploy/commit/2f91e8fbba7902e1e22871cc82c87f4ff797b058)) + +### [7.0.24](https://github.com/macite/doubtfire-deploy/compare/v7.0.23...v7.0.24) (2024-06-05) + + +### Bug Fixes + +* ensure download blob supports 206 responses ([6445f9f](https://github.com/macite/doubtfire-deploy/commit/6445f9f998db70fbe9b9abf723dc17fd298b5d2f)) + ### [8.0.10](https://github.com/macite/doubtfire-deploy/compare/v7.0.23...v8.0.10) (2024-06-21) diff --git a/package-lock.json b/package-lock.json index 5ec5842fc2..691cb53755 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "8.0.10", + "version": "8.0.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "8.0.10", + "version": "8.0.11", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index a6af7f3bba..fe9cf8dc2a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "8.0.10", + "version": "8.0.11", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 991230f7b527957116263b6abaa588ed43d3a787 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 25 Jun 2024 15:37:00 +1000 Subject: [PATCH 0134/1280] fix: reinstate unit import for teaching period --- .../teaching-period-list.component.html | 42 ++++++++++++++-- .../teaching-period-list.component.ts | 49 +++++++++++++++++-- src/app/doubtfire-angularjs.module.ts | 5 -- 3 files changed, 84 insertions(+), 12 deletions(-) diff --git a/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.html b/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.html index 5abff6ce87..5f009464f4 100644 --- a/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.html +++ b/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.html @@ -2,9 +2,20 @@

Teaching periods

- +
-
- Student + Student + - Name + Name + - Tutor + Tutor + Tutorial - + - Target + Target + Submitted as - + - Stats + Stats - Portfolio? + Portfolio? + - Grade + Grade +
{{student.hasPortfolio ? "Yes" : "No"}} + {{student.hasPortfolio ? "Yes" : "No"}} + {{student.grade}}
Check Similarity - @if (upreq.type === 'document') { -TurnItIn -} + @if (upreq.type === 'document' && tiiEnabled()) { + TurnItIn + } @if (upreq.type === 'code') { -Moss -} + Moss + }
+
+ + + + + - +
Active @@ -32,6 +43,26 @@

Teaching periods

{{ element.activeUntil | date }} Actions +
+ + + + +
+
- + diff --git a/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.ts b/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.ts index 87be5fbef8..17dc7efdf9 100644 --- a/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.ts +++ b/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.ts @@ -2,12 +2,13 @@ import { Component, Inject, OnInit, ViewChild } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialog, MatDialogRef } from '@angular/material/dialog'; import { MatPaginator } from '@angular/material/paginator'; import { MatSnackBar } from '@angular/material/snack-bar'; -import { MatSort } from '@angular/material/sort'; +import { MatSort, Sort } from '@angular/material/sort'; import { MatTableDataSource } from '@angular/material/table'; import { TeachingPeriodBreak } from 'src/app/api/models/teaching-period'; import { TeachingPeriod } from 'src/app/api/models/teaching-period'; import { TeachingPeriodBreakService } from 'src/app/api/services/teaching-period-break.service'; import { TeachingPeriodService } from 'src/app/api/services/teaching-period.service'; +import { TeachingPeriodUnitImportService } from '../teaching-period-unit-import/teaching-period-unit-import.dialog'; @Component({ selector: 'f-teaching-period-list', @@ -20,8 +21,13 @@ export class TeachingPeriodListComponent implements OnInit { public dataSource = new MatTableDataSource(); - displayedColumns: string[] = ['active', 'name', 'startDate', 'endDate', 'activeUntil']; - constructor(private teachingPeriodsService: TeachingPeriodService, public dialog: MatDialog) {} + displayedColumns: string[] = ['active', 'name', 'startDate', 'endDate', 'activeUntil', 'actions']; + + constructor( + private teachingPeriodsService: TeachingPeriodService, + public dialog: MatDialog, + public teachingPeriodUnitImportService: TeachingPeriodUnitImportService, + ) {} ngOnInit(): void { // update the Teaching Periods @@ -35,6 +41,10 @@ export class TeachingPeriodListComponent implements OnInit { }); } + importUnits(teachingPeriod: TeachingPeriod) { + this.teachingPeriodUnitImportService.openImportUnitsDialog(teachingPeriod); + } + addTeachingPeriod() { this.dialog.open(NewTeachingPeriodDialogComponent, { data: {}, @@ -46,6 +56,39 @@ export class TeachingPeriodListComponent implements OnInit { this.dialog.open(NewTeachingPeriodDialogComponent, { data: { teachingPeriod: teachingPeriod } }); }); } + + /** + * Function used by implemented sortTableData to determine the order + * of values within the EntityForm once sorting has been triggered. + * + * @param aValue value to be compared against bValue. + * @param bValue value to be compared against aValue. + * + * @returns truthy comparison between aValue and bValue. + */ + protected sortCompare(aValue: number | string, bValue: number | string, isAsc: boolean) { + return (aValue < bValue ? -1 : 1) * (isAsc ? 1 : -1); + } + + // Sorting function to sort data when sort + // event is triggered + sortTableData(sort: Sort) { + if (!sort.active || sort.direction === '') { + return; + } + switch (sort.active) { + case 'active': + case 'name': + case 'startDate': + case 'endDate': + case 'activeUntil': + this.dataSource.data = this.dataSource.data.sort((a, b) => { + const isAsc = sort.direction === 'asc'; + return this.sortCompare(a[sort.active], b[sort.active], isAsc); + }); + return; + } + } } @Component({ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 868e381213..304e0bf747 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -213,7 +213,6 @@ import {InboxComponent} from './units/states/tasks/inbox/inbox.component'; import {TaskDefinitionEditorComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component'; import {UnitAnalyticsComponent} from './units/states/analytics/unit-analytics-route.component'; import {UnitTaskEditorComponent} from './units/states/edit/directives/unit-tasks-editor/unit-task-editor.component'; -import {TeachingPeriodUnitImportService} from './admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog'; import {CreateNewUnitModal} from './admin/modals/create-new-unit-modal/create-new-unit-modal.component'; import {FUsersComponent} from './admin/states/f-users/f-users.component'; import {FUnitTaskListComponent} from './units/states/tasks/viewer/directives/f-unit-task-list/f-unit-task-list.component'; @@ -240,10 +239,6 @@ export const DoubtfireAngularJSModule = angular.module('doubtfire', [ // Downgrade angular modules that we need... // factory -> service DoubtfireAngularJSModule.factory('AboutDoubtfireModal', downgradeInjectable(AboutDoubtfireModal)); -DoubtfireAngularJSModule.factory( - 'TeachingPeriodUnitImportService', - downgradeInjectable(TeachingPeriodUnitImportService), -); DoubtfireAngularJSModule.factory('DoubtfireConstants', downgradeInjectable(DoubtfireConstants)); DoubtfireAngularJSModule.factory('ExtensionModal', downgradeInjectable(ExtensionModalService)); DoubtfireAngularJSModule.factory('Marked', downgradeInjectable(MarkedPipe)); From 32046e89eaaf2a9b36e88f078a7b695b1506886d Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 25 Jun 2024 20:05:16 +1000 Subject: [PATCH 0135/1280] fix: ensure null fields will not break in entity mapping --- src/app/api/models/task-definition.ts | 2 +- src/app/api/services/project.service.ts | 20 +++++++++++-------- src/app/api/services/task-comment.service.ts | 4 ++-- .../api/services/task-definition.service.ts | 14 +++++++++---- src/app/api/services/unit.service.ts | 8 ++++---- 5 files changed, 29 insertions(+), 19 deletions(-) diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index 1b49a2e856..0766f85eb6 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -21,7 +21,7 @@ export class TaskDefinition extends Entity { targetDate: Date; dueDate: Date; startDate: Date; - uploadRequirements: UploadRequirement[]; + uploadRequirements: UploadRequirement[] = []; tutorialStream: TutorialStream = null; plagiarismChecks: SimilarityCheck[] = []; plagiarismReportUrl: string; diff --git a/src/app/api/services/project.service.ts b/src/app/api/services/project.service.ts index e9ffc791ed..6bb50481a3 100644 --- a/src/app/api/services/project.service.ts +++ b/src/app/api/services/project.service.ts @@ -143,7 +143,7 @@ export class ProjectService extends CachedEntityService { keys: 'tutorialEnrolments', toEntityOp: (data: object, key: string, project: Project, params?: any) => { const unit: Unit = project.unit; - data[key].forEach((tutorialEnrolment: { tutorial_id: number; }) => { + data[key]?.forEach((tutorialEnrolment: {tutorial_id: number}) => { if (tutorialEnrolment.tutorial_id) { const tutorial = unit.tutorialsCache.get(tutorialEnrolment.tutorial_id); project.tutorialEnrolmentsCache.add(tutorial); @@ -154,12 +154,16 @@ export class ProjectService extends CachedEntityService { { keys: 'groups', toEntityOp: (data: object, key: string, project: Project, params?: any) => { - data[key].forEach((group) => { - const theGroup = project.unit.groupSetsCache.get(group.group_set_id).groupsCache.getOrCreate(group.id, this.groupService, group, {constructorParams: project.unit}); + data[key]?.forEach((group) => { + const theGroup = project.unit.groupSetsCache + .get(group.group_set_id) + .groupsCache.getOrCreate(group.id, this.groupService, group, { + constructorParams: project.unit, + }); project.groupCache.add(theGroup); theGroup.projectsCache.add(project); - }) + }); }, toJsonFn: (entity: Project, key: string) => { return entity.unit?.id; @@ -169,7 +173,7 @@ export class ProjectService extends CachedEntityService { keys: 'tasks', toEntityOp: (data: object, key: string, project: Project, params?: any) => { // create tasks from json - data['tasks'].forEach(taskData => { + data['tasks']?.forEach((taskData) => { project.taskCache.getOrCreate(taskData['id'], this.taskService, taskData, {constructorParams: project}); }); @@ -179,14 +183,14 @@ export class ProjectService extends CachedEntityService { { keys: 'taskOutcomeAlignments', toEntityOp: (data: object, key: string, project: Project, params?: any) => { - data[key].forEach(alignment => { + data[key]?.forEach((alignment) => { project.taskOutcomeAlignmentsCache.getOrCreate( alignment['id'], taskOutcomeAlignmentService, alignment, { - constructorParams: project - } + constructorParams: project, + }, ); }); } diff --git a/src/app/api/services/task-comment.service.ts b/src/app/api/services/task-comment.service.ts index 9e646be77d..7fdf94bc88 100644 --- a/src/app/api/services/task-comment.service.ts +++ b/src/app/api/services/task-comment.service.ts @@ -41,7 +41,7 @@ export class TaskCommentService extends CachedEntityService { { keys: 'author', toEntityFn: (data: object, key: string, comment: TaskComment) => { - const user = this.userService.cache.getOrCreate(data[key].id, userService, data[key]); + const user = this.userService.cache.getOrCreate(data[key]?.id, userService, data[key]); comment.initials = `${user.firstName[0]}${user.lastName[0]}`.toUpperCase(); return user; } @@ -49,7 +49,7 @@ export class TaskCommentService extends CachedEntityService { { keys: 'recipient', toEntityFn: (data: object, key: string, comment: TaskComment) => { - return this.userService.cache.getOrCreate(data[key].id, userService, data[key]); + return this.userService.cache.getOrCreate(data[key]?.id, userService, data[key]); } }, 'recipientReadTime', diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index 13a1dd2797..b2499251ea 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -41,7 +41,7 @@ export class TaskDefinitionService extends CachedEntityService { keys: 'uploadRequirements', toJsonFn: (taskDef: TaskDefinition, key: string) => { return JSON.stringify( - taskDef.uploadRequirements.map((upreq) => { + taskDef.uploadRequirements?.map((upreq) => { return { key: upreq.key, name: upreq.name, @@ -49,13 +49,19 @@ export class TaskDefinitionService extends CachedEntityService { tii_check: upreq.tiiCheck, tii_pct: upreq.tiiPct, }; - }) + }), ); }, toEntityFn: (data: object, key: string, taskDef: TaskDefinition, params?: any) => { return ( - data[key] as Array<{ key: string; name: string; type: string; tii_check: boolean; tii_pct: number }> - ).map((upreq) => { + data[key] as Array<{ + key: string; + name: string; + type: string; + tii_check: boolean; + tii_pct: number; + }> + )?.map((upreq) => { return { key: upreq.key, name: upreq.name, diff --git a/src/app/api/services/unit.service.ts b/src/app/api/services/unit.service.ts index 740e9b6cc1..4f6e896495 100644 --- a/src/app/api/services/unit.service.ts +++ b/src/app/api/services/unit.service.ts @@ -58,7 +58,7 @@ export class UnitService extends CachedEntityService { const unitRoleService = AppInjector.get(UnitRoleService); // Add staff entity.staffCache.clear(); - data[key].forEach(staff => { + data[key]?.forEach(staff => { entity.staffCache.add(unitRoleService.buildInstance(staff)); }); } @@ -133,7 +133,7 @@ export class UnitService extends CachedEntityService { { keys: 'ilos', toEntityOp: (data: object, key: string, unit: Unit) => { - data[key].forEach(ilo => { + data[key]?.forEach(ilo => { unit.learningOutcomesCache.getOrCreate(ilo['id'], this.learningOutcomeService, ilo); }); } @@ -160,7 +160,7 @@ export class UnitService extends CachedEntityService { { keys: 'groupSets', toEntityOp: (data, key, unit) => { - data[key].forEach((groupSetJson: object) => { + data[key]?.forEach((groupSetJson: object) => { unit.groupSetsCache.add(this.groupSetService.buildInstance(groupSetJson, {constructorParams: unit})); }); } @@ -168,7 +168,7 @@ export class UnitService extends CachedEntityService { { keys: 'groups', toEntityOp: (data, key, unit) => { - data[key].forEach((groupJson: object) => { + data[key]?.forEach((groupJson: object) => { const group = this.groupService.buildInstance(groupJson, {constructorParams: unit}); group.groupSet.groupsCache.add(group); }); From 0bb4869aafb633a74b417e6c5b0d819d99dc60aa Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 25 Jun 2024 20:25:35 +1000 Subject: [PATCH 0136/1280] chore(release): 8.0.12 --- CHANGELOG.md | 8 ++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54ea56c57d..cae648d1cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.12](https://github.com/macite/doubtfire-deploy/compare/v8.0.11...v8.0.12) (2024-06-25) + + +### Bug Fixes + +* ensure null fields will not break in entity mapping ([32046e8](https://github.com/macite/doubtfire-deploy/commit/32046e89eaaf2a9b36e88f078a7b695b1506886d)) +* reinstate unit import for teaching period ([991230f](https://github.com/macite/doubtfire-deploy/commit/991230f7b527957116263b6abaa588ed43d3a787)) + ### [8.0.11](https://github.com/macite/doubtfire-deploy/compare/v8.0.10...v8.0.11) (2024-06-24) diff --git a/package-lock.json b/package-lock.json index 691cb53755..5ba9364f0e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "8.0.11", + "version": "8.0.12", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "8.0.11", + "version": "8.0.12", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index fe9cf8dc2a..0492d4a2db 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "8.0.11", + "version": "8.0.12", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 8fe2f9e9ca60c02e55c24d0f2bb3eb6dbea8217c Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Thu, 27 Jun 2024 02:13:51 +1000 Subject: [PATCH 0137/1280] feat: get unique token for scorm asset retrieval --- src/app/api/models/user/user.ts | 1 + src/app/api/services/authentication.service.ts | 18 ++++++++++++++++++ .../scorm-player/scorm-player.component.ts | 18 ++++++++++++++++-- 3 files changed, 35 insertions(+), 2 deletions(-) diff --git a/src/app/api/models/user/user.ts b/src/app/api/models/user/user.ts index 10357a1898..552066cfd1 100644 --- a/src/app/api/models/user/user.ts +++ b/src/app/api/models/user/user.ts @@ -22,6 +22,7 @@ export class User extends Entity { receiveFeedbackNotifications: boolean; hasRunFirstTimeSetup: boolean; authenticationToken: string; + scormAuthenticationToken: string; pronouns: string | null; acceptedTiiEula: boolean; diff --git a/src/app/api/services/authentication.service.ts b/src/app/api/services/authentication.service.ts index b2cb12f402..fe2b8d0b1c 100644 --- a/src/app/api/services/authentication.service.ts +++ b/src/app/api/services/authentication.service.ts @@ -191,4 +191,22 @@ export class AuthenticationService { setTimeout(() => this.router.stateService.go('timeout'), 500); } } + + public getScormToken(): Observable { + return this.httpClient.get(this.AUTH_URL + '/scorm').pipe( + map((response) => { + this.userService.currentUser.scormAuthenticationToken = response['scorm_auth_token']; + localStorage.setItem(this.USERNAME_KEY, JSON.stringify(this.userService.currentUser)); + + // Token expires after 2 hours + setTimeout( + () => { + this.userService.currentUser.scormAuthenticationToken = ''; + localStorage.setItem(this.USERNAME_KEY, JSON.stringify(this.userService.currentUser)); + }, + 1000 * 60 * 60 * 2, + ); + }), + ); + } } diff --git a/src/app/common/scorm-player/scorm-player.component.ts b/src/app/common/scorm-player/scorm-player.component.ts index 4a32eb0ac7..b7f9b1b5a6 100644 --- a/src/app/common/scorm-player/scorm-player.component.ts +++ b/src/app/common/scorm-player/scorm-player.component.ts @@ -1,6 +1,10 @@ import {Component, OnInit, Input, HostListener} from '@angular/core'; import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser'; -import {ScormPlayerContext} from 'src/app/api/models/doubtfire-model'; +import { + AuthenticationService, + ScormPlayerContext, + UserService, +} from 'src/app/api/models/doubtfire-model'; import {ScormAdapterService} from 'src/app/api/services/scorm-adapter.service'; import {AppInjector} from 'src/app/app-injector'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; @@ -37,6 +41,8 @@ export class ScormPlayerComponent implements OnInit { constructor( private globalState: GlobalStateService, private scormAdapter: ScormAdapterService, + private userService: UserService, + private authService: AuthenticationService, private sanitizer: DomSanitizer, ) {} @@ -44,6 +50,14 @@ export class ScormPlayerComponent implements OnInit { this.globalState.setView(ViewType.OTHER); this.globalState.hideHeader(); + if (this.userService.currentUser.scormAuthenticationToken) { + this.setupScorm(); + } else { + this.authService.getScormToken().subscribe(() => this.setupScorm()); + } + } + + setupScorm(): void { this.scormAdapter.mode = this.mode; if (this.mode === 'normal') { this.scormAdapter.projectId = this.projectId; @@ -64,7 +78,7 @@ export class ScormPlayerComponent implements OnInit { }; this.iframeSrc = this.sanitizer.bypassSecurityTrustResourceUrl( - `${AppInjector.get(DoubtfireConstants).API_URL}/scorm/${this.taskDefId}/index.html`, + `${AppInjector.get(DoubtfireConstants).API_URL}/scorm/${this.taskDefId}/${this.userService.currentUser.username}/${this.userService.currentUser.scormAuthenticationToken}/index.html`, ); } From 7b5d35c89a577d0408a51d8390400f44615591eb Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 27 Jun 2024 14:51:01 +1000 Subject: [PATCH 0138/1280] fix: update discuss text to promote use --- src/app/api/models/task-status.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/app/api/models/task-status.ts b/src/app/api/models/task-status.ts index 0ab0f8f2d9..7470b9b143 100644 --- a/src/app/api/models/task-status.ts +++ b/src/app/api/models/task-status.ts @@ -287,17 +287,18 @@ export class TaskStatus { [ 'discuss', { - detail: "You're almost complete!", - reason: 'Your work looks good and your tutor believes it is complete.', - action: 'To mark as complete, attend class and discuss it with your tutor.', + detail: 'Your work needs to be discussed further.', + reason: 'Your work looks good and your tutor believes it is on track.', + action: 'For this to be marked as complete, attend class and discuss it with your tutor.', }, ], [ 'demonstrate', { - detail: "You're almost complete!", - reason: 'Your work looks good and your tutor believes it is complete.', - action: 'To mark as complete, attend class and demonstrate how your submission works to your tutor.', + detail: 'Your work needs to be demonstrated.', + reason: 'Your work looks good and your tutor believes it is on track.', + action: + 'For this to be marked as complete you need to attend class and demonstrate how your submission works for your tutor.', }, ], [ From dbb3a682639c959e946e1f3273d9e5f2996683db Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 27 Jun 2024 15:17:57 +1000 Subject: [PATCH 0139/1280] chore(release): 8.0.13 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cae648d1cf..fed8da62dd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.13](https://github.com/macite/doubtfire-deploy/compare/v8.0.12...v8.0.13) (2024-06-27) + + +### Bug Fixes + +* update discuss text to promote use ([7b5d35c](https://github.com/macite/doubtfire-deploy/commit/7b5d35c89a577d0408a51d8390400f44615591eb)) + ### [8.0.12](https://github.com/macite/doubtfire-deploy/compare/v8.0.11...v8.0.12) (2024-06-25) diff --git a/package-lock.json b/package-lock.json index 5ba9364f0e..351f4d773e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "8.0.12", + "version": "8.0.13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "8.0.12", + "version": "8.0.13", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 0492d4a2db..3ade29c77a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "8.0.12", + "version": "8.0.13", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 01013d3d16ab5b704acc589d34975693030def0b Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 27 Jun 2024 22:37:17 +1000 Subject: [PATCH 0140/1280] fix: ensure unit import allows unit code change --- .../teaching-period-unit-import.dialog.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts b/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts index 2925b4b59e..1a89a5538d 100644 --- a/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts +++ b/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts @@ -126,6 +126,10 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit { public codeChange(code: string, value: UnitImportData) { value.relatedUnits = this.relatedUnits(code); + // add source unit to realted units - so that it is retained on code change + if (value.sourceUnit && !value.relatedUnits.find((u) => u.value.id === value.sourceUnit.id)) { + value.relatedUnits.unshift({value: value.sourceUnit, text: value.sourceUnit.codeAndPeriod}); + } value.sourceUnit = value.relatedUnits.length > 0 ? value.relatedUnits[0].value : null; } From 4c966245d270af46107aae94bdd38e84b2188b65 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 27 Jun 2024 22:37:37 +1000 Subject: [PATCH 0141/1280] fix: ensure unit load sets main convenor user in all cases --- src/app/api/services/unit.service.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/api/services/unit.service.ts b/src/app/api/services/unit.service.ts index 4f6e896495..c3c38c7406 100644 --- a/src/app/api/services/unit.service.ts +++ b/src/app/api/services/unit.service.ts @@ -66,7 +66,9 @@ export class UnitService extends CachedEntityService { { keys: ['mainConvenor', 'main_convenor_id'], toEntityFn: (data, key, entity) => { - return entity.staffCache.get(data[key]); + let result = entity.staffCache.get(data[key]); + entity.mainConvenorUser = result?.user; + return result; }, toJsonFn: (unit: Unit, key: string) => { return unit.mainConvenor?.id; From 1dc58ce230e67c4a682600fb4b8153fc82586461 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 27 Jun 2024 22:46:27 +1000 Subject: [PATCH 0142/1280] chore(release): 8.0.14 --- CHANGELOG.md | 8 ++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fed8da62dd..9081badf55 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.14](https://github.com/macite/doubtfire-deploy/compare/v8.0.13...v8.0.14) (2024-06-27) + + +### Bug Fixes + +* ensure unit import allows unit code change ([01013d3](https://github.com/macite/doubtfire-deploy/commit/01013d3d16ab5b704acc589d34975693030def0b)) +* ensure unit load sets main convenor user in all cases ([4c96624](https://github.com/macite/doubtfire-deploy/commit/4c966245d270af46107aae94bdd38e84b2188b65)) + ### [8.0.13](https://github.com/macite/doubtfire-deploy/compare/v8.0.12...v8.0.13) (2024-06-27) diff --git a/package-lock.json b/package-lock.json index 351f4d773e..56e93ef1bd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "8.0.13", + "version": "8.0.14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "8.0.13", + "version": "8.0.14", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 3ade29c77a..c1de295951 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "8.0.13", + "version": "8.0.14", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 1857bdc708c81dc39d467f42c9e316a8664dc080 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 28 Jun 2024 19:06:54 +1000 Subject: [PATCH 0143/1280] fix: ensure zip uploads work on windows --- .../task-definition-overseer.component.html | 14 +++++++++++-- .../task-definition-overseer.component.ts | 4 +++- .../task-definition-resources.component.ts | 4 ++-- .../unit-task-editor.component.html | 21 ------------------- 4 files changed, 17 insertions(+), 26 deletions(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html index 92ef121ff3..31c683077f 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html @@ -1,5 +1,10 @@
- + Automation Enabled @@ -13,7 +18,12 @@ Docker image for Overseer - +
-
From a5690871a448f5b3aeb442df47a410ee2e3ca1a0 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 28 Jun 2024 19:07:01 +1000 Subject: [PATCH 0144/1280] chore(release): 8.0.15 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9081badf55..362eaeac79 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.15](https://github.com/macite/doubtfire-deploy/compare/v8.0.14...v8.0.15) (2024-06-28) + + +### Bug Fixes + +* ensure zip uploads work on windows ([1857bdc](https://github.com/macite/doubtfire-deploy/commit/1857bdc708c81dc39d467f42c9e316a8664dc080)) + ### [8.0.14](https://github.com/macite/doubtfire-deploy/compare/v8.0.13...v8.0.14) (2024-06-27) diff --git a/package-lock.json b/package-lock.json index 56e93ef1bd..1bcdf3b7fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "8.0.14", + "version": "8.0.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "8.0.14", + "version": "8.0.15", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index c1de295951..fb492d216c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "8.0.14", + "version": "8.0.15", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From f0505d7b62b97f1b821b19b1c4178973503789da Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 28 Jun 2024 19:31:49 +1000 Subject: [PATCH 0145/1280] fix: ensure drop works on task resource upload in windows --- .../task-definition-resources.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.html index 82ae176482..51bf4db54f 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.html @@ -19,7 +19,7 @@ @if (taskDefinition.hasTaskResources) { From 576076f1a7871f458526253ab18eade70fbd316a Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 28 Jun 2024 19:31:58 +1000 Subject: [PATCH 0146/1280] chore(release): 8.0.16 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 362eaeac79..0ccd7cdc27 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.16](https://github.com/macite/doubtfire-deploy/compare/v8.0.15...v8.0.16) (2024-06-28) + + +### Bug Fixes + +* ensure drop works on task resource upload in windows ([f0505d7](https://github.com/macite/doubtfire-deploy/commit/f0505d7b62b97f1b821b19b1c4178973503789da)) + ### [8.0.15](https://github.com/macite/doubtfire-deploy/compare/v8.0.14...v8.0.15) (2024-06-28) diff --git a/package-lock.json b/package-lock.json index 1bcdf3b7fe..53a1fccd78 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "8.0.15", + "version": "8.0.16", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "8.0.15", + "version": "8.0.16", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index fb492d216c..254a8eb450 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "8.0.15", + "version": "8.0.16", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 2394efb07c03da18fb8114d87b0c89e68bf7fd2d Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 1 Jul 2024 17:04:31 +1000 Subject: [PATCH 0147/1280] fix: switch date formats to date-fns Issues with moment caused failure to load task edit page. --- package-lock.json | 52 +++++++++++++------ package.json | 6 ++- src/app/doubtfire-angular.module.ts | 20 ++++--- .../unit-task-editor.component.ts | 3 +- 4 files changed, 55 insertions(+), 26 deletions(-) diff --git a/package-lock.json b/package-lock.json index 53a1fccd78..f31a23897f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,8 +16,8 @@ "@angular/compiler": "^17.3.6", "@angular/core": "^17.3.6", "@angular/forms": "^17.3.6", - "@angular/material": "^17.3.6", - "@angular/material-moment-adapter": "^17.3.6", + "@angular/material": "^17.3.10", + "@angular/material-date-fns-adapter": "^17.3.10", "@angular/platform-browser": "^17.3.6", "@angular/platform-browser-dynamic": "^17.3.6", "@angular/router": "^17.3.6", @@ -52,6 +52,7 @@ "codemirror": "5.65.0", "core-js": "^3.21.1", "d3": "3.5.17", + "date-fns": "^3.6.0", "es5-shim": "^4.5.12", "file-saver": "^2.0.5", "font-awesome": "~4.7.0", @@ -604,8 +605,9 @@ } }, "node_modules/@angular/cdk": { - "version": "17.3.8", - "license": "MIT", + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-17.3.10.tgz", + "integrity": "sha512-b1qktT2c1TTTe5nTji/kFAVW92fULK0YhYAvJ+BjZTPKu2FniZNe8o4qqQ0pUuvtMu+ZQxp/QqFYoidIVCjScg==", "dependencies": { "tslib": "^2.3.0" }, @@ -790,8 +792,9 @@ } }, "node_modules/@angular/material": { - "version": "17.3.8", - "license": "MIT", + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-17.3.10.tgz", + "integrity": "sha512-hHMQES0tQPH5JW33W+mpBPuM8ybsloDTqFPuRV8cboDjosAWfJhzAKF3ozICpNlUrs62La/2Wu/756GcQrxebg==", "dependencies": { "@material/animation": "15.0.0-canary.7f224ddd4.0", "@material/auto-init": "15.0.0-canary.7f224ddd4.0", @@ -844,7 +847,7 @@ }, "peerDependencies": { "@angular/animations": "^17.0.0 || ^18.0.0", - "@angular/cdk": "17.3.8", + "@angular/cdk": "17.3.10", "@angular/common": "^17.0.0 || ^18.0.0", "@angular/core": "^17.0.0 || ^18.0.0", "@angular/forms": "^17.0.0 || ^18.0.0", @@ -852,16 +855,17 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/material-moment-adapter": { - "version": "17.3.8", - "license": "MIT", + "node_modules/@angular/material-date-fns-adapter": { + "version": "17.3.10", + "resolved": "https://registry.npmjs.org/@angular/material-date-fns-adapter/-/material-date-fns-adapter-17.3.10.tgz", + "integrity": "sha512-Q4QAPGImZTjKW9ZhLSTkBeQX21I0dtak3JbexYx4CN/pHxKRpen6KaVAEqiORqq6vNUP2Kwb7cZznQyj6L7oQw==", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/core": "^17.0.0 || ^18.0.0", - "@angular/material": "17.3.8", - "moment": "^2.18.1" + "@angular/material": "17.3.10", + "date-fns": ">2.20.0 <4.0" } }, "node_modules/@angular/platform-browser": { @@ -8067,6 +8071,12 @@ "node": ">=4.0.0" } }, + "node_modules/concurrently/node_modules/date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", + "dev": true + }, "node_modules/concurrently/node_modules/has-flag": { "version": "1.0.0", "dev": true, @@ -8651,9 +8661,13 @@ } }, "node_modules/date-fns": { - "version": "1.30.1", - "dev": true, - "license": "MIT" + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/kossnocorp" + } }, "node_modules/date-format": { "version": "4.0.14", @@ -12917,6 +12931,14 @@ "tslib": "^2.1.0" } }, + "node_modules/install": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/install/-/install-0.13.0.tgz", + "integrity": "sha512-zDml/jzr2PKU9I8J/xyZBQn8rPCAY//UOYNmR01XwNwyfhEWObo2SWfSl1+0tm1u6PhxLwDnfsT/6jB7OUxqFA==", + "engines": { + "node": ">= 0.10" + } + }, "node_modules/internal-slot": { "version": "1.0.7", "dev": true, diff --git a/package.json b/package.json index 254a8eb450..df30c7bebd 100644 --- a/package.json +++ b/package.json @@ -33,8 +33,8 @@ "@angular/compiler": "^17.3.6", "@angular/core": "^17.3.6", "@angular/forms": "^17.3.6", - "@angular/material": "^17.3.6", - "@angular/material-moment-adapter": "^17.3.6", + "@angular/material": "^17.3.10", + "@angular/material-date-fns-adapter": "^17.3.10", "@angular/platform-browser": "^17.3.6", "@angular/platform-browser-dynamic": "^17.3.6", "@angular/router": "^17.3.6", @@ -69,9 +69,11 @@ "codemirror": "5.65.0", "core-js": "^3.21.1", "d3": "3.5.17", + "date-fns": "^3.6.0", "es5-shim": "^4.5.12", "file-saver": "^2.0.5", "font-awesome": "~4.7.0", + "install": "^0.13.0", "jquery": "2.1.4", "lodash": "~4.17", "lottie-web": "^5.12.2", diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 9be5408ace..69acaf196e 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -97,7 +97,11 @@ import {MatRadioModule} from '@angular/material/radio'; import {MatButtonToggleModule} from '@angular/material/button-toggle'; import {DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, MatOptionModule} from '@angular/material/core'; import {MatDatepickerModule} from '@angular/material/datepicker'; -import {MomentDateAdapter} from '@angular/material-moment-adapter'; + +import { DateFnsAdapter, MAT_DATE_FNS_FORMATS } from '@angular/material-date-fns-adapter'; +import { enAU } from 'date-fns/locale'; + + import {doubtfireStates} from './doubtfire.states'; import {MatTableModule} from '@angular/material/table'; import {MatTabsModule} from '@angular/material/tabs'; @@ -229,13 +233,13 @@ import {GradeService} from './common/services/grade.service'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { parse: { - dateInput: 'DD/MM/YYYY', // this is how your date will be parsed from Input + dateInput: 'dd/MM/yyyy', // this is how your date will be parsed from Input }, display: { - dateInput: 'DD/MM/YYYY', // this is how your date will get displayed on the Input - monthYearLabel: 'MMMM YYYY', - dateA11yLabel: 'LL', - monthYearA11yLabel: 'MMMM YYYY', + dateInput: 'dd/MM/yyyy', // this is how your date will get displayed on the Input + monthYearLabel: 'MMMM yyyy', + dateA11yLabel: 'do MMMM yyyy', + monthYearA11yLabel: 'MMMM yyyy', }, }; @@ -382,8 +386,8 @@ const MY_DATE_FORMAT = { dateServiceProvider, CsvUploadModalProvider, CsvResultModalProvider, - {provide: MAT_DATE_LOCALE, useValue: 'en-AU'}, - {provide: DateAdapter, useClass: MomentDateAdapter, deps: [MAT_DATE_LOCALE]}, + {provide: MAT_DATE_LOCALE, useValue: enAU}, + {provide: DateAdapter, useClass: DateFnsAdapter, deps: [MAT_DATE_LOCALE]}, {provide: MAT_DATE_FORMATS, useValue: MY_DATE_FORMAT}, UnitStudentEnrolmentModalProvider, TaskCommentService, diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts index ee0f135c26..72c309371d 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts @@ -8,6 +8,7 @@ import { TaskDefinition } from 'src/app/api/models/task-definition'; import { Unit } from 'src/app/api/models/unit'; import { TaskDefinitionService } from 'src/app/api/services/task-definition.service'; import { AlertService } from 'src/app/common/services/alert.service'; +import { addWeeks } from 'date-fns'; @Component({ selector: 'f-unit-task-editor', @@ -183,7 +184,7 @@ export class UnitTaskEditorComponent implements AfterViewInit { task.abbreviation = abbr; task.description = 'New Description'; task.startDate = new Date(); - task.targetDate = new Date(); + task.targetDate = addWeeks(new Date(), 2); task.uploadRequirements = []; task.weighting = 4; task.targetGrade = 0; From 4d81fa1fabb07e40d0d42068f23b8e756f4cdf4b Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 1 Jul 2024 17:08:20 +1000 Subject: [PATCH 0148/1280] fix: correct broken template in activities list --- .../activity-type-list.component.html | 29 ++++--------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.html b/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.html index 9b294d5597..9c91b329f7 100644 --- a/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.html +++ b/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.html @@ -15,27 +15,10 @@

Activities

{{ activityType.name }} } @else { - -
- - - - - -
- - } - - + } @@ -52,12 +35,11 @@

Activities

{{ activityType.abbreviation }}
- } @else { #edit| } - + } @else { - + } @@ -76,8 +58,7 @@

Activities

edit - } @else { #edit| } - + } @else {
-
+ }
From 17958955f65bab2b268826f2a7e19f311071615b Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 1 Jul 2024 17:11:09 +1000 Subject: [PATCH 0149/1280] fix: correct campus list templates --- .../campus-list/campus-list.component.html | 63 +++++++------------ 1 file changed, 21 insertions(+), 42 deletions(-) diff --git a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html index a97dcd2e16..3fe38272ec 100644 --- a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html +++ b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html @@ -11,31 +11,14 @@

Campuses

Name @if (!editing(campus)) { -
- {{ campus.name }} -
+
+ {{ campus.name }} +
} @else { - -
- - - - - -
- - } - - + } @@ -49,15 +32,14 @@

Campuses

Abbreviation @if (!editing(campus)) { -
- {{ campus.abbreviation }} -
- } @else { #edit| } - +
+ {{ campus.abbreviation }} +
+ } @else { -
+ } @@ -71,11 +53,10 @@

Campuses

Default Sync Mode @if (!editing(campus)) { -
- {{ campus.mode | titlecase }} -
- } @else { #edit| } - +
+ {{ campus.mode | titlecase }} +
+ } @else { Default Sync Mode @@ -86,7 +67,7 @@

Campuses

}
-
+ } @@ -107,13 +88,12 @@

Campuses

Active @if (!editing(campus)) { -
- -
- } @else { #edit| } - +
+ +
+ } @else { -
+ } @@ -135,8 +115,7 @@

Campuses

- } @else { #edit| } - + } @else {
-
+ }
From a2c5a4490224ab49cfb4ff966e86bb3dd44afaf5 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 1 Jul 2024 17:11:32 +1000 Subject: [PATCH 0150/1280] chore(release): 8.0.17 --- CHANGELOG.md | 9 +++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0ccd7cdc27..b578191a4d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.17](https://github.com/macite/doubtfire-deploy/compare/v8.0.16...v8.0.17) (2024-07-01) + + +### Bug Fixes + +* correct broken template in activities list ([4d81fa1](https://github.com/macite/doubtfire-deploy/commit/4d81fa1fabb07e40d0d42068f23b8e756f4cdf4b)) +* correct campus list templates ([1795895](https://github.com/macite/doubtfire-deploy/commit/17958955f65bab2b268826f2a7e19f311071615b)) +* switch date formats to date-fns ([2394efb](https://github.com/macite/doubtfire-deploy/commit/2394efb07c03da18fb8114d87b0c89e68bf7fd2d)) + ### [8.0.16](https://github.com/macite/doubtfire-deploy/compare/v8.0.15...v8.0.16) (2024-06-28) diff --git a/package-lock.json b/package-lock.json index f31a23897f..8236e0d60d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "8.0.16", + "version": "8.0.17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "8.0.16", + "version": "8.0.17", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index df30c7bebd..47e0c6b97a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "8.0.16", + "version": "8.0.17", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 1b1710f5015456cefad1d74617305981a22962ad Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Wed, 3 Jul 2024 12:47:16 +1000 Subject: [PATCH 0151/1280] refactor: center scorm comments if no review button --- .../scorm-comment/scorm-comment.component.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html index edde1e057c..0c44be728c 100644 --- a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html @@ -8,7 +8,11 @@ > Review -
+ @if (!user.isStaff && !task.definition.scormAllowReview) { +
+ } @else { +
+ }
- -
-
diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.scss index 05e8bffddc..82dc723d88 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.scss +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.scss @@ -8,3 +8,8 @@ .form-group { } + +#task-def-head { + background-color: white; + z-index: 10; +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html index a479f20ce3..634c71a98c 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html @@ -18,7 +18,7 @@
- Maximum Score + Quality Stars - Provide a score alongside the task status. We recommend avoiding this practice. + Provide a number of stars alongside the task status. Make sure you have a clear reason for + each star within your task description.
From f5388e45715597f0c92f252f721cf274bb8de0d5 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 10 Jul 2024 17:03:45 +1000 Subject: [PATCH 0157/1280] fix: ensure pdf is visible in task viewer mobile/narrow --- .../units/states/tasks/tasks-viewer/tasks-viewer.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.html b/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.html index 845e7203a5..56e528f29e 100644 --- a/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.html +++ b/src/app/units/states/tasks/tasks-viewer/tasks-viewer.component.html @@ -36,5 +36,6 @@
+ From e9046400e827481e09492bcb458b00b4e3aca347 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 10 Jul 2024 17:04:29 +1000 Subject: [PATCH 0158/1280] feat: add ability to minimise task details in task viewer --- .../f-task-details-view.component.html | 14 +++++++++++++- .../f-task-details-view.component.ts | 4 +++- 2 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.html b/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.html index 2ee4198b7c..5ca7a38d06 100644 --- a/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.html +++ b/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.html @@ -1,6 +1,18 @@
- + + + Task Details + + {{ panelOpenState() ? 'Hide' : 'Show' }} task details + + + +
diff --git a/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.ts b/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.ts index 57ea0b7993..8940b75542 100644 --- a/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.ts +++ b/src/app/units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component.ts @@ -1,4 +1,4 @@ -import { Component, Input, OnInit } from '@angular/core'; +import { Component, Input, OnInit, signal } from '@angular/core'; import { TaskDefinition } from 'src/app/api/models/task-definition'; import { Unit } from 'src/app/api/models/unit'; import { TasksViewerService } from '../../../tasks-viewer.service'; @@ -19,4 +19,6 @@ export class FTaskDetailsViewComponent implements OnInit { this.taskDef = taskDef; }); } + + public readonly panelOpenState = signal(false); } From 71df80b88ca626776e8e41d6530fbad6fe1355ec Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Wed, 10 Jul 2024 22:14:30 +1000 Subject: [PATCH 0159/1280] chore(release): 8.0.19 --- CHANGELOG.md | 13 +++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f108796bd4..c73daa7f9c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.19](https://github.com/macite/doubtfire-deploy/compare/v8.0.18...v8.0.19) (2024-07-10) + + +### Features + +* add ability to minimise task details in task viewer ([e904640](https://github.com/macite/doubtfire-deploy/commit/e9046400e827481e09492bcb458b00b4e3aca347)) + + +### Bug Fixes + +* ensure pdf is visible in task viewer mobile/narrow ([f5388e4](https://github.com/macite/doubtfire-deploy/commit/f5388e45715597f0c92f252f721cf274bb8de0d5)) +* task def editor so save is not over fields and header visible for task being edited ([22a2616](https://github.com/macite/doubtfire-deploy/commit/22a26165c9f2ef634b3e79d1e5d5d6b74e6f2731)) + ### [8.0.18](https://github.com/macite/doubtfire-deploy/compare/v8.0.17...v8.0.18) (2024-07-03) diff --git a/package-lock.json b/package-lock.json index 52445d86a0..4571e71e31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "8.0.18", + "version": "8.0.19", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "8.0.18", + "version": "8.0.19", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 8529506a2d..6237d6dae1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "8.0.18", + "version": "8.0.19", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 3d44c115b498366b80e5b8b99ccd3eaa660ff613 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 15 Jul 2024 19:51:28 +1000 Subject: [PATCH 0160/1280] fix: ensure turn it in eula is accessible by all --- src/app/doubtfire.states.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index b9f95e88af..c578d87b26 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -225,8 +225,8 @@ const EulaState: NgHybridStateDeclaration = { }, }, data: { - pageTitle: 'Teaching Periods', - roleWhitelist: ['Convenor', 'Admin'], + pageTitle: 'End User License Agreement', + roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin', 'Auditor'], }, }; From f4360977d42466dcf2706c487b7648cd0faa409b Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 15 Jul 2024 19:51:43 +1000 Subject: [PATCH 0161/1280] chore(release): 8.0.20 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c73daa7f9c..a5fe9f894e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [8.0.20](https://github.com/macite/doubtfire-deploy/compare/v8.0.19...v8.0.20) (2024-07-15) + + +### Bug Fixes + +* ensure turn it in eula is accessible by all ([3d44c11](https://github.com/macite/doubtfire-deploy/commit/3d44c115b498366b80e5b8b99ccd3eaa660ff613)) + ### [8.0.19](https://github.com/macite/doubtfire-deploy/compare/v8.0.18...v8.0.19) (2024-07-10) diff --git a/package-lock.json b/package-lock.json index 4571e71e31..d176f2345c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "8.0.19", + "version": "8.0.20", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "8.0.19", + "version": "8.0.20", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 6237d6dae1..762969722e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "8.0.19", + "version": "8.0.20", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 9436f57e327eaee86b192a7adccbe43d800d3146 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sat, 20 Jul 2024 14:37:39 +1000 Subject: [PATCH 0162/1280] refactor: create initial files for migration of comments-modal --- .../comments-modal/comments-modal.component.html | 0 .../comments-modal/comments-modal.component.scss | 0 .../modals/comments-modal/comments-modal.component.ts | 10 ++++++++++ 3 files changed, 10 insertions(+) create mode 100644 src/app/common/modals/comments-modal/comments-modal.component.html create mode 100644 src/app/common/modals/comments-modal/comments-modal.component.scss create mode 100644 src/app/common/modals/comments-modal/comments-modal.component.ts diff --git a/src/app/common/modals/comments-modal/comments-modal.component.html b/src/app/common/modals/comments-modal/comments-modal.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/common/modals/comments-modal/comments-modal.component.scss b/src/app/common/modals/comments-modal/comments-modal.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/common/modals/comments-modal/comments-modal.component.ts b/src/app/common/modals/comments-modal/comments-modal.component.ts new file mode 100644 index 0000000000..993f67ce00 --- /dev/null +++ b/src/app/common/modals/comments-modal/comments-modal.component.ts @@ -0,0 +1,10 @@ +import {Component, Input, Inject} from '@angular/core'; + +@Component({ + selector: 'comments-modal', + templateUrl: 'comments-modal.component.html', + styleUrls: ['comments-modal.component.scss'], +}) +export class CommentsModalComponent { + constructor() {} +} From 152b2fb30a6cbf0eaa9225bf04049b78c6161c4a Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sat, 20 Jul 2024 15:18:37 +1000 Subject: [PATCH 0163/1280] refactor: create service file for migration of comments-modal --- src/app/common/modals/comments-modal/comments-modal.service.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/app/common/modals/comments-modal/comments-modal.service.ts diff --git a/src/app/common/modals/comments-modal/comments-modal.service.ts b/src/app/common/modals/comments-modal/comments-modal.service.ts new file mode 100644 index 0000000000..e69de29bb2 From 13710e2fa17419f5c22940af87091d9c55dc0a87 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sat, 20 Jul 2024 20:53:31 +1000 Subject: [PATCH 0164/1280] refactor: migrate comments-modal --- .../comments-modal.component.html | 7 +++++++ .../comments-modal.component.scss | 17 +++++++++++++++++ .../comments-modal.component.ts | 19 ++++++++++++++----- .../comments-modal/comments-modal.service.ts | 18 ++++++++++++++++++ src/app/common/modals/modals.coffee | 1 - src/app/doubtfire-angular.module.ts | 2 ++ src/app/doubtfire-angularjs.module.ts | 5 +++-- 7 files changed, 61 insertions(+), 8 deletions(-) diff --git a/src/app/common/modals/comments-modal/comments-modal.component.html b/src/app/common/modals/comments-modal/comments-modal.component.html index e69de29bb2..888da289d2 100644 --- a/src/app/common/modals/comments-modal/comments-modal.component.html +++ b/src/app/common/modals/comments-modal/comments-modal.component.html @@ -0,0 +1,7 @@ + diff --git a/src/app/common/modals/comments-modal/comments-modal.component.scss b/src/app/common/modals/comments-modal/comments-modal.component.scss index e69de29bb2..76d21e070f 100644 --- a/src/app/common/modals/comments-modal/comments-modal.component.scss +++ b/src/app/common/modals/comments-modal/comments-modal.component.scss @@ -0,0 +1,17 @@ +.modal-comment { + padding: 15px; + + .image-comment { + width: 100%; + height: 100%; + align-content: center; + border-radius: 5px; + padding: 0; + border: none; + } + .pdf-comment { + width: 100%; + height: 80vh; + align-content: center; + } +} diff --git a/src/app/common/modals/comments-modal/comments-modal.component.ts b/src/app/common/modals/comments-modal/comments-modal.component.ts index 993f67ce00..6fa5e57b01 100644 --- a/src/app/common/modals/comments-modal/comments-modal.component.ts +++ b/src/app/common/modals/comments-modal/comments-modal.component.ts @@ -1,10 +1,19 @@ -import {Component, Input, Inject} from '@angular/core'; +import {Component, Input, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; @Component({ selector: 'comments-modal', - templateUrl: 'comments-modal.component.html', - styleUrls: ['comments-modal.component.scss'], + templateUrl: './comments-modal.component.html', + styleUrls: ['./comments-modal.component.scss'], }) -export class CommentsModalComponent { - constructor() {} +export class CommentsModalComponent implements OnInit { + @Input() commentType: string; + @Input() commentResourceUrl: string; + + constructor(@Inject(MAT_DIALOG_DATA) public data: any) {} + + ngOnInit(): void { + this.commentType = this.data.commentType; + this.commentResourceUrl = this.data.commentResourceUrl; + } } diff --git a/src/app/common/modals/comments-modal/comments-modal.service.ts b/src/app/common/modals/comments-modal/comments-modal.service.ts index e69de29bb2..d81a678160 100644 --- a/src/app/common/modals/comments-modal/comments-modal.service.ts +++ b/src/app/common/modals/comments-modal/comments-modal.service.ts @@ -0,0 +1,18 @@ +import {Injectable} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import {CommentsModalComponent} from './comments-modal.component'; + +@Injectable({ + providedIn: 'root', +}) +export class CommentsModalService { + constructor(public dialog: MatDialog) {} + + public show(commentResourceUrl: string, commentType: string) { + this.dialog.open(CommentsModalComponent, { + data: {commentResourceUrl, commentType}, + width: '100%', + maxWidth: '800px', + }); + } +} diff --git a/src/app/common/modals/modals.coffee b/src/app/common/modals/modals.coffee index 16d2be1ec8..003a522629 100644 --- a/src/app/common/modals/modals.coffee +++ b/src/app/common/modals/modals.coffee @@ -1,5 +1,4 @@ angular.module("doubtfire.common.modals", [ 'doubtfire.common.modals.csv-result-modal' 'doubtfire.common.modals.confirmation-modal' - 'doubtfire.common.modals.comments-modal' ]) diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 9284745988..58dc8baa67 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -224,6 +224,7 @@ import {FTaskSheetViewComponent} from './units/states/tasks/viewer/directives/f- import {TasksViewerComponent} from './units/states/tasks/tasks-viewer/tasks-viewer.component'; import {UnitCodeComponent} from './common/unit-code/unit-code.component'; import {GradeService} from './common/services/grade.service'; +import {CommentsModalComponent} from './common/modals/comments-modal/comments-modal.component'; @NgModule({ // Components we declare @@ -325,6 +326,7 @@ import {GradeService} from './common/services/grade.service'; FUsersComponent, FTaskBadgeComponent, FUnitsComponent, + CommentsModalComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 868e381213..d58937e8ad 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -119,7 +119,6 @@ import 'build/src/app/units/states/analytics/analytics.js'; import 'build/src/app/common/filters/filters.js'; import 'build/src/app/common/content-editable/content-editable.js'; import 'build/src/app/common/modals/confirmation-modal/confirmation-modal.js'; -import 'build/src/app/common/modals/comments-modal/comments-modal.js'; import 'build/src/app/common/modals/csv-result-modal/csv-result-modal.js'; import 'build/src/app/common/modals/modals.js'; import 'build/src/app/common/grade-icon/grade-icon.js'; @@ -220,11 +219,12 @@ import {FUnitTaskListComponent} from './units/states/tasks/viewer/directives/f-u import {FTaskDetailsViewComponent} from './units/states/tasks/viewer/directives/f-task-details-view/f-task-details-view.component'; import {FTaskSheetViewComponent} from './units/states/tasks/viewer/directives/f-task-sheet-view/f-task-sheet-view.component'; import {TasksViewerComponent} from './units/states/tasks/tasks-viewer/tasks-viewer.component'; - import {FUnitsComponent} from './admin/states/f-units/f-units.component'; import {MarkedPipe} from './common/pipes/marked.pipe'; import {AlertService} from './common/services/alert.service'; import {GradeService} from './common/services/grade.service'; +import {CommentsModalService} from './common/modals/comments-modal/comments-modal.service'; + export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', 'doubtfire.sessions', @@ -306,6 +306,7 @@ DoubtfireAngularJSModule.factory( downgradeInjectable(EditProfileDialogService), ); DoubtfireAngularJSModule.factory('CreateNewUnitModal', downgradeInjectable(CreateNewUnitModal)); +DoubtfireAngularJSModule.factory('CommentsModal', downgradeInjectable(CommentsModalService)); // directive -> component DoubtfireAngularJSModule.directive( From 4400a027d5388d2b14ae6e314d3fc973cd8012eb Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sat, 20 Jul 2024 20:56:57 +1000 Subject: [PATCH 0165/1280] refactor: remove old comments-modal files --- .../comments-modal/comments-modal.coffee | 32 ------------------- .../modals/comments-modal/comments-modal.scss | 15 --------- .../comments-modal/comments-modal.tpl.html | 10 ------ 3 files changed, 57 deletions(-) delete mode 100644 src/app/common/modals/comments-modal/comments-modal.coffee delete mode 100644 src/app/common/modals/comments-modal/comments-modal.scss delete mode 100644 src/app/common/modals/comments-modal/comments-modal.tpl.html diff --git a/src/app/common/modals/comments-modal/comments-modal.coffee b/src/app/common/modals/comments-modal/comments-modal.coffee deleted file mode 100644 index 59874c47e1..0000000000 --- a/src/app/common/modals/comments-modal/comments-modal.coffee +++ /dev/null @@ -1,32 +0,0 @@ -angular.module("doubtfire.common.modals.comments-modal", []) -# -# Modal to contain an image used in user comments. -# -.factory("CommentsModal", ($modal) -> - CommentsModal = {} - CommentsModal.show = (commentResourceUrl, commentType) -> - $modal.open - templateUrl: 'common/modals/comments-modal/comments-modal.tpl.html' - controller: 'CommentsModalCtrl' - size: 'lg' - resolve: - commentResourceUrl: -> commentResourceUrl - commentType: -> commentType - CommentsModal -) -.controller("CommentsModalCtrl", ($scope, $modalInstance, $sce, commentResourceUrl, commentType, alertService, fileDownloaderService) -> - # $scope.commentResourceUrl = $sce.trustAsResourceUrl(commentResourceUrl) - $scope.commentType = commentType - $scope.close = -> - fileDownloaderService.releaseBlob($scope.rawResourceUrl) - $modalInstance.dismiss() - - fileDownloaderService.downloadBlob( - commentResourceUrl, - (url, response) -> - $scope.rawResourceUrl = url - $scope.commentResourceUrl = $sce.trustAsResourceUrl(url) - (error) -> - alertService.error( "Error downloading comment: #{error}") - ) -) diff --git a/src/app/common/modals/comments-modal/comments-modal.scss b/src/app/common/modals/comments-modal/comments-modal.scss deleted file mode 100644 index 22ccacf4f8..0000000000 --- a/src/app/common/modals/comments-modal/comments-modal.scss +++ /dev/null @@ -1,15 +0,0 @@ -.modal-comment { - .image-comment { - width: 100%; - height: 100%; - align-content: center; - border-radius: 5px; - padding: 0; - border: none; - } - .pdf-comment { - width: 100%; - height: 80vh; - align-content: center; - } -} \ No newline at end of file diff --git a/src/app/common/modals/comments-modal/comments-modal.tpl.html b/src/app/common/modals/comments-modal/comments-modal.tpl.html deleted file mode 100644 index 59985945ff..0000000000 --- a/src/app/common/modals/comments-modal/comments-modal.tpl.html +++ /dev/null @@ -1,10 +0,0 @@ -
diff --git a/src/app/projects/states/project-root-state.component.ts b/src/app/projects/states/project-root-state.component.ts index 53de8a52b5..a8e026d5ac 100644 --- a/src/app/projects/states/project-root-state.component.ts +++ b/src/app/projects/states/project-root-state.component.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import {Component, Input} from '@angular/core'; -import {Observable, first} from 'rxjs'; +import {AsyncSubject, Observable, Subscriber, first} from 'rxjs'; import {Project, ProjectService} from 'src/app/api/models/doubtfire-model'; import {AppInjector} from 'src/app/app-injector'; import {NgHybridStateDeclaration} from '@uirouter/angular-hybrid'; @@ -32,19 +32,25 @@ export const ProjectRootState: NgHybridStateDeclaration = { project$: function ($stateParams) { const projectService = AppInjector.get(ProjectService); const globalState = AppInjector.get(GlobalStateService); + const projectId = parseInt($stateParams.projectId); - return new Observable((observer) => { - const projectId = parseInt($stateParams.projectId); + const result = new AsyncSubject(); - globalState.onLoad(() => { - projectService.get({id: projectId}, {cacheBehaviourOnGet: 'cacheQuery'}).subscribe({ - next: (project: Project) => { - observer.next(project); - observer.complete(); - }, - }); + const mappingCompleteCallback = (entity: Project) => { + result.next(entity); + result.complete(); + } + + // Async call to load the project + globalState.onLoad(() => { + projectService.get({id: projectId}, {cacheBehaviourOnGet: 'cacheQuery', mappingCompleteCallback: mappingCompleteCallback}).subscribe({ + next: (_project: Project) => { + // Do nothing - the mappingCompleteCallback will be called when complete + }, }); - }).pipe(first()); + }); + + return result; }, }, }; diff --git a/src/app/visualisations/progress-burndown-chart/progressburndownchart.component.ts b/src/app/visualisations/progress-burndown-chart/progressburndownchart.component.ts index 2fe29d2658..4c1920154a 100644 --- a/src/app/visualisations/progress-burndown-chart/progressburndownchart.component.ts +++ b/src/app/visualisations/progress-burndown-chart/progressburndownchart.component.ts @@ -1,16 +1,16 @@ -import { Component, OnInit, Input, SimpleChanges, LOCALE_ID } from '@angular/core'; +import { Component, OnInit, Input, SimpleChanges, LOCALE_ID, ViewContainerRef } from '@angular/core'; import { Project, Unit } from 'src/app/api/models/doubtfire-model'; import { formatDate } from '@angular/common'; import { MappingFunctions } from 'src/app/api/services/mapping-fn'; import { AppInjector } from 'src/app/app-injector'; +import { ChartBaseComponent } from 'src/app/common/chart-base/chart-base-component/chart-base-component.component'; @Component({ selector: 'f-progress-burndown-chart', templateUrl: './progressburndownchart.component.html', styleUrls: ['./progressburndownchart.component.scss'] }) - -export class ProgressBurndownChartComponent implements OnInit { +export class ProgressBurndownChartComponent extends ChartBaseComponent implements OnInit { @Input() project: Project; @Input() unit: Unit; @Input() grade: any; @@ -32,12 +32,16 @@ export class ProgressBurndownChartComponent implements OnInit { private seriesVisibility: { [key: string]: boolean } = {}; - constructor() { + constructor(public viewContainerRef: ViewContainerRef) { + super(viewContainerRef); this.data = []; this.temp = []; } ngOnInit(): void { + console.log('ProgressBurndownChartComponent: ngOnInit'); + console.log(this.project); + this.project.refreshBurndownChartData(); this.updateData(); this.data.forEach((item) => { @@ -53,8 +57,8 @@ export class ProgressBurndownChartComponent implements OnInit { } generateDates() { - const startDate: Date = this.unit.startDate; - const endDate: Date = this.unit.endDate; + const startDate: Date = this.project.unit.startDate; + const endDate: Date = this.project.unit.endDate; const locale: string = AppInjector.get(LOCALE_ID); const numberPoints = 10; // Get the number of days between dates diff --git a/src/app/visualisations/task-visualisation/taskvisualisation.component.html b/src/app/visualisations/task-visualisation/taskvisualisation.component.html index 891df20e2a..07c117cac4 100644 --- a/src/app/visualisations/task-visualisation/taskvisualisation.component.html +++ b/src/app/visualisations/task-visualisation/taskvisualisation.component.html @@ -1,7 +1,7 @@ diff --git a/src/app/visualisations/task-visualisation/taskvisualisation.component.ts b/src/app/visualisations/task-visualisation/taskvisualisation.component.ts index 9fa6ff4dec..bdca532a38 100644 --- a/src/app/visualisations/task-visualisation/taskvisualisation.component.ts +++ b/src/app/visualisations/task-visualisation/taskvisualisation.component.ts @@ -1,27 +1,23 @@ import { Component, OnInit, Input, SimpleChanges } from '@angular/core'; -import { TaskStatus } from 'src/app/api/models/task-status'; -import * as moment from 'moment'; - +import { Color } from 'd3'; +import { Project, TaskStatus, TaskStatusEnum } from 'src/app/api/models/doubtfire-model'; @Component({ - selector: 'app-task-visualisation', + selector: 'f-task-visualisation', templateUrl: './taskvisualisation.component.html', styleUrls: ['./taskvisualisation.component.scss'] }) export class TaskVisualisationComponent implements OnInit { - @Input() project: any; - @Input() grade: any; + @Input() project: Project; + @Input() grade: number; - data: any[] = []; - colors: any[] = []; + data: {name: string, value: number}[] = []; + colors: {name: string, value: string}[]; + view: number[] = [700, 400]; // options textColor: string = '#F5F5F5'; - constructor() { - this.data = []; - this.colors = []; - } ngOnInit(): void { this.updateData(); @@ -48,7 +44,7 @@ export class TaskVisualisationComponent implements OnInit { this.data = Array.from(taskCounts) .map(([status, count]) => { return { - name: this.formatTaskStatus(status), + name: TaskStatus.STATUS_LABELS.get(status), value: count, }; }) @@ -60,10 +56,11 @@ export class TaskVisualisationComponent implements OnInit { bIndex = bIndex === -1 ? sortOrder.length : bIndex; return aIndex - bIndex; - }); + }) + .filter((task) => task.value > 0); this.colors = Array.from(TaskStatus.STATUS_COLORS).map(([status, color]) => { - return { status: status, color: color }; + return { name: TaskStatus.STATUS_LABELS.get(status), value: color }; }); console.log('Data:', this.data); @@ -71,28 +68,6 @@ export class TaskVisualisationComponent implements OnInit { } } - getTaskChartColors(): any[] { - const customColors = this.colors.map((colorMapping) => { - const task = this.data.find( - (task) => this.formatTaskStatus(task.name) === this.formatTaskStatus(colorMapping.status) - ); - - const color = task && task.value > 0 ? colorMapping.color : '#EEEEEE'; - - return { - name: this.formatTaskStatus(colorMapping.status), - value: color, - }; - }); - return customColors; - } - - // to perform parsing of task labels.. - formatTaskStatus(status: string): string { - const words = status.replace(/[^a-zA-Z ]/g, ' ').split(' '); - return words.map((word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase()).join(' '); - } - onSelect(event) { console.log(event); } From 475c3165db099e1412e30fb6cf18bbaddd516e75 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 1 Nov 2024 21:25:05 +1100 Subject: [PATCH 0213/1280] feat: improve look of task status count --- src/app/api/models/task-status.ts | 3 ++- .../task-visualisation/taskvisualisation.component.ts | 10 +++++----- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/app/api/models/task-status.ts b/src/app/api/models/task-status.ts index 5068c0b7e5..f42850f430 100644 --- a/src/app/api/models/task-status.ts +++ b/src/app/api/models/task-status.ts @@ -151,7 +151,7 @@ export class TaskStatus { ]); public static readonly STATUS_LABELS = new Map([ - ['ready_for_feedback', 'Ready for Feedback'], + ['ready_for_feedback', 'Awaiting Feedback'], ['not_started', 'Not Started'], ['working_on_it', 'Working On It'], ['need_help', 'Need Help'], @@ -167,6 +167,7 @@ export class TaskStatus { public static readonly STATUS_NAME_TO_KEY = new Map([ ['Ready for Feedback', 'ready_for_feedback'], + ['Awaiting Feedback', 'ready_for_feedback'], ['Not Started', 'not_started'], ['Working On It', 'working_on_it'], ['Need Help', 'need_help'], diff --git a/src/app/visualisations/task-visualisation/taskvisualisation.component.ts b/src/app/visualisations/task-visualisation/taskvisualisation.component.ts index bdca532a38..8b5c1e1f50 100644 --- a/src/app/visualisations/task-visualisation/taskvisualisation.component.ts +++ b/src/app/visualisations/task-visualisation/taskvisualisation.component.ts @@ -39,7 +39,7 @@ export class TaskVisualisationComponent implements OnInit { } }); - const sortOrder = ['Complete', 'Not Started', 'Working On It']; + const sortOrder = ['Complete', 'Discuss', 'Awaiting Feedback', 'Working On It', 'Not Started']; this.data = Array.from(taskCounts) .map(([status, count]) => { @@ -48,6 +48,7 @@ export class TaskVisualisationComponent implements OnInit { value: count, }; }) + .filter((task) => task.value > 0 || sortOrder.includes(task.name)) .sort((a, b) => { let aIndex = sortOrder.indexOf(a.name); let bIndex = sortOrder.indexOf(b.name); @@ -56,15 +57,14 @@ export class TaskVisualisationComponent implements OnInit { bIndex = bIndex === -1 ? sortOrder.length : bIndex; return aIndex - bIndex; - }) - .filter((task) => task.value > 0); + }); this.colors = Array.from(TaskStatus.STATUS_COLORS).map(([status, color]) => { return { name: TaskStatus.STATUS_LABELS.get(status), value: color }; }); - console.log('Data:', this.data); - console.log('Colors:', this.colors); + // console.log('Data:', this.data); + // console.log('Colors:', this.colors); } } From e9cf3ecace83e2a742f7f34940bedc03babf62e9 Mon Sep 17 00:00:00 2001 From: Prabhjot Singh <81244246+PrabhKamboj@users.noreply.github.com> Date: Sun, 3 Nov 2024 20:03:10 +1100 Subject: [PATCH 0214/1280] Migrate/project tasks list (#867) * feat: create initial files for migration of project-tasks-list * feat: create initial files for migration of project-tasks-list * Revert "feat: create initial files for migration of project-tasks-list" This reverts commit 3d047b35da48b4eaf73cb551b308dbba2883a88d. * refactor: migrate project-tasks-list component to TypeScript * chore: update Angular module files for project-tasks-list migration * fix: update project progress dashboard template * chore: update tasks CoffeeScript file * style: update task status colors generator mixin * feat: add order-by and tasks-for-group-set pipes * fix: address layout and styling issues in project-tasks-list - Ensure task boxes are consistent in size - Align layout to match the original design for row consistency - Correct hover effect to include bold styling for 'Assignment #' using a tooltip component and change color to black - Add blue outline on task box click - Update Angular module file - Update global styles * chore: remove deprecated CoffeeScript and template files for project-tasks-list * style: update styles for project-tasks-list component * style: update outline and styles for project-tasks-list component * fix: minor fixes for project tasks list --------- Co-authored-by: Andrew Cain --- src/app/api/models/doubtfire-model.ts | 1 + src/app/common/filters/order-by.pipe.ts | 28 ++++ .../filters/tasks-for-group-set.pipe.ts | 15 +++ src/app/doubtfire-angular.module.ts | 6 + src/app/doubtfire-angularjs.module.ts | 7 +- .../project-progress-dashboard.tpl.html | 124 +++++++++++------- .../project-tasks-list.coffee | 59 --------- .../project-tasks-list.component.html | 22 ++++ .../project-tasks-list.component.scss | 25 ++++ .../project-tasks-list.component.ts | 69 ++++++++++ .../project-tasks-list.scss | 26 ---- .../project-tasks-list.tpl.html | 10 -- src/app/tasks/tasks.coffee | 1 - src/styles.scss | 1 + .../mixins/task-status-colors-generator.scss | 4 +- 15 files changed, 255 insertions(+), 143 deletions(-) create mode 100644 src/app/common/filters/order-by.pipe.ts create mode 100644 src/app/common/filters/tasks-for-group-set.pipe.ts delete mode 100644 src/app/tasks/project-tasks-list/project-tasks-list.coffee create mode 100644 src/app/tasks/project-tasks-list/project-tasks-list.component.html create mode 100644 src/app/tasks/project-tasks-list/project-tasks-list.component.scss create mode 100644 src/app/tasks/project-tasks-list/project-tasks-list.component.ts delete mode 100644 src/app/tasks/project-tasks-list/project-tasks-list.scss delete mode 100644 src/app/tasks/project-tasks-list/project-tasks-list.tpl.html diff --git a/src/app/api/models/doubtfire-model.ts b/src/app/api/models/doubtfire-model.ts index fffc361a4e..05ac017fc2 100644 --- a/src/app/api/models/doubtfire-model.ts +++ b/src/app/api/models/doubtfire-model.ts @@ -61,4 +61,5 @@ export * from '../services/teaching-period-break.service'; export * from '../services/learning-outcome.service'; export * from '../services/group-set.service'; export * from '../services/task-similarity.service'; +export * from '../../common/services/grade.service'; export * from '../services/test-attempt.service'; diff --git a/src/app/common/filters/order-by.pipe.ts b/src/app/common/filters/order-by.pipe.ts new file mode 100644 index 0000000000..b22c5db7ea --- /dev/null +++ b/src/app/common/filters/order-by.pipe.ts @@ -0,0 +1,28 @@ +import { Pipe, PipeTransform } from '@angular/core'; + +@Pipe({ + name: 'orderBy' +}) +export class OrderByPipe implements PipeTransform { + transform(array: any[], field: string, reverse: boolean = false): any[] { + if (!array || !field) { + return array; + } + + const sortedArray = [...array].sort((a, b) => { + if (a[field] < b[field]) { + return -1; + } + if (a[field] > b[field]) { + return 1; + } + return 0; + }); + + if (reverse) { + return sortedArray.reverse(); + } + + return sortedArray; + } +} diff --git a/src/app/common/filters/tasks-for-group-set.pipe.ts b/src/app/common/filters/tasks-for-group-set.pipe.ts new file mode 100644 index 0000000000..5e1832eaff --- /dev/null +++ b/src/app/common/filters/tasks-for-group-set.pipe.ts @@ -0,0 +1,15 @@ +import { Pipe, PipeTransform } from '@angular/core'; +import { Task, GroupSet } from 'src/app/api/models/doubtfire-model'; + +@Pipe({ + name: 'tasksForGroupset' +}) +export class TasksForGroupsetPipe implements PipeTransform { + transform(tasks: Task[], groupSet: GroupSet): Task[] { + if (!tasks) return tasks; + + return tasks.filter(task => { + return (task.definition.groupSet === groupSet) || (!task.definition.groupSet && !groupSet); + }); + } +} diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index b297b7643e..f74990816c 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -75,6 +75,7 @@ import { uploadSubmissionModalProvider, ConfirmationModalProvider, } from './ajs-upgraded-providers'; +import {ProjectTasksListComponent} from './tasks/project-tasks-list/project-tasks-list.component'; import { TaskCommentComposerComponent, DiscussionComposerDialog, @@ -140,6 +141,8 @@ import {TasksInTutorialsPipe} from './common/filters/tasks-in-tutorials.pipe'; import {TasksForInboxSearchPipe} from './common/filters/tasks-for-inbox-search.pipe'; import {StatusIconComponent} from './common/status-icon/status-icon.component'; import {ScrollingModule} from '@angular/cdk/scrolling'; +import {TasksForGroupsetPipe} from './common/filters/tasks-for-group-set.pipe'; +import {OrderByPipe} from './common/filters/order-by.pipe'; import {CheckForUpdateService} from './sessions/service-worker-updater/check-for-update.service'; import { ActivityTypeService, @@ -266,6 +269,7 @@ const MY_DATE_FORMAT = { AlertComponent, AboutDoubtfireModalContent, TeachingPeriodUnitImportDialogComponent, + ProjectTasksListComponent, TaskCommentComposerComponent, AudioCommentRecorderComponent, MicrophoneTesterComponent, @@ -318,6 +322,8 @@ const MY_DATE_FORMAT = { PdfViewerPanelComponent, StaffTaskListComponent, TaskSimilarityViewComponent, + TasksForGroupsetPipe, + OrderByPipe, FiltersPipe, TasksOfTaskDefinitionPipe, TasksInTutorialsPipe, diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 1507d28f32..c662225b34 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -46,7 +46,6 @@ import 'build/src/app/tasks/modals/upload-submission-modal/upload-submission-mod import 'build/src/app/tasks/modals/grade-task-modal/grade-task-modal.js'; import 'build/src/app/tasks/modals/modals.js'; import 'build/src/app/tasks/tasks.js'; -import 'build/src/app/tasks/project-tasks-list/project-tasks-list.js'; import 'build/src/app/tasks/task-ilo-alignment/task-ilo-alignment.js'; import 'build/src/app/tasks/task-ilo-alignment/task-ilo-alignment-rater/task-ilo-alignment-rater.js'; import 'build/src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment.js'; @@ -145,6 +144,7 @@ import 'build/src/i18n/resources-locale_en-GB.js'; //#endregion import {AboutDoubtfireModal} from 'src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.component'; +import {ProjectTasksListComponent} from './tasks/project-tasks-list/project-tasks-list.component'; import {TaskCommentComposerComponent} from 'src/app/tasks/task-comment-composer/task-comment-composer.component'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {IntelligentDiscussionPlayerComponent} from './tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-player.component'; @@ -223,6 +223,7 @@ import { TaskVisualisationComponent } from './visualisations/task-visualisation/ import {FUnitsComponent} from './admin/states/units/units.component'; import {MarkedPipe} from './common/pipes/marked.pipe'; import {AlertService} from './common/services/alert.service'; + import {GradeService} from './common/services/grade.service'; import {TaskScormCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component'; @@ -305,6 +306,10 @@ DoubtfireAngularJSModule.factory( DoubtfireAngularJSModule.factory('CreateNewUnitModal', downgradeInjectable(CreateNewUnitModal)); // directive -> component +DoubtfireAngularJSModule.directive( + 'fProjectTasksList', + downgradeComponent({component: ProjectTasksListComponent}), +); DoubtfireAngularJSModule.directive( 'taskCommentComposer', downgradeComponent({component: TaskCommentComposerComponent}), diff --git a/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html b/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html index 5dc40dc5b0..00d9887624 100644 --- a/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html +++ b/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html @@ -1,60 +1,95 @@
-
-
-
-
-
-
-

Task List

+
+
+
+
+
+
+

Task List

+
+
+
+ +
+
+
+
+
+
+

Target Grade

+ Select the grade you wish to achieve in the unit. +
+
+

+ +

-
- -
-
+
-
-
-
-

Target Grade

- Select the grade you wish to achieve in the unit. +
+ +
+
+
+
+
+

Burndown Chart

+ The Burndown chart shows how much work remains for you to achieve your target grade. +
+
+

Task Summary Chart

+ Summary of each of your task statuses +
+
+
+
+
+ + +
+
+
+
+
+
+
+
+ +

-
-
-
-
-
-
-
-
-
-
-

Burndown Chart

- The Burndown chart shows how much work remains for you to achieve your target grade.
+
+ -
-
-
- - -
+
+ Aim to keep your + Complete + line close to or ahead of the + Target + line to keep on track.
+
@@ -80,8 +115,9 @@

Task Summary Chart

line close to or ahead of the Target line to keep on track. +
-
-
-
+
+
+ \ No newline at end of file diff --git a/src/app/tasks/project-tasks-list/project-tasks-list.coffee b/src/app/tasks/project-tasks-list/project-tasks-list.coffee deleted file mode 100644 index 5e1dc4fd56..0000000000 --- a/src/app/tasks/project-tasks-list/project-tasks-list.coffee +++ /dev/null @@ -1,59 +0,0 @@ -angular.module('doubtfire.tasks.project-tasks-list', []) - -# -# Displays the tasks associated with a student's project which -# when a task is clicked will automatically jump to the task viewer -# of the task that was clicked -# -.directive('projectTasksList', -> - replace: true - restrict: 'E' - templateUrl: 'tasks/project-tasks-list/project-tasks-list.tpl.html' - scope: - unit: "=" - project: "=" - onSelect: "=" - inMenu: '@' - - controller: ($scope, $modal, newTaskService, analyticsService, gradeService) -> - analyticsService.event 'Student Project View', "Showed Task Button List" - - $scope.groupTasks = [] - - $scope.groupTasks.push.apply $scope.groupTasks, $scope.unit.groupSets.map (gs) -> - { - groupSet: gs, - name: gs.name - } - - $scope.groupTasks.push {groupSet: null, name: 'Individual Work'} - - # functions from task service - $scope.statusClass = newTaskService.statusClass - $scope.statusText = newTaskService.statusText - - $scope.taskDisabled = (task) -> - task.definition.targetGrade > $scope.project.targetGrade - - $scope.groupSetName = (id) -> - $scope.unit.groupSetsCache.get(id)?.name || "Individual Work" - - $scope.hideGroupSetName = $scope.unit.groupSets.length is 0 - - $scope.taskText = (task) -> - result = task.definition.abbreviation - - if task.definition.isGraded - if task.grade? - result += " (" + gradeService.gradeAcronyms[task.grade] + ")" - else - result += " (?)" - - if task.definition.maxQualityPts > 0 - if task.qualityPts? - result += " (" + task.qualityPts + "/" + task.definition.maxQualityPts + ")" - else - result += " (?/" + task.definition.maxQualityPts + ")" - - result -) diff --git a/src/app/tasks/project-tasks-list/project-tasks-list.component.html b/src/app/tasks/project-tasks-list/project-tasks-list.component.html new file mode 100644 index 0000000000..b4d993d733 --- /dev/null +++ b/src/app/tasks/project-tasks-list/project-tasks-list.component.html @@ -0,0 +1,22 @@ +
    +
    +
    {{ grouping.name }}
    +
    + + + + {{ + taskText(task) + }} +
    +
    +
diff --git a/src/app/tasks/project-tasks-list/project-tasks-list.component.scss b/src/app/tasks/project-tasks-list/project-tasks-list.component.scss new file mode 100644 index 0000000000..36bd44ade0 --- /dev/null +++ b/src/app/tasks/project-tasks-list/project-tasks-list.component.scss @@ -0,0 +1,25 @@ +.project-tasks-list { + .chip { + border-radius: 4px; + ::ng-deep .mdc-evolution-chip__text-label { + color: inherit !important; + } + } + + .group-set-name { + color: #777; + text-align: center; + font-size: 1em; + font-weight: bold; + } + + .mat-chip-clicked { + outline: #007bff auto 1px !important; + } + + .task-status { + ::ng-deep .mdc-evolution-chip__cell { + justify-content: center !important; + } + } +} diff --git a/src/app/tasks/project-tasks-list/project-tasks-list.component.ts b/src/app/tasks/project-tasks-list/project-tasks-list.component.ts new file mode 100644 index 0000000000..9e785100b8 --- /dev/null +++ b/src/app/tasks/project-tasks-list/project-tasks-list.component.ts @@ -0,0 +1,69 @@ +import {Component, OnInit, Input, Inject, Output, EventEmitter} from '@angular/core'; +import {analyticsService} from 'src/app/ajs-upgraded-providers'; +import {Project, Unit, Task, TaskService, TaskStatusEnum, GradeService} from 'src/app/api/models/doubtfire-model'; + +@Component({ + selector: 'f-project-tasks-list', + templateUrl: './project-tasks-list.component.html', + styleUrls: ['./project-tasks-list.component.scss'], +}) +export class ProjectTasksListComponent implements OnInit { + @Input() unit?: Unit; + @Input() project?: Project; + @Output() selectTask = new EventEmitter(); + selectedTask: Task | null = null; + + groupTasks = []; + + constructor( + private newTaskService: TaskService, + @Inject(analyticsService) private AnalyticsService, + public gradeService: GradeService, + ) {} + + ngOnInit(): void { + this.AnalyticsService.event('Student Project View', 'Showed Task Button List'); + this.groupTasks.push( + ...this.unit.groupSets.map((gs) => ({ + groupSet: gs, + name: gs.name, + })), + ); + this.groupTasks.push({groupSet: null, name: 'Individual Work'}); + } + + statusClass(status: TaskStatusEnum): string { + return this.newTaskService.statusClass(status); + } + + statusText(status: TaskStatusEnum): string { + return this.newTaskService.statusText(status); + } + + get hideGroupSetName(): boolean { + return this.unit.groupSets.length === 0; + } + + taskText(task: Task): string { + let result = task.definition.abbreviation; + if (task.definition.isGraded) { + if (task.grade) { + result += ` (${this.gradeService.gradeAcronyms[task.grade]})`; + } else { + result += ' (?)'; + } + } + if (task.definition.maxQualityPts > 0) { + if (task.qualityPts) { + result += ` (${task.qualityPts}/${task.definition.maxQualityPts})`; + } else { + result += ` (?/${task.definition.maxQualityPts})`; + } + } + return result; + } + + selectChip(task: Task): void { + this.selectedTask = task; + } +} diff --git a/src/app/tasks/project-tasks-list/project-tasks-list.scss b/src/app/tasks/project-tasks-list/project-tasks-list.scss deleted file mode 100644 index 4f94364fad..0000000000 --- a/src/app/tasks/project-tasks-list/project-tasks-list.scss +++ /dev/null @@ -1,26 +0,0 @@ -.project-tasks-list { - @include remove-list-padding; - text-align: center; - - .groupset-name { - color: #777; - text-align: center; - font-size: 1em; - font-weight: bold; - } - - li { - display: inline; - padding: 2px; - } - - .groupset-tasks:first-child .groupset-name { - margin-top: 0; - } - - // As a dropdown menu - &.dropdown-menu { - padding: 15px; - width: 400px; - } -} diff --git a/src/app/tasks/project-tasks-list/project-tasks-list.tpl.html b/src/app/tasks/project-tasks-list/project-tasks-list.tpl.html deleted file mode 100644 index ee9b845aed..0000000000 --- a/src/app/tasks/project-tasks-list/project-tasks-list.tpl.html +++ /dev/null @@ -1,10 +0,0 @@ -
    -
    -
    {{grouping.name}}
    -
  • - -
  • -
    -
diff --git a/src/app/tasks/tasks.coffee b/src/app/tasks/tasks.coffee index 5144dc6667..fedd49fc17 100644 --- a/src/app/tasks/tasks.coffee +++ b/src/app/tasks/tasks.coffee @@ -1,5 +1,4 @@ angular.module('doubtfire.tasks', [ 'doubtfire.tasks.modals' 'doubtfire.tasks.task-ilo-alignment' - 'doubtfire.tasks.project-tasks-list' ]) diff --git a/src/styles.scss b/src/styles.scss index f8ab056beb..0df654e6ba 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -63,3 +63,4 @@ $main-view-max-height: calc((var(--vh, 1vh) * (100)) - 85px); } } } + diff --git a/src/styles/mixins/task-status-colors-generator.scss b/src/styles/mixins/task-status-colors-generator.scss index e37542874a..9f473d74a7 100644 --- a/src/styles/mixins/task-status-colors-generator.scss +++ b/src/styles/mixins/task-status-colors-generator.scss @@ -14,9 +14,9 @@ } @mixin task-status-color($status) { - color: task-status-color($status, fore); + color: task-status-color($status, fore) !important; $base-color: task-status-color($status); - background-color: $base-color; + background-color: $base-color !important; @if $status == 'complete' { $lighter-color: task-status-color($status, light); @include gradient-vertical($lighter-color, $base-color); From eaa40e7f433156f11beec2dbec874df87690cf03 Mon Sep 17 00:00:00 2001 From: Leo Luong <65574142+leocomsci@users.noreply.github.com> Date: Mon, 4 Nov 2024 20:16:09 +1100 Subject: [PATCH 0215/1280] Migrate:grade task modal (#564) * fix: ensure test dependencies are compatible This commit fixes dependencies issues that causes - `npm install` fails - `ng test` does not pick up any specs * test: add test command and doc * fix: add missing dependencies in component tests This commits ensure the unit tests are setup with correct dependencies. * fix: disable incomplete user service tests * ci: run unit tests in GitHub CI We use 2 Karma configurations to regulate how tests are run locally and in CI. - In development, the server runs forever with watch mode, using Chrome browser - In CI, the service runs once, using Chrome headless * refactor: remove task sheet viewer component * new: create inital files for grade-icon migration * refactor: unlink old component, add in new and downgrade * migrate: complete grade-icon component migration * refactor: remove old grade-icon component * refactor: update all usages of component * refactor: improve component styling * test: add unit tests for grade-icon component * docs: update Thoth Tech build badge reference * refactor: remove duplicate line in scss files * refactor: use prettier on migrated component * feat: format code using ESLint and Prettier This adds ability to format code using both ESLint and Prettier rules. * fix: include angular relevant lint rules * fix: address minor eslint issues * fix: report all lint issues as warning There are a large number of violations in the code base. We will need to incrementally address them in future pull requests. * docs: update formatting instructions * ci: use same lint command for development and CI * fix: escape dashes in unicode regex This fixes 'Range out of order in character class' error when trying to parse regex marked with `/u` unicode flag. * new: create initial files for migration of grade-task-modal * new: create service to show grade-task-modal * refactor: add and downgrade service to angularjs module * refactor: unlink old component and add in new * refactor: update task service to call migrated component * migrate: complete migration for rating quality-point tasks * refactor: add ability to grade tasks, tidy up component * refactor: prevent negative ratings * test: add unit tests * refactor: remove old component files * fix: buttons alignment in safari * refactor: add spacing between rating and grading * refactor: ran prettier * refactor: append df prefix to component selector * refactor: remove br and add spacing with ngstyle * style: remove inline style and create class * refactor: perform rating calculation in ts file * refactor: allow mat-slider to begin at 0 * refactor: replace buttons style with align * style: replace margin with padding * test: fix test to reflect rating of 0 * test: add test for rating label * refactor: remove console logging * fix: fix some minor error * chore: change welcome component name --------- Co-authored-by: Tan Le Co-authored-by: Perry Rose Co-authored-by: PerryRose <49971210+PerryRose@users.noreply.github.com> Co-authored-by: Andrew Cain Co-authored-by: A Luan Luong --- README.md | 13 +- src/app/api/models/task.ts | 41 ++--- src/app/common/common.coffee | 1 - src/app/common/grade-icon/grade-icon.coffee | 16 -- .../grade-icon/grade-icon.component.html | 3 + .../grade-icon/grade-icon.component.scss | 13 ++ .../grade-icon/grade-icon.component.spec.ts | 86 +++++++++ .../common/grade-icon/grade-icon.component.ts | 25 +++ src/app/common/grade-icon/grade-icon.scss | 48 ----- src/app/common/grade-icon/grade-icon.tpl.html | 8 - src/app/doubtfire-angular.module.ts | 4 + src/app/doubtfire-angularjs.module.ts | 10 +- ...roup-member-contribution-assigner.tpl.html | 24 +-- .../group-member-list.tpl.html | 2 +- .../project-progress-dashboard.tpl.html | 7 +- .../portfolio-grade-select-step.coffee | 5 +- .../portfolio-grade-select-step.tpl.html | 4 +- .../grade-task-modal/grade-task-modal.coffee | 41 ----- .../grade-task-modal.component.html | 68 +++++++ .../grade-task-modal.component.scss | 36 ++++ .../grade-task-modal.component.spec.ts | 169 ++++++++++++++++++ .../grade-task-modal.component.ts | 77 ++++++++ .../grade-task-modal/grade-task-modal.scss | 19 -- .../grade-task-modal.service.ts | 28 +++ .../grade-task-modal.tpl.html | 27 --- src/app/tasks/modals/modals.coffee | 1 - .../units/states/portfolios/portfolios.scss | 14 ++ .../states/portfolios/portfolios.tpl.html | 7 +- .../students-list/students-list.tpl.html | 4 +- src/app/welcome/welcome.component.ts | 5 +- 30 files changed, 587 insertions(+), 219 deletions(-) delete mode 100644 src/app/common/grade-icon/grade-icon.coffee create mode 100644 src/app/common/grade-icon/grade-icon.component.html create mode 100644 src/app/common/grade-icon/grade-icon.component.scss create mode 100644 src/app/common/grade-icon/grade-icon.component.spec.ts create mode 100644 src/app/common/grade-icon/grade-icon.component.ts delete mode 100644 src/app/common/grade-icon/grade-icon.scss delete mode 100644 src/app/common/grade-icon/grade-icon.tpl.html delete mode 100644 src/app/tasks/modals/grade-task-modal/grade-task-modal.coffee create mode 100644 src/app/tasks/modals/grade-task-modal/grade-task-modal.component.html create mode 100644 src/app/tasks/modals/grade-task-modal/grade-task-modal.component.scss create mode 100644 src/app/tasks/modals/grade-task-modal/grade-task-modal.component.spec.ts create mode 100644 src/app/tasks/modals/grade-task-modal/grade-task-modal.component.ts delete mode 100644 src/app/tasks/modals/grade-task-modal/grade-task-modal.scss create mode 100644 src/app/tasks/modals/grade-task-modal/grade-task-modal.service.ts delete mode 100644 src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html diff --git a/README.md b/README.md index b213dcce33..3e5b0546e5 100644 --- a/README.md +++ b/README.md @@ -227,11 +227,14 @@ TODO: ## Table of Contents -1. [Getting Started](#getting-started) -2. [Resources](#resources) -3. [Contributing](#contributing) -4. [Deployment](#deployment) -5. [License](#license) +- [Doubtfire Web ![CI](https://github.com/doubtfire-lms/doubtfire-web/actions/workflows/nodejs-ci.yml)](#doubtfire-web-) + - [Migration Progress](#migration-progress) + - [Table of Contents](#table-of-contents) + - [Getting Started](#getting-started) + - [Deployment](#deployment) + - [Resources](#resources) + - [Contributing](#contributing) + - [License](#license) ## Getting Started diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index 553eb500cc..af279dd6c7 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -23,9 +23,10 @@ import {Grade} from './grade'; import {LOCALE_ID} from '@angular/core'; import { HttpClient } from '@angular/common/http'; import {Observable, map} from 'rxjs'; -import {gradeTaskModal, uploadSubmissionModal} from 'src/app/ajs-upgraded-providers'; +import {uploadSubmissionModal} from 'src/app/ajs-upgraded-providers'; import {AlertService} from 'src/app/common/services/alert.service'; import {MappingFunctions} from '../services/mapping-fn'; +import { GradeTaskModalService } from 'src/app/tasks/modals/grade-task-modal/grade-task-modal.service'; export class Task extends Entity { id: number; @@ -670,28 +671,22 @@ export class Task extends Entity { }); }; // end update function - // Must provide grade if graded and in a final complete state - if ( - (this.definition.isGraded || this.definition.maxQualityPts > 0) && - TaskStatus.GRADEABLE_STATUSES.includes(status) - ) { - const gradeModal: any = AppInjector.get(gradeTaskModal); - const modal = gradeModal.show(this); - if (modal) { - modal.result.then( - // Grade was selected (modal closed with result) - (response) => { - this.grade = response.selectedGrade; - this.qualityPts = response.qualityPts; - updateFunc(); - }, - // Grade was not selected (modal was dismissed) - () => { - this.status = oldStatus; - alerts.message('Status reverted, as no grade was specified', 6000); - }, - ); - } + // Must provide grade if graded and in a final complete state - so use callback to run update function + if ((this.definition.isGraded || this.definition.maxQualityPts > 0) && TaskStatus.GRADEABLE_STATUSES.includes(status)) { + const gradeModal: GradeTaskModalService = AppInjector.get(GradeTaskModalService); + gradeModal.show(this, + // Grade was selected (modal closed with result) + (response) => { + this.grade = response.grade; + this.qualityPts = response.qualityPts; + updateFunc(); + }, + // Grade was not selected (modal was dismissed) + () => { + this.status = oldStatus; + alerts.message('Status reverted, as no grade was specified', 6000); + }, + ); } else { updateFunc(); } diff --git a/src/app/common/common.coffee b/src/app/common/common.coffee index e5bbea48a2..f330d8f6ac 100644 --- a/src/app/common/common.coffee +++ b/src/app/common/common.coffee @@ -3,6 +3,5 @@ angular.module("doubtfire.common", [ 'doubtfire.common.filters' 'doubtfire.common.modals' 'doubtfire.common.file-uploader' - 'doubtfire.common.grade-icon' 'doubtfire.common.content-editable' ]) diff --git a/src/app/common/grade-icon/grade-icon.coffee b/src/app/common/grade-icon/grade-icon.coffee deleted file mode 100644 index f35f7fbfa4..0000000000 --- a/src/app/common/grade-icon/grade-icon.coffee +++ /dev/null @@ -1,16 +0,0 @@ -angular.module('doubtfire.common.grade-icon', []) - -.directive 'gradeIcon', -> - restrict: 'E' - replace: true - templateUrl: 'common/grade-icon/grade-icon.tpl.html' - scope: - inputGrade: '=?grade' - colorful: '=?' - controller: ($scope, gradeService) -> - $scope.$watch 'inputGrade', (newGrade) -> - $scope.grade = if _.isString($scope.inputGrade) then gradeService.stringToGrade($scope.inputGrade) else $scope.inputGrade - $scope.gradeText = (grade) -> - if grade? then gradeService.grades[grade] or "Grade" - $scope.gradeLetter = (grade) -> - gradeService.gradeAcronyms[grade] or 'G' diff --git a/src/app/common/grade-icon/grade-icon.component.html b/src/app/common/grade-icon/grade-icon.component.html new file mode 100644 index 0000000000..0b1f23bec2 --- /dev/null +++ b/src/app/common/grade-icon/grade-icon.component.html @@ -0,0 +1,3 @@ + + {{ gradeLetter }} + diff --git a/src/app/common/grade-icon/grade-icon.component.scss b/src/app/common/grade-icon/grade-icon.component.scss new file mode 100644 index 0000000000..3b67a46b27 --- /dev/null +++ b/src/app/common/grade-icon/grade-icon.component.scss @@ -0,0 +1,13 @@ +.grade-icon { + color: #fff; + font-size: 1em; + border-radius: 100%; + width: 2.25em; + height: 2.25em; + font-weight: 100; + margin: 0 auto; + display: flex; + align-items: center; + justify-content: center; + background-color: #333333; +} diff --git a/src/app/common/grade-icon/grade-icon.component.spec.ts b/src/app/common/grade-icon/grade-icon.component.spec.ts new file mode 100644 index 0000000000..f1c6f74d9f --- /dev/null +++ b/src/app/common/grade-icon/grade-icon.component.spec.ts @@ -0,0 +1,86 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { GradeIconComponent } from './grade-icon.component'; +import { gradeService } from 'src/app/ajs-upgraded-providers'; + +describe('GradeIconComponent', () => { + let component: GradeIconComponent; + let fixture: ComponentFixture; + let gradeServiceStub: jasmine.SpyObj; + + beforeEach( + waitForAsync(() => { + gradeServiceStub = { + grades: ['Pass', 'Credit', 'Distinction', 'High Distinction'], + gradeAcronyms: { + Fail: 'F', + Pass: 'P', + Credit: 'C', + Distinction: 'D', + 'High Distinction': 'HD', + 0: 'P', + 1: 'C', + 2: 'D', + 3: 'HD', + }, + }; + + gradeServiceStub.grades[-1] = 'Fail'; + gradeServiceStub.gradeAcronyms[-1] = 'F'; + + TestBed.configureTestingModule({ + declarations: [GradeIconComponent], + providers: [{ provide: gradeService, useValue: gradeServiceStub }], + }).compileComponents(); + }) + ); + + beforeEach(() => { + fixture = TestBed.createComponent(GradeIconComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should set the index value when undefined', () => { + component.index = undefined; + component.ngOnInit(); + + expect(component.index).toEqual(-1); + }); + + it('should set the grade to Fail when given invalid input', () => { + component.index = undefined; + component.grade = 'Tomato'; + component.ngOnInit(); + + expect(component.index).toEqual(-1); + expect(component.gradeText).toEqual('Fail'); + expect(component.gradeLetter).toEqual('F'); + }); + + it('should appropriate set the grade when passed a grade value', () => { + gradeServiceStub.grades.forEach((grade: string) => { + component.grade = grade; + component.index = undefined; + component.ngOnInit(); + + expect(component.index).toEqual(gradeServiceStub.grades.indexOf(grade)); + expect(component.gradeText).toEqual(grade); + expect(component.gradeLetter).toEqual(gradeServiceStub.gradeAcronyms[grade]); + }); + }); + + it('should appropriate set the grade when passed a grade index', () => { + gradeServiceStub.grades.forEach((_, index: number) => { + component.index = index - 1; + component.ngOnInit(); + + expect(component.index).toEqual(index - 1); + expect(component.gradeText).toEqual(gradeServiceStub.grades[component.index]); + expect(component.gradeLetter).toEqual(gradeServiceStub.gradeAcronyms[component.gradeText]); + }); + }); +}); diff --git a/src/app/common/grade-icon/grade-icon.component.ts b/src/app/common/grade-icon/grade-icon.component.ts new file mode 100644 index 0000000000..0a283c0d0c --- /dev/null +++ b/src/app/common/grade-icon/grade-icon.component.ts @@ -0,0 +1,25 @@ +import { Component, OnInit, Input } from '@angular/core'; +import { GradeService } from '../services/grade.service'; + +@Component({ + selector: 'grade-icon', + templateUrl: 'grade-icon.component.html', + styleUrls: ['grade-icon.component.scss'], +}) +export class GradeIconComponent implements OnInit { + @Input() grade: string | number = 'F'; + @Input() index: number; + + gradeText: string; + gradeLetter: string; + + constructor(private gradeService: GradeService) {} + + ngOnInit(): void { + if (this.index == undefined) { + this.index = this.gradeService.gradeNumbers[this.grade] || this.grade; + } + this.gradeText = this.gradeService.grades[this.index]; + this.gradeLetter = this.gradeService.gradeAcronyms[this.gradeText]; + } +} diff --git a/src/app/common/grade-icon/grade-icon.scss b/src/app/common/grade-icon/grade-icon.scss deleted file mode 100644 index 08db661a8b..0000000000 --- a/src/app/common/grade-icon/grade-icon.scss +++ /dev/null @@ -1,48 +0,0 @@ -.grade-icon.text-muted { - background-color: $text-muted; -} -.grade-icon.text-primary { - background-color: $brand-primary; -} -.grade-icon.text-success { - background-color: $brand-success; -} -.grade-icon.text-danger { - background-color: $brand-danger; -} -.grade-icon.text-info { - background-color: $brand-info; -} -.grade-icon.text-warning { - background-color: $brand-warning; -} -a .grade-icon:hover { - background-color: $link-hover-color; -} -.grade-icon { - color: #fff; - font-size: 1em; - background-color: $text-color; - border-radius: 100%; - width: 2.25em; - height: 2.25em; - font-weight: 100; - font-size: 1em; - @include no-select; - margin: 0 auto; - display: flex; - align-items: center; - justify-content: center; -} -.grade-icon.colorful { - &.grade-0 { background-color: $grade-color-p; } - &.grade-1 { background-color: $grade-color-c; } - &.grade-2 { background-color: $grade-color-d; } - &.grade-3 { background-color: $grade-color-hd; } -} -.text-left .grade-icon { - margin-left: 0; -} -.text-right .grade-icon { - margin-right: 0; -} diff --git a/src/app/common/grade-icon/grade-icon.tpl.html b/src/app/common/grade-icon/grade-icon.tpl.html deleted file mode 100644 index 1939b21361..0000000000 --- a/src/app/common/grade-icon/grade-icon.tpl.html +++ /dev/null @@ -1,8 +0,0 @@ -
- - {{gradeLetter(grade)}} - -
diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index f74990816c..a9d165749c 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -249,6 +249,8 @@ import {TaskScormCardComponent} from './projects/states/dashboard/directives/tas import {TestAttemptService} from './api/services/test-attempt.service'; import {ScormExtensionCommentComponent} from './tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component'; import {ScormExtensionModalComponent} from './common/modals/scorm-extension-modal/scorm-extension-modal.component'; +import { GradeIconComponent } from './common/grade-icon/grade-icon.component'; +import { GradeTaskModalComponent } from './tasks/modals/grade-task-modal/grade-task-modal.component'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { @@ -337,6 +339,8 @@ const MY_DATE_FORMAT = { TaskDropdownComponent, SplashScreenComponent, ProjectDashboardComponent, + GradeIconComponent, + GradeTaskModalComponent, ObjectSelectComponent, WelcomeComponent, AcceptEulaComponent, diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index c662225b34..650fa27fcd 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -43,7 +43,6 @@ import 'build/src/app/visualisations/achievement-custom-bar-chart.js'; import 'build/src/app/visualisations/alignment-bar-chart.js'; import 'build/src/app/visualisations/achievement-box-plot.js'; import 'build/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.js'; -import 'build/src/app/tasks/modals/grade-task-modal/grade-task-modal.js'; import 'build/src/app/tasks/modals/modals.js'; import 'build/src/app/tasks/tasks.js'; import 'build/src/app/tasks/task-ilo-alignment/task-ilo-alignment.js'; @@ -119,7 +118,6 @@ import 'build/src/app/common/modals/confirmation-modal/confirmation-modal.js'; import 'build/src/app/common/modals/comments-modal/comments-modal.js'; import 'build/src/app/common/modals/csv-result-modal/csv-result-modal.js'; import 'build/src/app/common/modals/modals.js'; -import 'build/src/app/common/grade-icon/grade-icon.js'; import 'build/src/app/common/file-uploader/file-uploader.js'; import 'build/src/app/common/common.js'; import 'build/src/app/common/services/listener-service.js'; @@ -195,6 +193,8 @@ import { HeaderComponent } from './common/header/header.component'; import { SplashScreenComponent } from './home/splash-screen/splash-screen.component'; import { GlobalStateService } from './projects/states/index/global-state.service'; import { TransitionHooksService } from './sessions/transition-hooks.service'; +import { GradeIconComponent } from './common/grade-icon/grade-icon.component'; +import { GradeTaskModalService } from './tasks/modals/grade-task-modal/grade-task-modal.service'; import { AuthenticationService } from './api/services/authentication.service'; import { ProjectService } from './api/services/project.service'; import { ObjectSelectComponent } from './common/obect-select/object-select.component'; @@ -211,7 +211,6 @@ import { InboxComponent } from './units/states/tasks/inbox/inbox.component'; import { TaskDefinitionEditorComponent } from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component'; import { UnitAnalyticsComponent } from './units/states/analytics/unit-analytics-route.component'; import { UnitTaskEditorComponent } from './units/states/edit/directives/unit-tasks-editor/unit-task-editor.component'; -import { TeachingPeriodUnitImportService } from './admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog'; import { CreateNewUnitModal } from './admin/modals/create-new-unit-modal/create-new-unit-modal.component'; import { FUsersComponent } from './admin/states/users/users.component'; import { FUnitTaskListComponent } from './units/task-viewer/directives/unit-task-list/unit-task-list.component'; @@ -304,12 +303,17 @@ DoubtfireAngularJSModule.factory( downgradeInjectable(EditProfileDialogService), ); DoubtfireAngularJSModule.factory('CreateNewUnitModal', downgradeInjectable(CreateNewUnitModal)); +DoubtfireAngularJSModule.factory('GradeTaskModal', downgradeInjectable(GradeTaskModalService)); // directive -> component DoubtfireAngularJSModule.directive( 'fProjectTasksList', downgradeComponent({component: ProjectTasksListComponent}), ); +DoubtfireAngularJSModule.directive( + 'gradeIcon', + downgradeComponent({component: GradeIconComponent}), +); DoubtfireAngularJSModule.directive( 'taskCommentComposer', downgradeComponent({component: TaskCommentComposerComponent}), diff --git a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.tpl.html b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.tpl.html index 4caab308f5..1fa8194d11 100644 --- a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.tpl.html +++ b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.tpl.html @@ -8,29 +8,29 @@ - - {{contrib.project.student.name}} + + {{member.student_name}} - + - - {{contrib.percent}} % effort + class="label {{percentClass(member.percent)}}" + ng-show="member.overStar"> + + {{member.percent}} % effort - + No effort diff --git a/src/app/groups/group-member-list/group-member-list.tpl.html b/src/app/groups/group-member-list/group-member-list.tpl.html index f483b4acbd..8c3b3c2dc5 100644 --- a/src/app/groups/group-member-list/group-member-list.tpl.html +++ b/src/app/groups/group-member-list/group-member-list.tpl.html @@ -38,7 +38,7 @@

No members in group

{{member.student.username || "N/A"}} {{member.student.name}} - +

+ + @@ -30,7 +34,7 @@

Target Grade

- +
@@ -120,4 +124,3 @@

Task Summary Chart

- \ No newline at end of file diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee index d29d0f65da..3a7ee7f2a4 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee @@ -9,7 +9,10 @@ angular.module('doubtfire.projects.states.portfolio.directives.portfolio-grade-s replace: true templateUrl: 'projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html' controller: ($scope, newProjectService, gradeService) -> - $scope.grades = gradeService.grades + if ! $scope.project.submittedGrade + $scope.project.submittedGrade = 0 + $scope.grades = gradeService.gradeValues + $scope.gradeName = (grade) -> gradeService.grades[grade] $scope.agreedToAssessmentCriteria = $scope.projectHasLearningSummaryReport() $scope.chooseGrade = (idx) -> $scope.project.submittedGrade = idx diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html index 244c110857..097b685e35 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html @@ -35,14 +35,14 @@

Grade Application

btn-radio="{{$index}}" >

Make sure your Learning Summary Report justifies how your portfolio demonstrates you have - met all unit learning outcomes to a {{targetGrade}} level + met all unit learning outcomes to a {{gradeName(project.submittedGrade)}} level

diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.coffee b/src/app/tasks/modals/grade-task-modal/grade-task-modal.coffee deleted file mode 100644 index 057dffee92..0000000000 --- a/src/app/tasks/modals/grade-task-modal/grade-task-modal.coffee +++ /dev/null @@ -1,41 +0,0 @@ -angular.module('doubtfire.tasks.modals.grade-task-modal', []) - -# -# A modal to grade a graded task -# -.factory('GradeTaskModal', ($modal) -> - GradeTaskModal = {} - - # - # Open a grade task modal with the provided task - # - GradeTaskModal.show = (task) -> - $modal.open - templateUrl: 'tasks/modals/grade-task-modal/grade-task-modal.tpl.html' - controller: 'GradeTaskModal' - resolve: - task: -> task - - GradeTaskModal -) -.controller('GradeTaskModal', ($scope, $modalInstance, gradeService, task) -> - $scope.task = task - $scope.data = { desiredGrade: task.grade, rating: task.qualityPts || 1, overStar: 0, confRating: 0 } - $scope.gradeValues = gradeService.allGradeValues - $scope.grades = gradeService.grades - $scope.dismiss = $modalInstance.dismiss - $scope.numStars = task.definition.maxQualityPts || 5 - $scope.close = -> - $modalInstance.close { qualityPts: $scope.data.rating, selectedGrade: $scope.data.desiredGrade} - - $scope.hoveringOver = (value) -> - $scope.data.overStar = value - - $scope.checkClearRating = -> - if $scope.data.confRating == 1 && $scope.data.rating == 1 && $scope.data.overStar == 1 - $scope.data.rating = 0 - else if $scope.data.confRating == 1 && $scope.data.overStar == 1 && $scope.data.rating == 0 - $scope.data.rating = 1 - - $scope.data.confRating = $scope.data.rating -) diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.html b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.html new file mode 100644 index 0000000000..ca25990989 --- /dev/null +++ b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.html @@ -0,0 +1,68 @@ + + Assess Task Quality + + +
+

+ Please provide a grade for task + + {{ task.definition.abbreviation }} + +

+
+ + + + + +
+
+ +
+

+ Please provide a quality rating for task + + {{ task.definition.abbreviation }} + +

+ + + +
+

Rating: {{ rating }} / {{totalRating}}

+
+
+
+ + + + + +
diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.scss b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.scss new file mode 100644 index 0000000000..ac4c1a21bf --- /dev/null +++ b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.scss @@ -0,0 +1,36 @@ +.grade-task-modal { + width: 450px; + padding-left: 2rem; + padding-right: 2rem; +} + +.slider { + width: 100%; +} + +.task-label { + background-color: #3939ff; + color: white; + padding: 0 0.75rem; + border-radius: 0.75rem; + margin-left: 0.5rem; + font-size: small; +} + +.label-rating { + display: flex; + justify-content: end; +} + +.grade-toggle-group { + display: flex; + justify-content: center; +} + +.grade-toggle { + padding: 0.5rem 0; +} + +.grade-task-item + .grade-task-item { + padding-top: 2rem; +} diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.spec.ts b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.spec.ts new file mode 100644 index 0000000000..32c6681f80 --- /dev/null +++ b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.spec.ts @@ -0,0 +1,169 @@ +import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; +import { GradeTaskModalComponent } from './grade-task-modal.component'; +import { gradeService } from 'src/app/ajs-upgraded-providers'; +import { MatDialogRef, MAT_DIALOG_DATA } from '@angular/material/dialog'; + +describe('GradeTaskModalComponent', () => { + let component: GradeTaskModalComponent; + let fixture: ComponentFixture; + let gradeServiceStub: jasmine.SpyObj; + let dialogRefMock: jasmine.SpyObj; + let dialogDataStub: jasmine.SpyObj; + + beforeEach( + waitForAsync(() => { + gradeServiceStub = { + grades: ['Pass', 'Credit', 'Distinction', 'High Distinction'], + gradeAcronyms: { + Fail: 'F', + Pass: 'P', + Credit: 'C', + Distinction: 'D', + 'High Distinction': 'HD', + 0: 'P', + 1: 'C', + 2: 'D', + 3: 'HD', + }, + allGradeValues: [-1, 0, 1, 2, 3], + }; + gradeServiceStub.grades[-1] = 'Fail'; + gradeServiceStub.gradeAcronyms[-1] = 'F'; + + dialogDataStub = { + task: { + grade: undefined, + quality_pts: undefined, + definition: { + max_quality_pts: undefined, + }, + }, + }; + + dialogRefMock = { + close: () => {}, + }; + + TestBed.configureTestingModule({ + declarations: [GradeTaskModalComponent], + providers: [ + { provide: gradeService, useValue: gradeServiceStub }, + { provide: MatDialogRef, useValue: dialogRefMock }, + { provide: MAT_DIALOG_DATA, useValue: dialogDataStub }, + ], + }).compileComponents(); + }) + ); + + beforeEach(() => { + fixture = TestBed.createComponent(GradeTaskModalComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); + + it('should return rating & grade when closed', () => { + spyOn(component.dialogRef, 'close'); + + component.rating = 5; + component.selectedGrade = 2; + component.close(); + + expect(component.dialogRef.close).toHaveBeenCalledWith({ + qualityPts: 5, + selectedGrade: 2, + }); + }); + + it('should dismiss', () => { + spyOn(component.dialogRef, 'close'); + component.dismiss(); + expect(component.dialogRef.close).toHaveBeenCalled(); + }); + + /** + * For Rating tasks + */ + it('should accept a new task object', () => { + const newRatingTask = { + grade: undefined, + quality_pts: 5, + definition: { + max_quality_pts: 10, + }, + }; + dialogDataStub.task = newRatingTask; + + component.ngOnInit(); + expect(component.task).toEqual(newRatingTask); + expect(component.rating).toEqual(newRatingTask.quality_pts); + expect(component.selectedGrade).toEqual(newRatingTask.grade); + expect(component.totalRating).toEqual(newRatingTask.definition.max_quality_pts); + }); + + it('should not allow a rating higher than the max rating', () => { + component.ngOnInit(); + component.rating = 1; + component.totalRating = 10; + component.updateRating(20); + + expect(component.rating).toEqual(1); + expect(component.totalRating).toEqual(10); + }); + + it('should not allow a rating lower than 0', () => { + component.ngOnInit(); + component.totalRating = 10; + component.updateRating(-10); + + expect(component.rating).toEqual(0); + expect(component.totalRating).toEqual(10); + }); + + it('should accept a new valid rating', () => { + component.ngOnInit(); + component.totalRating = 10; + component.updateRating(9); + + expect(component.rating).toEqual(9); + expect(component.totalRating).toEqual(10); + }); + + it('should reflect the rating in the rating label', () => { + component.ngOnInit(); + expect(component.ratingLabel).toEqual('0 / 5'); + + component.updateRating(-1); + expect(component.ratingLabel).toEqual('0 / 5'); + + component.updateRating(12); + expect(component.ratingLabel).toEqual('0 / 5'); + + component.updateRating(2); + expect(component.ratingLabel).toEqual('2 / 5'); + + component.updateRating(5); + expect(component.ratingLabel).toEqual('5 / 5'); + }); + + /** + * For Graded Tasks + */ + it('should accept a new valid grade', () => { + component.ngOnInit(); + component.updateGrade(3); + expect(component.selectedGrade).toEqual(3); + }); + + it('should not accept a new invalid grade', () => { + component.ngOnInit(); + component.updateGrade(10); + expect(component.selectedGrade).toEqual(undefined); + + component.updateGrade(-10); + expect(component.selectedGrade).toEqual(undefined); + }); +}); diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.ts b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.ts new file mode 100644 index 0000000000..1239308a3a --- /dev/null +++ b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.ts @@ -0,0 +1,77 @@ +import { Component, OnInit, Inject } from '@angular/core'; +import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; +import { Task, GradeService } from 'src/app/api/models/doubtfire-model'; + +@Component({ + selector: 'grade-task-modal', + templateUrl: './grade-task-modal.component.html', + styleUrls: ['./grade-task-modal.component.scss'], +}) +export class GradeTaskModalComponent implements OnInit { + task: Task; + gradeValues: number[]; + + // Task Rating + totalRating: number; + rating: number; + ratingLabel: string; + + // Grade Select + selectedGrade: number; + + constructor( + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public dialogData: {task: Task}, + private gradeService: GradeService + ) {} + + ngOnInit(): void { + this.task = this.dialogData.task; + this.rating = this.task.qualityPts || 0; + this.selectedGrade = this.task.grade || 0; + this.totalRating = this.task.definition.maxQualityPts || 5; + this.gradeValues = this.gradeService.allGradeValues; + this.updateRatingLabel(); + } + + gradeName(grade: number): string { + return this.gradeService.grades[grade]; + } + + dismiss(): void { + this.dialogRef.close(); + } + + close(): void { + // Pass values back to service + this.dialogRef.close({ + qualityPts: this.rating, + selectedGrade: this.selectedGrade, + }); + } + + isValid() { + return ( + (this.task.definition.isGraded && this.selectedGrade) || + (this.task.definition.maxQualityPts > 0 && this.rating) + ); + } + + updateRating(value: number): void { + if (value >= 0 && value <= this.totalRating) { + this.rating = value; + this.updateRatingLabel(); + } + } + + updateRatingLabel(): void { + this.ratingLabel = `${this.rating} / ${this.totalRating}`; + } + + updateGrade(grade: number | string): void { + const gradeValue = Number(grade) + if (this.gradeValues.includes(gradeValue)) { + this.selectedGrade = gradeValue; + } + } +} diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.scss b/src/app/tasks/modals/grade-task-modal/grade-task-modal.scss deleted file mode 100644 index 29e7941885..0000000000 --- a/src/app/tasks/modals/grade-task-modal/grade-task-modal.scss +++ /dev/null @@ -1,19 +0,0 @@ -.grade-task-modal { - .task-quality-rating { - &:focus { - outline: none; - } - i { - font-size: 2em; - cursor: pointer; - } - .icon-colorful { - color: rgb(255, 247, 141); - -webkit-text-stroke-width: 1px; - -webkit-text-stroke-color: orange; - } - .icon-disable { - color: #ccc; - } - } -} diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.service.ts b/src/app/tasks/modals/grade-task-modal/grade-task-modal.service.ts new file mode 100644 index 0000000000..ee2e0fad56 --- /dev/null +++ b/src/app/tasks/modals/grade-task-modal/grade-task-modal.service.ts @@ -0,0 +1,28 @@ +import { Injectable } from '@angular/core'; +import { MatDialog } from '@angular/material/dialog'; +import { GradeTaskModalComponent } from './grade-task-modal.component'; +import { Task } from 'src/app/api/models/doubtfire-model'; + +@Injectable({ + providedIn: 'root', +}) +export class GradeTaskModalService { + constructor(public dialog: MatDialog) {} + + public show(task: Task, successCallback: (response: {grade: number, qualityPts: number}) => void, errorCallback: () => void): void { + this.dialog + .open(GradeTaskModalComponent, { + data: { + task: task + }, + }) + .afterClosed() + .subscribe((result) => { + if (result) { + successCallback(result); + } else { + errorCallback(); + } + }); + } +} diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html b/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html deleted file mode 100644 index 0906d7b593..0000000000 --- a/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html +++ /dev/null @@ -1,27 +0,0 @@ -
- - - -
diff --git a/src/app/tasks/modals/modals.coffee b/src/app/tasks/modals/modals.coffee index 9dcd33874f..fae9a50a86 100644 --- a/src/app/tasks/modals/modals.coffee +++ b/src/app/tasks/modals/modals.coffee @@ -1,4 +1,3 @@ angular.module('doubtfire.tasks.modals', [ - 'doubtfire.tasks.modals.grade-task-modal' 'doubtfire.tasks.modals.upload-submission-modal' ]) diff --git a/src/app/units/states/portfolios/portfolios.scss b/src/app/units/states/portfolios/portfolios.scss index 704ea095ff..0e1e97b594 100644 --- a/src/app/units/states/portfolios/portfolios.scss +++ b/src/app/units/states/portfolios/portfolios.scss @@ -10,3 +10,17 @@ } } } + +.grade-icon { + color: #fff; + font-size: 1em; + border-radius: 100%; + width: 2.25em; + height: 2.25em; + font-weight: 100; + margin: 0 auto; + display: flex; + align-items: center; + justify-content: center; + background-color: #333333; +} diff --git a/src/app/units/states/portfolios/portfolios.tpl.html b/src/app/units/states/portfolios/portfolios.tpl.html index 89247569ca..75b9a955ee 100644 --- a/src/app/units/states/portfolios/portfolios.tpl.html +++ b/src/app/units/states/portfolios/portfolios.tpl.html @@ -65,10 +65,9 @@

Mark Portfolios

btn-radio="{{$index}}" >
@@ -194,10 +193,10 @@

Mark Portfolios

{{student.tutorNames()}} {{student.shortTutorialDescription()}} - + - + diff --git a/src/app/units/states/students-list/students-list.tpl.html b/src/app/units/states/students-list/students-list.tpl.html index 929cefe386..2ff4736816 100644 --- a/src/app/units/states/students-list/students-list.tpl.html +++ b/src/app/units/states/students-list/students-list.tpl.html @@ -84,7 +84,7 @@

No students found

Stats - + Flags - + diff --git a/src/app/welcome/welcome.component.ts b/src/app/welcome/welcome.component.ts index f6aaafb270..351b4839db 100644 --- a/src/app/welcome/welcome.component.ts +++ b/src/app/welcome/welcome.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit } from '@angular/core'; +import { Component } from '@angular/core'; import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; @Component({ @@ -6,9 +6,8 @@ import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants templateUrl: './welcome.component.html', styleUrls: ['./welcome.component.scss'], }) -export class WelcomeComponent implements OnInit { +export class WelcomeComponent { constructor(private constants: DoubtfireConstants) {} - ngOnInit(): void {} public externalName = this.constants.ExternalName; } From deaa1e940f8295ff962c111f1dbac75ed5ff51fa Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Mon, 4 Nov 2024 21:28:25 +1100 Subject: [PATCH 0216/1280] fix: ensure authorisation active in angular --- src/app/doubtfire.states.ts | 54 +++++-------------- .../states/dashboard/dashboard.coffee | 1 - src/app/projects/states/groups/groups.coffee | 1 - src/app/projects/states/index/index.coffee | 1 - .../projects/states/outcomes/outcomes.coffee | 1 - .../states/portfolio/portfolio.coffee | 1 - .../states/project-root-state.component.ts | 1 - .../states/tutorials/tutorials.coffee | 1 - src/app/sessions/transition-hooks.service.ts | 15 +++++- src/app/units/states/index/index.coffee | 2 +- src/app/units/states/tasks/inbox/inbox.coffee | 2 +- .../task-viewer-state.component.ts | 2 +- src/app/units/unit-root-state.component.ts | 2 +- 13 files changed, 31 insertions(+), 53 deletions(-) diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index ab4a95ff22..7baa910f57 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -4,17 +4,11 @@ import {HomeComponent} from './home/states/home/home.component'; import {WelcomeComponent} from './welcome/welcome.component'; import {SignInComponent} from './sessions/states/sign-in/sign-in.component'; import {EditProfileComponent} from './account/edit-profile/edit-profile.component'; -import {TeachingPeriodListComponent} from './admin/states/teaching-periods/teaching-period-list/teaching-period-list.component'; import {AcceptEulaComponent} from './eula/accept-eula/accept-eula.component'; import { UnauthorisedComponent } from './errors/states/unauthorised/unauthorised.component'; import {FUsersComponent} from './admin/states/users/users.component'; import {FUnitsComponent} from './admin/states/units/units.component'; import {ProjectDashboardComponent} from './projects/states/dashboard/project-dashboard/project-dashboard.component'; -import {AppInjector} from './app-injector'; -import {ProjectService} from './api/services/project.service'; -import {Observable, first} from 'rxjs'; -import {GlobalStateService} from './projects/states/index/global-state.service'; -import {Project} from './api/models/project'; import {UnitRootState} from './units/unit-root-state.component'; import {ProjectRootState} from './projects/states/project-root-state.component'; import { TaskViewerState } from './units/task-viewer/task-viewer-state.component'; @@ -39,7 +33,7 @@ const institutionSettingsState: NgHybridStateDeclaration = { }, data: { pageTitle: 'Institution Settings', - roleWhiteList: ['Admin'], + roleWhitelist: ['Admin'], }, }; @@ -54,7 +48,7 @@ const usersState: NgHybridStateDeclaration = { }, data: { pageTitle: 'Administer users', - roleWhiteList: ['Admin'], + roleWhitelist: ['Admin'], }, }; @@ -70,8 +64,7 @@ const HomeState: NgHybridStateDeclaration = { }, }, data: { - pageTitle: 'Home Page', - roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin', 'Auditor'], + pageTitle: 'Home Page' }, }; @@ -176,8 +169,7 @@ const WelcomeState: NgHybridStateDeclaration = { }, }, data: { - pageTitle: 'Welcome', - roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin', 'Auditor'], + pageTitle: 'Welcome' }, }; @@ -209,22 +201,7 @@ const EditProfileState: NgHybridStateDeclaration = { }, }, data: { - pageTitle: 'Edit Profile', - roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin', 'Auditor'], - }, -}; - -const TeachingPeriodsState: NgHybridStateDeclaration = { - name: 'teaching_periods', - url: '/admin/teachingperiods', - views: { - main: { - component: TeachingPeriodListComponent, - }, - }, - data: { - pageTitle: 'Teaching Periods', - roleWhitelist: ['Convenor', 'Admin'], + pageTitle: 'Edit Profile' }, }; @@ -237,8 +214,7 @@ const EulaState: NgHybridStateDeclaration = { }, }, data: { - pageTitle: 'End User License Agreement', - roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin', 'Auditor'], + pageTitle: 'End User License Agreement' }, }; @@ -256,8 +232,7 @@ const ViewAllProjectsState: NgHybridStateDeclaration = { }, }, data: { - pageTitle: 'Teaching Periods', - roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin'], + pageTitle: 'All Units' }, }; @@ -277,7 +252,7 @@ const AdministerUnits: NgHybridStateDeclaration = { }, data: { pageTitle: 'Administer units', - roleWhiteList: ['Admin'], + roleWhitelist: ['Admin', 'Convenor', 'Auditor'], }, }; @@ -292,8 +267,7 @@ const ProjectDashboardState: NgHybridStateDeclaration = { }, }, data: { - pageTitle: 'Project Dashboard', - roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin'], + pageTitle: 'Unit Dashboard', }, }; @@ -312,9 +286,9 @@ const ViewAllUnits: NgHybridStateDeclaration = { }, }, data: { - pageTitle: 'Teaching Periods', + pageTitle: 'View Units', mode: 'tutor', - roleWhitelist: ['Tutor', 'Convenor', 'Admin'], + roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Auditor'], }, }; @@ -335,8 +309,7 @@ const UnauthoriedState: NgHybridStateDeclaration = { }, data: { // Add data used by header - pageTitle: 'Unauthorised', - roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin'], + pageTitle: 'Unauthorised' }, }; /** @@ -409,7 +382,7 @@ const ScormPlayerStudentReviewState: NgHybridStateDeclaration = { }, data: { pageTitle: 'Review Knowledge Check', - roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin'], + roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin', 'Auditor'], }, }; @@ -443,7 +416,6 @@ const ScormPlayerReviewState: NgHybridStateDeclaration = { */ export const doubtfireStates = [ institutionSettingsState, - TeachingPeriodsState, HomeState, WelcomeState, SignInState, diff --git a/src/app/projects/states/dashboard/dashboard.coffee b/src/app/projects/states/dashboard/dashboard.coffee index d4d073c8ad..9e86c3b6a9 100644 --- a/src/app/projects/states/dashboard/dashboard.coffee +++ b/src/app/projects/states/dashboard/dashboard.coffee @@ -16,7 +16,6 @@ angular.module('doubtfire.projects.states.dashboard', [ data: task: "Dashboard" pageTitle: "_Home_" - roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Student', 'Auditor'] } ) diff --git a/src/app/projects/states/groups/groups.coffee b/src/app/projects/states/groups/groups.coffee index a20d2c0d8c..52fb04d9e1 100644 --- a/src/app/projects/states/groups/groups.coffee +++ b/src/app/projects/states/groups/groups.coffee @@ -12,7 +12,6 @@ angular.module('doubtfire.projects.states.groups', []) data: task: "Groups List" pageTitle: "_Home_" - roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Student', 'Auditor'] } ) diff --git a/src/app/projects/states/index/index.coffee b/src/app/projects/states/index/index.coffee index 0b9744b957..d77b2be900 100644 --- a/src/app/projects/states/index/index.coffee +++ b/src/app/projects/states/index/index.coffee @@ -13,7 +13,6 @@ angular.module('doubtfire.projects.states.index', []) templateUrl: "units/states/index/index.tpl.html" # We can re-use unit's index here data: pageTitle: "_Home_" - roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin', 'Auditor'] } ) diff --git a/src/app/projects/states/outcomes/outcomes.coffee b/src/app/projects/states/outcomes/outcomes.coffee index 5c5d610928..cc6cd7487b 100644 --- a/src/app/projects/states/outcomes/outcomes.coffee +++ b/src/app/projects/states/outcomes/outcomes.coffee @@ -12,7 +12,6 @@ angular.module('doubtfire.projects.states.outcomes', []) data: task: "Learning Outcomes" pageTitle: "_Home_" - roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Student', 'Auditor'] } ) diff --git a/src/app/projects/states/portfolio/portfolio.coffee b/src/app/projects/states/portfolio/portfolio.coffee index 4257ab1757..bed3cbd94b 100644 --- a/src/app/projects/states/portfolio/portfolio.coffee +++ b/src/app/projects/states/portfolio/portfolio.coffee @@ -14,7 +14,6 @@ angular.module('doubtfire.projects.states.portfolio', [ data: task: "Portfolio Creation" pageTitle: "_Home_" - roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Student', 'Auditor'] } ) diff --git a/src/app/projects/states/project-root-state.component.ts b/src/app/projects/states/project-root-state.component.ts index a8e026d5ac..53325cb784 100644 --- a/src/app/projects/states/project-root-state.component.ts +++ b/src/app/projects/states/project-root-state.component.ts @@ -21,7 +21,6 @@ export const ProjectRootState: NgHybridStateDeclaration = { abstract: true, data: { pageTitle: 'Unit Studied', - roleWhiteList: ['Student', 'Tutor', 'Convenor', 'Admin', 'Auditor'], }, views: { main: { diff --git a/src/app/projects/states/tutorials/tutorials.coffee b/src/app/projects/states/tutorials/tutorials.coffee index 06c8d3d531..5c22b609e3 100644 --- a/src/app/projects/states/tutorials/tutorials.coffee +++ b/src/app/projects/states/tutorials/tutorials.coffee @@ -12,7 +12,6 @@ angular.module('doubtfire.projects.states.tutorials', []) data: task: "Tutorial List" pageTitle: "_Home_" - roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Student', 'Auditor'] } ) diff --git a/src/app/sessions/transition-hooks.service.ts b/src/app/sessions/transition-hooks.service.ts index 834d0a886d..1215c3e6b7 100644 --- a/src/app/sessions/transition-hooks.service.ts +++ b/src/app/sessions/transition-hooks.service.ts @@ -4,6 +4,7 @@ import { UserService } from '../api/services/user.service'; import { DoubtfireAngularModule } from '../doubtfire-angular.module'; import { GlobalStateService } from '../projects/states/index/global-state.service'; import { DoubtfireConstants } from '../config/constants/doubtfire-constants'; +import { AuthenticationService } from '../api/services/authentication.service'; /** * The TransitionHooksService is responsible for intercepting transitions between states. @@ -20,7 +21,8 @@ export class TransitionHooksService { private userService: UserService, private transitions: TransitionService, private globalState: GlobalStateService, - private constants: DoubtfireConstants + private constants: DoubtfireConstants, + private authenticationService: AuthenticationService, ) { // Get the tii settings... this.constants.IsTiiEnabled.subscribe((enabled) => { @@ -35,6 +37,7 @@ export class TransitionHooksService { // Where is the transition coming from and going to? const toState = transition.to().name; + const toStateData = transition.to().data; // const fromState = transition.from().name; // Setup the global state @@ -44,6 +47,16 @@ export class TransitionHooksService { this.globalState.setNotInboxState(); } + // Check authorization whitelist + if (toStateData.roleWhitelist && !this.authenticationService.isAuthorised(toStateData.roleWhitelist)) { + if (authenticationService.isAuthenticated()) { + return transition.router.stateService.target("unauthorised"); + } else if (toState !== "sign_in") { + return transition.router.stateService.target("sign_in"); + } + return false; + } + // Adjust settings such as headers switch (toState) { case 'timeout': diff --git a/src/app/units/states/index/index.coffee b/src/app/units/states/index/index.coffee index 88d118d1c8..69b9888ea5 100644 --- a/src/app/units/states/index/index.coffee +++ b/src/app/units/states/index/index.coffee @@ -13,7 +13,7 @@ angular.module('doubtfire.units.states.index', []) templateUrl: "units/states/index/index.tpl.html" data: pageTitle: "_Home_" - roleWhitelist: ['Student', 'Tutor', 'Convenor', 'Admin', 'Auditor'] + roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Auditor'] } ) diff --git a/src/app/units/states/tasks/inbox/inbox.coffee b/src/app/units/states/tasks/inbox/inbox.coffee index 9f04950ca0..1be9546765 100644 --- a/src/app/units/states/tasks/inbox/inbox.coffee +++ b/src/app/units/states/tasks/inbox/inbox.coffee @@ -14,7 +14,7 @@ angular.module('doubtfire.units.states.tasks.inbox', []) data: task: "Task Inbox" pageTitle: "_Home_" - roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Auditor', 'Auditor'] + roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Auditor'] } ) diff --git a/src/app/units/task-viewer/task-viewer-state.component.ts b/src/app/units/task-viewer/task-viewer-state.component.ts index 833647f4cb..08fdcf38a6 100644 --- a/src/app/units/task-viewer/task-viewer-state.component.ts +++ b/src/app/units/task-viewer/task-viewer-state.component.ts @@ -39,7 +39,7 @@ export const TaskViewerState: NgHybridStateDeclaration = { parent: 'unit-root-state', data: { pageTitle: 'Unit Tasks', - roleWhiteList: ['Tutor', 'Convenor', 'Admin', 'Auditor'], + roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Auditor'], }, views: { unitView: { diff --git a/src/app/units/unit-root-state.component.ts b/src/app/units/unit-root-state.component.ts index 8a6109121f..cd239a61a5 100644 --- a/src/app/units/unit-root-state.component.ts +++ b/src/app/units/unit-root-state.component.ts @@ -34,7 +34,7 @@ export const UnitRootState: NgHybridStateDeclaration = { abstract: true, data: { pageTitle: 'Unit Root State', - roleWhiteList: ['Tutor', 'Convenor', 'Admin', 'Auditor'], + roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Auditor'], }, views: { main: { From efa89c344069d386f2411a417e570d4158af91b9 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 5 Nov 2024 14:12:35 +1100 Subject: [PATCH 0217/1280] fix: complete student enrolment modal --- src/app/api/models/unit.ts | 24 +++++++- src/app/common/header/header.component.ts | 4 +- src/app/doubtfire-angular.module.ts | 1 + src/app/doubtfire-angularjs.module.ts | 1 - ...nit-student-enrolment-modal.component.html | 14 ++--- .../unit-student-enrolment-modal.component.ts | 57 ++++++++----------- .../unit-student-enrolment-modal.service.ts | 10 ++-- 7 files changed, 63 insertions(+), 48 deletions(-) diff --git a/src/app/api/models/unit.ts b/src/app/api/models/unit.ts index b27159832e..9d8ed9fa3f 100644 --- a/src/app/api/models/unit.ts +++ b/src/app/api/models/unit.ts @@ -22,6 +22,7 @@ import { Project, TutorialStreamService, UnitRoleService, + Campus, } from './doubtfire-model'; import {LearningOutcome} from './learning-outcome'; import {AlertService} from 'src/app/common/services/alert.service'; @@ -78,7 +79,7 @@ export class Unit extends Entity { public readonly groupSetsCache: EntityCache = new EntityCache(); - groupMemberships: Array; + groupMemberships: GroupMembership[]; readonly studentCache: EntityCache = new EntityCache(); @@ -150,6 +151,27 @@ export class Unit extends Entity { return this.findStudent(id)?.enrolled; } + /** + * Enrol a student within the unit. + * + * @param idOrEmail The student id or email of the student to enrol. + * @param campus The student's campus + * @returns an observer of the post with the student project. + */ + public enrolStudent(idOrEmail: string, campus: Campus): Observable { + const projectService = AppInjector.get(ProjectService); + + return projectService.create( + { + unit_id: this.id, + student_num: idOrEmail, + campus_id: campus.id }, + { + cache: this.studentCache + } + ); + } + public get currentUserIsStaff(): boolean { return this.myRole !== 'Student'; } diff --git a/src/app/common/header/header.component.ts b/src/app/common/header/header.component.ts index a07349c94e..b5e1960c8a 100644 --- a/src/app/common/header/header.component.ts +++ b/src/app/common/header/header.component.ts @@ -71,8 +71,8 @@ export class HeaderComponent implements OnInit, OnDestroy { this.subscriptions.push( this.globalState.projectsSubject.subscribe({ next: (projects) => { - if (projects == null) return; - this.projects = projects.filter((project) => project.unit.myRole === 'Student'); + if (!projects) return; + this.projects = projects.filter((project) => project?.unit?.myRole === 'Student'); }, error: (err) => {}, }), diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 6967a7df3f..a81a58f0bb 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -271,6 +271,7 @@ import { UnitStudentEnrolmentModalComponent } from './units/modals/unit-student- // Components we declare declarations: [ AlertComponent, + UnitStudentEnrolmentModalComponent, AboutDoubtfireModalContent, TeachingPeriodUnitImportDialogComponent, ProjectTasksListComponent, diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 29a1b8b68d..1aee534ad4 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -90,7 +90,6 @@ import 'build/src/app/groups/groups.js'; import 'build/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.js'; import 'build/src/app/groups/group-member-list/group-member-list.js'; import 'build/src/app/groups/group-set-selector/group-set-selector.js'; -import 'build/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.js'; import 'build/src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.js'; import 'build/src/app/units/modals/modals.js'; import 'build/src/app/units/units.js'; diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.html b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.html index 7b25032b56..e3668f2b9b 100644 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.html +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.html @@ -1,4 +1,4 @@ - - Student ID - + Student ID or Email + Select Campus - - {{ campus.name }} + + {{ campus.name }} @@ -29,6 +29,6 @@ - + - + diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts index c58d56df74..09e1b2cf86 100644 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts @@ -1,56 +1,49 @@ -import { Component, Inject } from '@angular/core'; +import { Component, Inject, OnInit } from '@angular/core'; import { MAT_DIALOG_DATA, MatDialogRef } from '@angular/material/dialog'; -import { alertService, CampusService, Project } from 'src/app/ajs-upgraded-providers'; +import { Campus, Project, Unit } from 'src/app/api/models/doubtfire-model'; +import { CampusService } from 'src/app/api/services/campus.service'; +import { AlertService } from 'src/app/common/services/alert.service'; @Component({ - selector: 'unit-student-enrolment-modal', + selector: 'f-unit-student-enrolment-modal', templateUrl: 'unit-student-enrolment-modal.component.html', styleUrls: ['unit-student-enrolment-modal.component.scss'], }) -export class UnitStudentEnrolmentModalComponent { - unit: any; - campuses: any = []; - projects: any; - student_id: string; - campus_id: any; +export class UnitStudentEnrolmentModalComponent implements OnInit { + unit: Unit; + campuses: Campus[]; + studentIdOrEmail: string; + selectedCampus: Campus; constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any, - @Inject(alertService) public alert: any, - @Inject(CampusService) public campusService: any, - @Inject(Project) private project: any + @Inject(MAT_DIALOG_DATA) public data: {unit: Unit}, + public alertService: AlertService, + public campusService: CampusService, ) {} ngOnInit() { this.unit = this.data.unit; - this.projects = this.data.unit.students; - this.campusService.query().subscribe((campuses: any) => { + this.campusService.query().subscribe((campuses: Campus[]) => { this.campuses = campuses; }); - console.log(this.unit); - console.log(this.projects); } - enrolStudent(student_id, campus_id) { - console.log(this.unit.id, student_id, campus_id); - if (campus_id == null) { - this.alert.add('danger', 'Campus missing. Please indicate student campus', 5000); + enrolStudent(studentIdOrEmail: string, campus: Campus) { + if (!campus) { + this.alertService.error('Campus missing. Please indicate student campus', 5000); return; } - this.project.create( - { unit_id: this.unit.id, student_num: student_id, campus_id: campus_id }, - (project) => { - if (!this.unit.studentEnrolled(project.project_id)) { - this.unit.addStudent(project); - this.alert.add('success', 'Student enrolled', 2000); + this.unit.enrolStudent(studentIdOrEmail, campus). + subscribe({ + next: (_: Project) => { + this.alertService.success('Student enrolled', 2000); this.dialogRef.close(); - } else { - this.alert.add('danger', 'Student is already enrolled', 2000); + }, + error: (response: string) => { + this.alertService.error(`Error enrolling student: ${response}`, 6000); } - }, - (response: { data: { error } }) => - this.alert.add('danger', `Error enrolling student: ${response.data.error}`, 6000) + } ); } } diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service.ts index 5ecec93bc9..c7d5ac81bf 100644 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service.ts +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service.ts @@ -1,6 +1,7 @@ import { Injectable } from '@angular/core'; -import { MatDialogRef, MatDialog } from '@angular/material/dialog'; +import { MatDialog } from '@angular/material/dialog'; import { UnitStudentEnrolmentModalComponent } from './unit-student-enrolment-modal.component'; +import { Unit } from 'src/app/api/models/doubtfire-model'; @Injectable({ providedIn: 'root', @@ -8,11 +9,10 @@ import { UnitStudentEnrolmentModalComponent } from './unit-student-enrolment-mod export class UnitStudentEnrolmentModalService { constructor(public dialog: MatDialog) {} - public show(unit: any) { - let dialogRef: MatDialogRef; - dialogRef = this.dialog.open(UnitStudentEnrolmentModalComponent, { + public show(unit: Unit) { + this.dialog.open(UnitStudentEnrolmentModalComponent, { data: { - unit, + unit: unit, }, }); } From 1de217c0bc19b8dbedb21cf2e89e195772ae2a02 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Tue, 5 Nov 2024 15:08:04 +1100 Subject: [PATCH 0218/1280] fix: remove markdown filter from learning outcomes --- src/app/config/privacy-policy/privacy-policy.ts | 17 ++++++++--------- src/app/doubtfire-angularjs.module.ts | 2 -- .../upload-submission-modal.tpl.html | 4 ++-- .../task-ilo-alignment-modal.tpl.html | 2 +- .../task-ilo-alignment-viewer.tpl.html | 4 ++-- 5 files changed, 13 insertions(+), 16 deletions(-) diff --git a/src/app/config/privacy-policy/privacy-policy.ts b/src/app/config/privacy-policy/privacy-policy.ts index 8142d8b08c..ebfe968cd2 100644 --- a/src/app/config/privacy-policy/privacy-policy.ts +++ b/src/app/config/privacy-policy/privacy-policy.ts @@ -10,7 +10,6 @@ interface Response { @Injectable({ providedIn: 'root' }) - export class PrivacyPolicy { privacy = ''; plagiarism = ''; @@ -22,12 +21,12 @@ export class PrivacyPolicy { const url: string = `${this.API_URL}/settings/privacy`; - this.http - .get(url) - .subscribe(response => { - this.privacy = response.privacy; - this.plagiarism = response.plagiarism; - this.loaded = true; - }); + this.http.get(url) + .subscribe(response => { + this.privacy = response.privacy; + this.plagiarism = response.plagiarism; + this.loaded = true; + } + ); } -} \ No newline at end of file +} diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 68c662043e..d9dc6955d5 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -218,7 +218,6 @@ import { ProgressBurndownChartComponent } from './visualisations/progress-burndo import { TaskVisualisationComponent } from './visualisations/task-visualisation/taskvisualisation.component'; import {FUnitsComponent} from './admin/states/units/units.component'; -import {MarkedPipe} from './common/pipes/marked.pipe'; import {AlertService} from './common/services/alert.service'; import {GradeService} from './common/services/grade.service'; @@ -243,7 +242,6 @@ export const DoubtfireAngularJSModule = angular.module('doubtfire', [ DoubtfireAngularJSModule.factory('AboutDoubtfireModal', downgradeInjectable(AboutDoubtfireModal)); DoubtfireAngularJSModule.factory('DoubtfireConstants', downgradeInjectable(DoubtfireConstants)); DoubtfireAngularJSModule.factory('ExtensionModal', downgradeInjectable(ExtensionModalService)); -DoubtfireAngularJSModule.factory('Marked', downgradeInjectable(MarkedPipe)); DoubtfireAngularJSModule.factory('CalendarModal', downgradeInjectable(CalendarModalService)); DoubtfireAngularJSModule.factory('TaskCommentService', downgradeInjectable(TaskCommentService)); DoubtfireAngularJSModule.factory('alertService', downgradeInjectable(AlertService)); diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html index 9caab7897e..92070ac30f 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html @@ -167,9 +167,9 @@

@@ -194,10 +194,10 @@

Mark Portfolios

{{student.tutorNames()}} {{student.shortTutorialDescription()}} - + - + diff --git a/src/app/units/states/students-list/students-list.tpl.html b/src/app/units/states/students-list/students-list.tpl.html index d81fdb4cd6..830d0a4c3f 100644 --- a/src/app/units/states/students-list/students-list.tpl.html +++ b/src/app/units/states/students-list/students-list.tpl.html @@ -130,7 +130,7 @@

No students found

- + From 3da7a4b54a5892ea99cd365ae439677b0f52ed6f Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 19 Nov 2024 15:40:38 +1100 Subject: [PATCH 0221/1280] feat: add editor for task feedback templates --- src/app/api/models/doubtfire-model.ts | 2 +- src/app/api/models/feedback-template.ts | 78 +++++++++ src/app/api/models/task-definition.ts | 7 +- .../api/services/feedback-template.service.ts | 28 +++ src/app/doubtfire-angular.module.ts | 4 + .../task-definition-editor.component.html | 21 ++- .../task-definition-feedback.component.html | 127 ++++++++++++++ .../task-definition-feedback.component.scss | 0 .../task-definition-feedback.component.ts | 163 ++++++++++++++++++ 9 files changed, 426 insertions(+), 4 deletions(-) create mode 100644 src/app/api/models/feedback-template.ts create mode 100644 src/app/api/services/feedback-template.service.ts create mode 100644 src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.html create mode 100644 src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.scss create mode 100644 src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.ts diff --git a/src/app/api/models/doubtfire-model.ts b/src/app/api/models/doubtfire-model.ts index fffc361a4e..38b886a2ae 100644 --- a/src/app/api/models/doubtfire-model.ts +++ b/src/app/api/models/doubtfire-model.ts @@ -37,6 +37,7 @@ export * from './scorm-player-context'; export * from './test-attempt'; export * from './task-comment/scorm-comment'; export * from './task-comment/scorm-extension-comment'; +export * from './feedback-template'; // Users -- are students or staff export * from './user/user'; @@ -44,7 +45,6 @@ export * from './user/user'; // WebCal -- calendars used to track task due dates export * from './webcal/webcal'; - export * from '../services/authentication.service'; export * from '../services/unit.service'; export * from '../services/project.service'; diff --git a/src/app/api/models/feedback-template.ts b/src/app/api/models/feedback-template.ts new file mode 100644 index 0000000000..85da6af509 --- /dev/null +++ b/src/app/api/models/feedback-template.ts @@ -0,0 +1,78 @@ +import {Entity, EntityMapping} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; +import {AppInjector} from 'src/app/app-injector'; +import {TaskDefinition} from './task-definition'; +import {FeedbackTemplateService} from '../services/feedback-template.service'; + +export class FeedbackTemplate extends Entity { + id: number; + learningOutcome: string; + chipText: string; + description: string; + commentText: string; + summaryText: string; + + readonly taskDefinition: TaskDefinition; + + constructor(taskDef: TaskDefinition) { + super(); + this.taskDefinition = taskDef; + } + + public toJson(mappingData: EntityMapping, ignoreKeys?: string[]): object { + return { + feedback_template: super.toJson(mappingData, ignoreKeys), + }; + } + + public save(): Observable { + const svc = AppInjector.get(FeedbackTemplateService); + + if (this.isNew) { + return svc.create( + { + taskDefId: this.taskDefinition.id, + }, + { + entity: this, + cache: this.taskDefinition.feedbackTemplateCache, + constructorParams: this.taskDefinition, + }, + ); + } else { + return svc.update( + { + taskDefId: this.taskDefinition.id, + id: this.id, + }, + {entity: this}, + ); + } + } + + private originalSaveData: string; + + public get hasOriginalSaveData(): boolean { + return this.originalSaveData !== undefined && this.originalSaveData !== null; + } + + public setOriginalSaveData(mapping: EntityMapping) { + this.originalSaveData = JSON.stringify(this.toJson(mapping)); + } + + public hasChanges(mapping: EntityMapping): boolean { + if (!this.originalSaveData) { + return false; + } + + return this.originalSaveData != JSON.stringify(this.toJson(mapping)); + } + + public get isNew(): boolean { + return !this.id; + } + + public get taskDefId(): number { + return this.taskDefinition.id; + } +} diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index b848686768..2e17ac6cda 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -1,9 +1,9 @@ import { HttpClient } from '@angular/common/http'; -import { Entity, EntityMapping } from 'ngx-entity-service'; +import { Entity, EntityCache, EntityMapping } from 'ngx-entity-service'; import { Observable, tap } from 'rxjs'; import { AppInjector } from 'src/app/app-injector'; import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; -import { Grade, GroupSet, TutorialStream, Unit } from './doubtfire-model'; +import { FeedbackTemplate, Grade, GroupSet, TutorialStream, Unit } from './doubtfire-model'; import { TaskDefinitionService } from '../services/task-definition.service'; export type UploadRequirement = { key: string; name: string; type: string; tiiCheck?: boolean; tiiPct?: number }; @@ -44,6 +44,9 @@ export class TaskDefinition extends Entity { assessmentEnabled: boolean; mossLanguage: string = 'moss c'; + public readonly feedbackTemplateCache: EntityCache = + new EntityCache(); + readonly unit: Unit; constructor(unit: Unit) { diff --git a/src/app/api/services/feedback-template.service.ts b/src/app/api/services/feedback-template.service.ts new file mode 100644 index 0000000000..4d0bef50de --- /dev/null +++ b/src/app/api/services/feedback-template.service.ts @@ -0,0 +1,28 @@ +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import {FeedbackTemplate} from '../models/feedback-template'; +import {HttpClient} from '@angular/common/http'; +import API_URL from 'src/app/config/constants/apiURL'; +import {TaskDefinition} from '../models/task-definition'; + +@Injectable() +export class FeedbackTemplateService extends CachedEntityService { + protected readonly endpointFormat = 'feedback_templates/'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'learningOutcome', + 'chipText', + 'description', + 'commentText', + 'summaryText', + ); + } + + public override createInstanceFrom(json: object, other?: any): FeedbackTemplate { + return new FeedbackTemplate(other as TaskDefinition); + } +} diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 991ac397b4..fe50c5a40b 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -207,6 +207,7 @@ import {TaskDefinitionDatesComponent} from './units/states/edit/directives/unit- import {TaskDefinitionUploadComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component'; import {TaskDefinitionOptionsComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component'; import {TaskDefinitionResourcesComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component'; +import {TaskDefinitionFeedbackComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component'; import {TaskDefinitionOverseerComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component'; import {TaskDefinitionScormComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component'; import {UnitAnalyticsComponent} from './units/states/analytics/unit-analytics-route.component'; @@ -237,6 +238,7 @@ import {TaskScormCardComponent} from './projects/states/dashboard/directives/tas import {TestAttemptService} from './api/services/test-attempt.service'; import {ScormExtensionCommentComponent} from './tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component'; import {ScormExtensionModalComponent} from './common/modals/scorm-extension-modal/scorm-extension-modal.component'; +import {FeedbackTemplateService} from './api/services/feedback-template.service'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { @@ -287,6 +289,7 @@ const MY_DATE_FORMAT = { TaskDefinitionUploadComponent, TaskDefinitionOptionsComponent, TaskDefinitionResourcesComponent, + TaskDefinitionFeedbackComponent, TaskDefinitionOverseerComponent, TaskDefinitionScormComponent, UnitAnalyticsComponent, @@ -435,6 +438,7 @@ const MY_DATE_FORMAT = { provideLottieOptions({ player: () => player, }), + FeedbackTemplateService, ], imports: [ FlexLayoutModule, diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html index 7d6224f343..e33ba9297f 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html @@ -133,6 +133,25 @@

7 +
+

Task feedback templates

+

+ Upload feedback templates for tutors +

+
+ +
+
+ + +
+
+
+ 8 +
+

SCORM test

@@ -149,7 +168,7 @@

SCORM test

- 8 + 9
diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.html new file mode 100644 index 0000000000..8cdecc7f46 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.html @@ -0,0 +1,127 @@ +
+
+ Enable feedback templates + +
+ + + +
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Learning Outcome + {{ feedbackTemplate.learningOutcome }} + Chip Text + {{ feedbackTemplate.chipText }} + Description + {{ feedbackTemplate.description }} + Comment Text + {{ feedbackTemplate.commentText }} + Summary Text + {{ feedbackTemplate.summaryText }} + + @if (feedbackTemplateHasChanges(feedbackTemplate)) { + + } + +
+ + + + + + + + + +
diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.ts new file mode 100644 index 0000000000..7036148564 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.ts @@ -0,0 +1,163 @@ +import {AfterViewInit, Component, Inject, Input, ViewChild} from '@angular/core'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; +import {MatPaginator} from '@angular/material/paginator'; +import {TaskDefinition, FeedbackTemplate, Unit} from 'src/app/api/models/doubtfire-model'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {MatSort, Sort} from '@angular/material/sort'; +import { + confirmationModal, + csvResultModalService, + csvUploadModalService, +} from 'src/app/ajs-upgraded-providers'; +import {Subscription} from 'rxjs'; +import {FeedbackTemplateService} from 'src/app/api/services/feedback-template.service'; + +@Component({ + selector: 'f-task-definition-feedback', + templateUrl: 'task-definition-feedback.component.html', + styleUrls: ['task-definition-feedback.component.scss'], +}) +export class TaskDefinitionFeedbackComponent implements AfterViewInit { + @ViewChild(MatTable, {static: false}) table: MatTable; + @ViewChild(MatSort, {static: false}) sort: MatSort; + @ViewChild(MatPaginator, {static: false}) paginator: MatPaginator; + + @Input() taskDefinition: TaskDefinition; + + public feedbackTemplateSource: MatTableDataSource; + public columns: string[] = [ + 'learningOutcome', + 'chipText', + 'description', + 'commentText', + 'summaryText', + 'feedbackTemplateAction', + ]; + public filter: string; + public selectedFeedbackTemplate: FeedbackTemplate; + + constructor( + private alerts: AlertService, + private taskDefinitionService: TaskDefinitionService, + private feedbackTemplateService: FeedbackTemplateService, + @Inject(csvResultModalService) private csvResultModalService: any, + @Inject(csvUploadModalService) private csvUploadModal: any, + @Inject(confirmationModal) private confirmationModal: any, + ) {} + + public get unit(): Unit { + return this.taskDefinition?.unit; + } + + ngAfterViewInit(): void { + this.subscriptions.push( + this.taskDefinition.feedbackTemplateCache.values.subscribe((feedbackTemplates) => { + this.feedbackTemplateSource = new MatTableDataSource(feedbackTemplates); + this.feedbackTemplateSource.paginator = this.paginator; + this.feedbackTemplateSource.sort = this.sort; + this.feedbackTemplateSource.filterPredicate = (data: any, filter: string) => + data.matches(filter); + }), + ); + } + + public saveFeedbackTemplate(feedbackTemplate: FeedbackTemplate) { + feedbackTemplate.save().subscribe(() => { + this.alerts.success('Template saved'); + feedbackTemplate.setOriginalSaveData(this.feedbackTemplateService.mapping); + }); + } + + private subscriptions: Subscription[] = []; + ngOnDestroy(): void { + this.subscriptions.forEach((s) => s.unsubscribe()); + } + + public selectFeedbackTemplate(feedbackTemplate: FeedbackTemplate) { + if (this.selectedFeedbackTemplate === feedbackTemplate) { + this.selectedFeedbackTemplate = null; + } else { + this.selectedFeedbackTemplate = feedbackTemplate; + + if (!this.selectedFeedbackTemplate.hasOriginalSaveData) { + this.selectedFeedbackTemplate.setOriginalSaveData(this.feedbackTemplateService.mapping); + } + } + } + + public sortData(sort: Sort) { + const data = this.feedbackTemplateSource.data; + + if (!sort.active || sort.direction === '') { + this.feedbackTemplateSource.data = data; + return; + } + + this.feedbackTemplateSource.data = data.sort((a, b) => { + const isAsc = sort.direction === 'asc'; + switch (sort.active) { + case 'learningOutcome': + return this.compare(a.learningOutcome, b.learningOutcome, isAsc); + case 'chipText': + return this.compare(a.chipText, b.chipText, isAsc); + case 'description': + return this.compare(a.description, b.description, isAsc); + case 'commentText': + return this.compare(a.commentText, b.commentText, isAsc); + case 'summaryText': + return this.compare(a.summaryText, b.summaryText, isAsc); + default: + return 0; + } + }); + } + + public compare(a: number | string, b: number | string, isAsc: boolean): number { + return (a < b ? -1 : 1) * (isAsc ? 1 : -1); + } + + applyFilter(filterValue: string) { + this.feedbackTemplateSource.filter = filterValue.trim().toLowerCase(); + + if (this.feedbackTemplateSource.paginator) { + this.feedbackTemplateSource.paginator.firstPage(); + } + } + + public feedbackTemplateHasChanges(feedbackTemplate: FeedbackTemplate): boolean { + return feedbackTemplate.hasChanges(this.feedbackTemplateService.mapping); + } + + public deleteFeedbackTemplate(feedbackTemplate: FeedbackTemplate) { + this.confirmationModal.show( + 'Delete feedback template', + 'Are you sure you want to delete this template? This action is final.', + () => { + this.alerts.success('Task deleted'); + }, + ); + } + + public uploadFeedbackTemplatesCsv() { + this.csvUploadModal.show( + 'Upload Feedback Templates as CSV', + 'Test message', + {file: {name: 'Feedback Template CSV Data', type: 'csv'}}, + this.unit.getTaskDefinitionBatchUploadUrl(), + (response: any) => {}, + ); + } + + public createFeedbackTemplate() { + const feedbackTemplate = new FeedbackTemplate(this.taskDefinition); + + feedbackTemplate.learningOutcome = 'TLO'; + feedbackTemplate.chipText = 'lorem'; + feedbackTemplate.description = 'Lorem ipsum dolor'; + feedbackTemplate.commentText = 'Lorem dolor'; + feedbackTemplate.summaryText = 'Lorem ipsum'; + + this.selectedFeedbackTemplate = feedbackTemplate; + } +} From c12536bc4375b1ae5f19d4e54d0783b6948921eb Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Wed, 20 Nov 2024 22:19:56 +1100 Subject: [PATCH 0222/1280] feat: combine outcome and template editor --- .../feedback-template-editor.component.html | 258 +++++++++++++++++ .../feedback-template-editor.component.ts | 270 ++++++++++++++++++ src/app/doubtfire-angular.module.ts | 4 +- .../task-definition-editor.component.html | 44 ++- .../task-definition-feedback.component.html | 127 -------- .../task-definition-feedback.component.scss | 0 .../task-definition-feedback.component.ts | 163 ----------- 7 files changed, 551 insertions(+), 315 deletions(-) create mode 100644 src/app/common/feedback-template/feedback-template-editor.component.html create mode 100644 src/app/common/feedback-template/feedback-template-editor.component.ts delete mode 100644 src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.html delete mode 100644 src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.scss delete mode 100644 src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.ts diff --git a/src/app/common/feedback-template/feedback-template-editor.component.html b/src/app/common/feedback-template/feedback-template-editor.component.html new file mode 100644 index 0000000000..6922dab4ed --- /dev/null +++ b/src/app/common/feedback-template/feedback-template-editor.component.html @@ -0,0 +1,258 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Number + {{ learningOutcome.iloNumber }} + Abbreviation + {{ learningOutcome.abbreviation }} + Name + {{ learningOutcome.name }} + Description + {{ learningOutcome.description }} + + @if (learningOutcomeHasChanges(learningOutcome)) { + + } + +
+ +
+ + + +
+ + + + + + + +
+ @if (selectedOutcome) { +
+ + Outcome Number + + + + + Abbreviation + + + + + Name + + +
+ + + Description + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Learning Outcome + {{ feedbackTemplate.learningOutcome }} + Chip Text + {{ feedbackTemplate.chipText }} + Description + {{ feedbackTemplate.description }} + Comment Text + {{ feedbackTemplate.commentText }} + Summary Text + {{ feedbackTemplate.summaryText }} + + @if (feedbackTemplateHasChanges(feedbackTemplate)) { + + } + +
+ +
+ + + +
+ + + + + + + +
+
+ } +
diff --git a/src/app/common/feedback-template/feedback-template-editor.component.ts b/src/app/common/feedback-template/feedback-template-editor.component.ts new file mode 100644 index 0000000000..b5a94b3e91 --- /dev/null +++ b/src/app/common/feedback-template/feedback-template-editor.component.ts @@ -0,0 +1,270 @@ +import {AfterViewInit, Component, Inject, Input, ViewChild} from '@angular/core'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; +import {MatPaginator} from '@angular/material/paginator'; +import {TaskDefinition, Unit, LearningOutcome, LearningOutcomeService, FeedbackTemplate} from 'src/app/api/models/doubtfire-model'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {MatSort, Sort} from '@angular/material/sort'; +import { + confirmationModal, + csvResultModalService, + csvUploadModalService, +} from 'src/app/ajs-upgraded-providers'; +import {Subscription} from 'rxjs'; +import {FeedbackTemplateService} from 'src/app/api/services/feedback-template.service'; + +@Component({ + selector: 'f-feedback-template-editor', + templateUrl: 'feedback-template-editor.component.html', +}) +export class FeedbackTemplateEditorComponent implements AfterViewInit { + @Input() taskDefinition: TaskDefinition; + + @ViewChild(MatTable, {static: false}) outcomeTable: MatTable; + @ViewChild(MatSort, {static: false}) outcomeSort: MatSort; + @ViewChild(MatPaginator, {static: false}) outcomePaginator: MatPaginator; + + public outcomeSource: MatTableDataSource; + public outcomeColumns: string[] = [ + 'number', + 'abbreviation', + 'name', + 'description', + 'learningOutcomeAction', + ]; + public outcomeFilter: string; + public selectedOutcome: LearningOutcome; + + @ViewChild(MatTable, {static: false}) templateTable: MatTable; + @ViewChild(MatSort, {static: false}) templateSort: MatSort; + @ViewChild(MatPaginator, {static: false}) templatePaginator: MatPaginator; + + public templateSource: MatTableDataSource; + public templateColumns: string[] = [ + 'learningOutcome', + 'chipText', + 'description', + 'commentText', + 'summaryText', + 'feedbackTemplateAction', + ]; + public templateFilter: string; + public selectedTemplate: FeedbackTemplate; + + constructor( + private alerts: AlertService, + private taskDefinitionService: TaskDefinitionService, + private learningOutcomeService: LearningOutcomeService, + private feedbackTemplateService: FeedbackTemplateService, + @Inject(csvResultModalService) private csvResultModalService: any, + @Inject(csvUploadModalService) private csvUploadModal: any, + @Inject(confirmationModal) private confirmationModal: any, + ) {} + + public get unit(): Unit { + return this.taskDefinition?.unit; + } + + ngAfterViewInit(): void { + this.subscriptions.push( + this.unit.learningOutcomesCache.values.subscribe((learningOutcomes) => { + this.outcomeSource = new MatTableDataSource(learningOutcomes); + this.outcomeSource.paginator = this.outcomePaginator; + this.outcomeSource.sort = this.outcomeSort; + this.outcomeSource.filterPredicate = (data: any, filter: string) => data.matches(filter); + }), + this.taskDefinition.feedbackTemplateCache.values.subscribe((feedbackTemplates) => { + this.templateSource = new MatTableDataSource(feedbackTemplates); + this.templateSource.paginator = this.templatePaginator; + this.templateSource.sort = this.templateSort; + this.templateSource.filterPredicate = (data: any, filter: string) => data.matches(filter); + }), + ); + } + + public saveLearningOutcome(learningOutcome: LearningOutcome) { + // learningOutcome.save().subscribe(() => { + // this.alerts.success('Outcome saved'); + // learningOutcome.setOriginalSaveData(this.learningOutcomeService.mapping); + // }); + } + + public saveFeedbackTemplate(feedbackTemplate: FeedbackTemplate) { + feedbackTemplate.save().subscribe(() => { + this.alerts.success('Template saved'); + feedbackTemplate.setOriginalSaveData(this.feedbackTemplateService.mapping); + }); + } + + private subscriptions: Subscription[] = []; + ngOnDestroy(): void { + this.subscriptions.forEach((s) => s.unsubscribe()); + } + + public selectLearningOutcome(learningOutcome: LearningOutcome) { + if (this.selectedOutcome === learningOutcome) { + this.selectedOutcome = null; + } else { + this.selectedOutcome = learningOutcome; + + // if (!this.selectedFeedbackTemplate.hasOriginalSaveData) { + // this.selectedFeedbackTemplate.setOriginalSaveData(this.feedbackTemplateService.mapping); + // } + } + } + + public selectFeedbackTemplate(feedbackTemplate: FeedbackTemplate) { + if (this.selectedTemplate === feedbackTemplate) { + this.selectedTemplate = null; + } else { + this.selectedTemplate = feedbackTemplate; + + if (!this.selectedTemplate.hasOriginalSaveData) { + this.selectedTemplate.setOriginalSaveData(this.feedbackTemplateService.mapping); + } + } + } + + public sortOutcomeData(sort: Sort) { + const data = this.outcomeSource.data; + + if (!sort.active || sort.direction === '') { + this.outcomeSource.data = data; + return; + } + + this.outcomeSource.data = data.sort((a, b) => { + const isAsc = sort.direction === 'asc'; + switch (sort.active) { + case 'number': + return this.compare(a.iloNumber, b.iloNumber, isAsc); + case 'abbreviation': + return this.compare(a.abbreviation, b.abbreviation, isAsc); + case 'name': + return this.compare(a.name, b.name, isAsc); + case 'description': + return this.compare(a.description, b.description, isAsc); + default: + return 0; + } + }); + } + + public sortTemplateData(sort: Sort) { + const data = this.templateSource.data; + + if (!sort.active || sort.direction === '') { + this.templateSource.data = data; + return; + } + + this.templateSource.data = data.sort((a, b) => { + const isAsc = sort.direction === 'asc'; + switch (sort.active) { + case 'learningOutcome': + return this.compare(a.learningOutcome, b.learningOutcome, isAsc); + case 'chipText': + return this.compare(a.chipText, b.chipText, isAsc); + case 'description': + return this.compare(a.description, b.description, isAsc); + case 'commentText': + return this.compare(a.commentText, b.commentText, isAsc); + case 'summaryText': + return this.compare(a.summaryText, b.summaryText, isAsc); + default: + return 0; + } + }); + } + + public compare(a: number | string, b: number | string, isAsc: boolean): number { + return (a < b ? -1 : 1) * (isAsc ? 1 : -1); + } + + applyOutcomeFilter(filterValue: string) { + this.outcomeSource.filter = filterValue.trim().toLowerCase(); + + if (this.outcomeSource.paginator) { + this.outcomeSource.paginator.firstPage(); + } + } + + applyTemplateFilter(filterValue: string) { + this.templateSource.filter = filterValue.trim().toLowerCase(); + + if (this.templateSource.paginator) { + this.templateSource.paginator.firstPage(); + } + } + + public learningOutcomeHasChanges(learningOutcome: LearningOutcome): boolean { + return learningOutcome.hasChanges(this.learningOutcomeService.mapping); + } + + public feedbackTemplateHasChanges(feedbackTemplate: FeedbackTemplate): boolean { + return feedbackTemplate.hasChanges(this.feedbackTemplateService.mapping); + } + + public deleteLearningOutcome(learningOutcome: LearningOutcome) { + this.confirmationModal.show( + 'Delete learning outcome', + 'Are you sure you want to delete this outcome? This action is final.', + () => { + this.alerts.success('Outcome deleted'); + }, + ); + } + + public deleteFeedbackTemplate(feedbackTemplate: FeedbackTemplate) { + this.confirmationModal.show( + 'Delete feedback template', + 'Are you sure you want to delete this template? This action is final.', + () => { + this.alerts.success('Template deleted'); + }, + ); + } + + public uploadLearningOutcomesCsv() { + this.csvUploadModal.show( + 'Upload Learning Outcomes as CSV', + 'Test message', + {file: {name: 'Learning Outcome CSV Data', type: 'csv'}}, + this.unit.getTaskDefinitionBatchUploadUrl(), + (response: any) => {}, + ); + } + + public uploadFeedbackTemplatesCsv() { + this.csvUploadModal.show( + 'Upload Feedback Templates as CSV', + 'Test message', + {file: {name: 'Feedback Template CSV Data', type: 'csv'}}, + this.unit.getTaskDefinitionBatchUploadUrl(), + (response: any) => {}, + ); + } + + public createLearningOutcome() { + const learningOutcome = new LearningOutcome(); + + learningOutcome.iloNumber = 1; + learningOutcome.abbreviation = 'lm'; + learningOutcome.name = 'lorem'; + learningOutcome.description = 'Lorem ipsum dolor'; + + this.selectedOutcome = learningOutcome; + } + + public createFeedbackTemplate() { + const feedbackTemplate = new FeedbackTemplate(this.taskDefinition); + + feedbackTemplate.learningOutcome = 'TLO'; + feedbackTemplate.chipText = 'lorem'; + feedbackTemplate.description = 'Lorem ipsum dolor'; + feedbackTemplate.commentText = 'Lorem dolor'; + feedbackTemplate.summaryText = 'Lorem ipsum'; + + this.selectedTemplate = feedbackTemplate; + } +} diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index fe50c5a40b..07961095af 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -207,7 +207,6 @@ import {TaskDefinitionDatesComponent} from './units/states/edit/directives/unit- import {TaskDefinitionUploadComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component'; import {TaskDefinitionOptionsComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component'; import {TaskDefinitionResourcesComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component'; -import {TaskDefinitionFeedbackComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component'; import {TaskDefinitionOverseerComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component'; import {TaskDefinitionScormComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component'; import {UnitAnalyticsComponent} from './units/states/analytics/unit-analytics-route.component'; @@ -239,6 +238,7 @@ import {TestAttemptService} from './api/services/test-attempt.service'; import {ScormExtensionCommentComponent} from './tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component'; import {ScormExtensionModalComponent} from './common/modals/scorm-extension-modal/scorm-extension-modal.component'; import {FeedbackTemplateService} from './api/services/feedback-template.service'; +import {FeedbackTemplateEditorComponent} from './common/feedback-template/feedback-template-editor.component'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { @@ -289,7 +289,6 @@ const MY_DATE_FORMAT = { TaskDefinitionUploadComponent, TaskDefinitionOptionsComponent, TaskDefinitionResourcesComponent, - TaskDefinitionFeedbackComponent, TaskDefinitionOverseerComponent, TaskDefinitionScormComponent, UnitAnalyticsComponent, @@ -360,6 +359,7 @@ const MY_DATE_FORMAT = { TaskScormCardComponent, ScormExtensionCommentComponent, ScormExtensionModalComponent, + FeedbackTemplateEditorComponent, ], // Services we provide providers: [ diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html index e33ba9297f..c56b29c055 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html @@ -30,6 +30,23 @@

Task details

+
+

Task Learning Outcomes

+

Add learning outcomes for this task

+
+ +
+
+ + +
+
+
+ 3 +
+

Inbox

@@ -47,7 +64,7 @@

Inbox

- 3 + 4
@@ -65,7 +82,7 @@

Due dates

- 4 + 5
@@ -83,7 +100,7 @@

Upload requirem
- 5 + 6
@@ -105,7 +122,7 @@

- 6 + 7
@@ -125,25 +142,6 @@

-
-
-
- 7 -
-
-
-

Task feedback templates

-

- Upload feedback templates for tutors -

-
- -
-
-
-
-
- Enable feedback templates - -
- - - -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Learning Outcome - {{ feedbackTemplate.learningOutcome }} - Chip Text - {{ feedbackTemplate.chipText }} - Description - {{ feedbackTemplate.description }} - Comment Text - {{ feedbackTemplate.commentText }} - Summary Text - {{ feedbackTemplate.summaryText }} - - @if (feedbackTemplateHasChanges(feedbackTemplate)) { - - } - -
- - - - - - - - - -
diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.scss deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.ts deleted file mode 100644 index 7036148564..0000000000 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-feedback/task-definition-feedback.component.ts +++ /dev/null @@ -1,163 +0,0 @@ -import {AfterViewInit, Component, Inject, Input, ViewChild} from '@angular/core'; -import {MatTable, MatTableDataSource} from '@angular/material/table'; -import {MatPaginator} from '@angular/material/paginator'; -import {TaskDefinition, FeedbackTemplate, Unit} from 'src/app/api/models/doubtfire-model'; -import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; -import {AlertService} from 'src/app/common/services/alert.service'; -import {MatSort, Sort} from '@angular/material/sort'; -import { - confirmationModal, - csvResultModalService, - csvUploadModalService, -} from 'src/app/ajs-upgraded-providers'; -import {Subscription} from 'rxjs'; -import {FeedbackTemplateService} from 'src/app/api/services/feedback-template.service'; - -@Component({ - selector: 'f-task-definition-feedback', - templateUrl: 'task-definition-feedback.component.html', - styleUrls: ['task-definition-feedback.component.scss'], -}) -export class TaskDefinitionFeedbackComponent implements AfterViewInit { - @ViewChild(MatTable, {static: false}) table: MatTable; - @ViewChild(MatSort, {static: false}) sort: MatSort; - @ViewChild(MatPaginator, {static: false}) paginator: MatPaginator; - - @Input() taskDefinition: TaskDefinition; - - public feedbackTemplateSource: MatTableDataSource; - public columns: string[] = [ - 'learningOutcome', - 'chipText', - 'description', - 'commentText', - 'summaryText', - 'feedbackTemplateAction', - ]; - public filter: string; - public selectedFeedbackTemplate: FeedbackTemplate; - - constructor( - private alerts: AlertService, - private taskDefinitionService: TaskDefinitionService, - private feedbackTemplateService: FeedbackTemplateService, - @Inject(csvResultModalService) private csvResultModalService: any, - @Inject(csvUploadModalService) private csvUploadModal: any, - @Inject(confirmationModal) private confirmationModal: any, - ) {} - - public get unit(): Unit { - return this.taskDefinition?.unit; - } - - ngAfterViewInit(): void { - this.subscriptions.push( - this.taskDefinition.feedbackTemplateCache.values.subscribe((feedbackTemplates) => { - this.feedbackTemplateSource = new MatTableDataSource(feedbackTemplates); - this.feedbackTemplateSource.paginator = this.paginator; - this.feedbackTemplateSource.sort = this.sort; - this.feedbackTemplateSource.filterPredicate = (data: any, filter: string) => - data.matches(filter); - }), - ); - } - - public saveFeedbackTemplate(feedbackTemplate: FeedbackTemplate) { - feedbackTemplate.save().subscribe(() => { - this.alerts.success('Template saved'); - feedbackTemplate.setOriginalSaveData(this.feedbackTemplateService.mapping); - }); - } - - private subscriptions: Subscription[] = []; - ngOnDestroy(): void { - this.subscriptions.forEach((s) => s.unsubscribe()); - } - - public selectFeedbackTemplate(feedbackTemplate: FeedbackTemplate) { - if (this.selectedFeedbackTemplate === feedbackTemplate) { - this.selectedFeedbackTemplate = null; - } else { - this.selectedFeedbackTemplate = feedbackTemplate; - - if (!this.selectedFeedbackTemplate.hasOriginalSaveData) { - this.selectedFeedbackTemplate.setOriginalSaveData(this.feedbackTemplateService.mapping); - } - } - } - - public sortData(sort: Sort) { - const data = this.feedbackTemplateSource.data; - - if (!sort.active || sort.direction === '') { - this.feedbackTemplateSource.data = data; - return; - } - - this.feedbackTemplateSource.data = data.sort((a, b) => { - const isAsc = sort.direction === 'asc'; - switch (sort.active) { - case 'learningOutcome': - return this.compare(a.learningOutcome, b.learningOutcome, isAsc); - case 'chipText': - return this.compare(a.chipText, b.chipText, isAsc); - case 'description': - return this.compare(a.description, b.description, isAsc); - case 'commentText': - return this.compare(a.commentText, b.commentText, isAsc); - case 'summaryText': - return this.compare(a.summaryText, b.summaryText, isAsc); - default: - return 0; - } - }); - } - - public compare(a: number | string, b: number | string, isAsc: boolean): number { - return (a < b ? -1 : 1) * (isAsc ? 1 : -1); - } - - applyFilter(filterValue: string) { - this.feedbackTemplateSource.filter = filterValue.trim().toLowerCase(); - - if (this.feedbackTemplateSource.paginator) { - this.feedbackTemplateSource.paginator.firstPage(); - } - } - - public feedbackTemplateHasChanges(feedbackTemplate: FeedbackTemplate): boolean { - return feedbackTemplate.hasChanges(this.feedbackTemplateService.mapping); - } - - public deleteFeedbackTemplate(feedbackTemplate: FeedbackTemplate) { - this.confirmationModal.show( - 'Delete feedback template', - 'Are you sure you want to delete this template? This action is final.', - () => { - this.alerts.success('Task deleted'); - }, - ); - } - - public uploadFeedbackTemplatesCsv() { - this.csvUploadModal.show( - 'Upload Feedback Templates as CSV', - 'Test message', - {file: {name: 'Feedback Template CSV Data', type: 'csv'}}, - this.unit.getTaskDefinitionBatchUploadUrl(), - (response: any) => {}, - ); - } - - public createFeedbackTemplate() { - const feedbackTemplate = new FeedbackTemplate(this.taskDefinition); - - feedbackTemplate.learningOutcome = 'TLO'; - feedbackTemplate.chipText = 'lorem'; - feedbackTemplate.description = 'Lorem ipsum dolor'; - feedbackTemplate.commentText = 'Lorem dolor'; - feedbackTemplate.summaryText = 'Lorem ipsum'; - - this.selectedFeedbackTemplate = feedbackTemplate; - } -} From db2d2bc32b19165bac8ff6ba0282a16adffbb815 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Fri, 22 Nov 2024 19:04:02 +1100 Subject: [PATCH 0223/1280] feat: add field to connect outcomes --- .../feedback-template-editor.component.html | 48 +++++++++-- .../feedback-template-editor.component.ts | 81 +++++++++++++++++-- 2 files changed, 114 insertions(+), 15 deletions(-) diff --git a/src/app/common/feedback-template/feedback-template-editor.component.html b/src/app/common/feedback-template/feedback-template-editor.component.html index 6922dab4ed..51af89539a 100644 --- a/src/app/common/feedback-template/feedback-template-editor.component.html +++ b/src/app/common/feedback-template/feedback-template-editor.component.html @@ -16,8 +16,8 @@ {{ learningOutcome.iloNumber }} - - Abbreviation + + Tag + + Connected Learning Outcomes + + @for (outcome of connectedOutcomes(); track $index) { + + {{ outcome }} + + + } + + + + @for (outcome of filteredOutcomes(); track outcome) { + {{ outcome }} + } + + +
- - + + @@ -241,7 +270,10 @@ /> - + - + } diff --git a/src/app/common/feedback-template/feedback-template-editor.component.ts b/src/app/common/feedback-template/feedback-template-editor.component.ts index b5a94b3e91..fa8a82df27 100644 --- a/src/app/common/feedback-template/feedback-template-editor.component.ts +++ b/src/app/common/feedback-template/feedback-template-editor.component.ts @@ -1,7 +1,23 @@ -import {AfterViewInit, Component, Inject, Input, ViewChild} from '@angular/core'; +import { + AfterViewInit, + Component, + computed, + inject, + Inject, + Input, + model, + signal, + ViewChild, +} from '@angular/core'; import {MatTable, MatTableDataSource} from '@angular/material/table'; import {MatPaginator} from '@angular/material/paginator'; -import {TaskDefinition, Unit, LearningOutcome, LearningOutcomeService, FeedbackTemplate} from 'src/app/api/models/doubtfire-model'; +import { + TaskDefinition, + Unit, + LearningOutcome, + LearningOutcomeService, + FeedbackTemplate, +} from 'src/app/api/models/doubtfire-model'; import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {MatSort, Sort} from '@angular/material/sort'; @@ -12,6 +28,10 @@ import { } from 'src/app/ajs-upgraded-providers'; import {Subscription} from 'rxjs'; import {FeedbackTemplateService} from 'src/app/api/services/feedback-template.service'; +import {COMMA, ENTER} from '@angular/cdk/keycodes'; +import {LiveAnnouncer} from '@angular/cdk/a11y'; +import {MatChipInputEvent} from '@angular/material/chips'; +import {MatAutocompleteSelectedEvent} from '@angular/material/autocomplete'; @Component({ selector: 'f-feedback-template-editor', @@ -27,7 +47,7 @@ export class FeedbackTemplateEditorComponent implements AfterViewInit { public outcomeSource: MatTableDataSource; public outcomeColumns: string[] = [ 'number', - 'abbreviation', + 'tag', 'name', 'description', 'learningOutcomeAction', @@ -41,7 +61,7 @@ export class FeedbackTemplateEditorComponent implements AfterViewInit { public templateSource: MatTableDataSource; public templateColumns: string[] = [ - 'learningOutcome', + 'number', 'chipText', 'description', 'commentText', @@ -138,7 +158,7 @@ export class FeedbackTemplateEditorComponent implements AfterViewInit { switch (sort.active) { case 'number': return this.compare(a.iloNumber, b.iloNumber, isAsc); - case 'abbreviation': + case 'tag': return this.compare(a.abbreviation, b.abbreviation, isAsc); case 'name': return this.compare(a.name, b.name, isAsc); @@ -161,8 +181,8 @@ export class FeedbackTemplateEditorComponent implements AfterViewInit { this.templateSource.data = data.sort((a, b) => { const isAsc = sort.direction === 'asc'; switch (sort.active) { - case 'learningOutcome': - return this.compare(a.learningOutcome, b.learningOutcome, isAsc); + case 'number': + return this.compare(a.id, b.id, isAsc); case 'chipText': return this.compare(a.chipText, b.chipText, isAsc); case 'description': @@ -259,7 +279,7 @@ export class FeedbackTemplateEditorComponent implements AfterViewInit { public createFeedbackTemplate() { const feedbackTemplate = new FeedbackTemplate(this.taskDefinition); - feedbackTemplate.learningOutcome = 'TLO'; + feedbackTemplate.id = 0; feedbackTemplate.chipText = 'lorem'; feedbackTemplate.description = 'Lorem ipsum dolor'; feedbackTemplate.commentText = 'Lorem dolor'; @@ -267,4 +287,49 @@ export class FeedbackTemplateEditorComponent implements AfterViewInit { this.selectedTemplate = feedbackTemplate; } + + readonly separatorKeysCodes: number[] = [ENTER, COMMA]; + readonly currentConnectedOutcome = model(''); + readonly connectedOutcomes = signal([]); + readonly allOutcomes: string[] = ['TLO1', 'TLO2', 'TLO3', 'ULO1', 'ULO2']; + readonly filteredOutcomes = computed(() => { + const currentOutcome = this.currentConnectedOutcome().toLowerCase(); + return currentOutcome + ? this.allOutcomes.filter((outcome) => outcome.toLowerCase().includes(currentOutcome)) + : this.allOutcomes.slice(); + }); + + readonly announcer = inject(LiveAnnouncer); + + add(event: MatChipInputEvent): void { + const value = (event.value || '').trim(); + + if (value) { + this.connectedOutcomes.update((connectedOutcomes) => [...connectedOutcomes, value]); + } + + this.currentConnectedOutcome.set(''); + } + + remove(outcome: string): void { + this.connectedOutcomes.update((connectedOutcomes) => { + const index = connectedOutcomes.indexOf(outcome); + if (index < 0) { + return connectedOutcomes; + } + + connectedOutcomes.splice(index, 1); + this.announcer.announce(`Removed ${outcome}`); + return [...connectedOutcomes]; + }); + } + + selected(event: MatAutocompleteSelectedEvent): void { + this.connectedOutcomes.update((connectedOutcomes) => [ + ...connectedOutcomes, + event.option.viewValue, + ]); + this.currentConnectedOutcome.set(''); + event.option.deselect(); + } } From 9acc36502dc3fd2365817f73ccc742dd3947e293 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Fri, 22 Nov 2024 19:05:33 +1100 Subject: [PATCH 0224/1280] feat: add feedback template picker to comment composer --- src/app/doubtfire-angular.module.ts | 2 + .../task-comment-composer.component.html | 16 +++ .../task-comment-composer.component.scss | 7 ++ .../task-comment-composer.component.ts | 2 + .../task-feedback-templates.component.html | 103 ++++++++++++++++++ .../task-feedback-templates.component.ts | 58 ++++++++++ 6 files changed, 188 insertions(+) create mode 100644 src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.html create mode 100644 src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 07961095af..21b56cc9e8 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -239,6 +239,7 @@ import {ScormExtensionCommentComponent} from './tasks/task-comments-viewer/scorm import {ScormExtensionModalComponent} from './common/modals/scorm-extension-modal/scorm-extension-modal.component'; import {FeedbackTemplateService} from './api/services/feedback-template.service'; import {FeedbackTemplateEditorComponent} from './common/feedback-template/feedback-template-editor.component'; +import {TaskFeedbackTemplatesComponent} from './tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { @@ -360,6 +361,7 @@ const MY_DATE_FORMAT = { ScormExtensionCommentComponent, ScormExtensionModalComponent, FeedbackTemplateEditorComponent, + TaskFeedbackTemplatesComponent, ], // Services we provide providers: [ diff --git a/src/app/tasks/task-comment-composer/task-comment-composer.component.html b/src/app/tasks/task-comment-composer/task-comment-composer.component.html index 448f88f46c..db1cc099ee 100644 --- a/src/app/tasks/task-comment-composer/task-comment-composer.component.html +++ b/src/app/tasks/task-comment-composer/task-comment-composer.component.html @@ -1,3 +1,8 @@ + + +
+ + task +
diff --git a/src/app/tasks/task-comment-composer/task-comment-composer.component.scss b/src/app/tasks/task-comment-composer/task-comment-composer.component.scss index a79e6a5be4..d17c924344 100644 --- a/src/app/tasks/task-comment-composer/task-comment-composer.component.scss +++ b/src/app/tasks/task-comment-composer/task-comment-composer.component.scss @@ -95,6 +95,13 @@ $emoji-color: lighten( border-color: darken($color: white, $amount: 10); } +.feedback-template-picker { + z-index: 1060; + position: absolute; + right: 26px; + bottom: 150px; +} + #replyContainer { margin: 0.4em 1em -0.2em 1em; font-size: 14px; diff --git a/src/app/tasks/task-comment-composer/task-comment-composer.component.ts b/src/app/tasks/task-comment-composer/task-comment-composer.component.ts index 9a4a3297ea..ca4319969d 100644 --- a/src/app/tasks/task-comment-composer/task-comment-composer.component.ts +++ b/src/app/tasks/task-comment-composer/task-comment-composer.component.ts @@ -82,6 +82,7 @@ export class TaskCommentComposerComponent implements DoCheck { emojiRegex: RegExp = /(?:\:)(.*?)(?=\:|$)/; emojiSearchResults: EmojiData[] = []; emojiMatch: string; + showFeedbackTemplatePicker: boolean = false; recording = false; cagStartWidth: number; @@ -155,6 +156,7 @@ export class TaskCommentComposerComponent implements DoCheck { e.preventDefault(); this.emojiSearchMode = false; this.showEmojiPicker = false; + this.showFeedbackTemplatePicker = false; if (this.input.first.nativeElement.innerText.trim() !== '') { this.addComment(); } diff --git a/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.html b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.html new file mode 100644 index 0000000000..f92a30ec03 --- /dev/null +++ b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.html @@ -0,0 +1,103 @@ + diff --git a/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts new file mode 100644 index 0000000000..6a2ea98608 --- /dev/null +++ b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts @@ -0,0 +1,58 @@ +import {Component, ElementRef, ViewChild} from '@angular/core'; + +@Component({ + selector: 'f-task-feedback-templates', + templateUrl: './task-feedback-templates.component.html', +}) +export class TaskFeedbackTemplatesComponent { + searchTerm: string = ''; + hoveredTemplate: string = ''; + + categories = [ + {name: 'TLO', templates: ['Template A1', 'Template A2', 'Template A3', 'Template A4']}, + {name: 'ULO', templates: ['Template B1', 'Template B2', 'Template B3', 'Template B4']}, + {name: 'CLO', templates: ['Template C1', 'Template C2', 'Template C3', 'Template C4']}, + {name: 'GLO', templates: ['Template D1', 'Template D2', 'Template D3', 'Template D4']}, + {name: 'Section', templates: ['Template E1', 'Template E2', 'Template E3', 'Template E4']}, + ]; + + filteredCategories = [...this.categories]; + + filterTemplates() { + this.filteredCategories = this.categories.map((category) => ({ + ...category, + templates: category.templates.filter((template) => + template.toLowerCase().includes(this.searchTerm.toLowerCase()), + ), + })); + } + + @ViewChild('tloSection') tloSection!: ElementRef; + @ViewChild('uloSection') uloSection!: ElementRef; + @ViewChild('cloSection') cloSection!: ElementRef; + @ViewChild('gloSection') gloSection!: ElementRef; + @ViewChild('sectionSection') sectionSection!: ElementRef; + + scrollToSection(event: any) { + const sections = [ + this.tloSection, + this.uloSection, + this.cloSection, + this.gloSection, + this.sectionSection, + ]; + const selectedSection = sections[event.index]; + + if (selectedSection) { + selectedSection.nativeElement.scrollIntoView({behavior: 'smooth', block: 'start'}); + } + } + + selectTemplate(template: string) { + console.log('Selected template:', template); + } + + onHoverTemplate(template: string) { + this.hoveredTemplate = template; + } +} From e3fdd3b0fafe1988e1f19346b11b18a5b4274072 Mon Sep 17 00:00:00 2001 From: ShounakB <65479699+Shounaks@users.noreply.github.com> Date: Sat, 23 Nov 2024 00:46:19 +1100 Subject: [PATCH 0225/1280] Fixing updateGrade Method --- src/app/common/grade-icon/grade-icon.component.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/app/common/grade-icon/grade-icon.component.ts b/src/app/common/grade-icon/grade-icon.component.ts index d90bc6298c..5f8f31c7bc 100644 --- a/src/app/common/grade-icon/grade-icon.component.ts +++ b/src/app/common/grade-icon/grade-icon.component.ts @@ -11,7 +11,7 @@ export class GradeIconComponent implements OnInit, OnChanges { @Input() grade?: number | string; @Input() colorful: boolean = false; - gradeText: number | string = 'Grade'; + gradeText: string = 'Grade'; gradeLetter: string = 'G'; constructor(private gradeService: GradeService) {} @@ -27,10 +27,9 @@ export class GradeIconComponent implements OnInit, OnChanges { } private updateGrade(): void { - this.gradeText = - typeof this.grade === 'string' - ? this.gradeService.stringToGrade(this.grade) - : this.gradeService.grades[this.grade] || 'Grade'; - this.gradeLetter = this.gradeService.gradeAcronyms[this.grade] || 'G'; + const grade: number = + typeof this.grade === 'string' ? this.gradeService.stringToGrade(this.grade) : this.grade; + this.gradeText = this.gradeService.grades[grade] || 'Grade'; + this.gradeLetter = this.gradeService.gradeAcronyms[grade] || 'G'; } } From a42f177f61b3f7166edf3b9c93dfd2dcd3949df7 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 26 Nov 2024 01:21:41 +1100 Subject: [PATCH 0226/1280] feat: make template editor reusable across contexts --- src/app/api/models/feedback-template.ts | 20 +- src/app/api/models/task-definition.ts | 27 +- src/app/api/models/unit.ts | 7 + .../api/services/feedback-template.service.ts | 9 +- .../api/services/task-definition.service.ts | 35 +- src/app/api/services/unit.service.ts | 16 +- .../feedback-template-editor.component.html | 384 ++++++++++-------- .../feedback-template-editor.component.ts | 123 ++++-- src/app/doubtfire-angularjs.module.ts | 5 + .../task-definition-editor.component.html | 2 +- src/app/units/states/edit/edit.tpl.html | 2 +- 11 files changed, 395 insertions(+), 235 deletions(-) diff --git a/src/app/api/models/feedback-template.ts b/src/app/api/models/feedback-template.ts index 85da6af509..f0679a611f 100644 --- a/src/app/api/models/feedback-template.ts +++ b/src/app/api/models/feedback-template.ts @@ -1,7 +1,7 @@ import {Entity, EntityMapping} from 'ngx-entity-service'; import {Observable} from 'rxjs'; import {AppInjector} from 'src/app/app-injector'; -import {TaskDefinition} from './task-definition'; +import {TaskDefinition, Unit} from './doubtfire-model'; import {FeedbackTemplateService} from '../services/feedback-template.service'; export class FeedbackTemplate extends Entity { @@ -12,11 +12,11 @@ export class FeedbackTemplate extends Entity { commentText: string; summaryText: string; - readonly taskDefinition: TaskDefinition; + readonly context: TaskDefinition | Unit; - constructor(taskDef: TaskDefinition) { + constructor(context: TaskDefinition | Unit) { super(); - this.taskDefinition = taskDef; + this.context = context; } public toJson(mappingData: EntityMapping, ignoreKeys?: string[]): object { @@ -31,18 +31,18 @@ export class FeedbackTemplate extends Entity { if (this.isNew) { return svc.create( { - taskDefId: this.taskDefinition.id, + contextId: this.context.id, }, { entity: this, - cache: this.taskDefinition.feedbackTemplateCache, - constructorParams: this.taskDefinition, + cache: this.context.feedbackTemplateCache, + constructorParams: this.context, }, ); } else { return svc.update( { - taskDefId: this.taskDefinition.id, + contextId: this.context.id, id: this.id, }, {entity: this}, @@ -72,7 +72,7 @@ export class FeedbackTemplate extends Entity { return !this.id; } - public get taskDefId(): number { - return this.taskDefinition.id; + public getContextId(): number { + return this.context.id; } } diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index 2e17ac6cda..a2e9b85e73 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -3,8 +3,9 @@ import { Entity, EntityCache, EntityMapping } from 'ngx-entity-service'; import { Observable, tap } from 'rxjs'; import { AppInjector } from 'src/app/app-injector'; import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; -import { FeedbackTemplate, Grade, GroupSet, TutorialStream, Unit } from './doubtfire-model'; +import { FeedbackTemplate, Grade, GroupSet, LearningOutcome, TutorialStream, Unit } from './doubtfire-model'; import { TaskDefinitionService } from '../services/task-definition.service'; +import { AlertService } from 'src/app/common/services/alert.service'; export type UploadRequirement = { key: string; name: string; type: string; tiiCheck?: boolean; tiiPct?: number }; @@ -44,6 +45,8 @@ export class TaskDefinition extends Entity { assessmentEnabled: boolean; mossLanguage: string = 'moss c'; + public readonly learningOutcomesCache: EntityCache = + new EntityCache(); public readonly feedbackTemplateCache: EntityCache = new EntityCache(); @@ -114,6 +117,18 @@ export class TaskDefinition extends Entity { return this.originalSaveData != JSON.stringify(this.toJson(mapping)); } + public refresh(): void { + const alerts = AppInjector.get(AlertService); + AppInjector.get(TaskDefinitionService) + .fetch(this.id) + .subscribe({ + next: (taskDefinition) => { + console.log(taskDefinition.name); + }, + error: (message) => alerts.error(message, 6000), + }); + } + public get isNew(): boolean { return !this.id; } @@ -168,6 +183,16 @@ export class TaskDefinition extends Entity { }`; } + public getOutcomeBatchUploadUrl(): string { + const constants = AppInjector.get(DoubtfireConstants); + return `${constants.API_URL}/units/${this.unit.id}/task_definitions/${this.id}/outcomes/csv`; + } + + public getFeedbackTemplateBatchUploadUrl(): string { + const constants = AppInjector.get(DoubtfireConstants); + return `${constants.API_URL}/units/${this.unit.id}/task_definitions/${this.id}/feedback_templates/csv`; + } + /** * Open the SCORM test in a new tab - using preview mode. */ diff --git a/src/app/api/models/unit.ts b/src/app/api/models/unit.ts index b27159832e..a57f3c7db3 100644 --- a/src/app/api/models/unit.ts +++ b/src/app/api/models/unit.ts @@ -22,6 +22,7 @@ import { Project, TutorialStreamService, UnitRoleService, + FeedbackTemplate, } from './doubtfire-model'; import {LearningOutcome} from './learning-outcome'; import {AlertService} from 'src/app/common/services/alert.service'; @@ -73,6 +74,8 @@ export class Unit extends Entity { new EntityCache(); public readonly taskOutcomeAlignmentsCache: EntityCache = new EntityCache(); + public readonly feedbackTemplateCache: EntityCache = + new EntityCache(); readonly staffCache: EntityCache = new EntityCache(); @@ -388,6 +391,10 @@ export class Unit extends Entity { return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.id}/outcomes/csv`; } + public getFeedbackTemplateBatchUploadUrl(): string { + return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.id}/feedback_templates/csv`; + } + public hasStreams(): boolean { return this.tutorialStreamsCache.size > 1; } diff --git a/src/app/api/services/feedback-template.service.ts b/src/app/api/services/feedback-template.service.ts index 4d0bef50de..0c10e6debc 100644 --- a/src/app/api/services/feedback-template.service.ts +++ b/src/app/api/services/feedback-template.service.ts @@ -3,7 +3,7 @@ import {CachedEntityService} from 'ngx-entity-service'; import {FeedbackTemplate} from '../models/feedback-template'; import {HttpClient} from '@angular/common/http'; import API_URL from 'src/app/config/constants/apiURL'; -import {TaskDefinition} from '../models/task-definition'; +import {TaskDefinition, Unit} from '../models/doubtfire-model'; @Injectable() export class FeedbackTemplateService extends CachedEntityService { @@ -22,7 +22,10 @@ export class FeedbackTemplateService extends CachedEntityService { protected readonly endpointFormat = 'units/:unitId:/task_definitions/:id:'; - constructor(httpClient: HttpClient) { + constructor( + httpClient: HttpClient, + private learningOutcomeService: LearningOutcomeService, + private feedbackTemplateService: FeedbackTemplateService, + ) { super(httpClient, API_URL); this.mapping.addKeys( @@ -108,7 +113,31 @@ export class TaskDefinitionService extends CachedEntityService { 'isGraded', 'maxQualityPts', 'overseerImageId', - 'assessmentEnabled' + 'assessmentEnabled', + { + keys: 'tlos', + toEntityOp: (data: object, key: string, taskDefinition: TaskDefinition) => { + data[key]?.forEach((tlo) => { + taskDefinition.learningOutcomesCache.getOrCreate( + tlo['id'], + this.learningOutcomeService, + tlo, + ); + }); + }, + }, + { + keys: 'feedbackTemplates', + toEntityOp: (data: object, key: string, taskDefinition: TaskDefinition) => { + data[key]?.forEach((template) => { + taskDefinition.feedbackTemplateCache.getOrCreate( + template['id'], + this.feedbackTemplateService, + template, + ); + }); + }, + }, ); this.mapping.mapAllKeysToJsonExcept( diff --git a/src/app/api/services/unit.service.ts b/src/app/api/services/unit.service.ts index c3c38c7406..cd4eee6abb 100644 --- a/src/app/api/services/unit.service.ts +++ b/src/app/api/services/unit.service.ts @@ -9,6 +9,7 @@ import { TaskDefinitionService } from './task-definition.service'; import { GroupService } from './group.service'; import { Observable } from 'rxjs'; import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; +import { FeedbackTemplateService } from './feedback-template.service'; export type IloStats = { median: number; @@ -32,7 +33,8 @@ export class UnitService extends CachedEntityService { private taskDefinitionService: TaskDefinitionService, private taskOutcomeAlignmentService: TaskOutcomeAlignmentService, private groupSetService: GroupSetService, - private groupService: GroupService + private groupService: GroupService, + private feedbackTemplateService: FeedbackTemplateService, ) { super(httpClient, API_URL); @@ -210,6 +212,18 @@ export class UnitService extends CachedEntityService { }); } }, + { + keys: 'feedbackTemplates', + toEntityOp: (data: object, key: string, unit: Unit) => { + data[key]?.forEach((template) => { + unit.feedbackTemplateCache.getOrCreate( + template['id'], + this.feedbackTemplateService, + template, + ); + }); + }, + }, // 'groupMemberships', - map to group memberships ); diff --git a/src/app/common/feedback-template/feedback-template-editor.component.html b/src/app/common/feedback-template/feedback-template-editor.component.html index 51af89539a..fd4cccc16c 100644 --- a/src/app/common/feedback-template/feedback-template-editor.component.html +++ b/src/app/common/feedback-template/feedback-template-editor.component.html @@ -91,202 +91,246 @@ - - @if (selectedOutcome) { -
- - Outcome Number - - +
+
+

Edit Outcome

+ - - Abbreviation - - +
+ + Tag + + - - Name - - -
+ + Name + + +
- - Description - - + + Description + + - - Connected Learning Outcomes - - @for (outcome of connectedOutcomes(); track $index) { - - {{ outcome }} - - - } - - - - @for (outcome of filteredOutcomes(); track outcome) { - {{ outcome }} - } - - + + Connected Learning Outcomes + + @for (outcome of connectedOutcomes(); track $index) { + + {{ outcome }} + + + } + + + + @for (outcome of filteredOutcomes(); track outcome) { + {{ outcome }} + } + + -
-
Learning OutcomeNumber - {{ feedbackTemplate.learningOutcome }} + {{ feedbackTemplate.id }}
- - - - - - - - - - - - - - - - - - - - - - - - + + + - - - - + @if (selectedTemplate) { +
+

Edit Template

+ -
- -
Number - {{ feedbackTemplate.id }} - Chip Text - {{ feedbackTemplate.chipText }} - Description - {{ feedbackTemplate.description }} - Comment Text - {{ feedbackTemplate.commentText }} - Summary Text - {{ feedbackTemplate.summaryText }} - + + + + + +
+

Edit Feedback Templates

+ + +
+ - @if (feedbackTemplateHasChanges(feedbackTemplate)) { - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Number - save - - } - Chip Text + {{ feedbackTemplate.chipText }} + Description + {{ feedbackTemplate.description }} + Comment Text + {{ feedbackTemplate.commentText }} + Summary Text + {{ feedbackTemplate.summaryText }} + + @if (feedbackTemplateHasChanges(feedbackTemplate)) { + + } + +
+ +
+ + + +
+ + + + + -
- -
- - - +
+ + Chip Text + + + + + Summary Text + + +
+ + + Comment Text + + + + + Description + + + +
+ + +
+
+ }
- - - - - - - - +
} diff --git a/src/app/common/feedback-template/feedback-template-editor.component.ts b/src/app/common/feedback-template/feedback-template-editor.component.ts index fa8a82df27..ddf0334e54 100644 --- a/src/app/common/feedback-template/feedback-template-editor.component.ts +++ b/src/app/common/feedback-template/feedback-template-editor.component.ts @@ -32,13 +32,14 @@ import {COMMA, ENTER} from '@angular/cdk/keycodes'; import {LiveAnnouncer} from '@angular/cdk/a11y'; import {MatChipInputEvent} from '@angular/material/chips'; import {MatAutocompleteSelectedEvent} from '@angular/material/autocomplete'; +import {FileDownloaderService} from '../file-downloader/file-downloader.service'; @Component({ selector: 'f-feedback-template-editor', templateUrl: 'feedback-template-editor.component.html', }) export class FeedbackTemplateEditorComponent implements AfterViewInit { - @Input() taskDefinition: TaskDefinition; + @Input() context: TaskDefinition | Unit; @ViewChild(MatTable, {static: false}) outcomeTable: MatTable; @ViewChild(MatSort, {static: false}) outcomeSort: MatSort; @@ -52,7 +53,6 @@ export class FeedbackTemplateEditorComponent implements AfterViewInit { 'description', 'learningOutcomeAction', ]; - public outcomeFilter: string; public selectedOutcome: LearningOutcome; @ViewChild(MatTable, {static: false}) templateTable: MatTable; @@ -68,7 +68,6 @@ export class FeedbackTemplateEditorComponent implements AfterViewInit { 'summaryText', 'feedbackTemplateAction', ]; - public templateFilter: string; public selectedTemplate: FeedbackTemplate; constructor( @@ -76,28 +75,42 @@ export class FeedbackTemplateEditorComponent implements AfterViewInit { private taskDefinitionService: TaskDefinitionService, private learningOutcomeService: LearningOutcomeService, private feedbackTemplateService: FeedbackTemplateService, + private fileDownloaderService: FileDownloaderService, @Inject(csvResultModalService) private csvResultModalService: any, @Inject(csvUploadModalService) private csvUploadModal: any, @Inject(confirmationModal) private confirmationModal: any, ) {} - public get unit(): Unit { - return this.taskDefinition?.unit; - } - ngAfterViewInit(): void { this.subscriptions.push( - this.unit.learningOutcomesCache.values.subscribe((learningOutcomes) => { + this.context.learningOutcomesCache.values.subscribe((learningOutcomes) => { this.outcomeSource = new MatTableDataSource(learningOutcomes); this.outcomeSource.paginator = this.outcomePaginator; this.outcomeSource.sort = this.outcomeSort; - this.outcomeSource.filterPredicate = (data: any, filter: string) => data.matches(filter); + this.outcomeSource.filterPredicate = (data: LearningOutcome, filter: string) => { + const filterValue = filter.trim().toLowerCase(); + return ( + data.iloNumber.toString().includes(filterValue) || + data.abbreviation.toLowerCase().includes(filterValue) || + data.name.toLowerCase().includes(filterValue) || + data.description.toLowerCase().includes(filterValue) + ); + }; }), - this.taskDefinition.feedbackTemplateCache.values.subscribe((feedbackTemplates) => { + this.context.feedbackTemplateCache.values.subscribe((feedbackTemplates) => { this.templateSource = new MatTableDataSource(feedbackTemplates); this.templateSource.paginator = this.templatePaginator; this.templateSource.sort = this.templateSort; - this.templateSource.filterPredicate = (data: any, filter: string) => data.matches(filter); + this.templateSource.filterPredicate = (data: FeedbackTemplate, filter: string) => { + const filterValue = filter.trim().toLowerCase(); + return ( + data.id.toString().includes(filterValue) || + data.chipText.toLowerCase().includes(filterValue) || + data.commentText.toLowerCase().includes(filterValue) || + data.summaryText.toLowerCase().includes(filterValue) || + data.description.toLowerCase().includes(filterValue) + ); + }; }), ); } @@ -201,19 +214,17 @@ export class FeedbackTemplateEditorComponent implements AfterViewInit { return (a < b ? -1 : 1) * (isAsc ? 1 : -1); } - applyOutcomeFilter(filterValue: string) { - this.outcomeSource.filter = filterValue.trim().toLowerCase(); - - if (this.outcomeSource.paginator) { - this.outcomeSource.paginator.firstPage(); - } - } - - applyTemplateFilter(filterValue: string) { - this.templateSource.filter = filterValue.trim().toLowerCase(); - - if (this.templateSource.paginator) { - this.templateSource.paginator.firstPage(); + applyFilter(filterValue: string, table: string) { + if (table === 'outcome') { + this.outcomeSource.filter = filterValue; + if (this.outcomeSource.paginator) { + this.outcomeSource.paginator.firstPage(); + } + } else if (table === 'template') { + this.templateSource.filter = filterValue; + if (this.templateSource.paginator) { + this.templateSource.paginator.firstPage(); + } } } @@ -230,6 +241,15 @@ export class FeedbackTemplateEditorComponent implements AfterViewInit { 'Delete learning outcome', 'Are you sure you want to delete this outcome? This action is final.', () => { + this.learningOutcomeService + .delete( + {id: learningOutcome.id, unitId: this.context.id}, + {entity: learningOutcome, cache: this.context.learningOutcomesCache}, + ) + .subscribe({ + next: () => this.alerts.success('Learning outcome deleted'), + error: () => this.alerts.error('Failed to delete learning outcome. Please try again.'), + }); this.alerts.success('Outcome deleted'); }, ); @@ -245,45 +265,58 @@ export class FeedbackTemplateEditorComponent implements AfterViewInit { ); } - public uploadLearningOutcomesCsv() { + public uploadCsv(type: 'Learning Outcomes' | 'Feedback Templates') { + const url = + type === 'Learning Outcomes' + ? this.context.getOutcomeBatchUploadUrl() + : this.context.getFeedbackTemplateBatchUploadUrl(); + this.csvUploadModal.show( - 'Upload Learning Outcomes as CSV', + `Upload ${type} as CSV`, 'Test message', - {file: {name: 'Learning Outcome CSV Data', type: 'csv'}}, - this.unit.getTaskDefinitionBatchUploadUrl(), - (response: any) => {}, + {file: {name: `${type} CSV Data`, type: 'csv'}}, + url, + (response: any) => { + this.csvResultModalService.show(`${type} CSV Upload Results`, response); + if (response.success.length > 0) { + this.context.refresh(); + } + }, ); } - public uploadFeedbackTemplatesCsv() { - this.csvUploadModal.show( - 'Upload Feedback Templates as CSV', - 'Test message', - {file: {name: 'Feedback Template CSV Data', type: 'csv'}}, - this.unit.getTaskDefinitionBatchUploadUrl(), - (response: any) => {}, - ); + public downloadCsv(type: 'learning-outcomes' | 'feedback-templates') { + let name: string = ''; + if (this.context instanceof TaskDefinition) name = this.context.abbreviation; + else if (this.context instanceof Unit) name = this.context.code; + + const url = + type === 'learning-outcomes' + ? this.context.getOutcomeBatchUploadUrl() + : this.context.getFeedbackTemplateBatchUploadUrl(); + + this.fileDownloaderService.downloadFile(url, `${name}-${type}.csv`); } public createLearningOutcome() { const learningOutcome = new LearningOutcome(); learningOutcome.iloNumber = 1; - learningOutcome.abbreviation = 'lm'; - learningOutcome.name = 'lorem'; - learningOutcome.description = 'Lorem ipsum dolor'; + learningOutcome.abbreviation = ''; + learningOutcome.name = ''; + learningOutcome.description = ''; this.selectedOutcome = learningOutcome; } public createFeedbackTemplate() { - const feedbackTemplate = new FeedbackTemplate(this.taskDefinition); + const feedbackTemplate = new FeedbackTemplate(this.context); feedbackTemplate.id = 0; - feedbackTemplate.chipText = 'lorem'; - feedbackTemplate.description = 'Lorem ipsum dolor'; - feedbackTemplate.commentText = 'Lorem dolor'; - feedbackTemplate.summaryText = 'Lorem ipsum'; + feedbackTemplate.chipText = ''; + feedbackTemplate.description = ''; + feedbackTemplate.commentText = ''; + feedbackTemplate.summaryText = ''; this.selectedTemplate = feedbackTemplate; } diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index e14fdbb545..c227a43c05 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -225,6 +225,7 @@ import {MarkedPipe} from './common/pipes/marked.pipe'; import {AlertService} from './common/services/alert.service'; import {GradeService} from './common/services/grade.service'; import {TaskScormCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component'; +import {FeedbackTemplateEditorComponent} from './common/feedback-template/feedback-template-editor.component'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -463,6 +464,10 @@ DoubtfireAngularJSModule.directive( 'statusIcon', downgradeComponent({component: StatusIconComponent}), ); +DoubtfireAngularJSModule.directive( + 'fFeedbackTemplateEditor', + downgradeComponent({component: FeedbackTemplateEditorComponent}), +); DoubtfireAngularJSModule.directive('newFUnits', downgradeComponent({component: FUnitsComponent})); // Global configuration diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html index c56b29c055..59adc0f043 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html @@ -34,7 +34,7 @@

Task detailsTask Learning Outcomes

Add learning outcomes for this task

- +
diff --git a/src/app/units/states/edit/edit.tpl.html b/src/app/units/states/edit/edit.tpl.html index 3ba73129a5..c2db43e07f 100644 --- a/src/app/units/states/edit/edit.tpl.html +++ b/src/app/units/states/edit/edit.tpl.html @@ -5,7 +5,7 @@ - + From 5494384f1a4becf462dd031e89fae2734ed46e55 Mon Sep 17 00:00:00 2001 From: satikaj <117552851+satikaj@users.noreply.github.com> Date: Tue, 26 Nov 2024 15:29:16 +1100 Subject: [PATCH 0227/1280] fix: remove selected outcomes from dropdown --- .../feedback-template-editor.component.ts | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/app/common/feedback-template/feedback-template-editor.component.ts b/src/app/common/feedback-template/feedback-template-editor.component.ts index ddf0334e54..38358b0eab 100644 --- a/src/app/common/feedback-template/feedback-template-editor.component.ts +++ b/src/app/common/feedback-template/feedback-template-editor.component.ts @@ -327,9 +327,12 @@ export class FeedbackTemplateEditorComponent implements AfterViewInit { readonly allOutcomes: string[] = ['TLO1', 'TLO2', 'TLO3', 'ULO1', 'ULO2']; readonly filteredOutcomes = computed(() => { const currentOutcome = this.currentConnectedOutcome().toLowerCase(); - return currentOutcome - ? this.allOutcomes.filter((outcome) => outcome.toLowerCase().includes(currentOutcome)) - : this.allOutcomes.slice(); + return this.allOutcomes.filter((outcome) => { + return ( + !this.connectedOutcomes().includes(outcome) && + (!currentOutcome || outcome.toLowerCase().includes(currentOutcome)) + ); + }); }); readonly announcer = inject(LiveAnnouncer); From 9d017fbfaa1d5bae7f43da37ec7ae43e1dfafa8f Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Fri, 6 Dec 2024 10:25:51 +1100 Subject: [PATCH 0228/1280] feat: switch to html5 mode --- src/app/doubtfire-angularjs.module.ts | 4 +++- src/index.html | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index e14fdbb545..2f12cc2b57 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -236,7 +236,9 @@ export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.projects', 'doubtfire.groups', 'doubtfire.visualisations', -]); +]).config(['$locationProvider', ($locationProvider) => { + $locationProvider.html5Mode(true); +}]); // Downgrade angular modules that we need... // factory -> service diff --git a/src/index.html b/src/index.html index 54fed2d067..2e715e206f 100644 --- a/src/index.html +++ b/src/index.html @@ -1,6 +1,7 @@ + -
-
-

Modify Unit Staff

- Add staff members to the unit, assigning them a convenor or tutor role. -
-
-
-
This unit has no staff assigned
-
- - - - - - - - - - - - - - - - - - -
NameRoleMain ConvenorActions
- - {{staff.user.name}} -
- - -
-
- - - -
-
-
-
- -
- diff --git a/src/app/units/states/edit/edit.tpl.html b/src/app/units/states/edit/edit.tpl.html index 3ba73129a5..a49ba3561d 100644 --- a/src/app/units/states/edit/edit.tpl.html +++ b/src/app/units/states/edit/edit.tpl.html @@ -6,7 +6,7 @@ - + From 49fcba6bdfb9b83ead231114045c31583643b003 Mon Sep 17 00:00:00 2001 From: Jason Vellucci Date: Mon, 22 Sep 2025 11:18:15 +1000 Subject: [PATCH 0640/1280] refactor: migrate/unit staff editor 9.x (#933) * chore: migrate/unit-staff-editor - delete old Coffeescript file - delete old template - remove reference to old Coffeescript file - link new component - downgrade new component * chore: migrate/unit-staff-editor - port `unit-staff-editor-component` to Typescript from Coffeescript - port `unit-staff-editor` template to Angular template syntax w/ Angular Material - adjust parent component `Inputs` and attribute bindings * Update README.md * Update README.md --------- Co-authored-by: Boink <40929320+b0ink@users.noreply.github.com> --- README.md | 2 +- src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire-angularjs.module.ts | 11 +- .../states/edit/directives/directives.coffee | 1 - .../unit-staff-editor.component.html | 116 +++++++++++++++ .../unit-staff-editor.component.ts | 135 ++++++++++++++++++ .../unit-staff-editor.tpl.html | 101 ------------- src/app/units/states/edit/edit.tpl.html | 2 +- 8 files changed, 264 insertions(+), 106 deletions(-) create mode 100644 src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html create mode 100644 src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts delete mode 100644 src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.tpl.html diff --git a/README.md b/README.md index e748a9393b..5f4e969966 100644 --- a/README.md +++ b/README.md @@ -64,6 +64,7 @@ MIGRATED: - [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts - [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.ts - [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts +- [x] ./src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts - [x] ./src/app/units/states/analytics/unit-analytics-route.component.ts - [x] ./src/app/common/footer/footer.component.ts - [x] ./src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.ts @@ -189,7 +190,6 @@ TODO: - [ ] ./src/app/units/states/edit/directives/directives.coffee - [ ] ./src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.coffee - [ ] ./src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee -- [ ] ./src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee - [ ] ./src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.coffee - [ ] ./src/app/units/states/edit/edit.coffee - [ ] ./src/app/units/states/rollover/directives/directives.coffee diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index e20c993667..0e370154ff 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -286,6 +286,7 @@ import {TaskPrerequisiteService} from './api/services/task-prerequisite.service' // import { GradeIconComponent } from './common/grade-icon/grade-icon.component'; // import { GradeTaskModalComponent } from './tasks/modals/grade-task-modal/grade-task-modal.component'; // import { PrivacyPolicy } from './config/privacy-policy/privacy-policy'; +import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staff-editor/unit-staff-editor.component'; import {GroupSetSelectorComponent} from './groups/group-set-selector/group-set-selector.component'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 @@ -435,6 +436,7 @@ const MY_DATE_FORMAT = { LtiUnitLinkComponent, TaskDefinitionPrerequisitesComponent, TaskPrerequisitesCardComponent, + UnitStaffEditorComponent, GroupSetSelectorComponent, ], // Services we provide diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 7ce8c29c3d..223544d7bf 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -101,7 +101,6 @@ import 'build/src/app/units/states/groups/groups.js'; import 'build/src/app/units/states/states.js'; import 'build/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.js'; import 'build/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.js'; -import 'build/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.js'; import 'build/src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.js'; import 'build/src/app/units/states/edit/directives/directives.js'; import 'build/src/app/units/states/edit/edit.js'; @@ -229,6 +228,7 @@ import {SidekiqProgressModalService} from './common/modals/sidekiq-progress-moda import {TaskPrerequisitesCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component'; // import { UnitStudentEnrolmentModalService } from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service'; // import { PrivacyPolicy } from './config/privacy-policy/privacy-policy'; +import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staff-editor/unit-staff-editor.component'; import {GroupSetSelectorComponent} from './groups/group-set-selector/group-set-selector.component'; export const DoubtfireAngularJSModule = angular @@ -342,7 +342,10 @@ DoubtfireAngularJSModule.directive( 'objectSelect', downgradeComponent({component: ObjectSelectComponent}), ); -DoubtfireAngularJSModule.directive('fGradeIcon', downgradeComponent({component: GradeIconComponent})); +DoubtfireAngularJSModule.directive( + 'fGradeIcon', + downgradeComponent({component: GradeIconComponent}), +); DoubtfireAngularJSModule.directive('appHeader', downgradeComponent({component: HeaderComponent})); DoubtfireAngularJSModule.directive( 'splashScreen', @@ -499,6 +502,10 @@ DoubtfireAngularJSModule.directive( ); DoubtfireAngularJSModule.directive('newFUnits', downgradeComponent({component: FUnitsComponent})); +DoubtfireAngularJSModule.directive( + 'unitStaffEditor', + downgradeComponent({component: UnitStaffEditorComponent}), +); DoubtfireAngularJSModule.directive( 'fTaskIlosCard', downgradeComponent({component: TaskIlosCardComponent}), diff --git a/src/app/units/states/edit/directives/directives.coffee b/src/app/units/states/edit/directives/directives.coffee index bfb12ed317..fe06bf4510 100644 --- a/src/app/units/states/edit/directives/directives.coffee +++ b/src/app/units/states/edit/directives/directives.coffee @@ -2,5 +2,4 @@ angular.module('doubtfire.units.states.edit.directives', [ 'doubtfire.units.states.edit.directives.unit-details-editor' 'doubtfire.units.states.edit.directives.unit-group-set-editor' 'doubtfire.units.states.edit.directives.unit-ilo-editor' - 'doubtfire.units.states.edit.directives.unit-staff-editor' ]) diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html new file mode 100644 index 0000000000..84aa983f0a --- /dev/null +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html @@ -0,0 +1,116 @@ +
+ + + + + + + + +
+
+

Modify Unit Staff

+

Add staff members to the unit, assigning them a convenor or tutor role.

+
+ +
+
+ +
+ This unit has no staff assigned. +
+ + +
+ + + + + + + + + + + + + + + + + + +
NameRoleMain ConvenorActions
+ + {{ staff.user.name }} +
+ + +
+
+ + + +
+
+
+
+ +
+
diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts new file mode 100644 index 0000000000..167ed3210f --- /dev/null +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts @@ -0,0 +1,135 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {UnitRoleService} from 'src/app/api/services/unit-role.service'; +import {Unit} from 'src/app/api/models/unit'; +import {User} from 'src/app/api/models/doubtfire-model'; +import {UnitRole} from 'src/app/api/models/unit-role'; + +@Component({ + selector: 'unit-staff-editor', + templateUrl: 'unit-staff-editor.component.html', +}) +export class UnitStaffEditorComponent implements OnInit { + @Input() unit: Unit; + @Input() staff: User[]; + + temp = []; + users = []; + unitStaff: UnitRole[]; + filteredStaff: User[] = []; // Filtered staff members + searchTerm: string = ''; // Search term entered by the user + + // Inject services here + constructor( + private alertService: AlertService, + private unitRoleService: UnitRoleService, + ) {} + + ngOnInit(): void { + // Subscribe to staff cache + this.unit.staffCache.values.subscribe((staff: UnitRole[]) => { + this.unitStaff = staff; + }); + } + + /** + * Changes the role of a staff member. + * + * @param UnitRole unitRole + * @param number role_id + * + * @returns void + */ + changeRole(unitRole: UnitRole, role_id: number) { + unitRole.roleId = role_id; + this.unitRoleService.update(unitRole).subscribe({ + next: (response) => this.alertService.success('Role changed', 2000), + error: (response) => this.alertService.error(response, 6000), + }); + } + + /** + * Changes who the `Main Convenor` of the unit is. + * + * @param UnitRole staff + * + * @returns void + */ + changeMainConvenor(staff: UnitRole) { + this.unit.changeMainConvenor(staff).subscribe({ + next: (response) => this.alertService.success('Main convenor changed', 2000), + error: (response) => this.alertService.error(response, 6000), + }); + } + + /** + * Adds a staff member to the unit. + * + * @param User selectedStaff + * + * @returns void + */ + addSelectedStaff(selectedStaff: User) { + if (selectedStaff?.id) { + this.unit.addStaff(selectedStaff).subscribe({ + next: () => { + this.alertService.success('Staff member added', 2000); + this.searchTerm = ''; // Clear the input field + this.filterStaffList(); // Refilter the list + }, + error: (response) => this.alertService.error(response, 6000), + }); + } else { + this.alertService.error( + 'Unable to add staff member. Ensure they have a tutor or convenor account in User admin first', + ); + } + } + + /** + * Used in filtering the staff list. The `searchTerm` is bound to the auto-complete input in this class's template. + * + * @returns void + */ + filterStaffList(): void { + // `this.searchTerm` holds the selected staff member object from the dropdown OR the auto-complete input searchTerm (never at the same time). + // Thus, check the type here and exit early if string filtering is not needed. + if (typeof this.searchTerm !== 'string') { + return; + } + this.filteredStaff = this.staff.filter( + (staff) => + staff.name.toLowerCase().includes(this.searchTerm.toLowerCase()) && // Find by name + !this.unit.staff.find((listStaff) => staff.id === listStaff.user.id), // Not already assigned to the unit + ); + } + + /** + * Generates a human-readable name made up of the passed-in staff member's `first` and `last` names. + * + * @param User staff + * + * @returns void + */ + displayStaffName(staff: User): string { + return staff ? staff.name : ''; + } + + /** + * Removes a staff member from the unit. + * + * @param UnitRole staff + * + * @returns void + */ + removeStaff(staff: UnitRole) { + this.unitRoleService.delete(staff, {cache: this.unit.staffCache}).subscribe({ + next: (response) => this.alertService.success('Staff member removed', 2000), + error: (response) => this.alertService.error(response, 6000), + }); + } + + groupSetName(id: number) { + this.unit.groupSetsCache.get(id).name || 'Individual Work'; + } +} diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.tpl.html b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.tpl.html deleted file mode 100644 index f8b38cecb0..0000000000 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.tpl.html +++ /dev/null @@ -1,101 +0,0 @@ -
- -
-
-

Modify Unit Staff

- Add staff members to the unit, assigning them a convenor or tutor role. -
-
-
-
This unit has no staff assigned
-
- - - - - - - - - - - - - - - - - - -
NameRoleMain ConvenorActions
- - {{staff.user.name}} -
- - -
-
- - - -
-
-
-
- -
-
diff --git a/src/app/units/states/edit/edit.tpl.html b/src/app/units/states/edit/edit.tpl.html index 2c9699e496..4df8bf3d09 100644 --- a/src/app/units/states/edit/edit.tpl.html +++ b/src/app/units/states/edit/edit.tpl.html @@ -6,7 +6,7 @@ - + From 943e3bf761ab210e68d69982ccf91c0d093a836e Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 22 Sep 2025 12:44:53 +1000 Subject: [PATCH 0641/1280] refactor: unit staff editor material ui (#1001) * fix: revert staff role on error * fix: ensure full search for unit role * chore: fix casing * refactor: use mat table for staff editor * chore: remove unused variables * fix: null check * refactor: use icon button * chore: remove unit staff editor coffeescript file * chore: add back staff editor tooltips --- src/app/common/header/header.component.ts | 3 +- .../unit-staff-editor.coffee | 58 ------ .../unit-staff-editor.component.html | 197 ++++++++---------- .../unit-staff-editor.component.ts | 51 ++++- 4 files changed, 127 insertions(+), 182 deletions(-) delete mode 100644 src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee diff --git a/src/app/common/header/header.component.ts b/src/app/common/header/header.component.ts index 8d9e8f6a11..4601057b15 100644 --- a/src/app/common/header/header.component.ts +++ b/src/app/common/header/header.component.ts @@ -173,8 +173,7 @@ export class HeaderComponent implements OnInit, OnDestroy { } isUniqueRole = (unit) => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const units = this.unitRoles.filter((role: any) => role.unit.id === unit.unit.id); + const units = this.unitRoles.filter((role: UnitRole) => role.unit?.id === unit.unit?.id); return units.length == 1 || unit.role == 'Tutor'; }; diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee deleted file mode 100644 index 3856daefe5..0000000000 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee +++ /dev/null @@ -1,58 +0,0 @@ -angular.module('doubtfire.units.states.edit.directives.unit-staff-editor', []) - -# -# Editor for adding new staff to a unit and assigning those staff -# members new unit roles within the unit -# -.directive('unitStaffEditor', -> - replace: true - restrict: 'E' - templateUrl: 'units/states/edit/directives/unit-staff-editor/unit-staff-editor.tpl.html' - controller: ($scope, $rootScope, alertService, newUnitService, newUnitRoleService) -> - temp = [] - users = [] - - $scope.unit.staffCache.values.subscribe( (staff) -> $scope.unitStaff = staff ) - - $scope.changeRole = (unitRole, role_id) -> - unitRole.roleId = role_id - newUnitRoleService.update(unitRole).subscribe({ - next: (response) -> alertService.success( "Role changed", 2000) - error: (response) -> alertService.error( response, 6000) - }) - - $scope.changeMainConvenor = (staff) -> - $scope.unit.changeMainConvenor(staff).subscribe({ - next: (response) -> - alertService.success( "Main convenor changed", 2000) - error: (response) -> - alertService.error( response, 6000) - }) - - $scope.addSelectedStaff = -> - staff = $scope.selectedStaff - $scope.selectedStaff = null - $scope.unit.staff = [] unless $scope.unit.staff - - if staff.id? - $scope.unit.addStaff(staff).subscribe({ - next: (response) -> alertService.success( "Staff member added", 2000) - error: (response) -> alertService.error( response, 6000) - }) - else - alertService.error( "Unable to add staff member. Ensure they have a tutor or convenor account in User admin first.", 6000) - - # Used in the typeahead to filter staff already in unit - $scope.filterStaff = (staff) -> - not _.find($scope.unit.staff, (listStaff) -> staff.id == listStaff.user.id) - - $scope.removeStaff = (staff) -> - newUnitRoleService.delete(staff, {cache: $scope.unit.staffCache}).subscribe({ - next: (response) -> alertService.success( "Staff member removed", 2000) - error: (response) -> alertService.error( response, 6000) - }) - - $scope.groupSetName = (id) -> - $scope.unit.groupSetsCache.get(id)?.name || "Individual Work" - -) diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html index 84aa983f0a..82938cde3f 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html @@ -1,116 +1,89 @@ -
- - - - - - - - -
-
-

Modify Unit Staff

-

Add staff members to the unit, assigning them a convenor or tutor role.

-
- -
-
- -
- This unit has no staff assigned. -
+
+
+

Unit Staff

+

Manage unit staff by adding members and assigning them as convenors or tutors.

+
+ + + - -
-
Name
- - - - - - - - - - - - - - - - - -
NameRoleMain ConvenorActions
- - {{ staff.user.name }} -
- - -
-
- - - -
+ +
+ {{ unitRole.user.name }}
-
-
- -
+ Convenor + + + + + Main Convenor + + @if (unitRole?.role === 'Convenor') { + + } + + + + Actions + + + + + + + + + + + + {{ staff.name }} + + +
diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts index 167ed3210f..7c53a04671 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts @@ -4,6 +4,9 @@ import {UnitRoleService} from 'src/app/api/services/unit-role.service'; import {Unit} from 'src/app/api/models/unit'; import {User} from 'src/app/api/models/doubtfire-model'; import {UnitRole} from 'src/app/api/models/unit-role'; +import {MatTableDataSource} from '@angular/material/table'; +import {MatButtonToggleChange} from '@angular/material/button-toggle'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; @Component({ selector: 'unit-staff-editor', @@ -19,19 +22,32 @@ export class UnitStaffEditorComponent implements OnInit { filteredStaff: User[] = []; // Filtered staff members searchTerm: string = ''; // Search term entered by the user + displayedColumns: string[] = ['name', 'role', 'main-convenor', 'actions']; + dataSource = new MatTableDataSource(); + // Inject services here constructor( private alertService: AlertService, private unitRoleService: UnitRoleService, + private confirmationModalService: ConfirmationModalService, ) {} ngOnInit(): void { // Subscribe to staff cache this.unit.staffCache.values.subscribe((staff: UnitRole[]) => { this.unitStaff = staff; + this.dataSource.data = staff; }); } + onRoleChange(unitRole: UnitRole, event: MatButtonToggleChange) { + const role = event.value; + if (role !== 'Tutor' && role !== 'Convenor') { + return; + } + const roleId = role === 'Tutor' ? 2 : 3; // map however you like + this.changeRole(unitRole, roleId, role); + } /** * Changes the role of a staff member. * @@ -40,11 +56,20 @@ export class UnitStaffEditorComponent implements OnInit { * * @returns void */ - changeRole(unitRole: UnitRole, role_id: number) { - unitRole.roleId = role_id; + changeRole(unitRole: UnitRole, roleId: number, role: string) { + const previousRoleId = unitRole.roleId; + const previousRole = unitRole.role; + + unitRole.roleId = roleId; + unitRole.role = role; this.unitRoleService.update(unitRole).subscribe({ - next: (response) => this.alertService.success('Role changed', 2000), - error: (response) => this.alertService.error(response, 6000), + next: () => this.alertService.success('Role changed', 2000), + error: (response) => { + // Revert changes on error + unitRole.roleId = previousRoleId; + unitRole.role = previousRole; + this.alertService.error(response, 6000); + }, }); } @@ -56,10 +81,16 @@ export class UnitStaffEditorComponent implements OnInit { * @returns void */ changeMainConvenor(staff: UnitRole) { - this.unit.changeMainConvenor(staff).subscribe({ - next: (response) => this.alertService.success('Main convenor changed', 2000), - error: (response) => this.alertService.error(response, 6000), - }); + this.confirmationModalService.show( + 'Set Main Convenor', + `Do you want to make ${staff.user.name} the main convenor for this unit?`, + () => { + this.unit.changeMainConvenor(staff).subscribe({ + next: (_response) => this.alertService.success('Main convenor changed', 2000), + error: (response) => this.alertService.error(response, 6000), + }); + }, + ); } /** @@ -99,7 +130,7 @@ export class UnitStaffEditorComponent implements OnInit { } this.filteredStaff = this.staff.filter( (staff) => - staff.name.toLowerCase().includes(this.searchTerm.toLowerCase()) && // Find by name + staff.matches(this.searchTerm.toLowerCase()) && // Find by name !this.unit.staff.find((listStaff) => staff.id === listStaff.user.id), // Not already assigned to the unit ); } @@ -124,7 +155,7 @@ export class UnitStaffEditorComponent implements OnInit { */ removeStaff(staff: UnitRole) { this.unitRoleService.delete(staff, {cache: this.unit.staffCache}).subscribe({ - next: (response) => this.alertService.success('Staff member removed', 2000), + next: () => this.alertService.success('Staff member removed', 2000), error: (response) => this.alertService.error(response, 6000), }); } From d510b3b54340c225abb4db51b06bddc4404b9306 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 22 Sep 2025 12:44:53 +1000 Subject: [PATCH 0642/1280] refactor: unit staff editor material ui (#1001) * fix: revert staff role on error * fix: ensure full search for unit role * chore: fix casing * refactor: use mat table for staff editor * chore: remove unused variables * fix: null check * refactor: use icon button * chore: remove unit staff editor coffeescript file * chore: add back staff editor tooltips --- src/app/common/header/header.component.ts | 3 +- .../unit-staff-editor.coffee | 58 ------ .../unit-staff-editor.component.html | 197 ++++++++---------- .../unit-staff-editor.component.ts | 51 ++++- 4 files changed, 127 insertions(+), 182 deletions(-) delete mode 100644 src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee diff --git a/src/app/common/header/header.component.ts b/src/app/common/header/header.component.ts index b5e1960c8a..842287b92e 100644 --- a/src/app/common/header/header.component.ts +++ b/src/app/common/header/header.component.ts @@ -104,8 +104,7 @@ export class HeaderComponent implements OnInit, OnDestroy { } isUniqueRole = (unit) => { - // eslint-disable-next-line @typescript-eslint/no-explicit-any - const units = this.unitRoles.filter((role: any) => role.unit.id === unit.unit.id); + const units = this.unitRoles.filter((role: UnitRole) => role.unit?.id === unit.unit?.id); return units.length == 1 || unit.role == 'Tutor'; }; diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee deleted file mode 100644 index 3856daefe5..0000000000 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee +++ /dev/null @@ -1,58 +0,0 @@ -angular.module('doubtfire.units.states.edit.directives.unit-staff-editor', []) - -# -# Editor for adding new staff to a unit and assigning those staff -# members new unit roles within the unit -# -.directive('unitStaffEditor', -> - replace: true - restrict: 'E' - templateUrl: 'units/states/edit/directives/unit-staff-editor/unit-staff-editor.tpl.html' - controller: ($scope, $rootScope, alertService, newUnitService, newUnitRoleService) -> - temp = [] - users = [] - - $scope.unit.staffCache.values.subscribe( (staff) -> $scope.unitStaff = staff ) - - $scope.changeRole = (unitRole, role_id) -> - unitRole.roleId = role_id - newUnitRoleService.update(unitRole).subscribe({ - next: (response) -> alertService.success( "Role changed", 2000) - error: (response) -> alertService.error( response, 6000) - }) - - $scope.changeMainConvenor = (staff) -> - $scope.unit.changeMainConvenor(staff).subscribe({ - next: (response) -> - alertService.success( "Main convenor changed", 2000) - error: (response) -> - alertService.error( response, 6000) - }) - - $scope.addSelectedStaff = -> - staff = $scope.selectedStaff - $scope.selectedStaff = null - $scope.unit.staff = [] unless $scope.unit.staff - - if staff.id? - $scope.unit.addStaff(staff).subscribe({ - next: (response) -> alertService.success( "Staff member added", 2000) - error: (response) -> alertService.error( response, 6000) - }) - else - alertService.error( "Unable to add staff member. Ensure they have a tutor or convenor account in User admin first.", 6000) - - # Used in the typeahead to filter staff already in unit - $scope.filterStaff = (staff) -> - not _.find($scope.unit.staff, (listStaff) -> staff.id == listStaff.user.id) - - $scope.removeStaff = (staff) -> - newUnitRoleService.delete(staff, {cache: $scope.unit.staffCache}).subscribe({ - next: (response) -> alertService.success( "Staff member removed", 2000) - error: (response) -> alertService.error( response, 6000) - }) - - $scope.groupSetName = (id) -> - $scope.unit.groupSetsCache.get(id)?.name || "Individual Work" - -) diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html index 84aa983f0a..82938cde3f 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html @@ -1,116 +1,89 @@ -
- - - - - - - - -
-
-

Modify Unit Staff

-

Add staff members to the unit, assigning them a convenor or tutor role.

-
- -
-
- -
- This unit has no staff assigned. -
+
+
+

Unit Staff

+

Manage unit staff by adding members and assigning them as convenors or tutors.

+
+ + + - -
-
Name
- - - - - - - - - - - - - - - - - -
NameRoleMain ConvenorActions
- - {{ staff.user.name }} -
- - -
-
- - - -
+ +
+ {{ unitRole.user.name }}
-
-
- -
+ Convenor + + + + + Main Convenor + + @if (unitRole?.role === 'Convenor') { + + } + + + + Actions + + + + + + + + + + + + {{ staff.name }} + + +
diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts index 167ed3210f..7c53a04671 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts @@ -4,6 +4,9 @@ import {UnitRoleService} from 'src/app/api/services/unit-role.service'; import {Unit} from 'src/app/api/models/unit'; import {User} from 'src/app/api/models/doubtfire-model'; import {UnitRole} from 'src/app/api/models/unit-role'; +import {MatTableDataSource} from '@angular/material/table'; +import {MatButtonToggleChange} from '@angular/material/button-toggle'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; @Component({ selector: 'unit-staff-editor', @@ -19,19 +22,32 @@ export class UnitStaffEditorComponent implements OnInit { filteredStaff: User[] = []; // Filtered staff members searchTerm: string = ''; // Search term entered by the user + displayedColumns: string[] = ['name', 'role', 'main-convenor', 'actions']; + dataSource = new MatTableDataSource(); + // Inject services here constructor( private alertService: AlertService, private unitRoleService: UnitRoleService, + private confirmationModalService: ConfirmationModalService, ) {} ngOnInit(): void { // Subscribe to staff cache this.unit.staffCache.values.subscribe((staff: UnitRole[]) => { this.unitStaff = staff; + this.dataSource.data = staff; }); } + onRoleChange(unitRole: UnitRole, event: MatButtonToggleChange) { + const role = event.value; + if (role !== 'Tutor' && role !== 'Convenor') { + return; + } + const roleId = role === 'Tutor' ? 2 : 3; // map however you like + this.changeRole(unitRole, roleId, role); + } /** * Changes the role of a staff member. * @@ -40,11 +56,20 @@ export class UnitStaffEditorComponent implements OnInit { * * @returns void */ - changeRole(unitRole: UnitRole, role_id: number) { - unitRole.roleId = role_id; + changeRole(unitRole: UnitRole, roleId: number, role: string) { + const previousRoleId = unitRole.roleId; + const previousRole = unitRole.role; + + unitRole.roleId = roleId; + unitRole.role = role; this.unitRoleService.update(unitRole).subscribe({ - next: (response) => this.alertService.success('Role changed', 2000), - error: (response) => this.alertService.error(response, 6000), + next: () => this.alertService.success('Role changed', 2000), + error: (response) => { + // Revert changes on error + unitRole.roleId = previousRoleId; + unitRole.role = previousRole; + this.alertService.error(response, 6000); + }, }); } @@ -56,10 +81,16 @@ export class UnitStaffEditorComponent implements OnInit { * @returns void */ changeMainConvenor(staff: UnitRole) { - this.unit.changeMainConvenor(staff).subscribe({ - next: (response) => this.alertService.success('Main convenor changed', 2000), - error: (response) => this.alertService.error(response, 6000), - }); + this.confirmationModalService.show( + 'Set Main Convenor', + `Do you want to make ${staff.user.name} the main convenor for this unit?`, + () => { + this.unit.changeMainConvenor(staff).subscribe({ + next: (_response) => this.alertService.success('Main convenor changed', 2000), + error: (response) => this.alertService.error(response, 6000), + }); + }, + ); } /** @@ -99,7 +130,7 @@ export class UnitStaffEditorComponent implements OnInit { } this.filteredStaff = this.staff.filter( (staff) => - staff.name.toLowerCase().includes(this.searchTerm.toLowerCase()) && // Find by name + staff.matches(this.searchTerm.toLowerCase()) && // Find by name !this.unit.staff.find((listStaff) => staff.id === listStaff.user.id), // Not already assigned to the unit ); } @@ -124,7 +155,7 @@ export class UnitStaffEditorComponent implements OnInit { */ removeStaff(staff: UnitRole) { this.unitRoleService.delete(staff, {cache: this.unit.staffCache}).subscribe({ - next: (response) => this.alertService.success('Staff member removed', 2000), + next: () => this.alertService.success('Staff member removed', 2000), error: (response) => this.alertService.error(response, 6000), }); } From e3c4e8cb61739b43f4a7f4a33972e9ac17e10d38 Mon Sep 17 00:00:00 2001 From: Andrew Cain Date: Thu, 3 Apr 2025 17:38:51 +1100 Subject: [PATCH 0643/1280] Merge branch 'migrate/confirmation-modal' of https://github.com/b0ink/doubtfire-web into b0ink-migrate/confirmation-modal --- .../confirmation-modal.coffee | 35 -------------- .../confirmation-modal.component.html | 20 ++++++++ .../confirmation-modal.component.scss | 0 .../confirmation-modal.component.ts | 47 +++++++++++++++++++ .../confirmation-modal.scss | 3 -- .../confirmation-modal.service.ts | 26 ++++++++++ .../confirmation-modal.tpl.html | 22 --------- src/app/common/modals/modals.coffee | 1 - src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire-angularjs.module.ts | 3 +- .../unit-task-editor.component.ts | 4 +- 11 files changed, 98 insertions(+), 65 deletions(-) delete mode 100644 src/app/common/modals/confirmation-modal/confirmation-modal.coffee create mode 100644 src/app/common/modals/confirmation-modal/confirmation-modal.component.html create mode 100644 src/app/common/modals/confirmation-modal/confirmation-modal.component.scss create mode 100644 src/app/common/modals/confirmation-modal/confirmation-modal.component.ts delete mode 100644 src/app/common/modals/confirmation-modal/confirmation-modal.scss create mode 100644 src/app/common/modals/confirmation-modal/confirmation-modal.service.ts delete mode 100644 src/app/common/modals/confirmation-modal/confirmation-modal.tpl.html diff --git a/src/app/common/modals/confirmation-modal/confirmation-modal.coffee b/src/app/common/modals/confirmation-modal/confirmation-modal.coffee deleted file mode 100644 index c7999098cf..0000000000 --- a/src/app/common/modals/confirmation-modal/confirmation-modal.coffee +++ /dev/null @@ -1,35 +0,0 @@ -angular.module("doubtfire.common.modals.confirmation-modal", []) - -.factory("ConfirmationModal", ($modal) -> - ConfirmationModal = {} - - # - # Show a modal asking the user to confirm their indicated action. - # - ConfirmationModal.show = (title, message, action) -> - modalInstance = $modal.open - templateUrl: 'common/modals/confirmation-modal/confirmation-modal.tpl.html' - controller: 'ConfirmationModalCtrl' - resolve: - title: -> title - message: -> message - action: -> action - - ConfirmationModal -) - -# -# Controller for confirmation modal -# -.controller('ConfirmationModalCtrl', ($scope, $modalInstance, title, message, action, alertService) -> - $scope.title = title - $scope.message = message - - $scope.confirmAction = -> - action() - $modalInstance.dismiss() - - $scope.cancelAction = -> - alertService.message "#{title} action cancelled", 3000 - $modalInstance.dismiss() -) diff --git a/src/app/common/modals/confirmation-modal/confirmation-modal.component.html b/src/app/common/modals/confirmation-modal/confirmation-modal.component.html new file mode 100644 index 0000000000..3ec07fc729 --- /dev/null +++ b/src/app/common/modals/confirmation-modal/confirmation-modal.component.html @@ -0,0 +1,20 @@ +
+

+
+ +
+
{{ title }}
+ Please confirm that you want to perform this action. +
+
+

+ + {{ message }} + + + + + +
diff --git a/src/app/common/modals/confirmation-modal/confirmation-modal.component.scss b/src/app/common/modals/confirmation-modal/confirmation-modal.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/common/modals/confirmation-modal/confirmation-modal.component.ts b/src/app/common/modals/confirmation-modal/confirmation-modal.component.ts new file mode 100644 index 0000000000..f9506e5b8b --- /dev/null +++ b/src/app/common/modals/confirmation-modal/confirmation-modal.component.ts @@ -0,0 +1,47 @@ +import {Component, OnInit, Input, Inject} from '@angular/core'; +import {AlertService} from '../../services/alert.service'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; + +export interface ConfirmationModalData { + title: string; + message: string; + action?: any; +} + +@Component({ + selector: 'confirmation-modal', + templateUrl: './confirmation-modal.component.html', + styleUrls: ['./confirmation-modal.component.scss'], +}) +export class ConfirmationModalComponent implements OnInit { + @Input() title: string; + @Input() message: string; + @Input() action: () => void; + + constructor( + @Inject(AlertService) private alertService: AlertService, + @Inject(MAT_DIALOG_DATA) public data: ConfirmationModalData, + + public dialogRef: MatDialogRef, + ) {} + + ngOnInit(): void { + this.title = this.data.title; + this.message = this.data.message; + this.action = this.data.action; + } + + public confirmAction() { + if (typeof this.action === 'function') { + this.action(); + } else { + this.alertService.error(`${this.title} action failed.`); + } + this.dialogRef.close(); + } + + public cancelAction() { + this.alertService.success(`${this.title} action cancelled.`); + this.dialogRef.close(); + } +} diff --git a/src/app/common/modals/confirmation-modal/confirmation-modal.scss b/src/app/common/modals/confirmation-modal/confirmation-modal.scss deleted file mode 100644 index f30b0e345c..0000000000 --- a/src/app/common/modals/confirmation-modal/confirmation-modal.scss +++ /dev/null @@ -1,3 +0,0 @@ -.confirmation-modal .modal-body { - font-size: 1.5em; -} diff --git a/src/app/common/modals/confirmation-modal/confirmation-modal.service.ts b/src/app/common/modals/confirmation-modal/confirmation-modal.service.ts new file mode 100644 index 0000000000..6257277eff --- /dev/null +++ b/src/app/common/modals/confirmation-modal/confirmation-modal.service.ts @@ -0,0 +1,26 @@ +import {Injectable} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import {ConfirmationModalComponent, ConfirmationModalData} from './confirmation-modal.component'; + +@Injectable({ + providedIn: 'root', +}) +export class ConfirmationModalService { + constructor(public dialog: MatDialog) {} + + public show(title: string, message: string, action?: any) { + this.dialog.open( + ConfirmationModalComponent, + { + data: { + title, + message, + action, + }, + position: {top: '2.5%'}, + width: '100%', + maxWidth: '650px', + }, + ); + } +} diff --git a/src/app/common/modals/confirmation-modal/confirmation-modal.tpl.html b/src/app/common/modals/confirmation-modal/confirmation-modal.tpl.html deleted file mode 100644 index 4bd87f6868..0000000000 --- a/src/app/common/modals/confirmation-modal/confirmation-modal.tpl.html +++ /dev/null @@ -1,22 +0,0 @@ -
- - - -
diff --git a/src/app/common/modals/modals.coffee b/src/app/common/modals/modals.coffee index 16d2be1ec8..73aae8685b 100644 --- a/src/app/common/modals/modals.coffee +++ b/src/app/common/modals/modals.coffee @@ -1,5 +1,4 @@ angular.module("doubtfire.common.modals", [ 'doubtfire.common.modals.csv-result-modal' - 'doubtfire.common.modals.confirmation-modal' 'doubtfire.common.modals.comments-modal' ]) diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 338e6591f4..88c2206141 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -97,6 +97,7 @@ import {ExtensionCommentComponent} from './tasks/task-comments-viewer/extension- import {CampusListComponent} from './admin/institution-settings/campuses/campus-list/campus-list.component'; import {ExtensionModalComponent} from './common/modals/extension-modal/extension-modal.component'; import {CalendarModalComponent} from './common/modals/calendar-modal/calendar-modal.component'; +import { ConfirmationModalComponent } from './common/modals/confirmation-modal/confirmation-modal.component'; import {MatRadioModule} from '@angular/material/radio'; import {MatButtonToggleModule} from '@angular/material/button-toggle'; import { @@ -301,6 +302,7 @@ import {TaskStatusPieChartComponent} from './visualisations/task-status-pie-char OverseerImageListComponent, ExtensionModalComponent, CalendarModalComponent, + ConfirmationModalComponent, InstitutionSettingsComponent, HomeComponent, CommentBubbleActionComponent, diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index bd638cbea8..76ae8c64c5 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -107,7 +107,6 @@ import 'build/src/app/units/states/students-list/students-list.js'; import 'build/src/app/units/states/analytics/analytics.js'; import 'build/src/app/common/filters/filters.js'; import 'build/src/app/common/content-editable/content-editable.js'; -import 'build/src/app/common/modals/confirmation-modal/confirmation-modal.js'; import 'build/src/app/common/modals/comments-modal/comments-modal.js'; import 'build/src/app/common/modals/csv-result-modal/csv-result-modal.js'; import 'build/src/app/common/modals/modals.js'; @@ -140,6 +139,7 @@ import {ExtensionCommentComponent} from './tasks/task-comments-viewer/extension- import {TaskAssessmentCommentComponent} from './tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component'; import {ExtensionModalService} from './common/modals/extension-modal/extension-modal.service'; import {CalendarModalService} from './common/modals/calendar-modal/calendar-modal.service'; +import { ConfirmationModalService } from './common/modals/confirmation-modal/confirmation-modal.service'; import {CampusListComponent} from './admin/institution-settings/campuses/campus-list/campus-list.component'; import {ActivityTypeListComponent} from './admin/institution-settings/activity-type-list/activity-type-list.component'; import {InstitutionSettingsComponent} from './admin/institution-settings/institution-settings.component'; @@ -241,6 +241,7 @@ DoubtfireAngularJSModule.factory('AboutDoubtfireModal', downgradeInjectable(Abou DoubtfireAngularJSModule.factory('DoubtfireConstants', downgradeInjectable(DoubtfireConstants)); DoubtfireAngularJSModule.factory('ExtensionModal', downgradeInjectable(ExtensionModalService)); DoubtfireAngularJSModule.factory('CalendarModal', downgradeInjectable(CalendarModalService)); +DoubtfireAngularJSModule.factory('ConfirmationModal', downgradeInjectable(ConfirmationModalService)); DoubtfireAngularJSModule.factory('TaskCommentService', downgradeInjectable(TaskCommentService)); DoubtfireAngularJSModule.factory('alertService', downgradeInjectable(AlertService)); DoubtfireAngularJSModule.factory('tutorialService', downgradeInjectable(TutorialService)); diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts index 72c309371d..bf4c3b626b 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts @@ -138,9 +138,7 @@ export class UnitTaskEditorComponent implements AfterViewInit { () => { this.unit.deleteTaskDefinition(taskDefinition); //TODO: reinstate ProgressModal.show "Deleting Task #{task.abbreviation}", 'Please wait while student projects are updated.', promise - - this.alerts.success('Task deleted'); - } + }, ); } From d9560c3b68df0a09f577cdab990d252b5cd24c58 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 22 Sep 2025 13:45:33 +1000 Subject: [PATCH 0644/1280] fix: check for valid unit --- .../unit-staff-editor/unit-staff-editor.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html index 82938cde3f..9f3a65b727 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html @@ -45,13 +45,13 @@

Unit Staff

@if (unitRole?.role === 'Convenor') { } From bfae1ad69bb767cdad47dd8fac35cc84e5134534 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 22 Sep 2025 13:45:33 +1000 Subject: [PATCH 0645/1280] fix: check for valid unit --- .../unit-staff-editor/unit-staff-editor.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html index 82938cde3f..9f3a65b727 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html @@ -45,13 +45,13 @@

Unit Staff

@if (unitRole?.role === 'Convenor') { } From bfbcee98cfa4888241c5956372d004ec1cd813cb Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 22 Sep 2025 14:49:36 +1000 Subject: [PATCH 0646/1280] feat: add observer only ui --- src/app/api/models/unit-role.ts | 1 + src/app/api/services/unit-role.service.ts | 3 ++- .../unit-staff-editor.component.html | 13 +++++++++++++ .../unit-staff-editor.component.ts | 16 +++++++++++++++- 4 files changed, 31 insertions(+), 2 deletions(-) diff --git a/src/app/api/models/unit-role.ts b/src/app/api/models/unit-role.ts index 5868fa2f05..63bf9852de 100644 --- a/src/app/api/models/unit-role.ts +++ b/src/app/api/models/unit-role.ts @@ -11,6 +11,7 @@ export class UnitRole extends Entity { role: string; user: User; unit: Unit; + observerOnly: boolean; /** * The id for updated roles - but we need to move away from this to the role string... diff --git a/src/app/api/services/unit-role.service.ts b/src/app/api/services/unit-role.service.ts index 0100bb78ce..71cb194422 100644 --- a/src/app/api/services/unit-role.service.ts +++ b/src/app/api/services/unit-role.service.ts @@ -62,9 +62,10 @@ export class UnitRoleService extends CachedEntityService { return entity.unit?.id; }, }, + 'observerOnly', ); - this.mapping.addJsonKey('roleId', 'userId', 'unitId', 'role'); + this.mapping.addJsonKey('roleId', 'userId', 'unitId', 'role', 'observerOnly'); } public createInstanceFrom(json: any, other?: any): UnitRole { diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html index 9f3a65b727..ae0ca0114d 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html @@ -57,6 +57,19 @@

Unit Staff

} + + + Observer Only + + + + Actions diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts index 7c53a04671..f64d62d921 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts @@ -22,7 +22,7 @@ export class UnitStaffEditorComponent implements OnInit { filteredStaff: User[] = []; // Filtered staff members searchTerm: string = ''; // Search term entered by the user - displayedColumns: string[] = ['name', 'role', 'main-convenor', 'actions']; + displayedColumns: string[] = ['name', 'role', 'main-convenor', 'observer-only', 'actions']; dataSource = new MatTableDataSource(); // Inject services here @@ -73,6 +73,20 @@ export class UnitStaffEditorComponent implements OnInit { }); } + toggleObserverOnly(unitRole: UnitRole) { + const previousValue = unitRole.observerOnly; + unitRole.observerOnly = !unitRole.observerOnly; + unitRole.roleId = unitRole.role === 'Tutor' ? 2 : 3; + this.unitRoleService.update(unitRole).subscribe({ + next: () => this.alertService.success('Observer status updated', 2000), + error: (response) => { + // Revert changes on error + unitRole.observerOnly = previousValue; + this.alertService.error(response, 6000); + }, + }); + } + /** * Changes who the `Main Convenor` of the unit is. * From 75feec9c436a852c5e6ea69c93ae300d59cdaf38 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 22 Sep 2025 15:46:50 +1000 Subject: [PATCH 0647/1280] chore(release): 10.0.0-45 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 45aefeb73a..755a8eecd9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-45](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-44...v10.0.0-45) (2025-09-22) + + +### Bug Fixes + +* check for valid unit ([bfae1ad](https://github.com/b0ink/doubtfire-deploy/commit/bfae1ad69bb767cdad47dd8fac35cc84e5134534)) + ## [10.0.0-44](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-43...v10.0.0-44) (2025-09-18) ## [10.0.0-43](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-42...v10.0.0-43) (2025-09-17) diff --git a/package-lock.json b/package-lock.json index 3500ef85ca..a8b02747b3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-44", + "version": "10.0.0-45", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-44", + "version": "10.0.0-45", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 6ba1706bec..1f9c61185e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-44", + "version": "10.0.0-45", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 01db5769b77ba2d6b8a3242935ba73481f16bf00 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 24 Sep 2025 09:13:32 +1000 Subject: [PATCH 0648/1280] refactor: use students preferred name in greeting chip --- src/app/api/models/user/user.ts | 9 +++++++++ .../task-feedback-templates.component.ts | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/src/app/api/models/user/user.ts b/src/app/api/models/user/user.ts index 4fc56c9349..03a281bf12 100644 --- a/src/app/api/models/user/user.ts +++ b/src/app/api/models/user/user.ts @@ -53,6 +53,15 @@ export class User extends Entity { return `${fn} ${sn}${nn}`; } + public get preferredName(): string { + const nickname = this.nickname.trim(); + const firstName = this.firstName.trim(); + if (nickname) { + return nickname; + } + return firstName; + } + public matches(text: string): boolean { return ( this.studentId?.toLowerCase().indexOf(text) >= 0 || diff --git a/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts index ae3453dbaf..696e5ecca9 100644 --- a/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts +++ b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts @@ -191,7 +191,7 @@ export class TaskFeedbackTemplatesComponent implements OnInit, OnChanges { selectTemplate(template: FeedbackTemplate) { if (template.type === 'template') { if (template.chipText === 'Greeting') { - template.commentText = `Hi ${this.task.project.student.firstName}. `; + template.commentText = `Hi ${this.task.project.student.preferredName}. `; } else if (template.chipText === 'Summarise feedback') { if (!this.selectedTemplates || this.selectedTemplates.length < 1) return; template.commentText = 'Summary of the given feedback:'; From 568cb0e5730c9931225e750950506f42f6e6b4f8 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 24 Sep 2025 11:06:49 +1000 Subject: [PATCH 0649/1280] chore: format --- .../task-due-card.component.html | 133 +++++++++--------- 1 file changed, 70 insertions(+), 63 deletions(-) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html index 28baa761d9..24a8d8c1c7 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html @@ -1,15 +1,19 @@ -@if ( (!task?.inFinalState() || (task?.inTimeExceeded() && !task?.isPastDeadline())) && !task?.inAwaitingFeedbackState() +@if ( + (!task?.inFinalState() || (task?.inTimeExceeded() && !task?.isPastDeadline())) && + !task?.inAwaitingFeedbackState() ) { -
- - @if (task?.isDueSoon() && !task?.isPastDueDate()) { - - - - Aim To Complete Soon - Due in {{ task?.timeUntilDueDateDescription() }} - - - +
+ + @if (task?.isDueSoon() && !task?.isPastDueDate()) { + + + + Aim To Complete Soon - Due in {{ task?.timeUntilDueDateDescription() }} + + + @if (flexibleDatesEnabled) {

Your target due date for this task is @@ -22,9 +26,9 @@ >. You should aim to complete this task before then to keep your progress on track.

} -
- - + + + @if (flexibleDatesEnabled) {

This target due date for this task is {{ task?.localDueDateString() }} } - - } + + } - - @if (task?.betweenDueDateAndDeadlineDate()) { + + @if (task?.betweenDueDateAndDeadlineDate()) { } - - - + + + @if (flexibleDatesEnabled) {

You should have completed this task by @@ -97,52 +101,54 @@

} @else {

- You should have completed this task by {{ task?.localDueDateString() }}. Make sure to discuss this task with your tutor as soon as possible. If this task remains on this state for an - extended period, it will be marked as Time Exceeded. + You should have completed this task by + {{ task?.localDueDateString() }}. Make sure to discuss this task with your tutor as soon as possible. If this task + remains on this state for an extended period, it will be marked as Time Exceeded.

- Tasks are only considered completed once your tutor has discussed your work - with you. + Tasks are only considered completed once your tutor has + discussed your work with you.

} +
+
+ } - - - } - - - @if (task?.isPastDeadline()) { - - - error - Passed Due Date By {{ task?.timePastDueDateDescription() }} - - - -

- You should have completed this task by {{ task?.localDueDateString() }}. This task is now past the deadline and will be marked as Time Exceeded when submitted. You should - consult with the unit assessment details to determine the impact of failing to complete this task within the - allocated time. -

-
- - -

- You should have completed this task by {{ task?.localDueDateString() }}. Make sure to discuss this task with your tutor as soon as possible. -

-

- Tasks are only considered Completed once it demonstrates the required standard, and it is - discussed with your tutor. -

-
-
- } -
+ + @if (task?.isPastDeadline()) { + + + error + Passed Due Date By {{ task?.timePastDueDateDescription() }} + + + +

+ You should have completed this task by {{ task?.localDueDateString() }}. This task is now past the deadline and will be marked as Time Exceeded when + submitted. You should consult with the unit assessment details to determine the impact + of failing to complete this task within the allocated time. +

+
+ + +

+ You should have completed this task by {{ task?.localDueDateString() }}. Make sure to discuss this task with your tutor as soon as possible. +

+

+ Tasks are only considered Completed once it demonstrates the required + standard, and it is discussed with your tutor. +

+
+
+ } +
} @@ -154,7 +160,8 @@

You have submitted this task and should now wait for feedback from your tutor. Do not re-upload new files at this time as the status will be changed to Time Exceeded.Do not re-upload new files at this time as the status will be changed to + Time Exceeded.

From 3bf25e77fb9d64fb1ef9801967d69357ff209354 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 24 Sep 2025 11:23:27 +1000 Subject: [PATCH 0650/1280] refactor: change overdue task wording for assess in portfolio states --- .../task-due-card/task-due-card.component.html | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html index 24a8d8c1c7..83bc582179 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html @@ -129,10 +129,20 @@

- You should have completed this task by {{ task?.localDueDateString() }}. This task is now past the deadline and will be marked as Time Exceeded when - submitted. You should consult with the unit assessment details to determine the impact - of failing to complete this task within the allocated time. + @if (task?.taskDefinition?.unit.markLateSubmissionsAsAssessInPortfolio) { + You should have completed this task by + {{ task?.localDueDateString() }}. This task is now past the deadline and can only be submitted directly for your + portfolio without feedback. You should consult with the unit assessment details to + determine the impact of failing to complete this task within the allocated time. + } @else { + You should have completed this task by + {{ task?.localDueDateString() }}. This task is now past the deadline and will be marked as + Time Exceeded when submitted. You should consult with the unit assessment + details to determine the impact of failing to complete this task within the allocated + time. + }

From e5b15713c1d133d4e8a55c70249fcbf28294530b Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 24 Sep 2025 12:31:04 +1000 Subject: [PATCH 0651/1280] chore: return confirmation modal reference --- .../confirmation-modal/confirmation-modal.service.ts | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/src/app/common/modals/confirmation-modal/confirmation-modal.service.ts b/src/app/common/modals/confirmation-modal/confirmation-modal.service.ts index 6257277eff..660ddec60c 100644 --- a/src/app/common/modals/confirmation-modal/confirmation-modal.service.ts +++ b/src/app/common/modals/confirmation-modal/confirmation-modal.service.ts @@ -1,5 +1,5 @@ import {Injectable} from '@angular/core'; -import {MatDialog} from '@angular/material/dialog'; +import {MatDialog, MatDialogRef} from '@angular/material/dialog'; import {ConfirmationModalComponent, ConfirmationModalData} from './confirmation-modal.component'; @Injectable({ @@ -8,8 +8,12 @@ import {ConfirmationModalComponent, ConfirmationModalData} from './confirmation- export class ConfirmationModalService { constructor(public dialog: MatDialog) {} - public show(title: string, message: string, action?: any) { - this.dialog.open( + public show( + title: string, + message: string, + action?: any, + ): MatDialogRef { + return this.dialog.open( ConfirmationModalComponent, { data: { From 75172ba67d3eb5f83c7421fec7464298efb7c8ee Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 24 Sep 2025 12:31:33 +1000 Subject: [PATCH 0652/1280] refactor: require confirmation for enabling assess in portfolio for late submissions --- .../unit-details-editor.coffee | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee index a93c83b0ed..8049804f32 100644 --- a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee +++ b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee @@ -8,7 +8,7 @@ angular.module('doubtfire.units.states.edit.directives.unit-details-editor', []) replace: true restrict: 'E' templateUrl: 'units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html' - controller: ($scope, $state, $rootScope, DoubtfireConstants, newUnitService, alertService, newTeachingPeriodService, TaskSubmission, D2lUnitDetailsModal) -> + controller: ($scope, $timeout, $state, $rootScope, DoubtfireConstants, newUnitService, alertService, newTeachingPeriodService, TaskSubmission, D2lUnitDetailsModal, ConfirmationModal) -> $scope.overseerEnabled = DoubtfireConstants.IsOverseerEnabled $scope.calOptions = { @@ -83,6 +83,28 @@ angular.module('doubtfire.units.states.edit.directives.unit-details-editor', []) $scope.d2lEnabled = -> DoubtfireConstants.IsD2LEnabled.value + updatingAssessInPortfolio = false + $scope.$watch 'unit.markLateSubmissionsAsAssessInPortfolio', (newVal, oldVal) -> + return if newVal is oldVal or newVal == false or updatingAssessInPortfolio + updatingAssessInPortfolio = true + $scope.unit.markLateSubmissionsAsAssessInPortfolio = false + modal = ConfirmationModal.show( + 'Enable Assess in Portfolio?', + """ + Are you sure you want to enable "Assess in Portfolio" for late submissions? + This will update any existing Time/Feedback Exceeded tasks to the "Assess in Portfolio" state. + You will not be able to disable this setting while any tasks remain in the "Assess in Portfolio" state. + """ + () -> + $scope.unit.markLateSubmissionsAsAssessInPortfolio = true + $timeout -> + updatingAssessInPortfolio = false + ) + + modal.afterClosed().subscribe(() -> + $timeout -> + updatingAssessInPortfolio = false + ) ) From 29fffd36c437218491ef0bdffc4eb4969f5d4357 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 24 Sep 2025 14:38:38 +1000 Subject: [PATCH 0653/1280] chore: reword automated assess in portfolio message --- src/app/common/footer/footer.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/common/footer/footer.component.ts b/src/app/common/footer/footer.component.ts index 6d712f071c..a53bc9700e 100644 --- a/src/app/common/footer/footer.component.ts +++ b/src/app/common/footer/footer.component.ts @@ -78,7 +78,7 @@ export class FooterComponent implements OnInit { return; } task.addComment( - `**Automated Message:** Task "${task.definition.abbreviation} ${task.definition.name}" will be graded during portfolio assessment only. You must now submit it directly for portfolio assessment before the portfolio deadline.`, + `**Automated Message:** Task "${task.definition.abbreviation} ${task.definition.name}" will be graded during portfolio assessment only. You can keep submitting it for feedback before the task deadline, but you must still submit it directly for portfolio assessment before the portfolio deadline.`, ); setTimeout(() => { task.updateTaskStatus('working_on_it'); From e59e56f290d457ebb5c5c577128aeb9001942269 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 24 Sep 2025 14:49:33 +1000 Subject: [PATCH 0654/1280] chore: remove sentence regarding impact of late submission --- .../directives/task-due-card/task-due-card.component.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html index 83bc582179..3f3d5c6c6b 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html @@ -133,8 +133,7 @@ You should have completed this task by {{ task?.localDueDateString() }}. This task is now past the deadline and can only be submitted directly for your - portfolio without feedback. You should consult with the unit assessment details to - determine the impact of failing to complete this task within the allocated time. + portfolio without feedback. } @else { You should have completed this task by {{ task?.localDueDateString() }} Date: Wed, 24 Sep 2025 14:52:52 +1000 Subject: [PATCH 0655/1280] chore(release): 10.0.0-46 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 755a8eecd9..a02838d827 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-46](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-45...v10.0.0-46) (2025-09-24) + ## [10.0.0-45](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-44...v10.0.0-45) (2025-09-22) diff --git a/package-lock.json b/package-lock.json index a8b02747b3..199a950d63 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-45", + "version": "10.0.0-46", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-45", + "version": "10.0.0-46", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 1f9c61185e..12ccc6d73b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-45", + "version": "10.0.0-46", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From e122a6464b89ee8a5f2a17b2ff4c8e0bd5947fe7 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 24 Sep 2025 17:08:12 +1000 Subject: [PATCH 0656/1280] chore: require confirmation for assess in portfolio only option --- .../task-definition-options.component.html | 6 ++++- .../task-definition-options.component.ts | 27 ++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html index b846a681a5..6ef203ae27 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html @@ -10,7 +10,11 @@
- Assess in Portfolio Only diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts index 7fc62fa813..80a26895c1 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts @@ -1,6 +1,7 @@ -import { Component, Input } from '@angular/core'; -import { TaskDefinition } from 'src/app/api/models/task-definition'; -import { Unit } from 'src/app/api/models/unit'; +import {Component, Input} from '@angular/core'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; @Component({ selector: 'f-task-definition-options', @@ -9,8 +10,28 @@ import { Unit } from 'src/app/api/models/unit'; }) export class TaskDefinitionOptionsComponent { @Input() taskDefinition: TaskDefinition; + constructor(private confirmationModal: ConfirmationModalService) {} public get unit(): Unit { return this.taskDefinition?.unit; } + + public onToggleAssessInPortfolioOnly() { + if (!this.taskDefinition.assessInPortfolioOnly) { + return; + } + + setTimeout(() => { + this.taskDefinition.assessInPortfolioOnly = false; + console.log(this.taskDefinition.assessInPortfolioOnly); + + this.confirmationModal.show( + `Enable Assess in Portfolio Only?`, + `Enabling Assess in Portfolio Only will update all overdue tasks for ${this.taskDefinition.name} to the Assess in Portfolio state`, + () => { + this.taskDefinition.assessInPortfolioOnly = true; + }, + ); + }); + } } From db1ad9b8b6bde544d1e1dfc9cbe3fe3b5c79fff5 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Thu, 25 Sep 2025 12:42:34 +1000 Subject: [PATCH 0657/1280] refactor: migrate unit details editor (#1007) * refactor: init unit details editor migration * refactor: migrate unit details editor * refactor: migrate assess in portfolio confirmation * refactor: display teaching period dates when selected * refactor: add draft learning summary hint * chore: remove old unit details editor files * chore: remove debug logs --- src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire-angularjs.module.ts | 7 +- .../states/edit/directives/directives.coffee | 1 - .../unit-details-editor.coffee | 112 ---- .../unit-details-editor.component.html | 212 ++++++++ .../unit-details-editor.component.scss | 0 .../unit-details-editor.component.ts | 109 ++++ .../unit-details-editor.tpl.html | 501 ------------------ src/app/units/states/edit/edit.tpl.html | 2 +- 9 files changed, 330 insertions(+), 616 deletions(-) delete mode 100644 src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee create mode 100644 src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html create mode 100644 src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.scss create mode 100644 src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts delete mode 100644 src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 0e370154ff..cfea5a77ad 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -288,6 +288,7 @@ import {TaskPrerequisiteService} from './api/services/task-prerequisite.service' // import { PrivacyPolicy } from './config/privacy-policy/privacy-policy'; import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staff-editor/unit-staff-editor.component'; import {GroupSetSelectorComponent} from './groups/group-set-selector/group-set-selector.component'; +import {UnitDetailsEditorComponent} from './units/states/edit/directives/unit-details-editor/unit-details-editor.component'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { @@ -438,6 +439,7 @@ const MY_DATE_FORMAT = { TaskPrerequisitesCardComponent, UnitStaffEditorComponent, GroupSetSelectorComponent, + UnitDetailsEditorComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 223544d7bf..abf5a9ff2f 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -100,7 +100,6 @@ import 'build/src/app/units/states/portfolios/portfolios.js'; import 'build/src/app/units/states/groups/groups.js'; import 'build/src/app/units/states/states.js'; import 'build/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.js'; -import 'build/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.js'; import 'build/src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.js'; import 'build/src/app/units/states/edit/directives/directives.js'; import 'build/src/app/units/states/edit/edit.js'; @@ -230,6 +229,7 @@ import {TaskPrerequisitesCardComponent} from './projects/states/dashboard/direct // import { PrivacyPolicy } from './config/privacy-policy/privacy-policy'; import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staff-editor/unit-staff-editor.component'; import {GroupSetSelectorComponent} from './groups/group-set-selector/group-set-selector.component'; +import {UnitDetailsEditorComponent} from './units/states/edit/directives/unit-details-editor/unit-details-editor.component'; export const DoubtfireAngularJSModule = angular .module('doubtfire', [ @@ -520,6 +520,11 @@ DoubtfireAngularJSModule.directive( downgradeComponent({component: TaskPrerequisitesCardComponent}), ); +DoubtfireAngularJSModule.directive( + 'unitDetailsEditor', + downgradeComponent({component: UnitDetailsEditorComponent}), +); + // Global configuration // If the user enters a URL that doesn't match any known URL (state), send them to `/home` diff --git a/src/app/units/states/edit/directives/directives.coffee b/src/app/units/states/edit/directives/directives.coffee index fe06bf4510..4da41cacfb 100644 --- a/src/app/units/states/edit/directives/directives.coffee +++ b/src/app/units/states/edit/directives/directives.coffee @@ -1,5 +1,4 @@ angular.module('doubtfire.units.states.edit.directives', [ - 'doubtfire.units.states.edit.directives.unit-details-editor' 'doubtfire.units.states.edit.directives.unit-group-set-editor' 'doubtfire.units.states.edit.directives.unit-ilo-editor' ]) diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee deleted file mode 100644 index 8049804f32..0000000000 --- a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee +++ /dev/null @@ -1,112 +0,0 @@ -angular.module('doubtfire.units.states.edit.directives.unit-details-editor', []) - -# -# Editor for the basic details of a unit, such as the name, code -# start and end dates etc. -# -.directive('unitDetailsEditor', -> - replace: true - restrict: 'E' - templateUrl: 'units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html' - controller: ($scope, $timeout, $state, $rootScope, DoubtfireConstants, newUnitService, alertService, newTeachingPeriodService, TaskSubmission, D2lUnitDetailsModal, ConfirmationModal) -> - $scope.overseerEnabled = DoubtfireConstants.IsOverseerEnabled - - $scope.calOptions = { - startOpened: false - endOpened: false - portfolioAutoGenerationOpened: false - } - - # Get docker images available for automated task assessment for the unit. - TaskSubmission.getDockerImagesAsPromise().then (images) -> - $scope.dockerImages = images - - # Get the confugurable, external name of Doubtfire - $scope.externalName = DoubtfireConstants.ExternalName - - # get the teaching periods- gets an object with the loaded teaching periods - newTeachingPeriodService.query().subscribe((periods) -> - $scope.teachingPeriods = periods - $scope.teachingPeriodValues = [{value: undefined, text: "None"}] - other = _.map periods, (p) -> {value: p, text: "#{p.year} #{p.period}"} - _.each other, (d) -> $scope.teachingPeriodValues.push(d) - ) - - $scope.teachingPeriodSelected = ($event) -> - $scope.unit.teachingPeriod = $event - - $scope.unit.taskDefinitionCache.values.subscribe( - (taskDefs) -> - $scope.taskDefinitionValues = [{value: undefined, text: "None"}] - other = _.map taskDefs, (td) -> {value: td, text: "#{td.abbreviation}-#{td.name}"} - _.each other, (d) -> $scope.taskDefinitionValues.push(d) - ) - - $scope.draftTaskDefSelected = ($event) -> - $scope.unit.draftTaskDefinition = $event - - # Datepicker opener - $scope.open = ($event, pickerData) -> - $event.preventDefault() - $event.stopPropagation() - - if pickerData == 'start' - $scope.calOptions.startOpened = ! $scope.calOptions.startOpened - $scope.calOptions.endOpened = false - $scope.calOptions.portfolioAutoGenerationOpened = false - else if pickerData == 'end' - $scope.calOptions.startOpened = false - $scope.calOptions.endOpened = ! $scope.calOptions.endOpened - $scope.calOptions.portfolioAutoGenerationOpened = false - else if pickerData == 'autogen' - $scope.calOptions.startOpened = false - $scope.calOptions.endOpened = false - $scope.calOptions.portfolioAutoGenerationOpened = ! $scope.calOptions.portfolioAutoGenerationOpened - - $scope.dateOptions = { - formatYear: 'yy', - startingDay: 1 - } - $scope.studentSearch = "" - - $scope.saveUnit = -> - newUnitService.update($scope.unit).subscribe({ - next: (unit) -> - alertService.success( "Unit updated.", 2000) - error: (response) -> - alertService.error( "Failed to update unit. #{response}", 6000) - }) - - $scope.addD2lData = -> - D2lUnitDetailsModal.open($scope.unit) - - $scope.d2lEnabled = -> - DoubtfireConstants.IsD2LEnabled.value - - updatingAssessInPortfolio = false - $scope.$watch 'unit.markLateSubmissionsAsAssessInPortfolio', (newVal, oldVal) -> - return if newVal is oldVal or newVal == false or updatingAssessInPortfolio - updatingAssessInPortfolio = true - $scope.unit.markLateSubmissionsAsAssessInPortfolio = false - modal = ConfirmationModal.show( - 'Enable Assess in Portfolio?', - """ - Are you sure you want to enable "Assess in Portfolio" for late submissions? - This will update any existing Time/Feedback Exceeded tasks to the "Assess in Portfolio" state. - You will not be able to disable this setting while any tasks remain in the "Assess in Portfolio" state. - """ - () -> - $scope.unit.markLateSubmissionsAsAssessInPortfolio = true - $timeout -> - updatingAssessInPortfolio = false - ) - - modal.afterClosed().subscribe(() -> - $timeout -> - updatingAssessInPortfolio = false - ) -) - - - - diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html new file mode 100644 index 0000000000..7ee30534e9 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html @@ -0,0 +1,212 @@ +
+
+

Unit Details

+

Edit and configure all details and settings for this unit.

+
+ + + Code + + + + + Name + + + + + Description + + + + + + + Teaching Period + + None + @for (period of teachingPeriods; track period) { + {{ period.name }} + } + + + +
+ @if (!unit.teachingPeriod) { + + Start Date + + + + + + End Date + + + + + } @else { + + {{ unit.teachingPeriod.name }} Start Date + + + + {{ unit.teachingPeriod.name }} End Date + + + } +
+ + + Portfolio Auto-Generation Date + + + + + + + Draft Learning Summary + + None + @for (td of taskDefinitions; track td) { + {{ td.abbreviation }} - {{ td.name }} + } + + + When a draft learning summary task is selected, this will ensure a students uploaded draft + is automatically added to the students portfolio. + + + + + Extension duration onresubmit + + + When tutors request resubmission of a task, this setting determines how many weeks the task + will be extended to allow students to fix and resubmit their work. + + +
+ + +
+ Allow flexible dates +

Allows students to set planned due dates, without using extensions.

+
+ +
+ Allow student extensions +

When false only staff can request extensions on behalf of students.

+
+ +
+ Auto apply extensions +

+ When true, extensions will be automatically applied when they result in a date that is + between the task's due date and deadline. +

+
+ +
+ Has tasks assessed in portfolio +

+ When enabled, late submissions will not be automatically marked as "Time Exceeded" or + "Feedback Exceeded", and will instead appear as "Assess in Portfolio". Tutors can still sign + off tasks as complete unless the task definition has the "Assess in Portfolio Only" option + enabled. +

+
+ +
+ Allow students to change tutorial +

When false only staff can change student tutorials.

+
+ +
+ Send notification emails +

+ When true, emails will be set to students each week to indicate progress and suggest future + tasks for them to work on. +

+
+ +
+ Synchronise enrolments +

+ When true student enrolments will be synchronised with other systems where this is possible. +

+
+ +
+ Synchronise timetable +

+ When true timetable data will be synchronised with other systems where this is possible. +

+
+ +
+ Active +

Set to false to hide unit from students and tutors.

+
+
+ + @if (overseerEnabled.value) { + +
+ Overseer assessment +

If true, unit tasks will be able to make use of Overseer automated checking.

+
+ + + Overseer Docker Image + + @for (image of dockerImages; track image) { + {{ image.description }} + } + + Use this to select the default container used to check tasks with Overseer. + +
+ } + +
+ + + +
+
diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.scss b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts new file mode 100644 index 0000000000..0ea300bf8e --- /dev/null +++ b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts @@ -0,0 +1,109 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {MatSlideToggleChange} from '@angular/material/slide-toggle'; +import {OverseerImage, UnitService} from 'src/app/api/models/doubtfire-model'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {TeachingPeriod} from 'src/app/api/models/teaching-period'; +import {Unit} from 'src/app/api/models/unit'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {TeachingPeriodService} from 'src/app/api/services/teaching-period.service'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {TaskSubmissionService} from 'src/app/common/services/task-submission.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {D2lUnitDetailsModal} from './d2l-details-form/d2l-unit-details-form.component'; + +@Component({ + selector: 'f-unit-details-editor', + templateUrl: 'unit-details-editor.component.html', + styleUrls: ['unit-details-editor.component.scss'], +}) +export class UnitDetailsEditorComponent implements OnInit { + @Input() unit: Unit; + + constructor( + private teachingPeriodService: TeachingPeriodService, + private taskDefinitionService: TaskDefinitionService, + private doubtfireConstants: DoubtfireConstants, + private taskSubmissionService: TaskSubmissionService, + private d2lUnitDetailsModal: D2lUnitDetailsModal, + private unitService: UnitService, + private alertsService: AlertService, + private confirmationModal: ConfirmationModalService, + ) {} + + public teachingPeriods: TeachingPeriod[]; + public taskDefinitions: TaskDefinition[]; + public dockerImages: OverseerImage[]; + + public get overseerEnabled() { + return this.doubtfireConstants.IsOverseerEnabled; + } + + public get d2lEnabled() { + return this.doubtfireConstants.IsD2LEnabled; + } + + ngOnInit(): void { + this.teachingPeriodService.query().subscribe((periods) => { + this.teachingPeriods = periods; + }); + + this.unit.taskDefinitionCache.values.subscribe((taskDefs) => { + this.taskDefinitions = taskDefs; + }); + + this.taskSubmissionService.getDockerImagesAsPromise().then((images) => { + this.dockerImages = images; + }); + } + + addD2lData() { + this.d2lUnitDetailsModal.open(this.unit); + } + + saveUnit() { + this.unitService.update(this.unit).subscribe({ + next: (_unit) => { + this.alertsService.success('Unit updated.', 2000); + }, + error: (response) => { + this.alertsService.error(`Failed to update unit. ${response}`, 6000); + }, + }); + } + + private updatingAssessInPortfolio: boolean = false; + + onToggleAssessInPortfolio(event: MatSlideToggleChange) { + if (!event.checked || this.updatingAssessInPortfolio) { + return false; + } + + if (this.updatingAssessInPortfolio) { + return; + } + + this.updatingAssessInPortfolio = true; + + setTimeout(() => { + this.unit.markLateSubmissionsAsAssessInPortfolio = false; + const modal = this.confirmationModal.show( + 'Enable Assess in Portfolio?', + `Are you sure you want to enable "Assess in Portfolio" for late submissions? + This will update any existing Time/Feedback Exceeded tasks to the "Assess in Portfolio" state. + You will not be able to disable this setting while any tasks remain in the "Assess in Portfolio" state.`, + () => { + this.unit.markLateSubmissionsAsAssessInPortfolio = true; + setTimeout(() => { + this.updatingAssessInPortfolio = false; + }); + }, + ); + modal.afterClosed().subscribe(() => { + setTimeout(() => { + this.updatingAssessInPortfolio = false; + }); + }); + }); + } +} diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html deleted file mode 100644 index 5de919ee03..0000000000 --- a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html +++ /dev/null @@ -1,501 +0,0 @@ -
-
-
-

Create Unit

- Create a new unit with all overview unit details here. -
-
-

Update Unit

- Update overview details of the unit below. -
-
-
-
- -
- -
-
- - -
- -
- -
-
- - -
- -
- -
-
- - -
- -
- -
-
- - -
- -
- - - - When a draft learning summary task is selected, this will ensure a students uploaded draft is - automatically added to the students portfolio. - -
-
- - -
- -
-
- - - - - -
-
-
- - -
- -
-
- - - - - -
-
-
- - -
- -
-
- - - - -
-
-
- - -
- -
-
- - -
- Allows students to set planned due dates, without using extensions. -
-
- - -
- -
-
- - -
- When false only staff can request extensions on behalf of students. -
-
- - -
- -
- - - When tutors request resubmission of a task, this setting determines how many weeks the task will be - extended to allow students to fix and resubmit their work. - -
-
- - -
- -
-
- - -
- - When true, extensions will be automatically applied when they result in a date that is between the task's - due date and deadline. - -
-
- - -
- -
-
- - -
- - When enabled, late submissions will not be automatically marked as "Time Exceeded" or - "Feedback Exceeded", and will instead appear as "Assess in Portfolio". Tutors can - still sign off tasks as complete unless the task definition has the "Assess in - Portfolio Only" option enabled. - -
-
- - -
- -
-
- - -
- When false only staff can change student tutorials. -
-
- - -
- -
-
- - -
- - When true, emails will be set to students each week to indicate progress and suggest future tasks for them - to work on. - -
-
- - -
- -
-
- - -
- - When true student enrolments will be synchronised with other systems where this is possible. - -
-
- - -
- -
-
- - -
- - When true timetable data will be synchronised with other systems where this is possible. - -
-
- - -
- -
-
- - -
- - If true, unit tasks will be able to make use of Overseer automated checking. - -
-
- -
- -
- -
-
- -
-
diff --git a/src/app/units/states/edit/edit.tpl.html b/src/app/units/states/edit/edit.tpl.html index 4df8bf3d09..8a0dc37d52 100644 --- a/src/app/units/states/edit/edit.tpl.html +++ b/src/app/units/states/edit/edit.tpl.html @@ -4,7 +4,7 @@ {{tab.title}} - + From 04d3178e2e37a64c14109deaacb188056e07f225 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 25 Sep 2025 15:13:29 +1000 Subject: [PATCH 0658/1280] chore(release): 10.0.0-47 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a02838d827..ae329af052 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-47](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-46...v10.0.0-47) (2025-09-25) + + +### Features + +* add observer only ui ([bfbcee9](https://github.com/b0ink/doubtfire-deploy/commit/bfbcee98cfa4888241c5956372d004ec1cd813cb)) + ## [10.0.0-46](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-45...v10.0.0-46) (2025-09-24) ## [10.0.0-45](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-44...v10.0.0-45) (2025-09-22) diff --git a/package-lock.json b/package-lock.json index 199a950d63..4b1491ce8c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-46", + "version": "10.0.0-47", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-46", + "version": "10.0.0-47", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 12ccc6d73b..056ce41ad1 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-46", + "version": "10.0.0-47", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 10e8ab033469c2dd4e78d125cb8fcfe0127cbf88 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Fri, 3 Oct 2025 14:55:31 +1000 Subject: [PATCH 0659/1280] refactor: migrate portfolio grade select step (#1014) * Frontend migration of portfolio-grade-select-step to Angular 17 component * Addressed review comments in portfolio-grade-select-step component * Implement OnInit in PortfolioGradeSelectStepComponent * replaced bootsrap UI component with Angular material * chore: bring back deleted lines * refactor: replace css with tailwind * chore: revert import order * chore: revert import order * chore: revert import order * chore: revert order * refactor: simplify grade changing --------- Co-authored-by: Pasindu Fernando <116358471+Pasindufdo98@users.noreply.github.com> --- src/app/doubtfire-angular.module.ts | 7 +- src/app/doubtfire-angularjs.module.ts | 7 +- .../portfolio/directives/directives.coffee | 1 - .../portfolio-grade-select-step.coffee | 19 ---- ...portfolio-grade-select-step.component.html | 96 +++++++++++++++++++ ...portfolio-grade-select-step.component.scss | 0 .../portfolio-grade-select-step.component.ts | 57 +++++++++++ .../portfolio-grade-select-step.scss | 10 -- .../portfolio-grade-select-step.tpl.html | 60 ------------ .../states/portfolio/portfolio.tpl.html | 6 +- 10 files changed, 168 insertions(+), 95 deletions(-) delete mode 100644 src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee create mode 100644 src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html create mode 100644 src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.scss create mode 100644 src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts delete mode 100644 src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.scss delete mode 100644 src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index cfea5a77ad..369039dfbc 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -283,12 +283,12 @@ import {LtiService} from './api/services/lti.service'; import {TaskDefinitionPrerequisitesComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component'; import {TaskPrerequisitesCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component'; import {TaskPrerequisiteService} from './api/services/task-prerequisite.service'; -// import { GradeIconComponent } from './common/grade-icon/grade-icon.component'; -// import { GradeTaskModalComponent } from './tasks/modals/grade-task-modal/grade-task-modal.component'; -// import { PrivacyPolicy } from './config/privacy-policy/privacy-policy'; +// import {GradeTaskModalComponent} from './tasks/modals/grade-task-modal/grade-task-modal.component'; +// import {PrivacyPolicy} from './config/privacy-policy/privacy-policy'; import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staff-editor/unit-staff-editor.component'; import {GroupSetSelectorComponent} from './groups/group-set-selector/group-set-selector.component'; import {UnitDetailsEditorComponent} from './units/states/edit/directives/unit-details-editor/unit-details-editor.component'; +import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { @@ -440,6 +440,7 @@ const MY_DATE_FORMAT = { UnitStaffEditorComponent, GroupSetSelectorComponent, UnitDetailsEditorComponent, + PortfolioGradeSelectStepComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index abf5a9ff2f..963bf7d209 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -72,7 +72,6 @@ import 'build/src/app/projects/states/outcomes/outcomes.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.js'; -import 'build/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-tasks-step/portfolio-tasks-step.js'; import 'build/src/app/projects/states/portfolio/directives/directives.js'; @@ -230,6 +229,7 @@ import {TaskPrerequisitesCardComponent} from './projects/states/dashboard/direct import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staff-editor/unit-staff-editor.component'; import {GroupSetSelectorComponent} from './groups/group-set-selector/group-set-selector.component'; import {UnitDetailsEditorComponent} from './units/states/edit/directives/unit-details-editor/unit-details-editor.component'; +import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component'; export const DoubtfireAngularJSModule = angular .module('doubtfire', [ @@ -525,6 +525,11 @@ DoubtfireAngularJSModule.directive( downgradeComponent({component: UnitDetailsEditorComponent}), ); +DoubtfireAngularJSModule.directive( + 'fPortfolioGradeSelectStep', + downgradeComponent({component: PortfolioGradeSelectStepComponent}), +); + // Global configuration // If the user enters a URL that doesn't match any known URL (state), send them to `/home` diff --git a/src/app/projects/states/portfolio/directives/directives.coffee b/src/app/projects/states/portfolio/directives/directives.coffee index 8ce9be0be3..661acd16e7 100644 --- a/src/app/projects/states/portfolio/directives/directives.coffee +++ b/src/app/projects/states/portfolio/directives/directives.coffee @@ -1,6 +1,5 @@ angular.module('doubtfire.projects.states.portfolio.directives', [ 'doubtfire.projects.states.portfolio.directives.portfolio-add-extra-files-step' - 'doubtfire.projects.states.portfolio.directives.portfolio-grade-select-step' 'doubtfire.projects.states.portfolio.directives.portfolio-learning-summary-report-step' 'doubtfire.projects.states.portfolio.directives.portfolio-review-step' 'doubtfire.projects.states.portfolio.directives.portfolio-tasks-step' diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee deleted file mode 100644 index d29d0f65da..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee +++ /dev/null @@ -1,19 +0,0 @@ -angular.module('doubtfire.projects.states.portfolio.directives.portfolio-grade-select-step', []) - -# -# Allows students to select the target grade they are hoping -# to achieve with their portfolio -# -.directive('portfolioGradeSelectStep', -> - restrict: 'E' - replace: true - templateUrl: 'projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html' - controller: ($scope, newProjectService, gradeService) -> - $scope.grades = gradeService.grades - $scope.agreedToAssessmentCriteria = $scope.projectHasLearningSummaryReport() - $scope.chooseGrade = (idx) -> - $scope.project.submittedGrade = idx - newProjectService.update($scope.project).subscribe((project) -> - $scope.project.refreshBurndownChartData() - ) -) diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html new file mode 100644 index 0000000000..63385d6e5d --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html @@ -0,0 +1,96 @@ +
+ + + + +

Select Grade

+
+
+ + +

+ In preparing your portfolio, you need to undertake a self-assessment. Use the unit's + assessment criteria to determine the grade your portfolio should be awarded. +

+ + + + + + warning + Read the assessment criteria + + + + +

+ Make sure that you have reviewed the Assessment Criteria for the grade you are applying + for. Each grade will have a list of criteria that you can use to determine if you meet + the requirements to achieve that grade. +

+
+ + + + I have read the Assessment Criteria for this unit + + +
+ + + + @if (agreedToAssessmentCriteria) { + + + + Grade Application + + + + +

+ Select the grade you are applying for {{ unit.code }} + {{ unit.name }} below. +

+
+ + + + @for (grade of gradeValues; track grade) { + + + + } + + +

+ Make sure your Learning Summary Report justifies how your portfolio + demonstrates you have + met all unit learning outcomes to a {{ targetGrade }} level +

+
+
+ } +
+ + + + + + +
+
diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.scss b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts new file mode 100644 index 0000000000..cce8ee1748 --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts @@ -0,0 +1,57 @@ +import {Component, Injector, Input} from '@angular/core'; +import {Project, Unit} from 'src/app/api/models/doubtfire-model'; +import {ProjectService} from 'src/app/api/services/project.service'; +import {GradeService} from 'src/app/common/services/grade.service'; + +@Component({ + selector: 'f-portfolio-grade-select-step', + templateUrl: 'portfolio-grade-select-step.component.html', + styleUrls: ['portfolio-grade-select-step.component.scss'], +}) +export class PortfolioGradeSelectStepComponent { + @Input() project: Project; + @Input() unit: Unit; + + public agreedToAssessmentCriteria: boolean = false; + + constructor( + private gradeService: GradeService, + private injector: Injector, + private projectService: ProjectService, + ) { + this.$scope = this.injector.get('$scope'); + } + + public get gradeValues() { + return this.gradeService.gradeValues; + } + + updateSubmittedGrade(newGrade: number): void { + const previousSubmittedGrade = this.project.submittedGrade; + this.project.submittedGrade = newGrade; + + this.projectService.update(this.project).subscribe( + (project) => { + project.refreshBurndownChartData?.(); + }, + (error) => { + this.project.submittedGrade = previousSubmittedGrade; + console.error('Error updating target grade:', error); + }, + ); + } + + // TODO: remove this once parent component has been migrated + private $scope: any; + goToNextStep(): void { + if (typeof this.$scope?.advanceActiveTab === 'function') { + this.$scope.advanceActiveTab(1); + } + } + + goToPreviousStep(): void { + if (typeof this.$scope?.advanceActiveTab === 'function') { + this.$scope.advanceActiveTab(-1); + } + } +} diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.scss b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.scss deleted file mode 100644 index bfc229c4b1..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.scss +++ /dev/null @@ -1,10 +0,0 @@ -.project-portfolio-wizard .portfolio-grade-select-step { - .confirm-read-assessment-criteria { - font-size: 1.2em; - } - .select-the-grade { - .btn { - padding: 1em; - } - } -} diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html deleted file mode 100644 index 5e512edf25..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html +++ /dev/null @@ -1,60 +0,0 @@ -
-
-

Select Grade

-
-
-

- In preparing your portfolio, you need to undertake a self assessment. Use the unit's assessment criteria to - determine the grade your portfolio should be awarded. -

-
-
-

Read the assessment criteria

- Make sure that you have reviewed the Assessment Criteria for the grade you are applying for. Each grade will - have a list of criteria that you can use to determine if you meet the requirements to achieve that grade. -
-
- - -
-
- -
-
-

Grade Application

- Select the grade you are applying for {{unit.name}} below. -
-
-
- -
-

- Make sure your Learning Summary Report justifies how your portfolio demonstrates you have - met all unit learning outcomes to a {{targetGrade}} level -

-
-
- -
- - -
diff --git a/src/app/projects/states/portfolio/portfolio.tpl.html b/src/app/projects/states/portfolio/portfolio.tpl.html index be61edec29..934f90e76f 100644 --- a/src/app/projects/states/portfolio/portfolio.tpl.html +++ b/src/app/projects/states/portfolio/portfolio.tpl.html @@ -7,7 +7,11 @@ - + + From 373cd1eef326a528e1dd4546777a939c0db24d22 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Fri, 3 Oct 2025 14:55:31 +1000 Subject: [PATCH 0660/1280] refactor: migrate portfolio grade select step (#1014) * Frontend migration of portfolio-grade-select-step to Angular 17 component * Addressed review comments in portfolio-grade-select-step component * Implement OnInit in PortfolioGradeSelectStepComponent * replaced bootsrap UI component with Angular material * chore: bring back deleted lines * refactor: replace css with tailwind * chore: revert import order * chore: revert import order * chore: revert import order * chore: revert order * refactor: simplify grade changing --------- Co-authored-by: Pasindu Fernando <116358471+Pasindufdo98@users.noreply.github.com> --- src/app/doubtfire-angular.module.ts | 14 ++- src/app/doubtfire-angularjs.module.ts | 31 ++++-- .../portfolio/directives/directives.coffee | 1 - .../portfolio-grade-select-step.coffee | 22 ----- ...portfolio-grade-select-step.component.html | 96 +++++++++++++++++++ ...portfolio-grade-select-step.component.scss | 0 .../portfolio-grade-select-step.component.ts | 57 +++++++++++ .../portfolio-grade-select-step.scss | 10 -- .../portfolio-grade-select-step.tpl.html | 60 ------------ .../states/portfolio/portfolio.tpl.html | 6 +- 10 files changed, 189 insertions(+), 108 deletions(-) delete mode 100644 src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee create mode 100644 src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html create mode 100644 src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.scss create mode 100644 src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts delete mode 100644 src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.scss delete mode 100644 src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 88c2206141..e65faa1d11 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -97,7 +97,7 @@ import {ExtensionCommentComponent} from './tasks/task-comments-viewer/extension- import {CampusListComponent} from './admin/institution-settings/campuses/campus-list/campus-list.component'; import {ExtensionModalComponent} from './common/modals/extension-modal/extension-modal.component'; import {CalendarModalComponent} from './common/modals/calendar-modal/calendar-modal.component'; -import { ConfirmationModalComponent } from './common/modals/confirmation-modal/confirmation-modal.component'; +import {ConfirmationModalComponent} from './common/modals/confirmation-modal/confirmation-modal.component'; import {MatRadioModule} from '@angular/material/radio'; import {MatButtonToggleModule} from '@angular/material/button-toggle'; import { @@ -256,11 +256,14 @@ import {TaskScormCardComponent} from './projects/states/dashboard/directives/tas import {TestAttemptService} from './api/services/test-attempt.service'; import {ScormExtensionCommentComponent} from './tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component'; import {ScormExtensionModalComponent} from './common/modals/scorm-extension-modal/scorm-extension-modal.component'; -import { GradeIconComponent } from './common/grade-icon/grade-icon.component'; -import { GradeTaskModalComponent } from './tasks/modals/grade-task-modal/grade-task-modal.component'; -import { PrivacyPolicy } from './config/privacy-policy/privacy-policy'; -import { UnitStaffEditorComponent } from './units/states/edit/directives/unit-staff-editor/unit-staff-editor.component'; +import {GradeIconComponent} from './common/grade-icon/grade-icon.component'; +import {GradeTaskModalComponent} from './tasks/modals/grade-task-modal/grade-task-modal.component'; +import {PrivacyPolicy} from './config/privacy-policy/privacy-policy'; +// import {GradeTaskModalComponent} from './tasks/modals/grade-task-modal/grade-task-modal.component'; +// import {PrivacyPolicy} from './config/privacy-policy/privacy-policy'; +import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staff-editor/unit-staff-editor.component'; import {GroupSetSelectorComponent} from './groups/group-set-selector/group-set-selector.component'; +import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { @@ -403,6 +406,7 @@ import {TaskStatusPieChartComponent} from './visualisations/task-status-pie-char ScormExtensionModalComponent, UnitStaffEditorComponent, GroupSetSelectorComponent, + PortfolioGradeSelectStepComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 76ae8c64c5..0a48a0b2b7 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -71,7 +71,6 @@ import 'build/src/app/projects/states/outcomes/outcomes.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.js'; -import 'build/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-tasks-step/portfolio-tasks-step.js'; import 'build/src/app/projects/states/portfolio/directives/directives.js'; @@ -139,7 +138,7 @@ import {ExtensionCommentComponent} from './tasks/task-comments-viewer/extension- import {TaskAssessmentCommentComponent} from './tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component'; import {ExtensionModalService} from './common/modals/extension-modal/extension-modal.service'; import {CalendarModalService} from './common/modals/calendar-modal/calendar-modal.service'; -import { ConfirmationModalService } from './common/modals/confirmation-modal/confirmation-modal.service'; +import {ConfirmationModalService} from './common/modals/confirmation-modal/confirmation-modal.service'; import {CampusListComponent} from './admin/institution-settings/campuses/campus-list/campus-list.component'; import {ActivityTypeListComponent} from './admin/institution-settings/activity-type-list/activity-type-list.component'; import {InstitutionSettingsComponent} from './admin/institution-settings/institution-settings.component'; @@ -212,16 +211,19 @@ import {FTaskSheetViewComponent} from './units/task-viewer/directives/task-sheet import {ProgressBurndownChartComponent} from './visualisations/progress-burndown-chart/progressburndownchart.component'; import {TaskVisualisationComponent} from './visualisations/task-visualisation/taskvisualisation.component'; import {ProgressDashboardComponent} from './projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component'; - import {FUnitsComponent} from './admin/states/units/units.component'; import {AlertService} from './common/services/alert.service'; - import {GradeService} from './common/services/grade.service'; import {TaskScormCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component'; -import { UnitStudentEnrolmentModalService } from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service'; -import { PrivacyPolicy } from './config/privacy-policy/privacy-policy'; -import { UnitStaffEditorComponent } from './units/states/edit/directives/unit-staff-editor/unit-staff-editor.component'; + +// import { UnitStudentEnrolmentModalService } from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service'; +// import { PrivacyPolicy } from './config/privacy-policy/privacy-policy'; +import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staff-editor/unit-staff-editor.component'; import {GroupSetSelectorComponent} from './groups/group-set-selector/group-set-selector.component'; +import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component'; + +import {UnitStudentEnrolmentModalService} from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service'; +import {PrivacyPolicy} from './config/privacy-policy/privacy-policy'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -241,7 +243,10 @@ DoubtfireAngularJSModule.factory('AboutDoubtfireModal', downgradeInjectable(Abou DoubtfireAngularJSModule.factory('DoubtfireConstants', downgradeInjectable(DoubtfireConstants)); DoubtfireAngularJSModule.factory('ExtensionModal', downgradeInjectable(ExtensionModalService)); DoubtfireAngularJSModule.factory('CalendarModal', downgradeInjectable(CalendarModalService)); -DoubtfireAngularJSModule.factory('ConfirmationModal', downgradeInjectable(ConfirmationModalService)); +DoubtfireAngularJSModule.factory( + 'ConfirmationModal', + downgradeInjectable(ConfirmationModalService), +); DoubtfireAngularJSModule.factory('TaskCommentService', downgradeInjectable(TaskCommentService)); DoubtfireAngularJSModule.factory('alertService', downgradeInjectable(AlertService)); DoubtfireAngularJSModule.factory('tutorialService', downgradeInjectable(TutorialService)); @@ -481,12 +486,20 @@ DoubtfireAngularJSModule.directive( ); DoubtfireAngularJSModule.directive('newFUnits', downgradeComponent({component: FUnitsComponent})); -DoubtfireAngularJSModule.directive('unitStaffEditor', downgradeComponent({ component: UnitStaffEditorComponent })); +DoubtfireAngularJSModule.directive( + 'unitStaffEditor', + downgradeComponent({component: UnitStaffEditorComponent}), +); DoubtfireAngularJSModule.directive( 'unauthorised', downgradeComponent({component: UnauthorisedComponent}), ); +DoubtfireAngularJSModule.directive( + 'fPortfolioGradeSelectStep', + downgradeComponent({component: PortfolioGradeSelectStepComponent}), +); + // Global configuration // If the user enters a URL that doesn't match any known URL (state), send them to `/home` diff --git a/src/app/projects/states/portfolio/directives/directives.coffee b/src/app/projects/states/portfolio/directives/directives.coffee index 8ce9be0be3..661acd16e7 100644 --- a/src/app/projects/states/portfolio/directives/directives.coffee +++ b/src/app/projects/states/portfolio/directives/directives.coffee @@ -1,6 +1,5 @@ angular.module('doubtfire.projects.states.portfolio.directives', [ 'doubtfire.projects.states.portfolio.directives.portfolio-add-extra-files-step' - 'doubtfire.projects.states.portfolio.directives.portfolio-grade-select-step' 'doubtfire.projects.states.portfolio.directives.portfolio-learning-summary-report-step' 'doubtfire.projects.states.portfolio.directives.portfolio-review-step' 'doubtfire.projects.states.portfolio.directives.portfolio-tasks-step' diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee deleted file mode 100644 index 3a7ee7f2a4..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee +++ /dev/null @@ -1,22 +0,0 @@ -angular.module('doubtfire.projects.states.portfolio.directives.portfolio-grade-select-step', []) - -# -# Allows students to select the target grade they are hoping -# to achieve with their portfolio -# -.directive('portfolioGradeSelectStep', -> - restrict: 'E' - replace: true - templateUrl: 'projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html' - controller: ($scope, newProjectService, gradeService) -> - if ! $scope.project.submittedGrade - $scope.project.submittedGrade = 0 - $scope.grades = gradeService.gradeValues - $scope.gradeName = (grade) -> gradeService.grades[grade] - $scope.agreedToAssessmentCriteria = $scope.projectHasLearningSummaryReport() - $scope.chooseGrade = (idx) -> - $scope.project.submittedGrade = idx - newProjectService.update($scope.project).subscribe((project) -> - $scope.project.refreshBurndownChartData() - ) -) diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html new file mode 100644 index 0000000000..ad2c4c4f0c --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html @@ -0,0 +1,96 @@ +
+ + + + +

Select Grade

+
+
+ + +

+ In preparing your portfolio, you need to undertake a self-assessment. Use the unit's + assessment criteria to determine the grade your portfolio should be awarded. +

+ + + + + + warning + Read the assessment criteria + + + + +

+ Make sure that you have reviewed the Assessment Criteria for the grade you are applying + for. Each grade will have a list of criteria that you can use to determine if you meet + the requirements to achieve that grade. +

+
+ + + + I have read the Assessment Criteria for this unit + + +
+ + + + @if (agreedToAssessmentCriteria) { + + + + Grade Application + + + + +

+ Select the grade you are applying for {{ unit.code }} + {{ unit.name }} below. +

+
+ + + + @for (grade of gradeValues; track grade) { + + + + } + + +

+ Make sure your Learning Summary Report justifies how your portfolio + demonstrates you have + met all unit learning outcomes to a {{ targetGrade }} level +

+
+
+ } +
+ + + + + + +
+
diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.scss b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts new file mode 100644 index 0000000000..cce8ee1748 --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts @@ -0,0 +1,57 @@ +import {Component, Injector, Input} from '@angular/core'; +import {Project, Unit} from 'src/app/api/models/doubtfire-model'; +import {ProjectService} from 'src/app/api/services/project.service'; +import {GradeService} from 'src/app/common/services/grade.service'; + +@Component({ + selector: 'f-portfolio-grade-select-step', + templateUrl: 'portfolio-grade-select-step.component.html', + styleUrls: ['portfolio-grade-select-step.component.scss'], +}) +export class PortfolioGradeSelectStepComponent { + @Input() project: Project; + @Input() unit: Unit; + + public agreedToAssessmentCriteria: boolean = false; + + constructor( + private gradeService: GradeService, + private injector: Injector, + private projectService: ProjectService, + ) { + this.$scope = this.injector.get('$scope'); + } + + public get gradeValues() { + return this.gradeService.gradeValues; + } + + updateSubmittedGrade(newGrade: number): void { + const previousSubmittedGrade = this.project.submittedGrade; + this.project.submittedGrade = newGrade; + + this.projectService.update(this.project).subscribe( + (project) => { + project.refreshBurndownChartData?.(); + }, + (error) => { + this.project.submittedGrade = previousSubmittedGrade; + console.error('Error updating target grade:', error); + }, + ); + } + + // TODO: remove this once parent component has been migrated + private $scope: any; + goToNextStep(): void { + if (typeof this.$scope?.advanceActiveTab === 'function') { + this.$scope.advanceActiveTab(1); + } + } + + goToPreviousStep(): void { + if (typeof this.$scope?.advanceActiveTab === 'function') { + this.$scope.advanceActiveTab(-1); + } + } +} diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.scss b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.scss deleted file mode 100644 index bfc229c4b1..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.scss +++ /dev/null @@ -1,10 +0,0 @@ -.project-portfolio-wizard .portfolio-grade-select-step { - .confirm-read-assessment-criteria { - font-size: 1.2em; - } - .select-the-grade { - .btn { - padding: 1em; - } - } -} diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html deleted file mode 100644 index 097b685e35..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.tpl.html +++ /dev/null @@ -1,60 +0,0 @@ -
-
-

Select Grade

-
-
-

- In preparing your portfolio, you need to undertake a self assessment. Use the unit's assessment criteria to - determine the grade your portfolio should be awarded. -

-
-
-

Read the assessment criteria

- Make sure that you have reviewed the Assessment Criteria for the grade you are applying for. Each grade will - have a list of criteria that you can use to determine if you meet the requirements to achieve that grade. -
-
- - -
-
- -
-
-

Grade Application

- Select the grade you are applying for {{unit.name}} below. -
-
-
- -
-

- Make sure your Learning Summary Report justifies how your portfolio demonstrates you have - met all unit learning outcomes to a {{gradeName(project.submittedGrade)}} level -

-
-
- -
- - -
diff --git a/src/app/projects/states/portfolio/portfolio.tpl.html b/src/app/projects/states/portfolio/portfolio.tpl.html index 1c009b47ab..ae536e081f 100644 --- a/src/app/projects/states/portfolio/portfolio.tpl.html +++ b/src/app/projects/states/portfolio/portfolio.tpl.html @@ -7,7 +7,11 @@ - + + From 8d36c94f03563a0924cfeb7d2d9e8dd911b65960 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:22:49 +1100 Subject: [PATCH 0661/1280] fix: add assess in portfolio tasks as completed tasks in burndown chart --- src/app/api/models/project.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/models/project.ts b/src/app/api/models/project.ts index 167aeb1ec5..1064fb3c5b 100644 --- a/src/app/api/models/project.ts +++ b/src/app/api/models/project.ts @@ -413,7 +413,7 @@ export class Project extends Entity { const tasks = this.tasks; const readyOrCompleteTasks = tasks.filter((task) => - ['ready_for_feedback', 'discuss', 'demonstrate', 'complete'].includes(task.status), + ['ready_for_feedback', 'discuss', 'demonstrate', 'complete', 'assess_in_portfolio'].includes(task.status), ); let lastTargetDate: Date; From 95402a6f6678d9bad066386b60f0ce5a3b3766aa Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 8 Oct 2025 09:31:06 +1100 Subject: [PATCH 0662/1280] refactor: migrate/tutorials (#934) (#1013) * refactor: migrate/tutorials (#934) * chore: migrate tutorials - unlink old component - link new component - delete old files - add UI-router state declaration - remove reference to old state * chore: migrate tutorials - delete old files * chore: migrate tutorials - declare and define `tutorials` Typescript class - define `tutorials` markup in Angular and Angular material - add stylesheet * chore: migrate tutorials - delete old template * chore: amend file name - change template file name to adhere to styling convention - add `todo` comment to Typescript file --------- Co-authored-by: Boink <40929320+b0ink@users.noreply.github.com> * fix: map unit staff - 9.x api currently exposes :staff instead of :unit_roles * fix: accurately check for tutorial enrolment * fix: ensure tutorial for current enrolment is displayed * refactor: use mat table * refactor: improve tutorials component and add sorting - fetch unit to ensure tutorials are loaded correctly - add table sorting * chore: format * chore: remove styling * chore: remove unused class * chore: reword description --------- Co-authored-by: Jason Vellucci --- src/app/api/models/project.ts | 2 +- src/app/api/services/unit.service.ts | 3 +- src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire-angularjs.module.ts | 11 +- src/app/doubtfire.states.ts | 20 +++ src/app/projects/states/states.coffee | 1 - .../states/tutorials/tutorials.coffee | 23 --- .../states/tutorials/tutorials.component.html | 104 ++++++++++++ .../states/tutorials/tutorials.component.scss | 0 .../states/tutorials/tutorials.component.ts | 149 ++++++++++++++++++ .../projects/states/tutorials/tutorials.scss | 10 -- .../states/tutorials/tutorials.tpl.html | 71 --------- 12 files changed, 285 insertions(+), 111 deletions(-) delete mode 100644 src/app/projects/states/tutorials/tutorials.coffee create mode 100644 src/app/projects/states/tutorials/tutorials.component.html create mode 100644 src/app/projects/states/tutorials/tutorials.component.scss create mode 100644 src/app/projects/states/tutorials/tutorials.component.ts delete mode 100644 src/app/projects/states/tutorials/tutorials.scss delete mode 100644 src/app/projects/states/tutorials/tutorials.tpl.html diff --git a/src/app/api/models/project.ts b/src/app/api/models/project.ts index 380c62d199..3c154842e2 100644 --- a/src/app/api/models/project.ts +++ b/src/app/api/models/project.ts @@ -347,7 +347,7 @@ export class Project extends Entity { } public isEnrolledIn(tutorial: Tutorial): boolean { - return this.tutorials.includes(tutorial); + return this.tutorials.some((t) => t.id === tutorial.id); } public updateUnitEnrolment(): void { diff --git a/src/app/api/services/unit.service.ts b/src/app/api/services/unit.service.ts index e04d3bec82..42c8211ab8 100644 --- a/src/app/api/services/unit.service.ts +++ b/src/app/api/services/unit.service.ts @@ -53,7 +53,8 @@ export class UnitService extends CachedEntityService { }, }, { - keys: 'unitRoles', + // keys: 'unitRoles', + keys: 'staff', toEntityOp: (data, key, entity) => { const unitRoleService = AppInjector.get(UnitRoleService); // Add staff diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index e65faa1d11..5396335ffe 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -277,6 +277,7 @@ const MY_DATE_FORMAT = { monthYearA11yLabel: 'MMMM yyyy', }, }; +import {TutorialsComponent} from './projects/states/tutorials/tutorials.component'; import {UnitStudentEnrolmentModalComponent} from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component'; import {TaskStatusPieChartComponent} from './visualisations/task-status-pie-chart/taskstatuspiechart.component'; @@ -404,6 +405,7 @@ import {TaskStatusPieChartComponent} from './visualisations/task-status-pie-char TaskScormCardComponent, ScormExtensionCommentComponent, ScormExtensionModalComponent, + TutorialsComponent, UnitStaffEditorComponent, GroupSetSelectorComponent, PortfolioGradeSelectStepComponent, diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 0a48a0b2b7..ade3d4e6d3 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -76,7 +76,6 @@ import 'build/src/app/projects/states/portfolio/directives/portfolio-tasks-step/ import 'build/src/app/projects/states/portfolio/directives/directives.js'; import 'build/src/app/projects/states/portfolio/portfolio.js'; import 'build/src/app/projects/states/index/index.js'; -import 'build/src/app/projects/states/tutorials/tutorials.js'; import 'build/src/app/projects/project-outcome-alignment/project-outcome-alignment.js'; import 'build/src/app/admin/modals/modals.js'; import 'build/src/app/groups/group-selector/group-selector.js'; @@ -210,11 +209,14 @@ import {FTaskDetailsViewComponent} from './units/task-viewer/directives/task-det import {FTaskSheetViewComponent} from './units/task-viewer/directives/task-sheet-view/task-sheet-view.component'; import {ProgressBurndownChartComponent} from './visualisations/progress-burndown-chart/progressburndownchart.component'; import {TaskVisualisationComponent} from './visualisations/task-visualisation/taskvisualisation.component'; +import {TutorialsComponent} from './projects/states/tutorials/tutorials.component'; import {ProgressDashboardComponent} from './projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component'; import {FUnitsComponent} from './admin/states/units/units.component'; import {AlertService} from './common/services/alert.service'; import {GradeService} from './common/services/grade.service'; import {TaskScormCardComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component'; +import {UnitStudentEnrolmentModalService} from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service'; +import {PrivacyPolicy} from './config/privacy-policy/privacy-policy'; // import { UnitStudentEnrolmentModalService } from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service'; // import { PrivacyPolicy } from './config/privacy-policy/privacy-policy'; @@ -222,9 +224,6 @@ import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staf import {GroupSetSelectorComponent} from './groups/group-set-selector/group-set-selector.component'; import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component'; -import {UnitStudentEnrolmentModalService} from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.service'; -import {PrivacyPolicy} from './config/privacy-policy/privacy-policy'; - export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', 'doubtfire.sessions', @@ -486,6 +485,10 @@ DoubtfireAngularJSModule.directive( ); DoubtfireAngularJSModule.directive('newFUnits', downgradeComponent({component: FUnitsComponent})); +DoubtfireAngularJSModule.directive( + 'fTutorials', + downgradeComponent({component: TutorialsComponent}), +); DoubtfireAngularJSModule.directive( 'unitStaffEditor', downgradeComponent({component: UnitStaffEditorComponent}), diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index 7baa910f57..d2a7226cb2 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -14,6 +14,7 @@ import {ProjectRootState} from './projects/states/project-root-state.component'; import { TaskViewerState } from './units/task-viewer/task-viewer-state.component'; import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component'; import { Ng2ViewDeclaration } from '@uirouter/angular'; +import { TutorialsComponent } from './projects/states/tutorials/tutorials.component'; /* * Use this file to store any states that are sourced by angular components. @@ -411,6 +412,24 @@ const ScormPlayerReviewState: NgHybridStateDeclaration = { }, }; +const TutorialState: NgHybridStateDeclaration = { + name: 'projects/tutorials', + url: '/tutorials/project/:projectId', + views: { + main: { + component: TutorialsComponent, // Link to the Angular component + }, + }, + resolve: { + projectId: ['$stateParams', ($stateParams) => $stateParams.projectId], // Resolve the project object + }, + data: { + task: 'Tutorial List', + pageTitle: '_Home_', + roleWhiteList: ['Tutor', 'Convenor', 'Admin', 'Student', 'Auditor'], // Roles allowed to access this state + }, +}; + /** * Export the list of states we have created in angular */ @@ -433,4 +452,5 @@ export const doubtfireStates = [ ScormPlayerNormalState, ScormPlayerReviewState, ScormPlayerStudentReviewState, + TutorialState, ]; diff --git a/src/app/projects/states/states.coffee b/src/app/projects/states/states.coffee index 01b9d42dd4..a2a24c4bc4 100644 --- a/src/app/projects/states/states.coffee +++ b/src/app/projects/states/states.coffee @@ -1,7 +1,6 @@ angular.module('doubtfire.projects.states', [ 'doubtfire.projects.states.index' 'doubtfire.projects.states.dashboard' - 'doubtfire.projects.states.tutorials' 'doubtfire.projects.states.portfolio' 'doubtfire.projects.states.groups' 'doubtfire.projects.states.outcomes' diff --git a/src/app/projects/states/tutorials/tutorials.coffee b/src/app/projects/states/tutorials/tutorials.coffee deleted file mode 100644 index 5c22b609e3..0000000000 --- a/src/app/projects/states/tutorials/tutorials.coffee +++ /dev/null @@ -1,23 +0,0 @@ -angular.module('doubtfire.projects.states.tutorials', []) - -# -# Tasks state for projects -# -.config(($stateProvider) -> - $stateProvider.state 'projects/tutorials', { - parent: 'projects/index' - url: '/tutorials' - controller: 'ProjectsTutorialsStateCtrl' - templateUrl: 'projects/states/tutorials/tutorials.tpl.html' - data: - task: "Tutorial List" - pageTitle: "_Home_" - } -) - -.controller("ProjectsTutorialsStateCtrl", ($scope) -> - if $scope.unit.tutorialStreamsCache.size > 0 - $scope.sortOrder = 'tutorialStream.name' - else - $scope.sortOrder = 'abbreviation' -) diff --git a/src/app/projects/states/tutorials/tutorials.component.html b/src/app/projects/states/tutorials/tutorials.component.html new file mode 100644 index 0000000000..39ec57fbf8 --- /dev/null +++ b/src/app/projects/states/tutorials/tutorials.component.html @@ -0,0 +1,104 @@ +
+
+

Tutorials

+

+ View available tutorials and manage your enrolment. Note that availability is subject to + capacity. If you are unable to enrol in a tutorial, please contact your unit coordinator. +

+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Stream + @if (unit.tutorialStreamsCache.size > 0) { +
{{ tutorial.tutorialStream?.name || 'All' }}
+ } @else { +
N/A
+ } +
Campus + {{ tutorial.campus?.name || 'All' }} + Code + {{ tutorial.abbreviation }} + Day + {{ tutorial.meetingDay }} + Time + {{ shortTime(tutorial.meetingTime) }} + Room + {{ tutorial.meetingLocation }} + Tutor + {{ tutorial.tutorName }} + Actions + @if (project.isEnrolledIn(tutorial)) { + @if (unit.allowStudentChangeTutorial) { + + } @else { +
+ Enrolled +
+ } + } @else if (unit.allowStudentChangeTutorial) { + + } @else { +
+ + } +
+
diff --git a/src/app/projects/states/tutorials/tutorials.component.scss b/src/app/projects/states/tutorials/tutorials.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/tutorials/tutorials.component.ts b/src/app/projects/states/tutorials/tutorials.component.ts new file mode 100644 index 0000000000..6a28239240 --- /dev/null +++ b/src/app/projects/states/tutorials/tutorials.component.ts @@ -0,0 +1,149 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {Sort} from '@angular/material/sort'; +import {MatTableDataSource} from '@angular/material/table'; +import {Tutorial, UnitService} from 'src/app/api/models/doubtfire-model'; +import {Project} from 'src/app/api/models/project'; +import {Unit} from 'src/app/api/models/unit'; +import {ProjectService} from 'src/app/api/services/project.service'; + +@Component({ + selector: 'f-tutorials', + templateUrl: './tutorials.component.html', + styleUrls: ['./tutorials.component.scss'], +}) +export class TutorialsComponent implements OnInit { + @Input() projectId: number; + + filteredTutorials: Tutorial[] = []; + + project: Project; + unit: Unit; + + displayedColumns: string[] = [ + 'stream', + 'campus', + 'code', + 'day', + 'time', + 'room', + 'tutor', + 'actions', + ]; + + dataSource = new MatTableDataSource([]); + + constructor( + private projectService: ProjectService, + private unitService: UnitService, + ) {} + + ngOnInit(): void { + this.projectService.fetch(this.projectId).subscribe({ + next: (project) => { + this.unitService.get(project.unit.id).subscribe({ + next: (unit) => { + this.unit = unit; + this.project = project; + this.filteredTutorials = this.tutorialCampusFilter([...unit.tutorials], this.project); + this.dataSource.data = this.filteredTutorials; + }, + error: (error) => { + console.error('Error fetching unit:', error); + }, + }); + }, + error: (error) => { + console.error('Error fetching project:', error); + }, + }); + } + + /** + * Switches to the passed-in tutorial. + * + * @param tutorial + * + * @returns void + */ + switchToTutorial(tutorial: Tutorial): void { + this.project.switchToTutorial(tutorial); + } + + /** + * Filters a collection of passed-in tutorials based on the campus_id of the passed-in project. + * + * @param tutorials + * @param project + * + * @returns Tutorial[] + */ + tutorialCampusFilter(tutorials: Tutorial[], project: Project): Tutorial[] { + if (!project) { + return tutorials; + } + return tutorials.filter((tutorial) => { + return ( + !project.campus?.id || + !tutorial.campus || + tutorial.campus.id === project.campus.id || + project.isEnrolledIn(tutorial) + ); + }); + } + + /** + * Formats the passed-in time string to the format of: HH:mm + * Todo: Add date validation + * @param meetingTime + * + * @returns string + */ + shortTime(meetingTime: string): string { + const [hours, minutes] = meetingTime.split(':'); + const formattedHours = hours.padStart(2, '0'); + const formattedMinutes = minutes.padStart(2, '0'); + + return `${formattedHours}:${formattedMinutes}`; + } + + private sortCompare(aValue: number | string, bValue: number | string, isAsc: boolean) { + return (aValue < bValue ? -1 : 1) * (isAsc ? 1 : -1); + } + + sortTableData(sort: Sort) { + if (!sort.active || sort.direction === '') { + return; + } + this.dataSource.data = this.dataSource.data.sort((a, b) => { + switch (sort.active) { + case 'stream': + return this.sortCompare( + a.tutorialStream?.name, + b.tutorialStream?.name, + sort.direction === 'asc', + ); + case 'campus': + return this.sortCompare(a.campus?.name, b.campus?.name, sort.direction === 'asc'); + case 'code': + return this.sortCompare(a.abbreviation, b.abbreviation, sort.direction === 'asc'); + case 'day': { + return this.sortCompare(a.meetingDay, b.meetingDay, sort.direction === 'asc'); + } + case 'time': { + return this.sortCompare( + this.shortTime(a.meetingTime), + this.shortTime(b.meetingTime), + sort.direction === 'asc', + ); + } + case 'room': { + return this.sortCompare(a.meetingLocation, b.meetingLocation, sort.direction === 'asc'); + } + case 'tutor': + return this.sortCompare(a.tutorName, b.tutorName, sort.direction === 'asc'); + default: + return 0; + } + }); + } +} diff --git a/src/app/projects/states/tutorials/tutorials.scss b/src/app/projects/states/tutorials/tutorials.scss deleted file mode 100644 index d402eae6a6..0000000000 --- a/src/app/projects/states/tutorials/tutorials.scss +++ /dev/null @@ -1,10 +0,0 @@ -#tutorials-state table { - th.stream { width: 10%; } - th.campus { width: 20%; } - th.code { width: 10%; } - th.day { width: 10%; } - th.time { width: 10%; } - th.room { width: 10%; } - th.tutor { width: 15%; } - th.actions { width: 15%; } -} diff --git a/src/app/projects/states/tutorials/tutorials.tpl.html b/src/app/projects/states/tutorials/tutorials.tpl.html deleted file mode 100644 index fae91d6ae3..0000000000 --- a/src/app/projects/states/tutorials/tutorials.tpl.html +++ /dev/null @@ -1,71 +0,0 @@ -
-
-
-

Select a Tutorial

-
-
-

- Click the plus on the specific tutorial to enrol in that tutorial, or click the minus icon to withdraw from your - current tutorial. -

-
- - - - - - - - - - - - - - - - - - - - - - - - - -
- Stream - - Campus - - Code - - Day - - Time - - Room - - Tutor - Actions
{{tutorial.tutorialStream.name || 'All'}}{{tutorial.campus ? tutorial.campus.name : 'All'}}{{tutorial.abbreviation}}{{tutorial.meetingDay}}{{tutorial.meetingTime | date: 'shortTime'}}{{tutorial.meetingLocation}}{{tutorial.tutorName}} - - -
-
-
From 2b4afe24e3f8139fec23337facc7656eec9a9d3a Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 13 Oct 2025 10:21:09 +1100 Subject: [PATCH 0663/1280] feat: add tutor times summary download (#1015) * feat: add tutor times summary download * fix: typo * feat: add calendar view of marking sessions * refactor: simplify date in filename * refactor: remove get tutors call * refactor: custom number of days visible, show today at the end * refactor: date pickers to filter sessions * refactor: clean up ui * refactor: create tutor times analytics component * refactor: add loading spinner * refactor: fix timezone issues * refactor: improve ui * chore: update endpoint * feat: toggle hide sessions during tutorials * chore: remove button * refactor: implement marking session entity * chore: remove unused code * chore: remove comment --- package-lock.json | 64 +++++ package.json | 1 + src/app/api/models/marking-session.ts | 40 +++ src/app/api/models/unit.ts | 59 +++- .../api/services/marking-session.service.ts | 39 +++ src/app/doubtfire-angular.module.ts | 7 + .../analytics-tutor-times.component.html | 97 +++++++ .../analytics-tutor-times.component.scss | 0 .../analytics-tutor-times.component.ts | 253 ++++++++++++++++++ .../unit-analytics-route.component.html | 34 ++- .../unit-analytics-route.component.ts | 11 +- src/styles.scss | 6 + 12 files changed, 596 insertions(+), 15 deletions(-) create mode 100644 src/app/api/models/marking-session.ts create mode 100644 src/app/api/services/marking-session.service.ts create mode 100644 src/app/units/states/analytics/directives/analytics-tutor-times.component.html create mode 100644 src/app/units/states/analytics/directives/analytics-tutor-times.component.scss create mode 100644 src/app/units/states/analytics/directives/analytics-tutor-times.component.ts diff --git a/package-lock.json b/package-lock.json index 4b1491ce8c..cd419cdb8b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "@uirouter/core": "^6.1.0", "@uirouter/rx": "^1.0.0", "angular": "1.5.11", + "angular-calendar": "^0.31.1", "angular-filter": "0.5.17", "angular-markdown-filter": "1.3.2", "angular-md5": "0.1.10", @@ -4632,6 +4633,12 @@ "tslib": "^2.1.0" } }, + "node_modules/@mattlewis92/dom-autoscroller": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@mattlewis92/dom-autoscroller/-/dom-autoscroller-2.4.2.tgz", + "integrity": "sha512-YbrUWREPGEjE/FU6foXcAT1YbVwqD/jkYnY1dFb0o4AxtP3s4xKBthlELjndZih8uwsDWgQZx1eNskRNe2BgZQ==", + "license": "MIT" + }, "node_modules/@ngneat/hotkeys": { "version": "4.0.0", "license": "MIT", @@ -6410,6 +6417,39 @@ "version": "1.5.11", "license": "MIT" }, + "node_modules/angular-calendar": { + "version": "0.31.1", + "resolved": "https://registry.npmjs.org/angular-calendar/-/angular-calendar-0.31.1.tgz", + "integrity": "sha512-pjSIpoAaUzS/gx+14eOr4hPZhlQ8HxpiZypCSGqJNptq5PD+vOdVQ3h/Aaqnk86GraVcAQPXqfu64MtdKwTVNw==", + "license": "MIT", + "dependencies": { + "@scarf/scarf": "^1.1.1", + "angular-draggable-droppable": "^8.0.0", + "angular-resizable-element": "^7.0.0", + "calendar-utils": "^0.10.4", + "positioning": "^2.0.1", + "tslib": "^2.4.1" + }, + "funding": { + "url": "https://github.com/sponsors/mattlewis92" + }, + "peerDependencies": { + "@angular/core": ">=15.0.0" + } + }, + "node_modules/angular-draggable-droppable": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/angular-draggable-droppable/-/angular-draggable-droppable-8.0.0.tgz", + "integrity": "sha512-+gpSNBbygjV1pxTxsM3UPJKcXHXJabYoTtKcgQe74rGnb1umKc07XCBD1qDzvlG/kocthvhQ12qfYOYzHnE3ZA==", + "license": "MIT", + "dependencies": { + "@mattlewis92/dom-autoscroller": "^2.4.2", + "tslib": "^2.4.1" + }, + "peerDependencies": { + "@angular/core": ">=15.0.0" + } + }, "node_modules/angular-filter": { "version": "0.5.17", "license": "MIT", @@ -6443,6 +6483,18 @@ "nvd3": "^1.7.1" } }, + "node_modules/angular-resizable-element": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/angular-resizable-element/-/angular-resizable-element-7.0.2.tgz", + "integrity": "sha512-/BGuNiA38n9klexHO1xgnsA3VYigj9v+jUGjKtBRgfB26bCxZKsNWParSu2k3EqbATrfAJC4Nl8f7cORpJFf4w==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/core": ">=15.0.0" + } + }, "node_modules/angular-resource": { "version": "1.5.11", "license": "MIT" @@ -7573,6 +7625,12 @@ "node": ">=0.10.0" } }, + "node_modules/calendar-utils": { + "version": "0.10.4", + "resolved": "https://registry.npmjs.org/calendar-utils/-/calendar-utils-0.10.4.tgz", + "integrity": "sha512-gBK4xCJ42yjaUKwuUha6cZOfxAmGzvSgbdAaX3xLRioeKbYoOK1x1qeD6dch72rsMZlTgATPbBBx42bnkStqgQ==", + "license": "MIT" + }, "node_modules/call-bind": { "version": "1.0.7", "license": "MIT", @@ -17668,6 +17726,12 @@ "npm": ">=1.0.0" } }, + "node_modules/positioning": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/positioning/-/positioning-2.0.1.tgz", + "integrity": "sha512-DsAgM42kV/ObuwlRpAzDTjH9E8fGKkMDJHWFX+kfNXSxh7UCCQxEmdjv/Ws5Ft1XDnt3JT8fIDYeKNSE2TbttA==", + "license": "MIT" + }, "node_modules/posix-character-classes": { "version": "0.1.1", "dev": true, diff --git a/package.json b/package.json index 056ce41ad1..f9eb667eef 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "@uirouter/core": "^6.1.0", "@uirouter/rx": "^1.0.0", "angular": "1.5.11", + "angular-calendar": "^0.31.1", "angular-filter": "0.5.17", "angular-markdown-filter": "1.3.2", "angular-md5": "0.1.10", diff --git a/src/app/api/models/marking-session.ts b/src/app/api/models/marking-session.ts new file mode 100644 index 0000000000..8bfbe3a446 --- /dev/null +++ b/src/app/api/models/marking-session.ts @@ -0,0 +1,40 @@ +import {Entity, EntityMapping} from 'ngx-entity-service'; +import {User} from './doubtfire-model'; +import {Unit} from './unit'; + +export class MarkingSession extends Entity { + id: number; + + // Marking tutor + user: User; + + unit: Unit; + + startTime: Date; + endTime: Date; + duringTutorial: boolean; + durationMinutes: number; + + // Aggregated session activities count + commentsAdded: number; + assessments: number; + submissionsOpened: number; + + constructor(data?: Unit) { + super(); + if (data) { + this.unit = data; + } else { + console.error('Failed to get unit'); + } + } + + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { + return { + markingSession: super.toJson(mappingData, ignoreKeys), + }; + } +} diff --git a/src/app/api/models/unit.ts b/src/app/api/models/unit.ts index 6f4a2b0622..b144a53bb3 100644 --- a/src/app/api/models/unit.ts +++ b/src/app/api/models/unit.ts @@ -30,8 +30,10 @@ import {LearningOutcome} from './learning-outcome'; import {AlertService} from 'src/app/common/services/alert.service'; import {D2lAssessmentMapping} from './d2l/d2l_assessment_mapping'; import {SidekiqJob} from './sidekiq-job'; -import {HttpClient} from '@angular/common/http'; +import {HttpClient, HttpParams} from '@angular/common/http'; import {TaskPrerequisiteService} from '../services/task-prerequisite.service'; +import {MarkingSession} from './marking-session'; +import {MarkingSessionService} from '../services/marking-session.service'; export class Unit extends Entity { id: number; @@ -603,6 +605,61 @@ export class Unit extends Entity { ); } + public getUserMarkingSessions(startDate?: Date, endDate?: Date): Observable { + let params = new HttpParams(); + if (startDate) { + params = params.set( + 'start_date', + `${startDate.getFullYear()}-${(startDate.getMonth() + 1).toString().padStart(2, '0')}-${startDate.getDate().toString().padStart(2, '0')}`, + ); + } + + if (endDate) { + params = params.set( + 'end_date', + `${endDate.getFullYear()}-${(endDate.getMonth() + 1).toString().padStart(2, '0')}-${endDate.getDate().toString().padStart(2, '0')}`, + ); + } + + // TODO: we should cache the data by the same start/end date + const markingSessionService = AppInjector.get(MarkingSessionService); + return markingSessionService.fetchAll( + { + unitId: this.id, + }, + {params, constructorParams: this}, + ); + } + + public downloadTutorTimesSummaryCsv( + startDate?: Date, + endDate?: Date, + ignoreSessionsDuringTutorials?: boolean, + ): Observable { + let params = new HttpParams(); + + if (startDate) { + params = params.set( + 'start_date', + `${startDate.getFullYear()}-${(startDate.getMonth() + 1).toString().padStart(2, '0')}-${startDate.getDate().toString().padStart(2, '0')}`, + ); + } + + if (endDate) { + params = params.set( + 'end_date', + `${endDate.getFullYear()}-${(endDate.getMonth() + 1).toString().padStart(2, '0')}-${endDate.getDate().toString().padStart(2, '0')}`, + ); + } + + params = params.set('ignore_sessions_during_tutorials', ignoreSessionsDuringTutorials ?? false); + + return AppInjector.get(HttpClient).get( + `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/tutor_times_summary`, + {params}, + ); + } + public hasD2lMapping(): boolean { const doubtfireConstants = AppInjector.get(DoubtfireConstants); return ( diff --git a/src/app/api/services/marking-session.service.ts b/src/app/api/services/marking-session.service.ts new file mode 100644 index 0000000000..f1ce830a02 --- /dev/null +++ b/src/app/api/services/marking-session.service.ts @@ -0,0 +1,39 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import {Unit} from 'src/app/api/models/doubtfire-model'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {MarkingSession} from '../models/marking-session'; + +@Injectable() +export class MarkingSessionService extends CachedEntityService { + protected readonly endpointFormat = 'units/:unitId:/marking_sessions/:id:'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'startTime', + 'endTime', + 'duringTutorial', + 'durationMinutes', + + 'commentsAdded', + 'assessments', + 'submissionsOpened', + + { + keys: ['user', 'user_id'], + toEntityFn: (data: object, _key: string, markingSession: MarkingSession) => { + const userRole = markingSession.unit.staff.find((s) => s.user.id === data['user_id']); + return userRole.user; + }, + }, + ); + } + + public createInstanceFrom(json: object, other?: Unit): MarkingSession { + return new MarkingSession(other); + } +} diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 369039dfbc..47e4679234 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -111,6 +111,8 @@ import {MatDatepickerModule} from '@angular/material/datepicker'; import {DateFnsAdapter, MAT_DATE_FNS_FORMATS} from '@angular/material-date-fns-adapter'; import {enAU} from 'date-fns/locale'; +import {CalendarModule, DateAdapter as CalendarDateAdapter} from 'angular-calendar'; +import {adapterFactory} from 'angular-calendar/date-adapters/date-fns'; import {doubtfireStates} from './doubtfire.states'; import {MatTableModule} from '@angular/material/table'; @@ -289,6 +291,8 @@ import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staf import {GroupSetSelectorComponent} from './groups/group-set-selector/group-set-selector.component'; import {UnitDetailsEditorComponent} from './units/states/edit/directives/unit-details-editor/unit-details-editor.component'; import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component'; +import {AnalyticsTutorTimesComponent} from './units/states/analytics/directives/analytics-tutor-times.component'; +import {MarkingSessionService} from './api/services/marking-session.service'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { @@ -441,6 +445,7 @@ const MY_DATE_FORMAT = { GroupSetSelectorComponent, UnitDetailsEditorComponent, PortfolioGradeSelectStepComponent, + AnalyticsTutorTimesComponent, ], // Services we provide providers: [ @@ -529,6 +534,7 @@ const MY_DATE_FORMAT = { SidekiqJobService, LtiService, TaskPrerequisiteService, + MarkingSessionService, ], imports: [ FlexLayoutModule, @@ -590,6 +596,7 @@ const MY_DATE_FORMAT = { MatDatepickerModule, MatNativeDateModule, MatDialogModuleNew, + CalendarModule.forRoot({provide: CalendarDateAdapter, useFactory: adapterFactory}), ], }) diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html new file mode 100644 index 0000000000..faef0eaab1 --- /dev/null +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html @@ -0,0 +1,97 @@ + + + +

Tutor Times Session Summary

+
+ + +
+ +
+
+ + + +
+
+ + Choose a date + + Sessions from this day onward + + + + + + Choose a date + + Sessions up to this day + + + +
+
+ Hide sessions during tutorials +
+
+ + +
+ {{ event.name }} ({{ event.duration }} minutes) + {{ event.duringTutorial ? 'T' : '' }}
+ Assessments: {{ event.assessments || 0 }}
+ Comments: {{ event.comments_added || 0 }}
+ Submissions opened: {{ event.submissions_opened || 0 }}
+ During Tutorial?: {{ event.duringTutorial ? 'yes' : 'no' }} +
+
+ +
+ @if (isLoading) { + + + } + + +
+
diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.scss b/src/app/units/states/analytics/directives/analytics-tutor-times.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts new file mode 100644 index 0000000000..19735552cc --- /dev/null +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts @@ -0,0 +1,253 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {MatDatepickerInputEvent} from '@angular/material/datepicker'; +import {CalendarEvent} from 'angular-calendar'; +import {Observable} from 'rxjs'; +import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; +import {Unit} from 'src/app/api/models/unit'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-analytics-tutor-times', + templateUrl: 'analytics-tutor-times.component.html', + styleUrls: ['analytics-tutor-times.component.scss'], +}) +export class AnalyticsTutorTimesComponent implements OnInit { + @Input() unit: Unit; + + @Input() downloadCsvFn!: ( + newJob: Observable, + title: string, + filename: string, + ) => void; + + selectedUserId: number | null = null; + + viewDate = new Date(); + events = []; + filteredEvents = []; + + tutorTimeSummaryStartDate: Date; + tutorTimeSummaryEndDate: Date; + daysInWeek: number = 7; + + hideSessionsDuringTutorials: boolean = false; + + public canLoadSessions: boolean = false; + public isLoading: boolean = false; + + constructor( + private alertService: AlertService, + private sidekiqProgressModalService: SidekiqProgressModalService, + private fileDownloaderService: FileDownloaderService, + ) {} + + ngOnInit(): void { + if (!this.sidekiqProgressModalService || !this.fileDownloaderService) { + // NOTE: Our `downloadCsvFn` callback requires these services because it calls `this` context + console.error('Failed to load tutor times analytics'); + } + + this.tutorTimeSummaryEndDate = new Date(); + this.tutorTimeSummaryEndDate.setHours(0, 0, 0, 0); + + this.tutorTimeSummaryStartDate = new Date(this.tutorTimeSummaryEndDate); + this.tutorTimeSummaryStartDate.setDate(this.tutorTimeSummaryEndDate.getDate() - 7); + + const startOfWeek = new Date(this.viewDate); + startOfWeek.setDate(this.viewDate.getDate() - this.daysInWeek + 1); + + this.viewDate = startOfWeek; + + this.canLoadSessions = true; + this.getMarkingSesssions(); + } + + goPreviousWeek() { + this.canLoadSessions = true; + this.viewDate = new Date(this.viewDate.getTime() - this.daysInWeek * 24 * 60 * 60 * 1000); + } + + goNextWeek() { + this.canLoadSessions = true; + this.viewDate = new Date(this.viewDate.getTime() + this.daysInWeek * 24 * 60 * 60 * 1000); + } + + goTodayWeek() { + this.canLoadSessions = true; + + this.tutorTimeSummaryEndDate = new Date(); + this.tutorTimeSummaryStartDate = new Date( + this.tutorTimeSummaryEndDate.getTime() - 7 * 24 * 60 * 60 * 1000, + ); + this.daysInWeek = 7; + + this.viewDate = new Date(); + const startOfWeek = new Date(); + startOfWeek.setDate(this.viewDate.getDate() - this.daysInWeek + 1); + + this.viewDate = startOfWeek; + } + + public onToggleChangeHideSessionsDuringTutorial() { + setTimeout(() => { + this.applyFilters(); + }); + } + + applyFilters() { + this.filteredEvents = this.events.filter( + (e) => + (this.selectedUserId === null || e['user_id'] === this.selectedUserId) && + (!this.hideSessionsDuringTutorials || !e['duringTutorial']), + ); + } + + onDateChange(_event: MatDatepickerInputEvent) { + if (!this.tutorTimeSummaryStartDate || !this.tutorTimeSummaryEndDate) { + return; + } + + // Includes both the selected start & end days + const diffDays = + Math.floor( + (this.tutorTimeSummaryEndDate.getTime() - this.tutorTimeSummaryStartDate.getTime()) / + (1000 * 60 * 60 * 24), + ) + 1; + + if (diffDays > 366) { + this.alertService.error('You cannot select more than a year', 3000); + return; + } + console.log('diff days', diffDays); + if (diffDays < 1) { + this.tutorTimeSummaryStartDate = this.tutorTimeSummaryEndDate; + this.alertService.error('End date must be on or after the start date'); + return; + } + this.canLoadSessions = true; + this.daysInWeek = diffDays; + this.viewDate = new Date(this.tutorTimeSummaryStartDate); + } + + beforeViewRender(event): void { + console.log(event.period.start); + console.log(event.period.end); + + this.tutorTimeSummaryStartDate = event.period.start; + this.tutorTimeSummaryEndDate = event.period.end; + + this.getMarkingSesssions(); + } + + public getTutorTimesSummary() { + const start = `${this.tutorTimeSummaryStartDate.getFullYear()}-${(this.tutorTimeSummaryStartDate.getMonth() + 1).toString().padStart(2, '0')}-${this.tutorTimeSummaryStartDate.getDate().toString().padStart(2, '0')}`; + const end = `${this.tutorTimeSummaryEndDate.getFullYear()}-${(this.tutorTimeSummaryEndDate.getMonth() + 1).toString().padStart(2, '0')}-${this.tutorTimeSummaryEndDate.getDate().toString().padStart(2, '0')}`; + + this.downloadCsvFn( + this.unit.downloadTutorTimesSummaryCsv( + this.tutorTimeSummaryStartDate, + this.tutorTimeSummaryEndDate, + this.hideSessionsDuringTutorials, + ), + 'Tutor Times Summary CSV', + `${this.unit.code}-tutor-times-summary-${start}-to-${end}-${!this.hideSessionsDuringTutorials ? 'incl-tutorials' : ''}.csv`, + ); + } + + public getMarkingSesssions() { + if (!this.canLoadSessions) { + return; + } + + this.canLoadSessions = false; + this.isLoading = true; + this.unit + .getUserMarkingSessions(this.tutorTimeSummaryStartDate, this.tutorTimeSummaryEndDate) + .subscribe({ + next: (data) => { + this.isLoading = false; + this.canLoadSessions = false; + this.events = data.map((session) => { + const tutor = this.unit.staff.find((t) => t.user.id === session.user.id); + + const primary = this.stringToHexColor(tutor.user.firstName); + const secondary = this.stringToHexColor(tutor.user.firstName); + return { + start: new Date(session.startTime), + end: new Date(session.endTime), + title: `${tutor?.user.firstName} (${session.durationMinutes}m) ${session.duringTutorial ? '(T)' : ''}`, + color: {primary: secondary, secondary: primary}, + user_id: session.user.id, + comments_added: session.commentsAdded, + assessments: session.assessments, + submissions_opened: session.submissionsOpened, + duration: session.durationMinutes, + duringTutorial: session.duringTutorial, + name: tutor?.user.firstName, + }; + }); + + this.filteredEvents = this.events.filter( + (row) => this.selectedUserId === null || row['user_id'] === this.selectedUserId, + ); + + console.log(data); + }, + error: (error) => { + this.canLoadSessions = false; + + console.error(error); + }, + }); + } + + eventClicked({event}: {event: CalendarEvent}): void { + if (event['user_id'] !== undefined) { + if (this.selectedUserId === null) { + this.selectedUserId = Number(event['user_id']); + } else { + this.selectedUserId = null; + } + this.applyFilters(); + } + } + + private stringToHexColor( + name: string, + opts?: {hue?: [number, number]; sat?: [number, number]; lit?: [number, number]}, + ): string { + const options = { + hue: opts?.hue || [0, 360], + sat: opts?.sat || [40, 70], // lower saturation → softer color + lit: opts?.lit || [75, 90], // higher lightness → pastel tone + }; + + const range = (hash: number, min: number, max: number) => { + const diff = max - min; + const x = ((hash % diff) + diff) % diff; + return x + min; + }; + + let hash = 0; + for (let i = 0; i < name.length; i++) { + hash = name.charCodeAt(i) + ((hash << 5) - hash); + hash = hash & hash; + } + + const h = range(hash, options.hue[0], options.hue[1]); + const s = range(hash, options.sat[0], options.sat[1]) / 100; + const l = range(hash, options.lit[0], options.lit[1]) / 100; + + const a = s * Math.min(l, 1 - l); + const f = (n: number) => { + const k = (n + h / 30) % 12; + const color = l - a * Math.max(-1, Math.min(k - 3, 9 - k, 1)); + return Math.round(255 * color); + }; + + const toHex = (c: number) => c.toString(16).padStart(2, '0'); + return `#${toHex(f(0))}${toHex(f(8))}${toHex(f(4))}`; + } +} diff --git a/src/app/units/states/analytics/unit-analytics-route.component.html b/src/app/units/states/analytics/unit-analytics-route.component.html index 361c9ce18c..9388fae8d0 100644 --- a/src/app/units/states/analytics/unit-analytics-route.component.html +++ b/src/app/units/states/analytics/unit-analytics-route.component.html @@ -1,16 +1,24 @@

Unit Statistics

-
- - - - +
+ + + + + + + + + + @if (role === 'Convenor') { + + }
diff --git a/src/app/units/states/analytics/unit-analytics-route.component.ts b/src/app/units/states/analytics/unit-analytics-route.component.ts index 12e4770d84..73419c4dfe 100644 --- a/src/app/units/states/analytics/unit-analytics-route.component.ts +++ b/src/app/units/states/analytics/unit-analytics-route.component.ts @@ -1,7 +1,10 @@ -import {Component, Input} from '@angular/core'; +import {Component, Input, OnInit} from '@angular/core'; +import {MatDatepickerInputEvent} from '@angular/material/datepicker'; +import {CalendarEvent} from 'angular-calendar'; import {Observable} from 'rxjs'; import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; import {Unit} from 'src/app/api/models/unit'; +import {UserService} from 'src/app/api/services/user.service'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; @@ -18,8 +21,14 @@ export class UnitAnalyticsComponent { private sidekiqProgressModalService: SidekiqProgressModalService, private alertsService: AlertService, private fileDownloaderService: FileDownloaderService, + private userService: UserService, + private alertService: AlertService, ) {} + get role() { + return this.unit.staff.find((s) => s.user.id === this.userService.currentUser.id)?.role; + } + public getTaskCompletionCsv() { this.downloadCsv( this.unit.downloadTaskCompletionCsv(), diff --git a/src/styles.scss b/src/styles.scss index b0756f5acd..7eec75221c 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -4,6 +4,7 @@ @include mat.core(); @import './theme.scss'; +@import '../node_modules/angular-calendar/css/angular-calendar.css'; @tailwind base; @tailwind components; @@ -35,3 +36,8 @@ } } } + +.mat-mdc-progress-spinner circle, +.mat-spinner circle { + stroke: #ddd !important; +} From 376dad3125ed6757b997ef25e5866a43cb7919d0 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 13 Oct 2025 10:22:11 +1100 Subject: [PATCH 0664/1280] chore(release): 10.0.0-48 --- CHANGELOG.md | 12 ++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ae329af052..f2b6a8e01e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-48](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-47...v10.0.0-48) (2025-10-12) + + +### Features + +* add tutor times summary download ([#1015](https://github.com/b0ink/doubtfire-deploy/issues/1015)) ([2b4afe2](https://github.com/b0ink/doubtfire-deploy/commit/2b4afe24e3f8139fec23337facc7656eec9a9d3a)) + + +### Bug Fixes + +* add assess in portfolio tasks as completed tasks in burndown chart ([8d36c94](https://github.com/b0ink/doubtfire-deploy/commit/8d36c94f03563a0924cfeb7d2d9e8dd911b65960)) + ## [10.0.0-47](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-46...v10.0.0-47) (2025-09-25) diff --git a/package-lock.json b/package-lock.json index cd419cdb8b..df15a9fd8a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-47", + "version": "10.0.0-48", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-47", + "version": "10.0.0-48", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index f9eb667eef..f481fc788f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-47", + "version": "10.0.0-48", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From bb548b92d04bb7b8665444e7935317bc4b6a0981 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 13 Oct 2025 10:42:50 +1100 Subject: [PATCH 0665/1280] feat: display session start and end time --- .../directives/analytics-tutor-times.component.html | 1 + .../directives/analytics-tutor-times.component.ts | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html index faef0eaab1..2a8dccf5e1 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html @@ -66,6 +66,7 @@

Tutor Times Session Summary

>{{ event.name }} ({{ event.duration }} minutes) {{ event.duringTutorial ? 'T' : '' }}
+ {{ event.startHour }} — {{ event.endHour }}
Assessments: {{ event.assessments || 0 }}
Comments: {{ event.comments_added || 0 }}
Submissions opened: {{ event.submissions_opened || 0 }}
diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts index 19735552cc..a21aa9d230 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts @@ -177,6 +177,16 @@ export class AnalyticsTutorTimesComponent implements OnInit { return { start: new Date(session.startTime), end: new Date(session.endTime), + startHour: new Date(session.startTime).toLocaleTimeString([], { + hour: '2-digit', + minute: '2-digit', + hour12: false, + }), + endHour: new Date(session.endTime).toLocaleTimeString([], { + hour: '2-digit', + minute: '2-digit', + hour12: false, + }), title: `${tutor?.user.firstName} (${session.durationMinutes}m) ${session.duringTutorial ? '(T)' : ''}`, color: {primary: secondary, secondary: primary}, user_id: session.user.id, From a251c4f024b6dd9fa17b87cbafe3e0903dc18372 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 13 Oct 2025 10:44:02 +1100 Subject: [PATCH 0666/1280] chore(release): 10.0.0-49 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f2b6a8e01e..0f0f746ac0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-49](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-48...v10.0.0-49) (2025-10-12) + + +### Features + +* display session start and end time ([bb548b9](https://github.com/b0ink/doubtfire-deploy/commit/bb548b92d04bb7b8665444e7935317bc4b6a0981)) + ## [10.0.0-48](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-47...v10.0.0-48) (2025-10-12) diff --git a/package-lock.json b/package-lock.json index df15a9fd8a..df3e8388b7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-48", + "version": "10.0.0-49", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-48", + "version": "10.0.0-49", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index f481fc788f..2d1bf66d8f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-48", + "version": "10.0.0-49", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 9a7a860fe799e351831e2a3f9701792792b76b38 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 13 Oct 2025 11:44:54 +1100 Subject: [PATCH 0667/1280] feat: jplag base code (#1010) * feat: jplag base code * chore: reword base code description --- src/app/api/models/task-definition.ts | 1 + src/app/api/services/task-definition.service.ts | 1 + .../task-definition-upload.component.html | 13 +++++++++++++ 3 files changed, 15 insertions(+) diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index 0810326cdd..30aff474bf 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -54,6 +54,7 @@ export class TaskDefinition extends Entity { similarityLanguage: string = 'c'; hasJplagReport: boolean; assessInPortfolioOnly: boolean; + useResourcesForJplagBaseCode: boolean; public readonly taskPrerequisitesCache: EntityCache = new EntityCache(); diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index 7692ab936b..63708814f8 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -136,6 +136,7 @@ export class TaskDefinitionService extends CachedEntityService { }); }, }, + 'useResourcesForJplagBaseCode', ); this.mapping.mapAllKeysToJsonExcept( diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html index 48d7fd0080..28015f48b3 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html @@ -113,4 +113,17 @@
+
+
+ + Use Task Resources for JPlag Base Code +

+ Base code is a common framework included in all submissions. When enabled, student code + matching this base code will be ignored during JPlag similarity checks. The base code will + be automatically extracted from the task resources. +

+
+
+
} From 059d54f5450da29b3e21a2b893116decd8df1879 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 13 Oct 2025 11:45:26 +1100 Subject: [PATCH 0668/1280] chore(release): 10.0.0-50 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0f0f746ac0..28de2191c2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-50](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-49...v10.0.0-50) (2025-10-13) + + +### Features + +* jplag base code ([#1010](https://github.com/b0ink/doubtfire-deploy/issues/1010)) ([9a7a860](https://github.com/b0ink/doubtfire-deploy/commit/9a7a860fe799e351831e2a3f9701792792b76b38)) + ## [10.0.0-49](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-48...v10.0.0-49) (2025-10-12) diff --git a/package-lock.json b/package-lock.json index df3e8388b7..19dd45e590 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-49", + "version": "10.0.0-50", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-49", + "version": "10.0.0-50", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 2d1bf66d8f..dcc5e480c8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-49", + "version": "10.0.0-50", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 173d8c25375e231b25e64a04c1e3d2aedf741300 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 14 Oct 2025 18:00:11 +1100 Subject: [PATCH 0669/1280] fix: unlock tasks when prerequisite requires rff and task is in aip state --- src/app/api/models/task-prerequisite.ts | 1 + .../task-definition-prerequisites.component.ts | 1 + 2 files changed, 2 insertions(+) diff --git a/src/app/api/models/task-prerequisite.ts b/src/app/api/models/task-prerequisite.ts index 43450deedf..510d6ce3b6 100644 --- a/src/app/api/models/task-prerequisite.ts +++ b/src/app/api/models/task-prerequisite.ts @@ -21,6 +21,7 @@ export class TaskPrerequisite extends Entity { public readonly STATES: Partial> = { ready_for_feedback: 1, + assess_in_portfolio: 1, discuss: 2, demonstrate: 2, complete: 3, diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts index 1e11eed7ff..eff30b4bd3 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts @@ -35,6 +35,7 @@ export class TaskDefinitionPrerequisitesComponent implements OnInit, OnChanges { public readonly STATES: Partial> = { ready_for_feedback: 1, + assess_in_portfolio: 1, discuss: 2, demonstrate: 2, complete: 3, From 267fa1b27515184149543afdb2e87fbe9c915ef8 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 14 Oct 2025 18:03:40 +1100 Subject: [PATCH 0670/1280] chore(release): 10.0.0-51 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 6 +++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 28de2191c2..08159fda97 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-51](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-50...v10.0.0-51) (2025-10-14) + + +### Bug Fixes + +* unlock tasks when prerequisite requires rff and task is in aip state ([173d8c2](https://github.com/b0ink/doubtfire-deploy/commit/173d8c25375e231b25e64a04c1e3d2aedf741300)) + ## [10.0.0-50](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-49...v10.0.0-50) (2025-10-13) diff --git a/package-lock.json b/package-lock.json index 19dd45e590..38c5bd3f5f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-50", + "version": "10.0.0-51", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-50", + "version": "10.0.0-51", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index dcc5e480c8..d45df0c039 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-50", + "version": "10.0.0-51", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", @@ -16,8 +16,8 @@ "lint": "ng lint", "serve:angular17": "export NODE_OPTIONS=--max_old_space_size=4096 && ng serve --poll=2000 --configuration $NODE_ENV --proxy-config proxy.conf.json", "serve:angular17-compose": "export NODE_OPTIONS=--max_old_space_size=4096 && ng serve --configuration $NODE_ENV --proxy-config proxy-compose.conf.json", - "start": "npm-run-all -l -s build:angular1 serve:angular17", - "start-compose": "npm-run-all -l -s build:angular1 serve:angular17-compose", + "start": "npm-run-all -l -s build:angular1 -p watch:angular1 serve:angular17", + "start-compose": "npm-run-all -l -s build:angular1 -p watch:angular1 serve:angular17-compose", "watch:angular1": "grunt delta", "deploy:build2api": "ng build --delete-output-path=true --optimization=true --configuration production --output-path dist", "deploy": "run-s -l build:angular1 deploy:build2api", From 5c0b528d774cac7d73de28e6e9ec16c9d109e955 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 15 Oct 2025 10:03:30 +1100 Subject: [PATCH 0671/1280] chore: filter out sessions with less than 1 minute duration --- .../analytics-tutor-times.component.ts | 39 +++++++++++++------ 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts index a21aa9d230..3572e946ea 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts @@ -8,6 +8,25 @@ import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloa import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; +interface SessionEvent { + start: Date; + end: Date; + startHour: string; + endHour: string; + title: string; + color: { + primary: string; + secondary: string; + }; + userId: number; + commentsAdded: number; + assessments: number; + submissionsOpened: number; + duration: number; + duringTutorial: boolean; + tutorName: string; +} + @Component({ selector: 'f-analytics-tutor-times', templateUrl: 'analytics-tutor-times.component.html', @@ -25,7 +44,7 @@ export class AnalyticsTutorTimesComponent implements OnInit { selectedUserId: number | null = null; viewDate = new Date(); - events = []; + events: SessionEvent[] = []; filteredEvents = []; tutorTimeSummaryStartDate: Date; @@ -100,7 +119,8 @@ export class AnalyticsTutorTimesComponent implements OnInit { this.filteredEvents = this.events.filter( (e) => (this.selectedUserId === null || e['user_id'] === this.selectedUserId) && - (!this.hideSessionsDuringTutorials || !e['duringTutorial']), + (!this.hideSessionsDuringTutorials || !e['duringTutorial']) && + e.duration >= 1, ); } @@ -120,7 +140,6 @@ export class AnalyticsTutorTimesComponent implements OnInit { this.alertService.error('You cannot select more than a year', 3000); return; } - console.log('diff days', diffDays); if (diffDays < 1) { this.tutorTimeSummaryStartDate = this.tutorTimeSummaryEndDate; this.alertService.error('End date must be on or after the start date'); @@ -189,21 +208,17 @@ export class AnalyticsTutorTimesComponent implements OnInit { }), title: `${tutor?.user.firstName} (${session.durationMinutes}m) ${session.duringTutorial ? '(T)' : ''}`, color: {primary: secondary, secondary: primary}, - user_id: session.user.id, - comments_added: session.commentsAdded, + userId: session.user.id, + commentsAdded: session.commentsAdded, assessments: session.assessments, - submissions_opened: session.submissionsOpened, + submissionsOpened: session.submissionsOpened, duration: session.durationMinutes, duringTutorial: session.duringTutorial, - name: tutor?.user.firstName, + tutorName: tutor?.user.firstName, }; }); - this.filteredEvents = this.events.filter( - (row) => this.selectedUserId === null || row['user_id'] === this.selectedUserId, - ); - - console.log(data); + this.applyFilters(); }, error: (error) => { this.canLoadSessions = false; From 5c0c9974569e720a6c95aa8333c2a38d0ab4a1b0 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 15 Oct 2025 11:40:19 +1100 Subject: [PATCH 0672/1280] fix: filter out students from unit staff editor (#1018) --- .../unit-staff-editor/unit-staff-editor.component.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts index f64d62d921..f161c384aa 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts @@ -145,7 +145,10 @@ export class UnitStaffEditorComponent implements OnInit { this.filteredStaff = this.staff.filter( (staff) => staff.matches(this.searchTerm.toLowerCase()) && // Find by name - !this.unit.staff.find((listStaff) => staff.id === listStaff.user.id), // Not already assigned to the unit + !this.unit.staff.find((listStaff) => staff.id === listStaff.user.id) && // Not already assigned to the unit + // Filter out students from the staff search + // NOTE: This is a hotfix to an issue where loading the inbox populates this.staff with students... + staff.isStaff, ); } From 4487865ed551af44adcad8de01f062cdc258dc11 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 15 Oct 2025 14:45:35 +1100 Subject: [PATCH 0673/1280] refactor: send timezone of client to the api (#1019) --- src/app/api/models/unit.ts | 11 ++++++++++- .../directives/analytics-tutor-times.component.ts | 11 ++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/src/app/api/models/unit.ts b/src/app/api/models/unit.ts index b144a53bb3..37b27568a4 100644 --- a/src/app/api/models/unit.ts +++ b/src/app/api/models/unit.ts @@ -605,7 +605,11 @@ export class Unit extends Entity { ); } - public getUserMarkingSessions(startDate?: Date, endDate?: Date): Observable { + public getUserMarkingSessions( + startDate?: Date, + endDate?: Date, + timezone?: string, + ): Observable { let params = new HttpParams(); if (startDate) { params = params.set( @@ -621,6 +625,8 @@ export class Unit extends Entity { ); } + params = params.set('timezone', timezone); + // TODO: we should cache the data by the same start/end date const markingSessionService = AppInjector.get(MarkingSessionService); return markingSessionService.fetchAll( @@ -634,6 +640,7 @@ export class Unit extends Entity { public downloadTutorTimesSummaryCsv( startDate?: Date, endDate?: Date, + timezone?: string, ignoreSessionsDuringTutorials?: boolean, ): Observable { let params = new HttpParams(); @@ -652,6 +659,8 @@ export class Unit extends Entity { ); } + params = params.set('timezone', timezone); + params = params.set('ignore_sessions_during_tutorials', ignoreSessionsDuringTutorials ?? false); return AppInjector.get(HttpClient).get( diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts index 3572e946ea..dc6aa29351 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts @@ -164,14 +164,17 @@ export class AnalyticsTutorTimesComponent implements OnInit { const start = `${this.tutorTimeSummaryStartDate.getFullYear()}-${(this.tutorTimeSummaryStartDate.getMonth() + 1).toString().padStart(2, '0')}-${this.tutorTimeSummaryStartDate.getDate().toString().padStart(2, '0')}`; const end = `${this.tutorTimeSummaryEndDate.getFullYear()}-${(this.tutorTimeSummaryEndDate.getMonth() + 1).toString().padStart(2, '0')}-${this.tutorTimeSummaryEndDate.getDate().toString().padStart(2, '0')}`; + const tz = Intl.DateTimeFormat().resolvedOptions().timeZone; + this.downloadCsvFn( this.unit.downloadTutorTimesSummaryCsv( this.tutorTimeSummaryStartDate, this.tutorTimeSummaryEndDate, + tz, this.hideSessionsDuringTutorials, ), 'Tutor Times Summary CSV', - `${this.unit.code}-tutor-times-summary-${start}-to-${end}-${!this.hideSessionsDuringTutorials ? 'incl-tutorials' : ''}.csv`, + `${this.unit.code}-tutor-times-summary-${start}-to-${end}-${tz}-${!this.hideSessionsDuringTutorials ? 'incl-tutorials' : ''}.csv`, ); } @@ -180,10 +183,12 @@ export class AnalyticsTutorTimesComponent implements OnInit { return; } + const tz = Intl.DateTimeFormat().resolvedOptions().timeZone; + this.canLoadSessions = false; this.isLoading = true; this.unit - .getUserMarkingSessions(this.tutorTimeSummaryStartDate, this.tutorTimeSummaryEndDate) + .getUserMarkingSessions(this.tutorTimeSummaryStartDate, this.tutorTimeSummaryEndDate, tz) .subscribe({ next: (data) => { this.isLoading = false; @@ -222,7 +227,7 @@ export class AnalyticsTutorTimesComponent implements OnInit { }, error: (error) => { this.canLoadSessions = false; - + this.alertService.error(`Failed to load sessions: ${error}`, 6000); console.error(error); }, }); From e3fbe4404661eb16b9c0e5ba19a1369dac1fb5b0 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 15 Oct 2025 16:11:24 +1100 Subject: [PATCH 0674/1280] feat: download marking sessions for tutor --- src/app/api/models/unit.ts | 29 +++++++++++++++++++ .../analytics-tutor-times.component.html | 29 +++++++++++++------ .../analytics-tutor-times.component.ts | 19 ++++++++++++ 3 files changed, 68 insertions(+), 9 deletions(-) diff --git a/src/app/api/models/unit.ts b/src/app/api/models/unit.ts index 37b27568a4..8306a94f12 100644 --- a/src/app/api/models/unit.ts +++ b/src/app/api/models/unit.ts @@ -669,6 +669,35 @@ export class Unit extends Entity { ); } + public downloadMyTutorTimeSessionsCsv( + startDate?: Date, + endDate?: Date, + timezone?: string, + ): Observable { + let params = new HttpParams(); + + if (startDate) { + params = params.set( + 'start_date', + `${startDate.getFullYear()}-${(startDate.getMonth() + 1).toString().padStart(2, '0')}-${startDate.getDate().toString().padStart(2, '0')}`, + ); + } + + if (endDate) { + params = params.set( + 'end_date', + `${endDate.getFullYear()}-${(endDate.getMonth() + 1).toString().padStart(2, '0')}-${endDate.getDate().toString().padStart(2, '0')}`, + ); + } + + params = params.set('timezone', timezone); + + return AppInjector.get(HttpClient).get( + `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/my_marking_sessions`, + {params}, + ); + } + public hasD2lMapping(): boolean { const doubtfireConstants = AppInjector.get(DoubtfireConstants); return ( diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html index 2a8dccf5e1..ba944fc26c 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html @@ -4,15 +4,26 @@

Tutor Times Session Summary

- +
+ + +
diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts index dc6aa29351..7e99793801 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts @@ -4,6 +4,7 @@ import {CalendarEvent} from 'angular-calendar'; import {Observable} from 'rxjs'; import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; import {Unit} from 'src/app/api/models/unit'; +import {UserService} from 'src/app/api/services/user.service'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; @@ -60,6 +61,7 @@ export class AnalyticsTutorTimesComponent implements OnInit { private alertService: AlertService, private sidekiqProgressModalService: SidekiqProgressModalService, private fileDownloaderService: FileDownloaderService, + private userService: UserService, ) {} ngOnInit(): void { @@ -178,6 +180,23 @@ export class AnalyticsTutorTimesComponent implements OnInit { ); } + public getMyTutorTimesSessions() { + const start = `${this.tutorTimeSummaryStartDate.getFullYear()}-${(this.tutorTimeSummaryStartDate.getMonth() + 1).toString().padStart(2, '0')}-${this.tutorTimeSummaryStartDate.getDate().toString().padStart(2, '0')}`; + const end = `${this.tutorTimeSummaryEndDate.getFullYear()}-${(this.tutorTimeSummaryEndDate.getMonth() + 1).toString().padStart(2, '0')}-${this.tutorTimeSummaryEndDate.getDate().toString().padStart(2, '0')}`; + + const tz = Intl.DateTimeFormat().resolvedOptions().timeZone; + + this.downloadCsvFn( + this.unit.downloadMyTutorTimeSessionsCsv( + this.tutorTimeSummaryStartDate, + this.tutorTimeSummaryEndDate, + tz, + ), + 'My Marking Sessions CSV', + `${this.unit.code}-${this.userService.currentUser.name}-sessions-${start}-to-${end}-${tz}}.csv`, + ); + } + public getMarkingSesssions() { if (!this.canLoadSessions) { return; From 89560205d7316c53d77f376b5f7cfff5bf99e9c6 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 15 Oct 2025 16:23:36 +1100 Subject: [PATCH 0675/1280] fix: display tutor name --- .../analytics/directives/analytics-tutor-times.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html index ba944fc26c..717fac9603 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html @@ -74,7 +74,7 @@

Tutor Times Session Summary

{{ event.name }} ({{ event.duration }} minutes) + >{{ event.tutorName }} ({{ event.duration }} minutes) {{ event.duringTutorial ? 'T' : '' }}
{{ event.startHour }} — {{ event.endHour }}
From 4435fea9daaa3566ec9f1fb86aea9caad7645ce0 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 15 Oct 2025 16:25:16 +1100 Subject: [PATCH 0676/1280] refactor: expand hour segments ui --- .../analytics/directives/analytics-tutor-times.component.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html index 717fac9603..e2123b30c3 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html @@ -100,8 +100,10 @@

Tutor Times Session Summary

(eventClicked)="eventClicked($event)" [tooltipTemplate]="eventTooltipTemplate" [hourDuration]="60" - [hourSegments]="1" + [hourSegments]="4" [weekStartsOn]="0" + [hourSegmentHeight]="15" + [minimumEventHeight]="5" [daysInWeek]="daysInWeek" (beforeViewRender)="beforeViewRender($event)" /> From 697daf26693f20f61dcfbbeb0597a02715c9512d Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 15 Oct 2025 16:41:55 +1100 Subject: [PATCH 0677/1280] fix: re-enable user filtering on click --- .../directives/analytics-tutor-times.component.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts index 7e99793801..a60a756699 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts @@ -120,8 +120,8 @@ export class AnalyticsTutorTimesComponent implements OnInit { applyFilters() { this.filteredEvents = this.events.filter( (e) => - (this.selectedUserId === null || e['user_id'] === this.selectedUserId) && - (!this.hideSessionsDuringTutorials || !e['duringTutorial']) && + (this.selectedUserId === null || e.userId === this.selectedUserId) && + (!this.hideSessionsDuringTutorials || !e.duringTutorial) && e.duration >= 1, ); } @@ -252,10 +252,10 @@ export class AnalyticsTutorTimesComponent implements OnInit { }); } - eventClicked({event}: {event: CalendarEvent}): void { - if (event['user_id'] !== undefined) { + eventClicked({event}: {event: SessionEvent}): void { + if (event.userId !== undefined) { if (this.selectedUserId === null) { - this.selectedUserId = Number(event['user_id']); + this.selectedUserId = Number(event.userId); } else { this.selectedUserId = null; } From 85518268d0720f88ed7844c9af4bf187a3c49a60 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 15 Oct 2025 16:52:45 +1100 Subject: [PATCH 0678/1280] refactor: migrate group members list (#1017) * refactor: init group members list migration * refactor: migrate group members list * chore: update loading text * chore: remove old component files --- src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire-angularjs.module.ts | 7 +- .../group-member-list.coffee | 58 ---------------- .../group-member-list.component.html | 55 +++++++++++++++ .../group-member-list.component.scss | 0 .../group-member-list.component.ts | 68 +++++++++++++++++++ .../group-member-list/group-member-list.scss | 6 -- .../group-member-list.tpl.html | 55 --------------- .../group-set-manager.tpl.html | 14 ++-- src/app/groups/groups.coffee | 1 - 10 files changed, 138 insertions(+), 128 deletions(-) delete mode 100644 src/app/groups/group-member-list/group-member-list.coffee create mode 100644 src/app/groups/group-member-list/group-member-list.component.html create mode 100644 src/app/groups/group-member-list/group-member-list.component.scss create mode 100644 src/app/groups/group-member-list/group-member-list.component.ts delete mode 100644 src/app/groups/group-member-list/group-member-list.scss delete mode 100644 src/app/groups/group-member-list/group-member-list.tpl.html diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 5396335ffe..ff8b001f19 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -280,6 +280,7 @@ const MY_DATE_FORMAT = { import {TutorialsComponent} from './projects/states/tutorials/tutorials.component'; import {UnitStudentEnrolmentModalComponent} from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component'; import {TaskStatusPieChartComponent} from './visualisations/task-status-pie-chart/taskstatuspiechart.component'; +import {GroupMemberListComponent} from './groups/group-member-list/group-member-list.component'; @NgModule({ // Components we declare @@ -409,6 +410,7 @@ import {TaskStatusPieChartComponent} from './visualisations/task-status-pie-char UnitStaffEditorComponent, GroupSetSelectorComponent, PortfolioGradeSelectStepComponent, + GroupMemberListComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index ade3d4e6d3..c3fe30e065 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -82,7 +82,6 @@ import 'build/src/app/groups/group-selector/group-selector.js'; import 'build/src/app/groups/group-set-manager/group-set-manager.js'; import 'build/src/app/groups/groups.js'; import 'build/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.js'; -import 'build/src/app/groups/group-member-list/group-member-list.js'; import 'build/src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.js'; import 'build/src/app/units/modals/modals.js'; import 'build/src/app/units/units.js'; @@ -223,6 +222,7 @@ import {PrivacyPolicy} from './config/privacy-policy/privacy-policy'; import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staff-editor/unit-staff-editor.component'; import {GroupSetSelectorComponent} from './groups/group-set-selector/group-set-selector.component'; import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component'; +import {GroupMemberListComponent} from './groups/group-member-list/group-member-list.component'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -530,3 +530,8 @@ DoubtfireAngularJSModule.directive( 'groupSetSelector', downgradeComponent({component: GroupSetSelectorComponent}), ); + +DoubtfireAngularJSModule.directive( + 'fGroupMemberList', + downgradeComponent({component: GroupMemberListComponent}), +); diff --git a/src/app/groups/group-member-list/group-member-list.coffee b/src/app/groups/group-member-list/group-member-list.coffee deleted file mode 100644 index ddb80ece67..0000000000 --- a/src/app/groups/group-member-list/group-member-list.coffee +++ /dev/null @@ -1,58 +0,0 @@ -angular.module('doubtfire.groups.group-member-list', []) - -# -# Lists members in a group -# -.directive('groupMemberList', -> - restrict: 'E' - templateUrl: 'groups/group-member-list/group-member-list.tpl.html' - scope: - unit: '=' - project: '=' - unitRole: '=' - selectedGroup: '=' - onMembersLoaded: '=?' - controller: ($scope, $timeout, gradeService, alertService, listenerService) -> - # Cleanup - listeners = listenerService.listenTo($scope) - - # Initial sort orders - $scope.tableSort = - order: 'student_name' - reverse: false - - # Table sorting - $scope.sortTableBy = (column) -> - $scope.tableSort.order = column - $scope.tableSort.reverse = !$scope.tableSort.reverse - - # Loading - startLoading = -> $scope.loaded = false - finishLoading = -> $timeout(-> - $scope.loaded = true - $scope.onMembersLoaded?() - , 500) - - # Initially not loaded - $scope.loaded = false - - # Remove group members - $scope.removeMember = (member) -> - $scope.selectedGroup.removeMember(member) - - # Listen for changes to group - listeners.push $scope.$watch "selectedGroup.id", (newGroupId) -> - return unless newGroupId? - startLoading() - $scope.canRemoveMembers = $scope.unitRole || ($scope.selectedGroup.groupSet.allowStudentsToManageGroups && !$scope.selectedGroup.locked) - - $scope.selectedGroup.getMembers().subscribe({ - next: (members) -> - finishLoading() - error: (failure) -> - $timeout((-> - alertService.error( "Unauthorised to view members in this group", 3000) - $scope.selectedGroup = null - ), 1000) - }) -) diff --git a/src/app/groups/group-member-list/group-member-list.component.html b/src/app/groups/group-member-list/group-member-list.component.html new file mode 100644 index 0000000000..8d334d5640 --- /dev/null +++ b/src/app/groups/group-member-list/group-member-list.component.html @@ -0,0 +1,55 @@ +@if (loading) { +
+ Loading members... +
+} @else if (selectedGroup.members.length === 0) { +
+ group_off +

There are no members in this group

+
+} @else { + + + + + + + + + + + + + + + + + + + + + + + +
{{ unitRole ? 'Student ID' : '' }} + @if (unitRole) { + {{ member.student.username || 'N/A' }} + } + Name + {{ member.student.name }} + {{ unitRole ? 'Target Grade' : '' }} + @if (unitRole) { + + } + {{ canRemoveMembers ? 'Actions' : '' }} + @if (canRemoveMembers) { + @if (!project && unitRole) { + + } @else if (project && project.id === member.id) { + + } + } +
+} diff --git a/src/app/groups/group-member-list/group-member-list.component.scss b/src/app/groups/group-member-list/group-member-list.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/groups/group-member-list/group-member-list.component.ts b/src/app/groups/group-member-list/group-member-list.component.ts new file mode 100644 index 0000000000..e7f0e9f312 --- /dev/null +++ b/src/app/groups/group-member-list/group-member-list.component.ts @@ -0,0 +1,68 @@ +import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import {MatTableDataSource} from '@angular/material/table'; +import {Subscription} from 'rxjs'; +import {Group, UnitRole} from 'src/app/api/models/doubtfire-model'; +import {Project} from 'src/app/api/models/project'; +import {Unit} from 'src/app/api/models/unit'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-group-member-list', + templateUrl: './group-member-list.component.html', + styleUrls: ['./group-member-list.component.scss'], +}) +export class GroupMemberListComponent implements OnInit, OnChanges { + @Input() unit: Unit; + @Input() unitRole: UnitRole; + @Input() project: Project; + @Input() selectedGroup: Group; + @Input() onMembersLoaded: () => void; + + loading = false; + + canRemoveMembers = false; + + displayedColumns: string[] = ['student_id', 'name', 'target_grade', 'actions']; + groupMembers: Project[] = []; + dataSource = new MatTableDataSource(); + + private groupMembersSub?: Subscription; + + constructor(private alertService: AlertService) {} + + ngOnInit() { + this.groupMembersSub = this.selectedGroup.projectsCache.values.subscribe((values) => { + this.dataSource.data = values; + }); + } + + public removeMember(member: Project) { + this.selectedGroup.removeMember(member); + } + + ngOnChanges(changes: SimpleChanges) { + if (changes['selectedGroup'] && this.selectedGroup) { + this.loading = true; + this.selectedGroup.getMembers().subscribe({ + next: (members) => { + this.loading = false; + this.onMembersLoaded(); + this.canRemoveMembers = + !!this.unitRole || + (this.selectedGroup.groupSet.allowStudentsToManageGroups && !this.selectedGroup.locked); + + this.dataSource.data = members; + + this.groupMembersSub?.unsubscribe(); + this.groupMembersSub = this.selectedGroup.projectsCache.values.subscribe((values) => { + this.dataSource.data = values; + }); + }, + error: (error) => { + this.alertService.error(`Failed to fetch group members: ${error}`, 6000); + this.selectedGroup = null; + }, + }); + } + } +} diff --git a/src/app/groups/group-member-list/group-member-list.scss b/src/app/groups/group-member-list/group-member-list.scss deleted file mode 100644 index 75fb259794..0000000000 --- a/src/app/groups/group-member-list/group-member-list.scss +++ /dev/null @@ -1,6 +0,0 @@ -group-member-list table { - th.student-id { width: 25%; } - th.student-name { width: 50%; } - th.actions { width: 25%; } - th.student-grade { width: 50%; } -} diff --git a/src/app/groups/group-member-list/group-member-list.tpl.html b/src/app/groups/group-member-list/group-member-list.tpl.html deleted file mode 100644 index 8c3b3c2dc5..0000000000 --- a/src/app/groups/group-member-list/group-member-list.tpl.html +++ /dev/null @@ -1,55 +0,0 @@ -
- Loading Members... -
-
-
-

No members in group

-

There are no members in this group

-
-
- - - - - - - - - - - - - - - - - -
- - Student ID - - - - - Name - - - - - Target Grade - - - - Actions -
{{member.student.username || "N/A"}}{{member.student.name}} - - - - -
diff --git a/src/app/groups/group-set-manager/group-set-manager.tpl.html b/src/app/groups/group-set-manager/group-set-manager.tpl.html index 09386b1daa..da022a0b37 100644 --- a/src/app/groups/group-set-manager/group-set-manager.tpl.html +++ b/src/app/groups/group-set-manager/group-set-manager.tpl.html @@ -56,13 +56,13 @@

- - +
diff --git a/src/app/groups/groups.coffee b/src/app/groups/groups.coffee index 391a78d492..3d4534d754 100644 --- a/src/app/groups/groups.coffee +++ b/src/app/groups/groups.coffee @@ -1,6 +1,5 @@ angular.module('doubtfire.groups', [ 'doubtfire.groups.group-member-contribution-assigner' - 'doubtfire.groups.group-member-list' 'doubtfire.groups.group-selector' 'doubtfire.groups.group-set-manager' ]) From 7ea20939f45b013a56cc3405faaf0855ebe9926a Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Thu, 16 Oct 2025 15:18:48 +1100 Subject: [PATCH 0679/1280] refactor: collapse related tutorial list --- .../task-definition-who.component.html | 37 ++++++++++++++++--- .../task-definition-who.component.ts | 5 +++ 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html index 814e814197..5d93345d7f 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html @@ -13,7 +13,11 @@
Tutorial Stream - Which tutor provides feedback? - + @for (stream of unit.tutorialStreams; track stream) { {{ stream.name }} } @@ -23,11 +27,32 @@ Related tutorials
    - @for (tutorial of taskDefinition.tutorialStream?.tutorialsIn(unit); track tutorial) { -
  • - {{ tutorial?.abbreviation }} {{ tutorial.tutor?.name }} -
  • -} + @for ( + tutorial of taskDefinition.tutorialStream?.tutorialsIn(unit) + | slice: 0 : (showAllTutorials ? undefined : 3); + track tutorial + ) { +
  • {{ tutorial?.abbreviation }} {{ tutorial.tutor?.name }}
  • + } + + @if (!showAllTutorials && taskDefinition.tutorialStream?.tutorialsIn(unit)?.length > 3) { +
  • + +{{ taskDefinition.tutorialStream.tutorialsIn(unit).length - 3 }} more tutorials +
  • + } + @if (taskDefinition.tutorialStream?.tutorialsIn(unit).length > 3) { +
    + @if (!showAllTutorials) { + + } @else { + + } +
    + }
diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts index 9732998592..53c87c7bf1 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts @@ -10,7 +10,12 @@ import { Unit } from 'src/app/api/models/unit'; export class TaskDefinitionWhoComponent { @Input() taskDefinition: TaskDefinition; + showAllTutorials: boolean = false; public get unit(): Unit { return this.taskDefinition?.unit; } + + onTutorialStreamChange() { + this.showAllTutorials = false; + } } From 4384b376eaedf8ab66febec4c0ada53111311ff0 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Fri, 17 Oct 2025 09:38:43 +1100 Subject: [PATCH 0680/1280] feat: campus timezone (#1022) --- .../campus-list/campus-list.component.html | 24 +++++++++++++++++++ .../campus-list/campus-list.component.ts | 4 +++- src/app/api/models/campus/campus.ts | 1 + src/app/api/services/campus.service.ts | 2 +- 4 files changed, 29 insertions(+), 2 deletions(-) diff --git a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html index 3fe38272ec..6fed39bc24 100644 --- a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html +++ b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html @@ -83,6 +83,30 @@

Campuses

+ + + Timezone + + @if (!editing(campus)) { +
+ {{ campus.timezone }} +
+ } @else { + + Timezone + + + + } + + + + Timezone + + + +
+ Active diff --git a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts index 3ab6b9e71e..1fa8871cc3 100644 --- a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts +++ b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts @@ -18,7 +18,7 @@ export class CampusListComponent extends EntityFormComponent { syncModes = ['timetable', 'automatic', 'manual']; // Set up the table - columns: string[] = ['name', 'abbreviation', 'mode', 'active', 'options']; + columns: string[] = ['name', 'abbreviation', 'mode', 'timezone', 'active', 'options']; campuses: Campus[] = new Array(); dataSource = new MatTableDataSource(this.campuses); @@ -33,6 +33,7 @@ export class CampusListComponent extends EntityFormComponent { abbreviation: new UntypedFormControl('', [Validators.required]), name: new UntypedFormControl('', [Validators.required]), mode: new UntypedFormControl('', [Validators.required]), + timezone: new UntypedFormControl('', [Validators.required]), active: new UntypedFormControl(false), }, 'Campus', @@ -91,6 +92,7 @@ export class CampusListComponent extends EntityFormComponent { case 'name': case 'abbreviation': case 'mode': + case 'timezone': case 'active': return super.sortTableData(sort); } diff --git a/src/app/api/models/campus/campus.ts b/src/app/api/models/campus/campus.ts index 164b3704f6..9491e29e53 100644 --- a/src/app/api/models/campus/campus.ts +++ b/src/app/api/models/campus/campus.ts @@ -7,6 +7,7 @@ export class Campus extends Entity { name: string; mode: campusModes; abbreviation: string; + timezone: string; public override toJson(mappingData: EntityMapping, ignoreKeys?: string[]): object { return { diff --git a/src/app/api/services/campus.service.ts b/src/app/api/services/campus.service.ts index ddf3e95942..d46d793cc3 100644 --- a/src/app/api/services/campus.service.ts +++ b/src/app/api/services/campus.service.ts @@ -11,7 +11,7 @@ export class CampusService extends CachedEntityService { constructor(httpClient: HttpClient) { super(httpClient, API_URL); - this.mapping.addKeys('id', 'name', 'mode', 'abbreviation', 'active'); + this.mapping.addKeys('id', 'name', 'mode', 'abbreviation', 'active', 'timezone'); this.mapping.mapAllKeysToJsonExcept('id'); } From 1b08535443ffc7723d018c518cf7d77b12920a0e Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 17 Oct 2025 10:08:20 +1100 Subject: [PATCH 0681/1280] refactor: enable marking sessions calendar for tutors --- .../analytics-tutor-times.component.html | 21 +++++++++++-------- .../analytics-tutor-times.component.ts | 4 ++++ .../unit-analytics-route.component.html | 4 +--- .../unit-analytics-route.component.ts | 2 +- 4 files changed, 18 insertions(+), 13 deletions(-) diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html index e2123b30c3..d826a68de2 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html @@ -5,15 +5,18 @@

Tutor Times Session Summary

- + @if (role === 'Convenor') { + + } +
diff --git a/src/app/units/states/analytics/unit-analytics-route.component.ts b/src/app/units/states/analytics/unit-analytics-route.component.ts index 73419c4dfe..4c8e068722 100644 --- a/src/app/units/states/analytics/unit-analytics-route.component.ts +++ b/src/app/units/states/analytics/unit-analytics-route.component.ts @@ -61,7 +61,7 @@ export class UnitAnalyticsComponent { ); } - private downloadCsv(newJob: Observable, title: string, filename: string) { + public downloadCsv(newJob: Observable, title: string, filename: string) { newJob.subscribe({ next: (job) => { if (!job || !job.id) { From b972dde2047172cc45f1756d866e07f54c8a355d Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 17 Oct 2025 12:00:03 +1100 Subject: [PATCH 0682/1280] chore(release): 10.0.0-52 --- CHANGELOG.md | 15 +++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 08159fda97..e1c0f0d73d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-52](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-51...v10.0.0-52) (2025-10-17) + + +### Features + +* campus timezone ([#1022](https://github.com/b0ink/doubtfire-deploy/issues/1022)) ([4384b37](https://github.com/b0ink/doubtfire-deploy/commit/4384b376eaedf8ab66febec4c0ada53111311ff0)) +* download marking sessions for tutor ([e3fbe44](https://github.com/b0ink/doubtfire-deploy/commit/e3fbe4404661eb16b9c0e5ba19a1369dac1fb5b0)) + + +### Bug Fixes + +* display tutor name ([8956020](https://github.com/b0ink/doubtfire-deploy/commit/89560205d7316c53d77f376b5f7cfff5bf99e9c6)) +* filter out students from unit staff editor ([#1018](https://github.com/b0ink/doubtfire-deploy/issues/1018)) ([5c0c997](https://github.com/b0ink/doubtfire-deploy/commit/5c0c9974569e720a6c95aa8333c2a38d0ab4a1b0)) +* re-enable user filtering on click ([697daf2](https://github.com/b0ink/doubtfire-deploy/commit/697daf26693f20f61dcfbbeb0597a02715c9512d)) + ## [10.0.0-51](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-50...v10.0.0-51) (2025-10-14) diff --git a/package-lock.json b/package-lock.json index 38c5bd3f5f..5a2e04aac3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-51", + "version": "10.0.0-52", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-51", + "version": "10.0.0-52", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index d45df0c039..3356d560a7 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-51", + "version": "10.0.0-52", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 3b684a3395c9ccdfb412ff439a08e2ab88f808d7 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:50:45 +1100 Subject: [PATCH 0683/1280] refactor: include all submitted tasks in portfolio task list (#1023) * refactor: include all submitted tasks in portfolio task list * refactor: fetch tasks included in portfolio from api * refactor: reword * refactor: reword * refactor: show warning if no tasks found * refactor: wording * refactor: add error alert --- src/app/api/models/project.ts | 9 +++++ src/app/doubtfire-angular.module.ts | 2 ++ src/app/doubtfire-angularjs.module.ts | 6 ++++ .../portfolio-included-tasks.component.html | 26 ++++++++++++++ .../portfolio-included-tasks.component.scss | 0 .../portfolio-included-tasks.component.ts | 36 +++++++++++++++++++ .../portfolio-review-step.tpl.html | 22 +++++------- .../states/portfolio/portfolio.coffee | 2 +- 8 files changed, 89 insertions(+), 14 deletions(-) create mode 100644 src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.html create mode 100644 src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.scss create mode 100644 src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.ts diff --git a/src/app/api/models/project.ts b/src/app/api/models/project.ts index 1064fb3c5b..df3c3cda26 100644 --- a/src/app/api/models/project.ts +++ b/src/app/api/models/project.ts @@ -528,4 +528,13 @@ export class Project extends Entity { }), ); } + + public tasksIncludedInPortfolioUrl(): string { + return `${AppInjector.get(DoubtfireConstants).API_URL}/projects/${this.id}/portfolio_tasks`; + } + + public getTasksIncludedInPortfolio(): Observable { + const httpClient = AppInjector.get(HttpClient); + return httpClient.get(this.tasksIncludedInPortfolioUrl()); + } } diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 47e4679234..12f65dc8a5 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -293,6 +293,7 @@ import {UnitDetailsEditorComponent} from './units/states/edit/directives/unit-de import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component'; import {AnalyticsTutorTimesComponent} from './units/states/analytics/directives/analytics-tutor-times.component'; import {MarkingSessionService} from './api/services/marking-session.service'; +import {PortfolioIncludedTasksComponent} from './projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { @@ -446,6 +447,7 @@ const MY_DATE_FORMAT = { UnitDetailsEditorComponent, PortfolioGradeSelectStepComponent, AnalyticsTutorTimesComponent, + PortfolioIncludedTasksComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 963bf7d209..886886135c 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -230,6 +230,7 @@ import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staf import {GroupSetSelectorComponent} from './groups/group-set-selector/group-set-selector.component'; import {UnitDetailsEditorComponent} from './units/states/edit/directives/unit-details-editor/unit-details-editor.component'; import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component'; +import {PortfolioIncludedTasksComponent} from './projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component'; export const DoubtfireAngularJSModule = angular .module('doubtfire', [ @@ -557,3 +558,8 @@ DoubtfireAngularJSModule.directive( 'groupSetSelector', downgradeComponent({component: GroupSetSelectorComponent}), ); + +DoubtfireAngularJSModule.directive( + 'fPortfolioIncludedTasks', + downgradeComponent({component: PortfolioIncludedTasksComponent}), +); diff --git a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.html b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.html new file mode 100644 index 0000000000..7444d7176c --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.html @@ -0,0 +1,26 @@ +@if (loading) { +
+
Loading tasks...
+ +
+} @else { + @if (tasksInPortfolio.length === 0) { +
+ assignment_late +

No tasks found

+
+ } @else { +
    + @for (task of tasksInPortfolio; track task) { +
  1. +
    +
    +
    {{ task.definition.abbreviation }} — {{ task.definition.name }}
    +
    + +
    +
  2. + } +
+ } +} diff --git a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.scss b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.ts b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.ts new file mode 100644 index 0000000000..e425d93976 --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.ts @@ -0,0 +1,36 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {Project} from 'src/app/api/models/project'; +import {Task} from 'src/app/api/models/task'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-portfolio-included-tasks', + templateUrl: 'portfolio-included-tasks.component.html', + styleUrls: ['portfolio-included-tasks.component.scss'], +}) +export class PortfolioIncludedTasksComponent implements OnInit { + @Input() project: Project; + + constructor(private alertService: AlertService) {} + + loading: boolean = false; + + tasksInPortfolio: Task[] = []; + ngOnInit() { + this.loading = true; + this.project.getTasksIncludedInPortfolio().subscribe({ + next: (tasks) => { + for (const taskId of tasks) { + const task = this.project.tasks.find((t) => t.id === taskId); + if (task) { + this.tasksInPortfolio.push(task); + } + } + this.loading = false; + }, + error: (error) => { + this.alertService.error(`Failed to get tasks for portfolio: ${error}`, 6000); + }, + }); + } +} diff --git a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.tpl.html b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.tpl.html index ba23ed6f53..00dffc0906 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.tpl.html +++ b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.tpl.html @@ -51,19 +51,15 @@

Portfolio Processing

  • {{file.name}}
  • -
    -

    - You have included {{selectedTasks().length}} tasks in your portfolio. If you wish to add or - remove some of these tasks, please review the Select Tasks step to adjust your alignments of each - task to the unit's learning outcomes. Each task will be attached in the order below: -

    -
      -
    1. - - {{task.definition.name}} -
    2. -
    -
    +

    + Only submitted tasks will be included in your portfolio. If a task is missing from the list, + ensure that you have submitted it before compiling your portfolio. All feedback and comments + for each task will appear in the final portfolio, so you can add any additional comments now + if there's something you'd like to address. +

    The following tasks will be included + automatically in this order:

    +

    +
    diff --git a/src/app/projects/states/portfolio/portfolio.coffee b/src/app/projects/states/portfolio/portfolio.coffee index 63e93ea961..01b6bf8972 100644 --- a/src/app/projects/states/portfolio/portfolio.coffee +++ b/src/app/projects/states/portfolio/portfolio.coffee @@ -82,7 +82,7 @@ angular.module('doubtfire.projects.states.portfolio', [ # Gets selected tasks in the task selector $scope.selectedTasks = -> # Filter by included in portfolio - tasks = _.filter $scope.project.tasks, (t) -> t.includeInPortfolio + tasks = $scope.project.tasks tasks = _.filter tasks, (t) -> !_.includes(newTaskService.toBeWorkedOn, t.status) _.sortBy tasks, (t) -> t.definition.seq From ea42bd63d82f082689bc860b53f43b4ffb5f50e8 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 17 Oct 2025 13:52:04 +1100 Subject: [PATCH 0684/1280] chore(release): 10.0.0-53 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1c0f0d73d..0d250861d3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-53](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-52...v10.0.0-53) (2025-10-17) + ## [10.0.0-52](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-51...v10.0.0-52) (2025-10-17) diff --git a/package-lock.json b/package-lock.json index 5a2e04aac3..e94c4152ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-52", + "version": "10.0.0-53", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-52", + "version": "10.0.0-53", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 3356d560a7..52bf9d5075 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-52", + "version": "10.0.0-53", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From b67810743c18b4f178a07421f0c9acde6b8b989a Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 17 Oct 2025 14:20:52 +1100 Subject: [PATCH 0685/1280] refactor: number list --- .../portfolio-welcome-step/portfolio-welcome-step.tpl.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.tpl.html b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.tpl.html index 524101329b..51297a7060 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.tpl.html +++ b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.tpl.html @@ -4,10 +4,9 @@

    Portfolio Preparation

    Preparing your portfolio involves 5 steps:

    -
      +
      1. Select your Grade you are applying for
      2. Upload your Learning Summary Report
      3. -
      4. Select the Tasks you want included
      5. Upload any Other Resources you want to add
      6. Compile your resources into your portfolio and review
      From 2eec7ce1ecc229f672e7f02a27c76ffce4f45291 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 17 Oct 2025 15:10:13 +1100 Subject: [PATCH 0686/1280] chore: add margin --- .../portfolio-welcome-step/portfolio-welcome-step.tpl.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.tpl.html b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.tpl.html index 51297a7060..cb062284f1 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.tpl.html +++ b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.tpl.html @@ -4,7 +4,7 @@

      Portfolio Preparation

    Preparing your portfolio involves 5 steps:

    -
      +
      1. Select your Grade you are applying for
      2. Upload your Learning Summary Report
      3. Upload any Other Resources you want to add
      4. From 3b225388981272f14ab2f2f17af1df8be10ecbcc Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 17 Oct 2025 15:11:05 +1100 Subject: [PATCH 0687/1280] chore(release): 10.0.0-54 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0d250861d3..f710943bd7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-54](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-53...v10.0.0-54) (2025-10-17) + ## [10.0.0-53](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-52...v10.0.0-53) (2025-10-17) ## [10.0.0-52](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-51...v10.0.0-52) (2025-10-17) diff --git a/package-lock.json b/package-lock.json index e94c4152ee..7b09dfd70d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-53", + "version": "10.0.0-54", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-53", + "version": "10.0.0-54", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 52bf9d5075..6eb504c354 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-53", + "version": "10.0.0-54", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 8a1dd1ac806c5acbbf8d1ccf7bdcb6af1c68dd14 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 17 Oct 2025 15:23:49 +1100 Subject: [PATCH 0688/1280] fix: typo --- .../analytics/directives/analytics-tutor-times.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts index b8d6ac3574..b9606b7fc7 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts @@ -197,7 +197,7 @@ export class AnalyticsTutorTimesComponent implements OnInit { tz, ), 'My Marking Sessions CSV', - `${this.unit.code}-${this.userService.currentUser.name}-sessions-${start}-to-${end}-${tz}}.csv`, + `${this.unit.code}-${this.userService.currentUser.name}-sessions-${start}-to-${end}-${tz}.csv`, ); } From c49ffeddedb2b79c39252770692e7df9dcd97bfc Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Sun, 19 Oct 2025 13:02:30 +1100 Subject: [PATCH 0689/1280] fix: display correct marking session details --- .../analytics/directives/analytics-tutor-times.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html index d826a68de2..dbd2f4302a 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html @@ -82,8 +82,8 @@

        Tutor Times Session Summary

        >
        {{ event.startHour }} — {{ event.endHour }}
        Assessments: {{ event.assessments || 0 }}
        - Comments: {{ event.comments_added || 0 }}
        - Submissions opened: {{ event.submissions_opened || 0 }}
        + Comments: {{ event.commentsAdded || 0 }}
        + Submissions opened: {{ event.submissionsOpened || 0 }}
        During Tutorial?: {{ event.duringTutorial ? 'yes' : 'no' }}
    From 3858e3792fef3f0542d954e213987484ac97a990 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 20 Oct 2025 13:06:08 +1100 Subject: [PATCH 0690/1280] feat: display task count in inbox (#1025) * feat: display number of tasks in inbox * chore: only display task count if not empty --- .../directives/staff-task-list/staff-task-list.component.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.html b/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.html index 2291a5e7a6..2a36a9704f 100644 --- a/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.html +++ b/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.html @@ -200,6 +200,9 @@ @if (filteredTasks) { + @if (filteredTasks.length) { +
    {{ filteredTasks.length }} Tasks
    + } Date: Mon, 20 Oct 2025 16:22:26 +1100 Subject: [PATCH 0691/1280] refactor: scrollable calendar (#1027) --- .../analytics-tutor-times.component.scss | 16 ++++++++++++++++ .../analytics-tutor-times.component.ts | 4 ++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.scss b/src/app/units/states/analytics/directives/analytics-tutor-times.component.scss index e69de29bb2..2ce45fc98d 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.scss +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.scss @@ -0,0 +1,16 @@ +.cal-week-view { + position: relative; + max-height: 750px; + overflow-y: scroll; + overscroll-behavior: contain; +} + +.cal-day-headers { + position: sticky; + top: 0; + right: 0; + z-index: 2; + background-color: white; + width: 100%; + min-height: 35px; +} diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts index b9606b7fc7..9b65234bbd 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts @@ -1,6 +1,5 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {Component, Input, OnInit, ViewEncapsulation} from '@angular/core'; import {MatDatepickerInputEvent} from '@angular/material/datepicker'; -import {CalendarEvent} from 'angular-calendar'; import {Observable} from 'rxjs'; import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; import {Unit} from 'src/app/api/models/unit'; @@ -32,6 +31,7 @@ interface SessionEvent { selector: 'f-analytics-tutor-times', templateUrl: 'analytics-tutor-times.component.html', styleUrls: ['analytics-tutor-times.component.scss'], + encapsulation: ViewEncapsulation.None, }) export class AnalyticsTutorTimesComponent implements OnInit { @Input() unit: Unit; From f751ef30a66f4ff3638252443737767441795e1e Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 20 Oct 2025 17:32:47 +1100 Subject: [PATCH 0692/1280] chore(release): 10.0.0-55 --- CHANGELOG.md | 13 +++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f710943bd7..22fec1df51 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-55](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-54...v10.0.0-55) (2025-10-20) + + +### Features + +* display task count in inbox ([#1025](https://github.com/b0ink/doubtfire-deploy/issues/1025)) ([3858e37](https://github.com/b0ink/doubtfire-deploy/commit/3858e3792fef3f0542d954e213987484ac97a990)) + + +### Bug Fixes + +* display correct marking session details ([c49ffed](https://github.com/b0ink/doubtfire-deploy/commit/c49ffeddedb2b79c39252770692e7df9dcd97bfc)) +* typo ([8a1dd1a](https://github.com/b0ink/doubtfire-deploy/commit/8a1dd1ac806c5acbbf8d1ccf7bdcb6af1c68dd14)) + ## [10.0.0-54](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-53...v10.0.0-54) (2025-10-17) ## [10.0.0-53](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-52...v10.0.0-53) (2025-10-17) diff --git a/package-lock.json b/package-lock.json index 7b09dfd70d..1a5c744864 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-54", + "version": "10.0.0-55", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-54", + "version": "10.0.0-55", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 6eb504c354..d9ba47fd69 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-54", + "version": "10.0.0-55", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From a4aa3525d07868d6085f331adbac481a86313291 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Tue, 21 Oct 2025 13:16:52 +1100 Subject: [PATCH 0693/1280] refactor: require comment for assess in portfolio tasks submitting for feedback (#1026) * refactor: require comment for assess in portfolio tasks submitting for feedback * chore: fix comment * chore: fix indentation * fix: condition * chore: update character count text color * chore: add tooltip --- .../upload-submission-modal.coffee | 10 ++++---- .../upload-submission-modal.tpl.html | 24 ++++++++++--------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee index 486ae9bcbb..b6bcd6b50e 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee @@ -70,6 +70,8 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) $scope.uploader.payload.contributions = mapTeamToPayload() if _.includes(states.shown, 'group') $scope.uploader.payload.trigger = 'need_help' if $scope.submissionType == 'need_help' $scope.uploader.payload.trigger = 'assess_in_portfolio' if $scope.submissionType == 'assess_in_portfolio' || $scope.task.status == 'assess_in_portfolio' + if $scope.comment? and $scope.comment.trim() isnt '' + $scope.uploader.payload.comment = $scope.comment onSuccess: (response) -> # Ensure our response contains the data we're expecting if typeof response is 'object' and response? and response.id? and response.project_id? and response.status? @@ -88,9 +90,9 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) onComplete: -> return unless $scope.uploader.response? and $scope.uploader.response.id? $modalInstance.close(task) - unless $scope.task.isTestSubmission + # unless $scope.task.isTestSubmission # Add comment if requested - task.addComment($scope.comment) if $scope.comment.trim().length > 0 + # task.addComment($scope.comment) if $scope.comment.trim().length > 0 # Broadcast that upload is complete $rootScope.$broadcast('TaskSubmissionUploadComplete', task) # Perform as timeout to show 'Upload Complete' @@ -176,8 +178,8 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) back: -> false submit: -> - # Disable if no comment is supplied with need_help - !$scope.uploader.isReady || ($scope.comment.trim().length == 0 && $scope.submissionType == 'need_help') + # Disable if no comment is supplied with need_help, or if submitting for feedback and task is assess in portfolio only + !$scope.uploader.isReady or ($scope.comment.trim().length < 25 && ($scope.submissionType == 'ready_for_feedback' && $scope.task.definition.assessInPortfolioOnly) || $scope.submissionType == 'need_help') cancel: -> # Can't cancel whilst uploading $scope.uploader.isUploading diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html index 89067b9b11..49fb538af6 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html @@ -83,23 +83,25 @@

    ng-class="{'state-hidden-left': isHidden('comments').left, 'state-hidden-right': isHidden('comments').right}">
    -
    -

    - What do you need help with? -

    -

    - Final comments -

    - +
    +

    What do you need help with?

    + Supply a comment on what you would like help on for this task so your tutor can assist you. - +
    +
    +

    Final comments

    + + Please supply a comment specifying which areas of your submission you would like feedback on. + + Supply an optional comment about this submission for your tutor to read as they assess.
    - +
    Character count: {{comment.length}} (Min. 25)
    @@ -138,7 +140,7 @@

    Plagiarism and Collusion

    - From 32e03d111e61df42a9c67cb9e68d271f9300d5bc Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 23 Oct 2025 22:12:12 +1100 Subject: [PATCH 0694/1280] fix: ensure grade has been selected --- .../portfolio-grade-select-step.component.html | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html index 63385d6e5d..575a9f5faf 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html @@ -86,7 +86,11 @@

    Select Grade

    +
    + } +
    + @if (unitRole) { +
    + + All Tutorials + My Tutorials + +
    + } +

    + + + @if (selectedGroupSet && selectedGroupSet.groups.length === 0) { +
    + group_off +

    There are no groups in this set

    +
    + } @else { + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Name + @if (editing(group)) { + + + + } @else { + {{ group.name || 'Not set' }} + } + Tutorial + @if (editing(group)) { + + + @for (tutorial of unit.tutorials; track tutorial) { + {{ tutorial.abbreviation }} + } + + + } @else { + {{ group.tutorial.abbreviation }} + } + + @if (unitRole) { + Capacity Adjustment + } + + @if (unitRole) { + @if (editing(group)) { + + + + } @else { + {{ group.capacityAdjustment }} + } + } + Capacity + @if (group.hasSpace()) { + Available + } @else { + Full + } + + @if (unitRole || (project && selectedGroupSet.allowStudentsToManageGroups)) { + Actions + } + + @if (project && group.hasSpace() && selectedGroupSet.allowStudentsToManageGroups) { +
    + @if (!group.locked && !selectedGroupSet.locked) { + + } @else { + lock + } +
    + } + @if (unitRole) { +
    + @if (editing(group)) { +
    + + +
    + } @else { + + + + } +
    + } +
    + + } + + @if (selectedGroupSet.keepGroupsInSameClass && selectedGroupSet.groups.length > 0 && !unitRole) { +

    + Can't see the group you need to join? Groups shown are limited to those in your allocated + tutorials. Use the + Tutorial List to check and update + your tutorial enrolment if needed. +

    + } + diff --git a/src/app/groups/group-selector/group-selector.component.scss b/src/app/groups/group-selector/group-selector.component.scss new file mode 100644 index 0000000000..200fdfce50 --- /dev/null +++ b/src/app/groups/group-selector/group-selector.component.scss @@ -0,0 +1,9 @@ +.mat-mdc-row .mat-mdc-cell { + border-bottom: 1px solid transparent; + border-top: 1px solid transparent; + cursor: pointer; +} + +.mat-mdc-row:hover { + background-color: #eee; +} diff --git a/src/app/groups/group-selector/group-selector.component.ts b/src/app/groups/group-selector/group-selector.component.ts new file mode 100644 index 0000000000..f0fc2b3615 --- /dev/null +++ b/src/app/groups/group-selector/group-selector.component.ts @@ -0,0 +1,264 @@ +import { + AfterViewInit, + Component, + Input, + OnChanges, + OnInit, + SimpleChanges, + ViewChild, +} from '@angular/core'; +import {UntypedFormControl, Validators} from '@angular/forms'; +import {MatButtonToggleChange} from '@angular/material/button-toggle'; +import {MatPaginator} from '@angular/material/paginator'; +import {MatTableDataSource} from '@angular/material/table'; +import {Subscription} from 'rxjs'; +import {Group, GroupSet, UnitRole, UserService} from 'src/app/api/models/doubtfire-model'; +import {Project} from 'src/app/api/models/project'; +import {Unit} from 'src/app/api/models/unit'; +import {GroupService} from 'src/app/api/services/group.service'; +import {EntityFormComponent} from 'src/app/common/entity-form/entity-form.component'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-group-selector', + templateUrl: './group-selector.component.html', + styleUrls: ['./group-selector.component.scss'], +}) +export class GroupSelectorComponent + extends EntityFormComponent + implements OnInit, OnChanges, AfterViewInit +{ + @Input() unit: Unit; + @Input() unitRole: UnitRole; + @Input() project: Project; + @Input() selectedGroup: Group; + @Input() selectedGroupSet: GroupSet; + @Input() onSelect: (group: Group) => void; + + @ViewChild(MatPaginator) paginator!: MatPaginator; + displayedColumns: string[] = ['name', 'tutorial', 'capacity_adjustment', 'capacity', 'actions']; + public groups: Group[] = []; + + public newGroupName: string; + public staffTutorialFilter: 'all' | 'mine' = 'all'; + + private groupsSub?: Subscription; + + constructor( + private userService: UserService, + private groupService: GroupService, + private alertService: AlertService, + ) { + super( + { + name: new UntypedFormControl('', [Validators.required]), + tutorial: new UntypedFormControl(null, [Validators.required]), + capacityAdjustment: new UntypedFormControl('', [Validators.required]), + }, + 'Group', + ); + } + + public get showGroupSetSelector() { + return this.unit.groupSets.length > 1; + } + + ngOnInit(): void { + if (this.unit.groupSets.length > 0) { + this.selectedGroupSet = this.unit.groupSets[0]; + } + } + + selectGroupSet(groupSet: GroupSet) { + this.selectedGroupSet = groupSet; + this.refreshGroups(); + } + + ngAfterViewInit() { + this.dataSource = new MatTableDataSource(); + this.dataSource.paginator = this.paginator; + + if (this.unit.groupSets.length > 0) { + this.selectedGroupSet = this.unit.groupSets[0]; + } + + this.refreshGroups(); + } + + refreshGroups() { + this.groupsSub?.unsubscribe(); + this.groupsSub = this.selectedGroupSet.groupsCache.values.subscribe((values) => { + this.groups = [...values]; + }); + this.applyFilters(); + } + + onGroupNameChange() { + this.applyFilters(); + } + + applyFilters() { + const filteredGroups = this.groups + .filter( + (g) => + this.staffTutorialFilter === 'all' || + (this.unitRole && g.tutorial.tutor.id === this.unitRole.user.id), + ) + .filter( + (g) => !this.newGroupName || g.name.toLowerCase().includes(this.newGroupName.toLowerCase()), + ); + + this.dataSource.data = filteredGroups.sort((a, b) => a.name.localeCompare(b.name)); + } + + ngOnChanges(changes: SimpleChanges) { + if (changes['selectedGroupSet'] && this.selectedGroupSet) { + if (!this.dataSource) { + this.dataSource = new MatTableDataSource(); + } + this.refreshGroups(); + } + } + + onTutorialFilterChange(event: MatButtonToggleChange) { + this.staffTutorialFilter = event.value; + this.applyFilters(); + } + + addGroup(name: string) { + if (this.unit.tutorials.length == 0) { + this.alertService.error( + `Please ensure there is at least one tutorial before groups are created`, + 6000, + ); + return; + } + let tutorialId = -1; + if (this.project) { + tutorialId = this.project.tutorials[0].id || this.unit.tutorials[0].id; + } else { + const tutorName = this.unitRole?.user.name || this.userService.currentUser.name; + tutorialId = + this.unit.tutorials.find((t) => t.tutor?.name === tutorName)?.id ?? + this.unit.tutorials[0].id; + } + + this.groupService + .create( + { + unitId: this.unit.id, + groupSetId: this.selectedGroupSet.id, + }, + { + cache: this.selectedGroupSet.groupsCache, + constructorParams: this.unit, + body: { + group: { + name, + tutorial_id: tutorialId, + }, + }, + }, + ) + .subscribe({ + next: (group) => { + this.alertService.success('Successfully created group', 3000); + this.selectedGroup = group; + this.newGroupName = ''; + this.applyFilters(); + }, + error: (error) => { + this.alertService.error(`Failed to create group: ${error}`); + }, + }); + } + + isPartOfGroup(project: Project, group: Group) { + return project.inGroup(group); + } + + joinGroup(group: Group) { + if (!this.project) { + return; + } + + if (this.isPartOfGroup(this.project, group)) { + this.alertService.error('You are already member of this group'); + return; + } + + group.addMember(this.project, () => { + this.selectedGroup = group; + this.selectGroup(group); + }); + } + + selectGroup(group: Group) { + if (this.project && !this.project.inGroup(group)) { + // Return because we're in the student view + return; + } + + if (this.editing(group)) { + return; + } + + this.selectedGroup = group; + this.onSelect(group); + } + + deleteGroup(event: Event, group: Group) { + event.stopPropagation(); + + this.groupService.delete(group, {cache: this.selectedGroupSet.groupsCache}).subscribe({ + next: () => { + this.alertService.success('Deleted group', 3000); + if (group.id === this.selectedGroup?.id) { + this.selectedGroup = null; + this.selectGroup(null); + } + }, + error: (error) => { + this.alertService.error(`Failed to delete group: ${error}`, 6000); + }, + }); + } + + toggleLocked(event: Event, group: Group) { + event.stopPropagation(); + + const originalLockedState = group.locked; + group.locked = !group.locked; + + this.groupService.update(group).subscribe({ + next: (success) => { + group.locked = success.locked; + this.alertService.success(`Group has been ${!group.locked ? 'un' : ''}locked`, 3000); + }, + error: (error) => { + this.alertService.error(`Failed to ${!group.locked ? 'un' : ''}lock group: ${error}`, 6000); + group.locked = originalLockedState; + }, + }); + } + + startEditGroup(event: Event, group: Group) { + event.stopPropagation(); + this.flagEdit(group); + } + + cancelEditGroup(event: Event) { + event.stopPropagation(); + this.cancelEdit(); + } + + saveEdit(event: Event) { + event.stopPropagation(); + super.submit(this.groupService, this.alertService, this.onSuccess.bind(this)); + this.cancelEdit(); + } + + onSuccess(): void { + this.refreshGroups(); + } +} diff --git a/src/app/groups/group-selector/group-selector.scss b/src/app/groups/group-selector/group-selector.scss deleted file mode 100644 index c176bf951a..0000000000 --- a/src/app/groups/group-selector/group-selector.scss +++ /dev/null @@ -1,45 +0,0 @@ -group-selector { - display: block; -} -group-selector table { - th.name { - width: 25%; - } - th.tutorial { - width: 15%; - } - th.capacity_adjustment { - width: 15%; - } - th.capacity { - width: 15%; - } - th.actions { - width: 25%; - } -} -group-selector .panel-title > group-set-selector { - display: inline-block; - max-width: 50%; - padding-left: 1ex; -} -@media (max-width: $screen-md) { - group-selector .input-group.staff-filter { - margin-bottom: 1em; - &, - .btn-group { - width: 100%; - } - .btn { - width: 50%; - } - } -} - -.lockButton { - width: 70px; -} - -.joinButton { - width: 70px; -} diff --git a/src/app/groups/group-selector/group-selector.tpl.html b/src/app/groups/group-selector/group-selector.tpl.html deleted file mode 100644 index e0a9446a14..0000000000 --- a/src/app/groups/group-selector/group-selector.tpl.html +++ /dev/null @@ -1,220 +0,0 @@ -
    -

    - Groups for - {{selectedGroupSet.name}} - - -

    -
    - -
    -
    -
    -
    - - -
    -
    - -
    - - - - -
    - -
    -
    - -
    Loading Groups...
    - -
    -
    -

    No Groups To Show

    -

    - There are no groups available for {{selectedGroupSet.name}}{{staffFilter == 'mine' || - selectedGroupSet.keepGroupsInSameClass ? " in your tutorials." : ""}}{{newGroupName.length > 0 ? " with name " + newGroupName + "." : "."}} -

    -

    - Please make sure that you are enrolled in the correct tutorial. You can only join a group that is running in your - allocated tutorial. Use the Tutorial List to - check and update your tutorial enrolment. -

    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - Name - - - - Tutorial - - - - - Capacity Adjustment - - - - - Capacity - - - - Actions -
    - - {{ group.name || 'Not Set' }} - - - - - {{group.tutorial.abbreviation}} - - - - - {{group.capacityAdjustment}} - - - Available - Full - -
    - - - - -
    -
    -
    - - -
    - - -
    -
    - diff --git a/src/app/groups/group-set-manager/group-set-manager.coffee b/src/app/groups/group-set-manager/group-set-manager.coffee index 5e8506f7cb..91d1d81c1c 100644 --- a/src/app/groups/group-set-manager/group-set-manager.coffee +++ b/src/app/groups/group-set-manager/group-set-manager.coffee @@ -17,7 +17,8 @@ angular.module('doubtfire.groups.group-set-manager', []) if !$scope.unitRole? && !$scope.project? throw Error "Group set group manager must have exactly one unit role or project" # Reset member panel toolbar visibility - $scope.newGroupSelected = -> + $scope.newGroupSelected = (group) -> + $scope.selectedGroup = group $scope.showMemberPanelToolbar = false if $scope.unitRole? $scope.groupMembersLoaded = -> $scope.showMemberPanelToolbar = true if $scope.unitRole? diff --git a/src/app/groups/group-set-manager/group-set-manager.tpl.html b/src/app/groups/group-set-manager/group-set-manager.tpl.html index da022a0b37..8b99425cb0 100644 --- a/src/app/groups/group-set-manager/group-set-manager.tpl.html +++ b/src/app/groups/group-set-manager/group-set-manager.tpl.html @@ -1,14 +1,13 @@ - - +
    diff --git a/src/app/groups/group-set-selector/group-set-selector.component.html b/src/app/groups/group-set-selector/group-set-selector.component.html deleted file mode 100644 index 46486cf3f8..0000000000 --- a/src/app/groups/group-set-selector/group-set-selector.component.html +++ /dev/null @@ -1,10 +0,0 @@ - - - @for (gs of unit.groupSets; track gs.id) { - {{gs.name}} - } - - diff --git a/src/app/groups/group-set-selector/group-set-selector.component.scss b/src/app/groups/group-set-selector/group-set-selector.component.scss deleted file mode 100644 index 6dee9e802c..0000000000 --- a/src/app/groups/group-set-selector/group-set-selector.component.scss +++ /dev/null @@ -1,7 +0,0 @@ -.groupset-selector .dropdown { - cursor: pointer; -} - -.lockButton { - width: 70px; -} diff --git a/src/app/groups/group-set-selector/group-set-selector.component.ts b/src/app/groups/group-set-selector/group-set-selector.component.ts deleted file mode 100644 index 60ece272be..0000000000 --- a/src/app/groups/group-set-selector/group-set-selector.component.ts +++ /dev/null @@ -1,31 +0,0 @@ -import { Component, Input, Output, EventEmitter, OnInit } from '@angular/core'; -import { Unit, GroupSet } from 'src/app/api/models/doubtfire-model'; - -@Component({ - selector: 'group-set-selector', - templateUrl: './group-set-selector.component.html', - styleUrls: ['./group-set-selector.component.scss'] -}) -export class GroupSetSelectorComponent implements OnInit { - @Input() unit: Unit; - @Input() selectedGroupSet: GroupSet; - @Output() selectedGroupSetChange = new EventEmitter(); - - ngOnInit(): void { - if (!this.unit) { - throw new Error('Unit not supplied to group set selector'); - } - } - - /** - * Emits the selected group set and updates the parent component. - * - * Also updates the local state. - * - * @param {GroupSet} groupSet - */ - selectGroupSet(groupSet: GroupSet): void { - this.selectedGroupSet = groupSet; - this.selectedGroupSetChange.emit(this.selectedGroupSet); - } -} diff --git a/src/app/groups/groups.coffee b/src/app/groups/groups.coffee index 3d4534d754..5f95e962e9 100644 --- a/src/app/groups/groups.coffee +++ b/src/app/groups/groups.coffee @@ -1,5 +1,4 @@ angular.module('doubtfire.groups', [ 'doubtfire.groups.group-member-contribution-assigner' - 'doubtfire.groups.group-selector' 'doubtfire.groups.group-set-manager' ]) From 7b3759ca0e302598cbd0db1e17e696706ab3f784 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Tue, 28 Oct 2025 08:59:15 +1100 Subject: [PATCH 0700/1280] refactor: use students preferred name in task comments (#1028) * refactor: use students preferred name in task comments * refactor: use users preferred name --- src/app/api/services/task-comment.service.ts | 2 +- .../projects/states/staff-notes/staff-notes.component.html | 4 ++-- .../task-comments-viewer/task-comments-viewer.component.html | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/api/services/task-comment.service.ts b/src/app/api/services/task-comment.service.ts index afeb1f38ca..b804b164b4 100644 --- a/src/app/api/services/task-comment.service.ts +++ b/src/app/api/services/task-comment.service.ts @@ -57,7 +57,7 @@ export class TaskCommentService extends CachedEntityService { keys: 'author', toEntityFn: (data: object, key: string, comment: TaskComment) => { const user = this.userService.cache.getOrCreate(data[key]?.id, userService, data[key]); - comment.initials = `${user.firstName[0]}${user.lastName[0]}`.toUpperCase(); + comment.initials = `${user.preferredName[0]}${user.lastName[0]}`.toUpperCase(); return user; }, }, diff --git a/src/app/projects/states/staff-notes/staff-notes.component.html b/src/app/projects/states/staff-notes/staff-notes.component.html index 4d1b6fb978..9c89b3a391 100644 --- a/src/app/projects/states/staff-notes/staff-notes.component.html +++ b/src/app/projects/states/staff-notes/staff-notes.component.html @@ -1,7 +1,7 @@
    @if (!loadingStaffNotes && project?.staffNoteCount === 0) {
    - No staff notes for {{ project.student.firstName }} {{ project.student.lastName }} + No staff notes for {{ project.student.preferredName }} {{ project.student.lastName }}
    }
    @@ -20,7 +20,7 @@
    @if (note.replyTo) { - Replying to {{ note.replyTo.user.firstName }} + Replying to {{ note.replyTo.user.preferredName }} {{ note.replyTo.user.lastName }} ({{ note.replyTo.user.nickname }}) {{ note.replyTo.note }} diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html index ff7197b321..e0c2b036de 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html @@ -38,7 +38,7 @@ *ngIf="comment.shouldShowTimestamp" [ngClass]="{own: comment.authorIsMe}" > - {{ comment.author.firstName }} {{ comment.author.lastName }} + {{ comment.author.preferredName }} {{ comment.author.lastName }} {{ comment.createdAt | humanizedDate }}

    -
    Date: Wed, 29 Oct 2025 09:54:36 +1100 Subject: [PATCH 0701/1280] fix: typo --- .../directives/task-due-card/task-due-card.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html index 3f3d5c6c6b..9b40ddb5d6 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html @@ -129,7 +129,7 @@

    - @if (task?.taskDefinition?.unit.markLateSubmissionsAsAssessInPortfolio) { + @if (task?.definition?.unit.markLateSubmissionsAsAssessInPortfolio) { You should have completed this task by {{ task?.localDueDateString() }}. This task is now past the deadline and can only be submitted directly for your From 10711a468effe77f33125ac1ba164a8b4a349c1d Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:05:04 +1100 Subject: [PATCH 0702/1280] chore: update task status from latest submission details (#1031) --- src/app/api/models/task.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index 63843d7b88..c920e985a7 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -570,6 +570,9 @@ export class Task extends Entity { this.hasPdf = response['has_pdf']; this.processingPdf = response['processing_pdf']; this.submissionDate = MappingFunctions.mapDate(response, 'submission_date', this); + if (response['task_status'] && TaskStatus.STATUS_KEYS.includes(response['task_status'])) { + this.status = response['task_status']; + } return this; }), ); From 07de5b1e34f78f83c1418399f45e8c754aea530a Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 29 Oct 2025 10:05:17 +1100 Subject: [PATCH 0703/1280] fix: enable submission button for 'need help' trigger (#1034) --- .../upload-submission-modal/upload-submission-modal.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee index b6bcd6b50e..961c65be99 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee @@ -179,7 +179,7 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) false submit: -> # Disable if no comment is supplied with need_help, or if submitting for feedback and task is assess in portfolio only - !$scope.uploader.isReady or ($scope.comment.trim().length < 25 && ($scope.submissionType == 'ready_for_feedback' && $scope.task.definition.assessInPortfolioOnly) || $scope.submissionType == 'need_help') + !$scope.uploader.isReady or ($scope.comment.trim().length < 25 && (($scope.submissionType == 'ready_for_feedback' && $scope.task.definition.assessInPortfolioOnly) || $scope.submissionType == 'need_help') ) cancel: -> # Can't cancel whilst uploading $scope.uploader.isUploading From f682901287ddf087e91db732cb91749718d36a25 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 29 Oct 2025 11:09:43 +1100 Subject: [PATCH 0704/1280] refactor: replace task definition editor with vertical stepper (#1032) * refactor: replace task def editor with vertical stepper * chore: capitalise labels * fix: typo * fix: typo --- .../task-definition-editor.component.html | 282 ++++++------------ 1 file changed, 84 insertions(+), 198 deletions(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html index 75b9583484..7744269ca5 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html @@ -2,218 +2,104 @@

    Details for {{ taskDefinition.abbreviation }} - {{ taskDefinition.name }}

    -
    -
    -
    -
    -
    - 1 -
    -
    -
    -

    Task details

    -

    Name the task and set target grade

    -
    - -
    -
    + + + Task Details +
    +

    Name the task and set target grade

    +
    +
    -
    -
    -
    - 2 -
    -
    -
    -

    Task Learning Outcomes

    -

    Add learning outcomes for this task

    -
    - -
    -
    + + Task Learning Outcomes +
    +

    Add learning outcomes for this task

    +
    - -
    -
    -
    - 3 -
    -
    - -
    -

    Inbox

    -

    - Who assesses {{ unit.hasGroupwork() ? 'and submits ' : '' }}this task? -

    -
    - -
    -
    + + + + Inbox +
    +

    + Who assesses {{ unit.hasGroupwork() ? 'and submits ' : '' }}this task? +

    +
    +
    -
    -
    -
    - 4 -
    -
    - -
    -

    Due dates

    -

    When is this task due?

    -
    - -
    -
    + + Due Dates +
    +

    When is the task due?

    +
    +
    -
    -
    -
    - 5 -
    -
    - -
    -

    Upload requirements

    -

    What do students need to upload?

    -
    - -
    -
    + + Upload Requirements +
    +

    What do students need to upload?

    +
    +
    -
    -
    -
    - 6 -
    -
    - -
    -

    - Task description and resources -

    -

    Upload task descriptions and resources

    -
    - -
    -
    + + Task Resources +
    +

    Upload task descriptions and resources

    +
    - -
    -
    -
    - 7 -
    -
    -
    -

    Prerequisite Tasks

    -

    - Select which tasks need to be submitted before - {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} - can be submitted -

    -
    - - -
    -
    -
    - -
    -
    -
    - 8 -
    -
    - -
    -

    - Task assessment automation -

    -

    Automation is not enabled

    -

    - Configure automated assessment -

    -
    - -
    -
    + + + + Prerequisite Tasks +
    +

    + Select which tasks need to be submitted before + {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} + can be submitted +

    + + +
    - -
    -
    -
    - 9 -
    -
    -
    -

    SCORM test

    -

    - Upload the corresponding SCORM 2004 test (e.g. Numbas) -

    -
    - -
    -
    + + + @if (overseerEnabled) { + + Task Assessment Automation +
    +

    Configure automated assessment

    + +
    +
    + } + + + SCORM Test +
    +

    + Upload the corresponding SCORM 2004 test (e.g. Numbas) +

    +
    +
    -
    -
    -
    - 10 -
    -
    - -
    -

    Optional settings

    -

    Apply other options

    -
    - - - Options - - - -
    -
    - -
    -
    - -
    -
    + + Optional Settings +
    +

    Apply other options

    +
    +
    + +
    +
    +
    From ec0af0cbe47392d6542d9741e1131954195d407f Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Thu, 30 Oct 2025 10:52:19 +1100 Subject: [PATCH 0705/1280] feat: open similarities from project dashboard (#1035) * feat: open similarities from project dashboard * chore: add task similarity view component --- src/app/doubtfire-angularjs.module.ts | 6 ++++++ .../directives/task-dashboard/task-dashboard.coffee | 2 +- .../directives/task-dashboard/task-dashboard.tpl.html | 6 ++++++ 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 886886135c..ab7736ca88 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -231,6 +231,7 @@ import {GroupSetSelectorComponent} from './groups/group-set-selector/group-set-s import {UnitDetailsEditorComponent} from './units/states/edit/directives/unit-details-editor/unit-details-editor.component'; import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component'; import {PortfolioIncludedTasksComponent} from './projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component'; +import {TaskSimilarityViewComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component'; export const DoubtfireAngularJSModule = angular .module('doubtfire', [ @@ -563,3 +564,8 @@ DoubtfireAngularJSModule.directive( 'fPortfolioIncludedTasks', downgradeComponent({component: PortfolioIncludedTasksComponent}), ); + +DoubtfireAngularJSModule.directive( + 'fTaskSimilarityView', + downgradeComponent({component: TaskSimilarityViewComponent}), +); diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee index 8fe60b7574..f70113800c 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee @@ -25,7 +25,7 @@ angular.module('doubtfire.projects.states.dashboard.directives.task-dashboard', # Is the current user a tutor? $scope.tutor = $stateParams.tutor # the ways in which the dashboard can be viewed - $scope.dashboardViews = ["details", "submission", "task"] + $scope.dashboardViews = ["details", "submission", "task", "similarities"] # set the current dashboard view to details by default updateCurrentView = -> diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html index d845a5bcd9..16d998bc0a 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html @@ -22,6 +22,9 @@
  • View Task Sheet
  • +
  • + View Similarities +
  • Download Submission PDF @@ -88,6 +91,9 @@
  • +
    + +
    From fa722e6b6dedb140ebbd411ce41745a9b9e81859 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 30 Oct 2025 11:00:51 +1100 Subject: [PATCH 0706/1280] chore(release): 10.0.0-57 --- CHANGELOG.md | 13 +++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a671c033c..e80c7c93d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,19 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-57](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-56...v10.0.0-57) (2025-10-30) + + +### Features + +* open similarities from project dashboard ([#1035](https://github.com/b0ink/doubtfire-deploy/issues/1035)) ([ec0af0c](https://github.com/b0ink/doubtfire-deploy/commit/ec0af0cbe47392d6542d9741e1131954195d407f)) + + +### Bug Fixes + +* enable submission button for 'need help' trigger ([#1034](https://github.com/b0ink/doubtfire-deploy/issues/1034)) ([07de5b1](https://github.com/b0ink/doubtfire-deploy/commit/07de5b1e34f78f83c1418399f45e8c754aea530a)) +* typo ([2712a68](https://github.com/b0ink/doubtfire-deploy/commit/2712a68f6031794c571a7ee5866c653bf67de1dd)) + ## [10.0.0-56](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-55...v10.0.0-56) (2025-10-23) diff --git a/package-lock.json b/package-lock.json index 237e8df708..c74890a9cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-56", + "version": "10.0.0-57", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-56", + "version": "10.0.0-57", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 212482a3f5..bfd5a18315 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-56", + "version": "10.0.0-57", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From a48c7d6f58d2367677aa6c1c5c5bd43195730ec2 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Fri, 31 Oct 2025 11:26:19 +1100 Subject: [PATCH 0707/1280] refactor: group set manager migration (#1036) * refactor: init group set manager migration * refactor: allow editable group name * chore: display locked icon * refactor: replace with new component * refactor: shorten create group button * refactor: remove old component * chore: cleanup * refactor: hide search bar for students * refactor: remove css --- README.md | 2 +- src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire-angularjs.module.ts | 7 +- .../group-selector.component.html | 2 +- .../group-set-manager.coffee | 45 ------- .../group-set-manager.component.html | 76 ++++++++++++ .../group-set-manager.component.scss | 0 .../group-set-manager.component.ts | 115 ++++++++++++++++++ .../group-set-manager/group-set-manager.scss | 6 - .../group-set-manager.tpl.html | 67 ---------- src/app/groups/groups.coffee | 1 - .../projects/states/groups/groups.tpl.html | 10 +- .../unit-group-set-editor.tpl.html | 25 ++-- src/app/units/states/groups/groups.tpl.html | 13 +- 14 files changed, 224 insertions(+), 147 deletions(-) delete mode 100644 src/app/groups/group-set-manager/group-set-manager.coffee create mode 100644 src/app/groups/group-set-manager/group-set-manager.component.html create mode 100644 src/app/groups/group-set-manager/group-set-manager.component.scss create mode 100644 src/app/groups/group-set-manager/group-set-manager.component.ts delete mode 100644 src/app/groups/group-set-manager/group-set-manager.scss delete mode 100644 src/app/groups/group-set-manager/group-set-manager.tpl.html diff --git a/README.md b/README.md index 77fafe2a61..7885b47a9b 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,7 @@ MIGRATED: - [x] ./src/app/common/modals/confirmation-modal/confirmation-modal.coffee - [x] ./src/app/common/modals/comments-modal/comments-modal.coffee (IN 10.0.x) - [x] ./src/app/groups/group-selector/group-selector.coffee +- [x] ./src/app/groups/group-set-manager/group-set-manager.coffee TODO: @@ -193,7 +194,6 @@ TODO: - [ ] ./src/app/projects/project-outcome-alignment/project-outcome-alignment.coffee - [ ] ./src/app/projects/states/tutorials/tutorials.coffee - [ ] ./src/app/admin/modals/modals.coffee -- [ ] ./src/app/groups/group-set-manager/group-set-manager.coffee - [ ] ./src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.coffee - [ ] ./src/app/groups/tutor-group-manager/tutor-group-manager.coffee - [ ] ./src/app/groups/groups.coffee diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 61b1586d71..4bf79b47d1 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -281,6 +281,7 @@ import {UnitStudentEnrolmentModalComponent} from './units/modals/unit-student-en import {TaskStatusPieChartComponent} from './visualisations/task-status-pie-chart/taskstatuspiechart.component'; import {GroupMemberListComponent} from './groups/group-member-list/group-member-list.component'; import {GroupSelectorComponent} from './groups/group-selector/group-selector.component'; +import {GroupSetManagerComponent} from './groups/group-set-manager/group-set-manager.component'; @NgModule({ // Components we declare @@ -411,6 +412,7 @@ import {GroupSelectorComponent} from './groups/group-selector/group-selector.com PortfolioGradeSelectStepComponent, GroupMemberListComponent, GroupSelectorComponent, + GroupSetManagerComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 29ec49ed15..ba04e6285a 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -78,7 +78,6 @@ import 'build/src/app/projects/states/portfolio/portfolio.js'; import 'build/src/app/projects/states/index/index.js'; import 'build/src/app/projects/project-outcome-alignment/project-outcome-alignment.js'; import 'build/src/app/admin/modals/modals.js'; -import 'build/src/app/groups/group-set-manager/group-set-manager.js'; import 'build/src/app/groups/groups.js'; import 'build/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.js'; import 'build/src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.js'; @@ -222,6 +221,7 @@ import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staf import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component'; import {GroupMemberListComponent} from './groups/group-member-list/group-member-list.component'; import {GroupSelectorComponent} from './groups/group-selector/group-selector.component'; +import {GroupSetManagerComponent} from './groups/group-set-manager/group-set-manager.component'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -534,3 +534,8 @@ DoubtfireAngularJSModule.directive( 'fGroupSelector', downgradeComponent({component: GroupSelectorComponent}), ); + +DoubtfireAngularJSModule.directive( + 'fGroupSetManager', + downgradeComponent({component: GroupSetManagerComponent}), +); diff --git a/src/app/groups/group-selector/group-selector.component.html b/src/app/groups/group-selector/group-selector.component.html index 857f840a64..0bf47af51e 100644 --- a/src/app/groups/group-selector/group-selector.component.html +++ b/src/app/groups/group-selector/group-selector.component.html @@ -31,7 +31,7 @@ />
    } diff --git a/src/app/groups/group-set-manager/group-set-manager.coffee b/src/app/groups/group-set-manager/group-set-manager.coffee deleted file mode 100644 index 91d1d81c1c..0000000000 --- a/src/app/groups/group-set-manager/group-set-manager.coffee +++ /dev/null @@ -1,45 +0,0 @@ -angular.module('doubtfire.groups.group-set-manager', []) - -# -# Manager directive for tutors to add and remove group -# members from a group within a group set context -# -.directive('groupSetManager', -> - restrict: 'E' - templateUrl: 'groups/group-set-manager/group-set-manager.tpl.html' - scope: - unit: '=' - unitRole: '=' - project: '=' - selectedGroupSet: '=' - showGroupSetSelector: '=?' - controller: ($scope, newGroupService, gradeService, alertService) -> - if !$scope.unitRole? && !$scope.project? - throw Error "Group set group manager must have exactly one unit role or project" - # Reset member panel toolbar visibility - $scope.newGroupSelected = (group) -> - $scope.selectedGroup = group - $scope.showMemberPanelToolbar = false if $scope.unitRole? - $scope.groupMembersLoaded = -> - $scope.showMemberPanelToolbar = true if $scope.unitRole? - - # Add new member to the group - $scope.addMember = (member) -> - $scope.selectedGroup.addMember(member) - $scope.selectedStudent = null - - # Update name of group - $scope.updateGroup = (data) -> - newGroupService.update({ - unitId: $scope.unit.id, - groupSetId: $scope.selectedGroupSet.id, - id: $scope.selectedGroup.id, - }, { - entity: data - }).subscribe({ - next: (response) -> - alertService.success( "Group changed", 2000) - error: (response) -> - alertService.error( response, 6000) - }) -) diff --git a/src/app/groups/group-set-manager/group-set-manager.component.html b/src/app/groups/group-set-manager/group-set-manager.component.html new file mode 100644 index 0000000000..08b85bf29d --- /dev/null +++ b/src/app/groups/group-set-manager/group-set-manager.component.html @@ -0,0 +1,76 @@ +
    + + + + @if (selectedGroup) { + + + Members of + @if (!editingGroupName) { + {{ selectedGroup?.name }} + @if (unitRole || selectedGroup.groupSet?.allowStudentsToManageGroups) { + + } + } @else { + @if (unitRole || selectedGroup.groupSet?.allowStudentsToManageGroups) { + + + + + + } + } + + @if (selectedGroup.locked) { + lock + } + + + + + @if (unitRole) { + + + + + @for (project of filteredProjects | async; track project) { + {{ project.student.name }} + } + + + + } + + } +
    diff --git a/src/app/groups/group-set-manager/group-set-manager.component.scss b/src/app/groups/group-set-manager/group-set-manager.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/groups/group-set-manager/group-set-manager.component.ts b/src/app/groups/group-set-manager/group-set-manager.component.ts new file mode 100644 index 0000000000..ae3873315b --- /dev/null +++ b/src/app/groups/group-set-manager/group-set-manager.component.ts @@ -0,0 +1,115 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {FormControl} from '@angular/forms'; +import {map, Observable, startWith} from 'rxjs'; +import {Group, GroupSet, Project, Unit, UnitRole} from 'src/app/api/models/doubtfire-model'; +import {GroupService} from 'src/app/api/services/group.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-group-set-manager', + templateUrl: './group-set-manager.component.html', + styleUrls: ['./group-set-manager.component.scss'], +}) +export class GroupSetManagerComponent implements OnInit { + @Input() project: Project; + @Input() unit: Unit; + @Input() selectedGroupSet: GroupSet; + @Input() showGroupSetSelector: boolean; + @Input() unitRole: UnitRole; + + public selectedGroup: Group; + + editingGroupName = false; + + control = new FormControl(''); + projects: Project[] = []; + filteredProjects: Observable; + + constructor( + private groupService: GroupService, + private alertService: AlertService, + ) {} + + ngOnInit(): void { + this.filteredProjects = this.control.valueChanges.pipe( + startWith(''), + map((value) => this._filter(value)), + ); + } + + get groupSelectHandler() { + return (group: Group) => this.newGroupSelected(group); + } + + displayFn(project: Project): string { + return project && project.student.name ? project.student.name : ''; + } + + newGroupSelected(group: Group) { + if (this.selectedGroup) { + this.selectedGroup.name = this.originalGroupName; + } + this.editingGroupName = false; + this.selectedGroup = group; + + const students = this.unit.studentsForGroupTypeAhead(group) || []; + this.projects = students.filter((project) => !group.projects.find((p) => project.id === p.id)); + + this.originalGroupName = group.name; + } + + private _filter(value: string | Project): Project[] { + if (typeof value !== 'string') { + return; + } + + const filterValue = value.toLowerCase(); + return this.projects.filter( + (project) => + project.student.name.toLowerCase().includes(filterValue.toLowerCase()) && // Find by name + !this.selectedGroup.projects.find((p) => project.id === p.id), // Not already assigned to the group + ); + } + + groupMembersLoaded() {} + + addMember(project: Project) { + this.selectedGroup.addMember(project); + this.control.setValue(''); + } + + private originalGroupName: string; + startEditingGroupName() { + this.originalGroupName = this.selectedGroup.name; + this.editingGroupName = true; + } + + stopEditinGroupName() { + this.selectedGroup.name = this.originalGroupName; + this.editingGroupName = false; + } + + updateGroup() { + this.editingGroupName = false; + this.groupService + .update( + { + unitId: this.unit.id, + groupSetId: this.selectedGroup.groupSet.id, + id: this.selectedGroup.id, + }, + { + entity: this.selectedGroup, + }, + ) + .subscribe({ + next: () => { + this.alertService.success('Successfully updated group', 3000); + }, + error: (error) => { + this.selectedGroup.name = this.originalGroupName; + this.alertService.error(`Failed to update gorup: ${error}`, 6000); + }, + }); + } +} diff --git a/src/app/groups/group-set-manager/group-set-manager.scss b/src/app/groups/group-set-manager/group-set-manager.scss deleted file mode 100644 index b65662abca..0000000000 --- a/src/app/groups/group-set-manager/group-set-manager.scss +++ /dev/null @@ -1,6 +0,0 @@ -@media (min-width: $screen-lg) { - group-set-manager { - display: block; - @include panel-row; - } -} diff --git a/src/app/groups/group-set-manager/group-set-manager.tpl.html b/src/app/groups/group-set-manager/group-set-manager.tpl.html deleted file mode 100644 index 8b99425cb0..0000000000 --- a/src/app/groups/group-set-manager/group-set-manager.tpl.html +++ /dev/null @@ -1,67 +0,0 @@ - - -
    -
    -
    -
    -

    - Members of - {{selectedGroup.name}} -

    -
    -
    - -
    -
    -
    - -
    -
    - -
    - -
    -
    -
    - - - -
    - diff --git a/src/app/groups/groups.coffee b/src/app/groups/groups.coffee index 5f95e962e9..feae90ec11 100644 --- a/src/app/groups/groups.coffee +++ b/src/app/groups/groups.coffee @@ -1,4 +1,3 @@ angular.module('doubtfire.groups', [ 'doubtfire.groups.group-member-contribution-assigner' - 'doubtfire.groups.group-set-manager' ]) diff --git a/src/app/projects/states/groups/groups.tpl.html b/src/app/projects/states/groups/groups.tpl.html index e5086ab3c6..804d268d35 100644 --- a/src/app/projects/states/groups/groups.tpl.html +++ b/src/app/projects/states/groups/groups.tpl.html @@ -1,10 +1,8 @@
    - - -
    + + +
    +
    diff --git a/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.tpl.html b/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.tpl.html index db550ef42d..c83b2d5fd7 100644 --- a/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.tpl.html +++ b/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.tpl.html @@ -123,18 +123,21 @@

    No Group Sets Created

    New Group Set -
    -
    -
    -
    - +
    + +
    +
    + + + +

    diff --git a/src/app/units/states/groups/groups.tpl.html b/src/app/units/states/groups/groups.tpl.html index 319f46e08f..6d79bdb9a3 100644 --- a/src/app/units/states/groups/groups.tpl.html +++ b/src/app/units/states/groups/groups.tpl.html @@ -1,11 +1,8 @@ -
    - - -
    +
    + + +
    +
    From 560394c4705a5db03b10aeb50556e88086f6d144 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 31 Oct 2025 11:31:10 +1100 Subject: [PATCH 0708/1280] chore: display joined status --- src/app/groups/group-selector/group-selector.component.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/groups/group-selector/group-selector.component.html b/src/app/groups/group-selector/group-selector.component.html index 0bf47af51e..b0984e69f3 100644 --- a/src/app/groups/group-selector/group-selector.component.html +++ b/src/app/groups/group-selector/group-selector.component.html @@ -129,7 +129,9 @@ } - @if (project && group.hasSpace() && selectedGroupSet.allowStudentsToManageGroups) { + @if (isPartOfGroup(project, group)) { +
    Joined
    + } @else if (project && group.hasSpace() && selectedGroupSet.allowStudentsToManageGroups) {
    @if (!group.locked && !selectedGroupSet.locked) {
    From 58ec499a8d59c7202f591de661551d8a32c37527 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 4 Nov 2025 00:47:50 +1100 Subject: [PATCH 0715/1280] fix: require comment for new evidence --- .../upload-submission-modal/upload-submission-modal.tpl.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html index 7cc0372a34..65695e16ec 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html @@ -140,7 +140,7 @@

    Plagiarism and Collusion

    - From 8f599725d670f37d50d015692be7d58f163eab8d Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 4 Nov 2025 21:57:19 +1100 Subject: [PATCH 0716/1280] chore(release): 10.0.0-59 --- CHANGELOG.md | 8 ++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb40436959..d8a6450419 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-59](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-58...v10.0.0-59) (2025-11-04) + + +### Bug Fixes + +* require comment for new evidence ([58ec499](https://github.com/b0ink/doubtfire-deploy/commit/58ec499a8d59c7202f591de661551d8a32c37527)) +* require comment for new evidence ([c5397fc](https://github.com/b0ink/doubtfire-deploy/commit/c5397fc5c444e76b431aa5d6487553c60e711c2e)) + ## [10.0.0-58](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-57...v10.0.0-58) (2025-11-01) ## [10.0.0-57](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-56...v10.0.0-57) (2025-10-30) diff --git a/package-lock.json b/package-lock.json index 52d3b0a995..19cbbb3eb4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-58", + "version": "10.0.0-59", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-58", + "version": "10.0.0-59", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 830c9eee29..c3df336ac0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-58", + "version": "10.0.0-59", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From c67ceaa84d02bb71626890fc28bb4aaea164b952 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:34:31 +1100 Subject: [PATCH 0717/1280] feat: upload grades csv (#1038) * feat: upload grades csv * chore: remove debug --- src/app/api/models/unit.ts | 4 ++ src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire-angularjs.module.ts | 6 ++ .../states/portfolios/portfolios.tpl.html | 1 + .../upload-grades.component.html | 3 + .../upload-grades.component.scss | 0 .../upload-grades/upload-grades.component.ts | 55 +++++++++++++++++++ 7 files changed, 71 insertions(+) create mode 100644 src/app/units/states/portfolios/upload-grades/upload-grades.component.html create mode 100644 src/app/units/states/portfolios/upload-grades/upload-grades.component.scss create mode 100644 src/app/units/states/portfolios/upload-grades/upload-grades.component.ts diff --git a/src/app/api/models/unit.ts b/src/app/api/models/unit.ts index 8306a94f12..0caa668085 100644 --- a/src/app/api/models/unit.ts +++ b/src/app/api/models/unit.ts @@ -414,6 +414,10 @@ export class Unit extends Entity { }/learning_alignments/csv.json`; } + public get gradesCSVUploadUrl(): string { + return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.id}/grades/csv`; + } + public taskStatusFactor(td: TaskDefinition): number { return 1; } diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 12f65dc8a5..ee3dcd3889 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -294,6 +294,7 @@ import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/dir import {AnalyticsTutorTimesComponent} from './units/states/analytics/directives/analytics-tutor-times.component'; import {MarkingSessionService} from './api/services/marking-session.service'; import {PortfolioIncludedTasksComponent} from './projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component'; +import {UploadGradesComponent} from './units/states/portfolios/upload-grades/upload-grades.component'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { @@ -448,6 +449,7 @@ const MY_DATE_FORMAT = { PortfolioGradeSelectStepComponent, AnalyticsTutorTimesComponent, PortfolioIncludedTasksComponent, + UploadGradesComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index ab7736ca88..8187457400 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -232,6 +232,7 @@ import {UnitDetailsEditorComponent} from './units/states/edit/directives/unit-de import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component'; import {PortfolioIncludedTasksComponent} from './projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component'; import {TaskSimilarityViewComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component'; +import {UploadGradesComponent} from './units/states/portfolios/upload-grades/upload-grades.component'; export const DoubtfireAngularJSModule = angular .module('doubtfire', [ @@ -569,3 +570,8 @@ DoubtfireAngularJSModule.directive( 'fTaskSimilarityView', downgradeComponent({component: TaskSimilarityViewComponent}), ); + +DoubtfireAngularJSModule.directive( + 'fUploadGrades', + downgradeComponent({component: UploadGradesComponent}), +); diff --git a/src/app/units/states/portfolios/portfolios.tpl.html b/src/app/units/states/portfolios/portfolios.tpl.html index 98a6c019f7..376277513e 100644 --- a/src/app/units/states/portfolios/portfolios.tpl.html +++ b/src/app/units/states/portfolios/portfolios.tpl.html @@ -240,6 +240,7 @@

    Mark Portfolios

    + diff --git a/src/app/units/states/portfolios/upload-grades/upload-grades.component.html b/src/app/units/states/portfolios/upload-grades/upload-grades.component.html new file mode 100644 index 0000000000..c63db48f51 --- /dev/null +++ b/src/app/units/states/portfolios/upload-grades/upload-grades.component.html @@ -0,0 +1,3 @@ + diff --git a/src/app/units/states/portfolios/upload-grades/upload-grades.component.scss b/src/app/units/states/portfolios/upload-grades/upload-grades.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts b/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts new file mode 100644 index 0000000000..5d8e9a0020 --- /dev/null +++ b/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts @@ -0,0 +1,55 @@ +import {Component, Inject, Input, OnInit} from '@angular/core'; +import {csvResultModalService, csvUploadModalService} from 'src/app/ajs-upgraded-providers'; +import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; +import {Unit} from 'src/app/api/models/unit'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-upload-grades', + templateUrl: 'upload-grades.component.html', + styleUrl: 'upload-grades.component.scss', +}) +export class UploadGradesComponent implements OnInit { + @Input() unit: Unit; + + constructor( + @Inject(csvUploadModalService) private csvUploadModal: any, + private sidekiqModalService: SidekiqProgressModalService, + @Inject(csvResultModalService) private csvResultModal: any, + private alertService: AlertService, + ) {} + + public ngOnInit(): void { + if (!this.unit) { + return console.error(`Invalid unit`); + } + } + + public uploadGradesCSV() { + this.csvUploadModal.show( + 'Upload Student Grades as CSV', + 'Import student grades', + { + file: {name: 'Feedback Templates CSV Data', type: 'csv'}, + }, + this.unit.gradesCSVUploadUrl, + (response: SidekiqJob) => { + if (!response) { + this.alertService.error('Failed to import grades', 6000); + return; + } + + this.sidekiqModalService.show('Import student grades', response.id).subscribe({ + next: (job) => { + this.csvResultModal.show('Student grade import results', JSON.parse(job.result)); + }, + error: (error) => { + console.error(error); + this.alertService.error('Failed to import grades', 6000); + }, + }); + }, + ); + } +} From dd2582e2b418318dec015c715086cbfc679b48ac Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 5 Nov 2025 16:36:07 +1100 Subject: [PATCH 0718/1280] chore(release): 10.0.0-60 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index d8a6450419..4650b3c42e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-60](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-59...v10.0.0-60) (2025-11-05) + + +### Features + +* upload grades csv ([#1038](https://github.com/b0ink/doubtfire-deploy/issues/1038)) ([c67ceaa](https://github.com/b0ink/doubtfire-deploy/commit/c67ceaa84d02bb71626890fc28bb4aaea164b952)) + ## [10.0.0-59](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-58...v10.0.0-59) (2025-11-04) diff --git a/package-lock.json b/package-lock.json index 19cbbb3eb4..a2fb633540 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-59", + "version": "10.0.0-60", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-59", + "version": "10.0.0-60", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index c3df336ac0..be72c68d67 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-59", + "version": "10.0.0-60", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 8bcffda3dfb73873c48d68fcce4e82920be19b4f Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Thu, 6 Nov 2025 15:26:35 +1100 Subject: [PATCH 0719/1280] refactor: overseer sidekiq (#1029) * refactor: use sidekiq jobs for pulling overseer images * refactor: overseer execution script editor * chore: remove overseer view * refactor: increase size of script editor * chore: add icon for incomplete overseer runs * chore: add typing * refactor: format assessment comment layout * refactor: enable test submissions if script exists --- .../overseer-image-list.component.html | 35 +++++++++--- .../overseer-image-list.component.ts | 30 +++++++++-- .../models/overseer/overseer-assessment.ts | 28 +++++----- src/app/api/models/task-definition.ts | 1 + .../services/overseer-assessment.service.ts | 5 +- .../api/services/overseer-image.service.ts | 15 ++---- .../api/services/task-definition.service.ts | 1 + src/app/common/footer/footer.component.html | 4 ++ src/app/common/footer/footer.component.ts | 6 +++ src/app/doubtfire-angular.module.ts | 7 ++- .../task-assessment-comment.component.html | 19 ++++--- .../task-comments-viewer.component.html | 5 +- .../task-submission-history.component.html | 53 +++++++++++------- ...verseer-script-editor-modal.component.html | 14 +++++ ...verseer-script-editor-modal.component.scss | 0 .../overseer-script-editor-modal.component.ts | 54 +++++++++++++++++++ .../overseer-script-editor-modal.service.ts | 28 ++++++++++ .../task-definition-overseer.component.html | 21 +++----- .../task-definition-overseer.component.ts | 27 ++++++---- 19 files changed, 260 insertions(+), 93 deletions(-) create mode 100644 src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html create mode 100644 src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.scss create mode 100644 src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts create mode 100644 src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.service.ts diff --git a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html index d2e70e730d..bf6ca86233 100644 --- a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html +++ b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html @@ -1,3 +1,9 @@ + + +
    {{ data.text }}
    +
    +
    +
    @@ -5,7 +11,13 @@

    Overseer Images

    Add new image or modify existing ones used for automated task analysis

    - +
    @@ -51,7 +63,9 @@

    Overseer Images

    @@ -62,7 +76,7 @@

    Overseer Images

    @@ -80,10 +94,10 @@

    Overseer Images

    overseerImage.pulledImageStatus === 'success' ? 'green' : overseerImage.pulledImageStatus === 'loading' - ? 'orange' - : overseerImage.pulledImageStatus === 'failed' - ? 'red' - : '' + ? 'orange' + : overseerImage.pulledImageStatus === 'failed' + ? 'red' + : '' }" > @@ -113,7 +128,11 @@

    Overseer Images

    +
    Name
    - +
    Last Pulled
    - {{ overseerImage.lastPulledDate }} + {{ overseerImage.lastPulledDate | humanizedDate }}
    - diff --git a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts index 703054827e..526660962d 100644 --- a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts +++ b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts @@ -1,17 +1,24 @@ -import {Component, ViewChild} from '@angular/core'; +import {AfterViewInit, Component, TemplateRef, ViewChild} from '@angular/core'; import {MatTableDataSource, MatTable} from '@angular/material/table'; import {OverseerImage, OverseerImageService} from 'src/app/api/models/doubtfire-model'; import {EntityFormComponent} from 'src/app/common/entity-form/entity-form.component'; import {UntypedFormControl, Validators} from '@angular/forms'; import {MatSort, Sort} from '@angular/material/sort'; import {AlertService} from 'src/app/common/services/alert.service'; +import {MatDialog} from '@angular/material/dialog'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; @Component({ selector: 'overseer-image-list', templateUrl: 'overseer-image-list.component.html', styleUrls: ['overseer-image-list.component.scss'], }) -export class OverseerImageListComponent extends EntityFormComponent { +export class OverseerImageListComponent + extends EntityFormComponent + implements AfterViewInit +{ + @ViewChild('textDialog') textDialog!: TemplateRef; + @ViewChild(MatTable, {static: true}) table: MatTable; @ViewChild(MatSort, {static: true}) sort: MatSort; @@ -26,6 +33,8 @@ export class OverseerImageListComponent extends EntityFormComponent { - this.loading = false; + this.overseerImageService.pullDockerImage(image).subscribe((job) => { + this.sidekiqProgressModalService + .show(`Pulling image ${image.name} (${image.tag})`, job.id) + .subscribe((_job) => { + this.overseerImageService.fetch(image.id).subscribe((newImage) => { + console.log(newImage); + this.loading = false; + }); + }); }); } @@ -96,4 +112,10 @@ export class OverseerImageListComponent extends EntityFormComponent(mappingData: EntityMapping, ignoreKeys?: string[]): object { + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { return { - overseer_assessment: super.toJson(mappingData, ignoreKeys) + overseer_assessment: super.toJson(mappingData, ignoreKeys), }; } } diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index 30aff474bf..e82ae135f0 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -47,6 +47,7 @@ export class TaskDefinition extends Entity { scormTimeDelayEnabled: boolean; scormAttemptLimit: number = 0; hasTaskAssessmentResources: boolean; + hasTaskAssessmentScript: boolean; isGraded: boolean; maxQualityPts: number; overseerImageId: number; diff --git a/src/app/api/services/overseer-assessment.service.ts b/src/app/api/services/overseer-assessment.service.ts index cfb21c8879..2226887caf 100644 --- a/src/app/api/services/overseer-assessment.service.ts +++ b/src/app/api/services/overseer-assessment.service.ts @@ -4,6 +4,7 @@ import {Observable} from 'rxjs'; import {HttpClient} from '@angular/common/http'; import API_URL from 'src/app/config/constants/apiUrl'; import {OverseerAssessment} from '../models/overseer/overseer-assessment'; +import {Task} from '../models/doubtfire-model'; @Injectable() export class OverseerAssessmentService extends EntityService { @@ -37,13 +38,13 @@ export class OverseerAssessmentService extends EntityService return new OverseerAssessment(other); } - public queryForTask(task: any): Observable { + public queryForTask(task: Task): Observable { const pathIds = { project_id: task.project.id, td_id: task.definition.id, }; - return this.query(pathIds, task); + return this.query(pathIds); } public triggerOverseer(assessment: OverseerAssessment): Observable { diff --git a/src/app/api/services/overseer-image.service.ts b/src/app/api/services/overseer-image.service.ts index ebb5558b3a..7edc65932f 100644 --- a/src/app/api/services/overseer-image.service.ts +++ b/src/app/api/services/overseer-image.service.ts @@ -4,6 +4,7 @@ import {OverseerImage} from 'src/app/api/models/doubtfire-model'; import {Injectable} from '@angular/core'; import {HttpClient} from '@angular/common/http'; import API_URL from 'src/app/config/constants/apiUrl'; +import {SidekiqJob} from '../models/sidekiq-job'; @Injectable() export class OverseerImageService extends CachedEntityService { @@ -25,16 +26,10 @@ export class OverseerImageService extends CachedEntityService { this.mapping.mapAllKeysToJsonExcept('id'); } - public pullDockerImage(image: OverseerImage): Observable { - return super - .put(image, { - endpointFormat: this.pullImageEndpointFormat, - }) - .pipe( - switchMap((response) => { - return super.update(image); - }), - ); + public pullDockerImage(image: OverseerImage): Observable { + return super.put(image, { + endpointFormat: this.pullImageEndpointFormat, + }); } public createInstanceFrom(json: object, other?: any): OverseerImage { diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index 63708814f8..06bea8da49 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -114,6 +114,7 @@ export class TaskDefinitionService extends CachedEntityService { 'hasTaskSheet', 'hasTaskResources', 'hasTaskAssessmentResources', + 'hasTaskAssessmentScript', 'scormEnabled', 'hasScormData', 'scormAllowReview', diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index 6fa4a27af5..8fd9e50a33 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -188,6 +188,10 @@ crisis_alert View similarities + -
    -
    - } @else { - -
    + @if (comment.assessment_result && comment.assessment_result.is_successful) { +
    +
    +
    {{ comment.text }}
    + +
    +
    + } @else { +
    } diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html index e0c2b036de..8cbc442d50 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html @@ -127,7 +127,10 @@
    -
    +
    -
    -
    -
    Submissions
    - +
    +
    +
    +
    Submissions
    + @for (tab of tabs; track tab) { - -
    {{tab.timestamp | date: 'dd/MM/yy, hh:mm a'}}
    -   -
    -} + +
    +
    + {{ tab.timestamp | humanizedDate }} +
    + @if (tab.status === 'pre_queued') { + schedule + } @else { + + } +
    +
    + }
    -
    +
    @for (selTab of selectedTab.content; track selTab) { - -
    {{selTab.result}} 
    - -
    -} + +
    {{ selTab.result }} 
    + +
    + }
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html new file mode 100644 index 0000000000..1d6a563570 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html @@ -0,0 +1,14 @@ +
    +
    +

    {{ data.taskDefinition.abbreviation }} {{ data.taskDefinition.name }}

    +

    Overseer script

    +
    +
    + +
    + @if (!loading) { + + } +
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts new file mode 100644 index 0000000000..f64d3b4763 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts @@ -0,0 +1,54 @@ +import {HttpClient} from '@angular/common/http'; +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {CodeModel} from '@ngstack/code-editor'; +import {AppInjector} from 'src/app/app-injector'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {OverseerScriptEditorModalData} from './overseer-script-editor-modal.service'; + +@Component({ + selector: 'f-overseer-script-editor-modal', + templateUrl: './overseer-script-editor-modal.component.html', + styleUrls: ['./overseer-script-editor-modal.component.scss'], +}) +export class OverseerScriptEditorModalComponent implements OnInit { + constructor( + @Inject(MAT_DIALOG_DATA) public data: OverseerScriptEditorModalData, + public dialogRef: MatDialogRef, + private httpClient: HttpClient, + ) {} + + public model: CodeModel = { + language: 'shell', + uri: 'run.sh', + value: '', + }; + + scriptContent: string; + + loading: boolean = false; + ngOnInit() { + this.loading = true; + // TODO: move to taskDefinition model + const url = `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.data.taskDefinition.unit.id}/task_definitions/${this.data.taskDefinition.id}/overseer_script`; + this.httpClient.get(url).subscribe((data: string) => { + this.model.value = data; + this.loading = false; + }); + } + + save() { + console.log(this.model.value); + const url = `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.data.taskDefinition.unit.id}/task_definitions/${this.data.taskDefinition.id}/overseer_script`; + + this.httpClient.put(url, {script_content: this.model.value}).subscribe({ + next: (result) => { + console.log(result); + this.dialogRef.close(); + }, + error: (error) => { + console.error(error); + }, + }); + } +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.service.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.service.ts new file mode 100644 index 0000000000..c238db3eaf --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.service.ts @@ -0,0 +1,28 @@ +import {Injectable} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import {OverseerScriptEditorModalComponent} from './overseer-script-editor-modal.component'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; + +export interface OverseerScriptEditorModalData { + taskDefinition: TaskDefinition; +} + +@Injectable({ + providedIn: 'root', +}) +export class OverseerScriptEditorModalService { + constructor(public dialog: MatDialog) {} + + public show(taskDefinition: TaskDefinition) { + const _dialogRef = this.dialog.open< + OverseerScriptEditorModalComponent, + OverseerScriptEditorModalData + >(OverseerScriptEditorModalComponent, { + data: { + taskDefinition: taskDefinition, + }, + width: '100%', + maxWidth: '1200px', + }); + } +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html index bf187030aa..0e5c521bcb 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html @@ -18,6 +18,10 @@ Docker image for Overseer + + @if (taskDefinition.hasTaskAssessmentResources) {
    - -
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts index 597296d707..ea0f92ba89 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts @@ -1,5 +1,5 @@ -import { Component, Input, OnChanges } from '@angular/core'; -import { Observable } from 'rxjs'; +import {Component, Input, OnChanges} from '@angular/core'; +import {Observable} from 'rxjs'; import { OverseerAssessment, OverseerImage, @@ -8,13 +8,14 @@ import { User, UserService, } from 'src/app/api/models/doubtfire-model'; -import { TaskDefinition } from 'src/app/api/models/task-definition'; -import { Unit } from 'src/app/api/models/unit'; -import { TaskDefinitionService } from 'src/app/api/services/task-definition.service'; -import { FileDownloaderService } from 'src/app/common/file-downloader/file-downloader.service'; -import { TaskAssessmentModalService } from 'src/app/common/modals/task-assessment-modal/task-assessment-modal.service'; -import { AlertService } from 'src/app/common/services/alert.service'; -import { TaskSubmissionService } from 'src/app/common/services/task-submission.service'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {TaskAssessmentModalService} from 'src/app/common/modals/task-assessment-modal/task-assessment-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {TaskSubmissionService} from 'src/app/common/services/task-submission.service'; +import {OverseerScriptEditorModalService} from './overseer-script-editor-modal/overseer-script-editor-modal.service'; @Component({ selector: 'f-task-definition-overseer', @@ -34,6 +35,7 @@ export class TaskDefinitionOverseerComponent implements OnChanges { private userService: UserService, private taskDefinitionService: TaskDefinitionService, private fileDownloaderService: FileDownloaderService, + private overseerScriptEditorModal: OverseerScriptEditorModalService, ) {} public get overseerEnabled(): boolean { @@ -73,6 +75,10 @@ export class TaskDefinitionOverseerComponent implements OnChanges { this.currentUserTask.presentTaskSubmissionModal(this.currentUserTask.status, false, true); } + editScript() { + this.overseerScriptEditorModal.show(this.taskDefinition); + } + testSubmissionHistory() { this.modalService.show(this.currentUserTask); } @@ -93,7 +99,7 @@ export class TaskDefinitionOverseerComponent implements OnChanges { next: () => { this.alerts.success('Deleted Overseer Resources', 2000); this.taskDefinition.hasTaskAssessmentResources = false; - } + }, }); } @@ -104,7 +110,6 @@ export class TaskDefinitionOverseerComponent implements OnChanges { ); } - public uploadOverseerResources(files: FileList) { const validFiles = Array.from(files as ArrayLike).filter( (f) => f.type === 'application/zip' || f.type === 'application/x-zip-compressed', From 1a4a3f6c64743f7fd7e9d96697bdfa4cdb792c8e Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 6 Nov 2025 15:36:36 +1100 Subject: [PATCH 0720/1280] chore(release): 10.0.0-61 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 4650b3c42e..c2462bcfcf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-61](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-60...v10.0.0-61) (2025-11-06) + ## [10.0.0-60](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-59...v10.0.0-60) (2025-11-05) diff --git a/package-lock.json b/package-lock.json index a2fb633540..0f3a3c3b45 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-60", + "version": "10.0.0-61", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-60", + "version": "10.0.0-61", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index be72c68d67..09053700c4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-60", + "version": "10.0.0-61", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 29fbc1498b0d48811cb59c5f2a66871fbac06849 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Thu, 6 Nov 2025 15:59:27 +1100 Subject: [PATCH 0721/1280] feat: restrict assessments to tutors in the same tutorial stream (#1033) * feat: restrict assessments to tutors in the same tutorial stream * refactor: unselect tasks that are locked to a tutorial stream --- src/app/api/models/task-definition.ts | 1 + src/app/api/services/task-definition.service.ts | 1 + .../tutor-discussion.component.html | 6 +++++- .../tutor-discussion/tutor-discussion.component.ts | 14 ++++++++++++++ .../task-definition-who.component.html | 6 ++++++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index e82ae135f0..1560b94909 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -56,6 +56,7 @@ export class TaskDefinition extends Entity { hasJplagReport: boolean; assessInPortfolioOnly: boolean; useResourcesForJplagBaseCode: boolean; + lockAssessmentsToTutorialStream: boolean; public readonly taskPrerequisitesCache: EntityCache = new EntityCache(); diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index 06bea8da49..cb36d3cc32 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -138,6 +138,7 @@ export class TaskDefinitionService extends CachedEntityService { }, }, 'useResourcesForJplagBaseCode', + 'lockAssessmentsToTutorialStream', ); this.mapping.mapAllKeysToJsonExcept( diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html index 0c669784dd..89cf35865f 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html @@ -81,7 +81,11 @@ class="clearfix w-full" style="padding: 0; height: 60px" togglePosition="before" - [selected]="task.status === 'discuss' || attendance" + [selected]=" + (task.status === 'discuss' || attendance) && + (!task.definition.lockAssessmentsToTutorialStream || + currentUserTutorsInStream(task.definition.tutorialStream)) + " > @if (task) {
    diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts index 445eb16cc3..567988d53d 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts @@ -12,6 +12,7 @@ import { TaskDefinition, TaskService, TaskStatusEnum, + TutorialStream, Unit, UnitService, UserService, @@ -69,6 +70,19 @@ export class TutorDiscussionComponent implements AfterViewInit { private taskService: TaskService, ) {} + public currentUserTutorsInStream(tutorialStream: TutorialStream): boolean { + const user = this.userService.currentUser; + const tutorials = this.unit.tutorials.filter( + (t) => + t.tutorialStream.abbreviation === tutorialStream.abbreviation && + t.tutorialStream.name === tutorialStream.name, + ); + if (tutorials.some((t) => t.tutor.id === user.id)) { + return true; + } + return false; + } + onTabChange(event: MatTabChangeEvent): void { if (event.index === 0) { this.showComments(); diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html index 5d93345d7f..f36a92f380 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html @@ -56,3 +56,9 @@
    + +
    + Only allow tutors in this tutorial stream to assess this task +
    From 8a56b651ec2f032585de734d8e5f66908fa7098a Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 6 Nov 2025 16:28:29 +1100 Subject: [PATCH 0722/1280] chore(release): 10.0.0-62 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c2462bcfcf..7fde181cd4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-62](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-61...v10.0.0-62) (2025-11-06) + + +### Features + +* restrict assessments to tutors in the same tutorial stream ([#1033](https://github.com/b0ink/doubtfire-deploy/issues/1033)) ([29fbc14](https://github.com/b0ink/doubtfire-deploy/commit/29fbc1498b0d48811cb59c5f2a66871fbac06849)) + ## [10.0.0-61](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-60...v10.0.0-61) (2025-11-06) ## [10.0.0-60](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-59...v10.0.0-60) (2025-11-05) diff --git a/package-lock.json b/package-lock.json index 0f3a3c3b45..8087a7e128 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-61", + "version": "10.0.0-62", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-61", + "version": "10.0.0-62", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 09053700c4..21346adcca 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-61", + "version": "10.0.0-62", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 24f358ecae920e3eeb2f8b50e181be0ae68afde2 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 30 Sep 2025 13:39:20 +1000 Subject: [PATCH 0723/1280] refactor: replace range datepickers with three separate datepickers --- .../task-definition-dates.component.html | 74 +++++++++---------- 1 file changed, 37 insertions(+), 37 deletions(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.html index a2285a0969..c6a3eb74c6 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.html @@ -1,43 +1,43 @@
    - - Start date to suggested completion date - - - - - - - + + Start Date + + + + Suggested date for students to begin the task. - - Suggestion completion date to final feedback - - - - + + Target Date + + + + Recommended target date for students to complete the task. + - - + + Final Feedback Date + + + + Final deadline for receiving feedback.
    From 6c4931bd40e94b9a2fbafe3b0b6c9d8670564c74 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:17:53 +1100 Subject: [PATCH 0724/1280] chore: replace doubtfire with ontrack --- src/app/common/file-uploader/file-uploader.coffee | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/common/file-uploader/file-uploader.coffee b/src/app/common/file-uploader/file-uploader.coffee index c492dac115..89c0c17755 100644 --- a/src/app/common/file-uploader/file-uploader.coffee +++ b/src/app/common/file-uploader/file-uploader.coffee @@ -263,7 +263,7 @@ angular.module('doubtfire.common.file-uploader', ["ngFileUpload"]) response = JSON.parse xhr.responseText catch e if xhr.status is 0 - response = { error: 'Could not connect to the Doubtfire server' } + response = { error: 'Could not connect to the OnTrack server' } else response = xhr.responseText # Success (20x success range) From 5b4b097a9b189e5a816695cce7438104f1144283 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 10 Nov 2025 15:21:56 +1100 Subject: [PATCH 0725/1280] feat: open project dashboard from portfolios view (#1040) --- src/app/units/states/portfolios/portfolios.coffee | 4 ++++ src/app/units/states/portfolios/portfolios.tpl.html | 7 +++++++ 2 files changed, 11 insertions(+) diff --git a/src/app/units/states/portfolios/portfolios.coffee b/src/app/units/states/portfolios/portfolios.coffee index e87a17027d..d13cca4433 100644 --- a/src/app/units/states/portfolios/portfolios.coffee +++ b/src/app/units/states/portfolios/portfolios.coffee @@ -149,4 +149,8 @@ angular.module('doubtfire.units.states.portfolios', []) $scope.transferToD2L = -> D2lTransferModal.open($scope.unit) + + $scope.openProject = ($event, project) -> + $event.stopPropagation() + window.open("/projects/#{project.id}/dashboard/?tutor=true", "_blank") ) diff --git a/src/app/units/states/portfolios/portfolios.tpl.html b/src/app/units/states/portfolios/portfolios.tpl.html index 376277513e..34d00d5d7f 100644 --- a/src/app/units/states/portfolios/portfolios.tpl.html +++ b/src/app/units/states/portfolios/portfolios.tpl.html @@ -214,6 +214,13 @@

    Mark Portfolios

    {{student.hasPortfolio ? "Yes" : "No"}}
    {{student.grade}} + +
    From 770b1718f307f6dbb835bef706bff1aa46bb68d5 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 10 Nov 2025 15:23:30 +1100 Subject: [PATCH 0726/1280] chore(release): 10.0.0-63 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fde181cd4..25972b520c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-63](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-62...v10.0.0-63) (2025-11-10) + + +### Features + +* open project dashboard from portfolios view ([5b4b097](https://github.com/b0ink/doubtfire-deploy/commit/5b4b097a9b189e5a816695cce7438104f1144283)), closes [#1040](https://github.com/b0ink/doubtfire-deploy/issues/1040) + ## [10.0.0-62](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-61...v10.0.0-62) (2025-11-06) diff --git a/package-lock.json b/package-lock.json index 8087a7e128..ac840fcd6d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-62", + "version": "10.0.0-63", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-62", + "version": "10.0.0-63", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 21346adcca..47621b97b8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-62", + "version": "10.0.0-63", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 9ab015d168cf7e421500910766b9e6fb0bf907f5 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 10 Nov 2025 16:49:02 +1100 Subject: [PATCH 0727/1280] fix: avoid calling window to open project in new tab --- src/app/units/states/portfolios/portfolios.coffee | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/app/units/states/portfolios/portfolios.coffee b/src/app/units/states/portfolios/portfolios.coffee index d13cca4433..62c70a04f3 100644 --- a/src/app/units/states/portfolios/portfolios.coffee +++ b/src/app/units/states/portfolios/portfolios.coffee @@ -152,5 +152,9 @@ angular.module('doubtfire.units.states.portfolios', []) $scope.openProject = ($event, project) -> $event.stopPropagation() - window.open("/projects/#{project.id}/dashboard/?tutor=true", "_blank") + # HACK: avoids using window.open() to prevent AngularJS error + link = document.createElement('a') + link.href = "/projects/#{project.id}/dashboard/?tutor=true" + link.target = '_blank' + link.click() ) From 7d1dbc33476cd669ab5217cfd70a53017c557d6e Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 11 Nov 2025 12:04:28 +1100 Subject: [PATCH 0728/1280] refactor: move overseer script url to task definition model --- src/app/api/models/task-definition.ts | 4 ++ .../overseer-script-editor-modal.component.ts | 40 +++++++++---------- 2 files changed, 24 insertions(+), 20 deletions(-) diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index 1560b94909..814c7a9c53 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -276,6 +276,10 @@ export class TaskDefinition extends Entity { }/task_assessment_resources.json`; } + public get taskOverseerExecutionScriptUrl() { + return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.unit.id}/task_definitions/${this.id}/overseer_script`; + } + public getJplagReportUrl() { return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.unit.id}/task_definitions/${this.id}/jplag_report`; } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts index f64d3b4763..ddcf7c1d40 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts @@ -2,8 +2,7 @@ import {HttpClient} from '@angular/common/http'; import {Component, Inject, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {CodeModel} from '@ngstack/code-editor'; -import {AppInjector} from 'src/app/app-injector'; -import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {AlertService} from 'src/app/common/services/alert.service'; import {OverseerScriptEditorModalData} from './overseer-script-editor-modal.service'; @Component({ @@ -16,6 +15,7 @@ export class OverseerScriptEditorModalComponent implements OnInit { @Inject(MAT_DIALOG_DATA) public data: OverseerScriptEditorModalData, public dialogRef: MatDialogRef, private httpClient: HttpClient, + private alertService: AlertService, ) {} public model: CodeModel = { @@ -29,26 +29,26 @@ export class OverseerScriptEditorModalComponent implements OnInit { loading: boolean = false; ngOnInit() { this.loading = true; - // TODO: move to taskDefinition model - const url = `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.data.taskDefinition.unit.id}/task_definitions/${this.data.taskDefinition.id}/overseer_script`; - this.httpClient.get(url).subscribe((data: string) => { - this.model.value = data; - this.loading = false; - }); + this.httpClient + .get(this.data.taskDefinition.taskOverseerExecutionScriptUrl) + .subscribe((data: string) => { + this.model.value = data; + this.loading = false; + }); } save() { - console.log(this.model.value); - const url = `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.data.taskDefinition.unit.id}/task_definitions/${this.data.taskDefinition.id}/overseer_script`; - - this.httpClient.put(url, {script_content: this.model.value}).subscribe({ - next: (result) => { - console.log(result); - this.dialogRef.close(); - }, - error: (error) => { - console.error(error); - }, - }); + this.httpClient + .put(this.data.taskDefinition.taskOverseerExecutionScriptUrl, { + script_content: this.model.value, + }) + .subscribe({ + next: (_result) => { + this.dialogRef.close(); + }, + error: (error) => { + this.alertService.error(`Failed to save script: ${error}`, 6000); + }, + }); } } From 8eaffbcb65b835d615646d4c9560cbf1881deeb9 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 11 Nov 2025 12:17:16 +1100 Subject: [PATCH 0729/1280] refactor: base64 encode overseer script before sending to server --- .../overseer-script-editor-modal.component.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts index ddcf7c1d40..128e2410f0 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts @@ -38,9 +38,12 @@ export class OverseerScriptEditorModalComponent implements OnInit { } save() { + const scriptOriginal = this.model.value; + const scriptEncoded = this.base64UrlEncode(scriptOriginal); + this.httpClient .put(this.data.taskDefinition.taskOverseerExecutionScriptUrl, { - script_content: this.model.value, + script_content: scriptEncoded, }) .subscribe({ next: (_result) => { @@ -51,4 +54,8 @@ export class OverseerScriptEditorModalComponent implements OnInit { }, }); } + + private base64UrlEncode(str) { + return btoa(str).replace(/\+/g, '-').replace(/\//g, '_').replace(/=+$/, ''); + } } From 40f2640e6579536cef8e82e9476733083b82bac1 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Thu, 13 Nov 2025 08:15:27 +1100 Subject: [PATCH 0730/1280] fix: use new google fonts api for proper weight loading (#1039) --- src/index.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/index.html b/src/index.html index 2e715e206f..af609f230c 100644 --- a/src/index.html +++ b/src/index.html @@ -18,7 +18,10 @@ href="https://fonts.googleapis.com/icon?family=Material+Icons|Material+Icons+Outlined" rel="stylesheet" /> - + Loading... From 5aef6cfddaf61408e6f3169002f9b8ce00b7dfac Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 13 Nov 2025 15:09:02 +1100 Subject: [PATCH 0731/1280] chore: specify only time exceeded tasks are updated --- .../unit-details-editor/unit-details-editor.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts index 0ea300bf8e..7ac7161a73 100644 --- a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts @@ -90,7 +90,7 @@ export class UnitDetailsEditorComponent implements OnInit { const modal = this.confirmationModal.show( 'Enable Assess in Portfolio?', `Are you sure you want to enable "Assess in Portfolio" for late submissions? - This will update any existing Time/Feedback Exceeded tasks to the "Assess in Portfolio" state. + This will update any existing Time Exceeded tasks to the "Assess in Portfolio" state. You will not be able to disable this setting while any tasks remain in the "Assess in Portfolio" state.`, () => { this.unit.markLateSubmissionsAsAssessInPortfolio = true; From 223f4ea3711fcbd6f3b1353f8d896df000e4f09c Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 17 Nov 2025 12:59:54 +1100 Subject: [PATCH 0732/1280] chore: disable no inferrable types rule --- eslint.config.js | 1 + 1 file changed, 1 insertion(+) diff --git a/eslint.config.js b/eslint.config.js index a327c5d852..a519ed7891 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -29,6 +29,7 @@ module.exports = tseslint.config( processor: angular.processInlineTemplates, // Override specific rules for TypeScript files (these will take priority over the extended configs above) rules: { + '@typescript-eslint/no-inferrable-types': 'off', '@angular-eslint/directive-selector': [ 'error', { From 572f104c3c9659ea1a176fa862e5dec66f82fa8b Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 17 Nov 2025 13:09:34 +1100 Subject: [PATCH 0733/1280] refactor: migrate file uploader (#1043) * chore: init file uploader migration * refactor: clean up ui and reset uploader after completion * chore: use external name on error * refactor: migrate remaining file uploaders * refactor: center error size * refactor: ensure uploader is hidden but remains in dom * refactor: remove logs * refactor: improve type safety * chore: typo --- package-lock.json | 16 + package.json | 1 + src/app/common/common.coffee | 1 - .../file-uploader.component.html | 164 +++++++++ .../file-uploader.component.scss | 16 + .../file-uploader/file-uploader.component.ts | 325 ++++++++++++++++++ .../csv-upload-modal.tpl.html | 2 +- src/app/doubtfire-angular.module.ts | 4 + src/app/doubtfire-angularjs.module.ts | 7 +- .../portfolio-add-extra-files-step.tpl.html | 16 +- ...olio-learning-summary-report-step.tpl.html | 10 +- .../upload-submission-modal.coffee | 6 + .../upload-submission-modal.tpl.html | 29 +- .../task-ilo-alignment-editor.tpl.html | 13 +- .../unit-group-set-editor.tpl.html | 36 +- .../unit-ilo-editor/unit-ilo-editor.tpl.html | 6 +- 16 files changed, 598 insertions(+), 54 deletions(-) create mode 100644 src/app/common/file-uploader/file-uploader.component.html create mode 100644 src/app/common/file-uploader/file-uploader.component.scss create mode 100644 src/app/common/file-uploader/file-uploader.component.ts diff --git a/package-lock.json b/package-lock.json index c3968a6562..f95bc84f0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,6 +23,7 @@ "@angular/service-worker": "^18.0", "@angular/upgrade": "^18.0", "@ctrl/ngx-emoji-mart": "^9.2.0", + "@iplab/ngx-file-upload": "^18.0.0", "@ngneat/hotkeys": "^4.0.0", "@swimlane/ngx-charts": "^20.5.0", "@uirouter/angular": "^14.0", @@ -4534,6 +4535,21 @@ "node": ">=18" } }, + "node_modules/@iplab/ngx-file-upload": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/@iplab/ngx-file-upload/-/ngx-file-upload-18.0.0.tgz", + "integrity": "sha512-Uz+011ZOGtVeFAPuOcFHBB/hyLZrV3RNOqT21J13YMqWr5jadba0t67towrQ7VTHLMYt1Du/UHDmv5wV/h7/sg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/animations": "^18.0.0", + "@angular/common": "^18.0.0", + "@angular/core": "^18.0.0", + "@angular/forms": "^18.0.0", + "rxjs": "^7.0.0" + } + }, "node_modules/@isaacs/cliui": { "version": "8.0.2", "dev": true, diff --git a/package.json b/package.json index e3ad87adbc..506258d1be 100644 --- a/package.json +++ b/package.json @@ -40,6 +40,7 @@ "@angular/service-worker": "^18.0", "@angular/upgrade": "^18.0", "@ctrl/ngx-emoji-mart": "^9.2.0", + "@iplab/ngx-file-upload": "^18.0.0", "@ngneat/hotkeys": "^4.0.0", "@uirouter/angular": "^14.0", "@uirouter/angular-hybrid": "^18.0", diff --git a/src/app/common/common.coffee b/src/app/common/common.coffee index f330d8f6ac..6710f40ec4 100644 --- a/src/app/common/common.coffee +++ b/src/app/common/common.coffee @@ -2,6 +2,5 @@ angular.module("doubtfire.common", [ 'doubtfire.common.services' 'doubtfire.common.filters' 'doubtfire.common.modals' - 'doubtfire.common.file-uploader' 'doubtfire.common.content-editable' ]) diff --git a/src/app/common/file-uploader/file-uploader.component.html b/src/app/common/file-uploader/file-uploader.component.html new file mode 100644 index 0000000000..54dc30d842 --- /dev/null +++ b/src/app/common/file-uploader/file-uploader.component.html @@ -0,0 +1,164 @@ + + + @if (!showUploader) { + + } + +
    + @if (showUploader && uploadingInfo === null && shownUploadZones.length) { +
    + @for (upload of shownUploadZones; track upload) { + @if (!singleDropZone && showName) { +
    + {{ uploadZones.length === 1 ? '' : $index + 1 + ' - ' }} + {{ upload.display.name }} +
    + } + + @if (singleDropZone && showName) { +
    Select {{ upload.display.name }}
    + } + +
    + + +
    + @if (!upload.display.error) { + {{ upload.display.icon }} + @if (dropSupported) { +

    + Drop {{ upload.display.type }} file here
    or click to select +

    + } @else { +

    Click to select {{ upload.display.type }} file

    + } + } @else { +
    + block +

    Invalid file provided

    + Accepted: {{ upload.accept.split(',').join(', ') }} +
    + } +
    +
    + + Browse for file +
    +
    + + @if (!singleDropZone && upload.model?.length > 0) { +
    + {{ upload.display.icon }} + {{ upload.model[0].name }} + +
    + } + } +
    + } + + @if (showUploader && singleDropZone && uploadingInfo === null) { +
    +
    Upload Summary
    + + @for (upload of uploadZones; track upload) { +
    +
    + {{ upload.display.icon }} + {{ upload.display.name }} +
    + + @if (upload.model?.length > 0) { + {{ upload.model[0].name }} + + } @else { + File Pending + } +
    + } +
    + } +
    + + @if (showUploader && !isUploading) { +
    + @if (showUploadButton && readyToUpload() && uploadingInfo === null) { + + } + + @if (asButton) { + + } +
    + } + + @if (showUploader && readyToUpload() && isUploading) { + @if (!uploadingInfo?.complete) { +
    +
    + @for (upload of uploadZones; track upload) { + {{ upload.display.icon }} + } + arrow_right_alt + +
    + + + +
    + } + + @if (uploadingInfo?.complete) { +
    +
    + + {{ uploadingInfo.success ? 'check_circle' : 'cancel' }} + + + + File Upload {{ uploadingInfo.success ? 'Successful' : 'Failed' }} + +
    + + @if (!uploadingInfo.success) { +
    +
    +

    Error Message: {{ uploadingInfo.error }}

    + +
    + + +
    +
    + } +
    + } + } +
    +
    diff --git a/src/app/common/file-uploader/file-uploader.component.scss b/src/app/common/file-uploader/file-uploader.component.scss new file mode 100644 index 0000000000..6809e06815 --- /dev/null +++ b/src/app/common/file-uploader/file-uploader.component.scss @@ -0,0 +1,16 @@ +file-upload .mat-icon, +.complete .mat-icon { + font-size: 50px; + height: 50px; + width: 50px; +} + +.uploading .mat-icon { + font-size: 75px; + height: 75px; + width: 75px; +} + +::ng-deep file-upload .upload-input { + width: 100%; +} diff --git a/src/app/common/file-uploader/file-uploader.component.ts b/src/app/common/file-uploader/file-uploader.component.ts new file mode 100644 index 0000000000..877eddc9cd --- /dev/null +++ b/src/app/common/file-uploader/file-uploader.component.ts @@ -0,0 +1,325 @@ +import { + Component, + EventEmitter, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges, +} from '@angular/core'; +import {FileUploadControl} from '@iplab/ngx-file-upload'; +import {UserService} from 'src/app/api/services/user.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; + +interface File { + name: string; + type: string; +} + +interface UploadDisplay { + name: string; + icon: string; + type: string; + error: boolean; +} +interface UploadZone { + name: string; + model: any; + accept: string; + accepts: string[]; + rejects: string[]; + display: UploadDisplay; +} + +interface UploadingInfo { + progress: number; + success: boolean; + error: string; + complete: boolean; +} + +export const ACCEPTED_TYPES = { + document: { + extensions: ['pdf', 'ps'], + // icon: 'fa-file-pdf-o', + icon: 'article_outlined', + name: 'PDF', + }, + csv: { + extensions: ['csv', 'xls', 'xlsx'], + icon: 'insert_chart_outlined', + name: 'CSV', + }, + code: { + // prettier-ignore + extensions: [ + 'pas', 'cpp', 'c', 'cs', 'csv', 'h', 'hpp', 'java', 'py', 'js', 'html', 'coffee', 'rb', 'css', + 'scss', 'yaml', 'yml', 'xml', 'json', 'ts', 'r', 'rmd', 'rnw', 'rhtml', 'rpres', 'tex', + 'vb', 'sql', 'txt', 'md', 'jack', 'hack', 'asm', 'hdl', 'tst', 'out', 'cmp', 'vm', 'sh', 'bat', + 'dat', 'ipynb', 'pml', 'vue' + ], + // icon: 'fa-file-code-o', + // icon: 'code', + icon: 'integration_instructions_outlined', + name: 'code', + }, + image: { + extensions: ['png', 'bmp', 'tiff', 'tif', 'jpeg', 'jpg', 'gif'], + // icon: 'fa-file-image-o', + icon: 'image_outlined', + name: 'image', + }, + zip: { + extensions: ['zip', 'tar.gz', 'tar'], + // icon: 'fa-file-zip-o', + icon: 'zip_outlined', + name: 'archive', + }, +} as const; + +@Component({ + selector: 'f-file-uploader', + templateUrl: './file-uploader.component.html', + styleUrls: ['./file-uploader.component.scss'], +}) +export class FileUploaderComponent implements OnInit, OnChanges { + @Input() files: File[]; + @Input() url: string; + @Input() method = 'POST'; + @Input() payload?: any; + + @Input() onBeforeUpload?: () => void; + @Input() onSuccess?: (response: any) => void; + @Input() onFailure?: (response: any) => void; + @Input() onComplete?: () => void; + @Input() onClickFailureCancel?: () => void; + + @Input() isUploading: boolean; + @Input() isReady: boolean; + @Input() showName: boolean = true; + @Input() asButton: boolean = false; + @Input() singleDropZone: boolean = false; + @Input() showUploadButton: boolean = true; + @Input() resetAfterUpload: boolean = true; + + @Input() initiateUpload?: () => void; + + // HACK: workaround for TypeScript -> Coffeescript communication + // Once all parent components such as upload-submission-modal are migrated.. + // .. these *wont* be necessary anymore + // Parent components should declare the file-uploader using @ViewChild() and directly call initiateUpload() + @Output() isReadyChange = new EventEmitter(); + @Output() uploadReady = new EventEmitter<() => void>(); + + public readonly ACCEPTED_TYPES = ACCEPTED_TYPES; + + public showUploader: boolean = false; + public uploadingInfo: UploadingInfo = null; + + public fileUploadControl = new FileUploadControl({listVisible: false, discardInvalid: true}); + public shownUploadZones: UploadZone[] = []; + public uploadZones: UploadZone[] = []; + public dropSupported: boolean = true; + + constructor( + private userService: UserService, + private constants: DoubtfireConstants, + ) {} + + private externalName: string = 'OnTrack'; + + ngOnInit(): void { + this.showUploader = !this.asButton; + this.createUploadZones(this.files); + + this.fileUploadControl.valueChanges.subscribe(() => { + setTimeout(() => { + this.validateFiles(); + }); + }); + + this.uploadReady.emit(this.initiateUploadInternal.bind(this)); + + if (!this.onClickFailureCancel) { + this.onClickFailureCancel = this.resetUploader; + } + + this.resetUploader(); + + this.constants.ExternalName.subscribe((name) => { + this.externalName = name; + }); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['files']) { + this.createUploadZones(changes.files.currentValue); + } + } + + public backToUpload() { + this.isUploading = false; + this.uploadingInfo = null; + } + + validateFiles() { + for (const upload of this.shownUploadZones) { + if (upload.model?.length) { + const name: string = upload.model[0].name.toLowerCase(); + const accepts: string[] = upload.accepts.map((ext: string) => ext.toLowerCase()); + const valid = accepts.some((ext) => name.endsWith(ext)); + if (!valid) { + upload.model = null; + upload.display.error = true; + setTimeout(() => { + upload.display.error = null; + }, 5000); + } + } + } + this.refreshShownUploadZones(); + } + + clearEnqueuedUpload(upload: UploadZone) { + upload.model = null; + this.refreshShownUploadZones(); + } + + readyToUpload(): boolean { + const allSelected = this.uploadZones.every((zone) => zone.model?.length); + this.updateReadyState(allSelected); + return allSelected; + } + + updateReadyState(ready: boolean) { + this.isReady = ready; + this.isReadyChange.emit(ready); + } + + resetUploader() { + this.uploadingInfo = null; + this.isUploading = false; + this.showUploader = !this.asButton; + for (const upload of this.uploadZones) { + this.clearEnqueuedUpload(upload); + } + } + + initiateUploadInternal() { + if (!this.readyToUpload()) { + return; + } + if (this.onBeforeUpload) { + this.onBeforeUpload(); + } + + this.uploadingInfo = { + progress: 5, + success: null, + error: null, + complete: false, + }; + + this.isUploading = true; + + const xhr = new XMLHttpRequest(); + const form = new FormData(); + + // Append files + for (const zone of this.uploadZones) { + if (zone.model?.length) { + form.append(zone.name, zone.model[0]); + } + } + + // Append payload + if (this.payload) { + for (const [key, value] of Object.entries(this.payload)) { + let v = value; + if (typeof v === 'object') v = JSON.stringify(v); + form.append(key, v as any); + } + } + + xhr.upload.onprogress = (event) => { + if (event.total) { + this.uploadingInfo.progress = Math.floor((event.loaded / event.total) * 100); + } + }; + + xhr.onreadystatechange = () => { + if (xhr.readyState === 4) { + setTimeout(() => { + this.uploadingInfo.complete = true; + let response: any = null; + try { + response = JSON.parse(xhr.responseText); + } catch (_e) { + if (xhr.status === 0) { + response = {error: `Could not connect to ${this.externalName} the server`}; + } else { + response = xhr.responseText; + } + } + + if (xhr.status >= 200 && xhr.status < 300) { + this.onSuccess?.(response); + this.uploadingInfo.success = true; + setTimeout(() => { + this.onComplete?.(); + if (this.resetAfterUpload) { + this.resetUploader(); + } + }, 2500); + } else { + this.onFailure?.(response); + this.uploadingInfo.success = false; + this.uploadingInfo.error = (response?.error ?? 'Unknown error') as string; + } + }, 2000); + } + }; + const method = this.method ?? 'POST'; + xhr.open(method, this.url, true); + + xhr.setRequestHeader('Auth-Token', this.userService.currentUser.authenticationToken); + xhr.setRequestHeader('Username', this.userService.currentUser.username); + + xhr.send(form); + } + + // onClickFailureCancelInternal() { + // console.log('onClickFailureCancelInternal'); + // } + + refreshShownUploadZones = () => { + if (this.singleDropZone) { + const firstEmpty = this.uploadZones.find((z) => !z.model || z.model.length === 0); + this.shownUploadZones = firstEmpty ? [firstEmpty] : []; + } + }; + + createUploadZones(files: File[]) { + const zones = Object.entries(files).map(([uploadName, uploadData]) => { + const typeData = ACCEPTED_TYPES[uploadData.type]; + if (!typeData) throw new Error(`Invalid type provided to File Uploader ${uploadData.type}`); + + return { + name: uploadName, + model: null, + accept: `.${typeData.extensions.join(',.')}`, + accepts: typeData.extensions, + rejects: null, + display: { + name: uploadData.name, + icon: typeData.icon, + type: typeData.name, + error: false, + }, + }; + }); + + this.shownUploadZones = this.singleDropZone ? [zones[0]] : zones; + this.uploadZones = zones; + } +} diff --git a/src/app/common/modals/csv-result-modal/csv-upload-modal.tpl.html b/src/app/common/modals/csv-result-modal/csv-upload-modal.tpl.html index 6112f50c7e..5f94b642fe 100644 --- a/src/app/common/modals/csv-result-modal/csv-upload-modal.tpl.html +++ b/src/app/common/modals/csv-result-modal/csv-upload-modal.tpl.html @@ -7,7 +7,7 @@
    - - + +
    diff --git a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.tpl.html b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.tpl.html index 960c0014ab..b190d6f35c 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.tpl.html +++ b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.tpl.html @@ -55,11 +55,11 @@

    you have achieved a {{targetGrade}} in {{unit.name}}.

    - +
    diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee index b9c9ebd2b9..7646c70ff4 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee @@ -55,6 +55,12 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) $scope.submissionTypes = submissionTypes + $scope.isReadyChange = (ready) -> + $scope.uploader.isReady = ready + + $scope.uploadIsReady = (callback) -> + $scope.uploader.start = callback + # Upload files $scope.uploader = { # url: Task.generateSubmissionUrl($scope.task.project, $scope.task) diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html index 92070ac30f..9b96abcd0b 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html @@ -60,20 +60,21 @@

    - +
    diff --git a/src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.tpl.html b/src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.tpl.html index e95245bd46..20f3664c5c 100644 --- a/src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.tpl.html +++ b/src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.tpl.html @@ -105,12 +105,13 @@

    Import Task Outcome Alignments

    Import links between tasks and outcomes from a CSV containing: unit_code, learning_outcome, task_abbr, rating.
    - +

    Export Task Outcome Alignments

    diff --git a/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.tpl.html b/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.tpl.html index c83b2d5fd7..90313b86b6 100644 --- a/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.tpl.html +++ b/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.tpl.html @@ -162,14 +162,14 @@

    Import Groups for {{selectedGroupSet.name}} Download CSV
    - - + +

    @@ -195,15 +195,17 @@

    Download CSV
    - - -

    + + +
    +
    diff --git a/src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.tpl.html b/src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.tpl.html index 3ce30ff314..84bd7ef0ab 100644 --- a/src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.tpl.html +++ b/src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.tpl.html @@ -54,7 +54,11 @@

    Batch Upload Outcome Definitions

    description.
    - +
    From db32f072fa912ee648c636f64e4a26ed10e5e35b Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 17 Nov 2025 13:19:48 +1100 Subject: [PATCH 0734/1280] chore: remove any types --- .../file-uploader/file-uploader.component.ts | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/app/common/file-uploader/file-uploader.component.ts b/src/app/common/file-uploader/file-uploader.component.ts index 877eddc9cd..85eb85e792 100644 --- a/src/app/common/file-uploader/file-uploader.component.ts +++ b/src/app/common/file-uploader/file-uploader.component.ts @@ -11,7 +11,7 @@ import {FileUploadControl} from '@iplab/ngx-file-upload'; import {UserService} from 'src/app/api/services/user.service'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; -interface File { +interface FileData { name: string; type: string; } @@ -24,7 +24,7 @@ interface UploadDisplay { } interface UploadZone { name: string; - model: any; + model: File[]; accept: string; accepts: string[]; rejects: string[]; @@ -83,14 +83,14 @@ export const ACCEPTED_TYPES = { styleUrls: ['./file-uploader.component.scss'], }) export class FileUploaderComponent implements OnInit, OnChanges { - @Input() files: File[]; + @Input() files: FileData[]; @Input() url: string; @Input() method = 'POST'; - @Input() payload?: any; + @Input() payload?: unknown; @Input() onBeforeUpload?: () => void; - @Input() onSuccess?: (response: any) => void; - @Input() onFailure?: (response: any) => void; + @Input() onSuccess?: (response) => void; + @Input() onFailure?: (response) => void; @Input() onComplete?: () => void; @Input() onClickFailureCancel?: () => void; @@ -237,7 +237,7 @@ export class FileUploaderComponent implements OnInit, OnChanges { for (const [key, value] of Object.entries(this.payload)) { let v = value; if (typeof v === 'object') v = JSON.stringify(v); - form.append(key, v as any); + form.append(key, v); } } @@ -251,10 +251,11 @@ export class FileUploaderComponent implements OnInit, OnChanges { if (xhr.readyState === 4) { setTimeout(() => { this.uploadingInfo.complete = true; - let response: any = null; + let response = null; try { response = JSON.parse(xhr.responseText); - } catch (_e) { + } catch (e) { + console.error(e); if (xhr.status === 0) { response = {error: `Could not connect to ${this.externalName} the server`}; } else { @@ -299,7 +300,7 @@ export class FileUploaderComponent implements OnInit, OnChanges { } }; - createUploadZones(files: File[]) { + createUploadZones(files: FileData[]) { const zones = Object.entries(files).map(([uploadName, uploadData]) => { const typeData = ACCEPTED_TYPES[uploadData.type]; if (!typeData) throw new Error(`Invalid type provided to File Uploader ${uploadData.type}`); From 37e109a9fffa0e2d71143afabb9423b5511cf2fd Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 17 Nov 2025 13:29:14 +1100 Subject: [PATCH 0735/1280] chore: remove old file uploader component --- .../common/file-uploader/file-uploader.coffee | 298 ------------------ .../common/file-uploader/file-uploader.scss | 139 -------- .../file-uploader/file-uploader.tpl.html | 104 ------ 3 files changed, 541 deletions(-) delete mode 100644 src/app/common/file-uploader/file-uploader.coffee delete mode 100644 src/app/common/file-uploader/file-uploader.scss delete mode 100644 src/app/common/file-uploader/file-uploader.tpl.html diff --git a/src/app/common/file-uploader/file-uploader.coffee b/src/app/common/file-uploader/file-uploader.coffee deleted file mode 100644 index c492dac115..0000000000 --- a/src/app/common/file-uploader/file-uploader.coffee +++ /dev/null @@ -1,298 +0,0 @@ -angular.module('doubtfire.common.file-uploader', ["ngFileUpload"]) - -.directive 'fileUploader', -> - restrict: 'E' - replace: true - templateUrl: 'common/file-uploader/file-uploader.tpl.html' - scope: - # Files map a key (file name to be uploaded) to a value (containing a - # a display name, and the type of file that is to be accepted, where - # type is one of [document, csv, archive, code, image] - # E.g.: - # { file0: { name: 'Silly Name Code', type: 'code' }, - # fileX: { name: 'Silly name Shot', type: 'image' } ... } - files: '=' - # URL to where image is to be uploaded - url: '=' - # Optional HTTP method used to post data (defaults to POST) - method: '@' - # Other payload data to pass in the upload - # E.g.: - # { unit_id: 10, other: { key: data, with: [array, of, stuff] } ... } - payload: '=?' - # Optional function to notify just prior to upload, enables injection of payload for example - onBeforeUpload: '=?' - # Optional function to perform on success (with one response parameter) - onSuccess: '=?' - # Optional function to perform on failure (with one response parameter) - onFailure: '=?' - # Optional function to perform when the upload is successful and about - # to go back into its default state - onComplete: '=?' - # This value is bound to whether or not the uploader is currently uploading - isUploading: '=?' - # This value is bound to whether or not the uploader is ready to upload - isReady: '=?' - # Shows the names of files to be uploaded (defaults to true) - showName: '=?' - # Shows initially as button - asButton: '=?' - # Exposed files that are in the zone - filesSelected: '=?' - # Whether we have one or many drop zones (default is false) - singleDropZone: '=?' - # Whether or not we show the upload button or do we hide it allowing an - # external trigger to upload (default is true) - showUploadButton: '=?' - # Sets this scope variable to a function that can then be triggered externally - # from outside the scope - initiateUpload: '=?' - # What happens when we click cancel on failure - onClickFailureCancel: '=?' - # Whether we should reset after upload - resetAfterUpload: '=?' - controller: ($scope, $timeout, newUserService) -> - # - # Accepted upload types with associated data - # - ACCEPTED_TYPES = - document: - extensions: ['pdf', 'ps'] - icon: 'fa-file-pdf-o' - name: 'PDF' - csv: - extensions: ['csv','xls','xlsx'] - icon: 'fa-file-excel-o' - name: 'CSV' - code: - extensions: ['pas', 'cpp', 'c', 'cs', 'csv', 'h', 'hpp', 'java', 'py', 'js', 'html', 'coffee', 'rb', 'css', - 'scss', 'yaml', 'yml', 'xml', 'json', 'ts', 'r', 'rmd', 'rnw', 'rhtml', 'rpres', 'tex', - 'vb', 'sql', 'txt', 'md', 'jack', 'hack', 'asm', 'hdl', 'tst', 'out', 'cmp', 'vm', 'sh', 'bat', - 'dat', 'ipynb', 'pml', 'vue'] - icon: 'fa-file-code-o' - name: 'code' - image: - extensions: ['png', 'bmp', 'tiff', 'tif', 'jpeg', 'jpg', 'gif'] - name: 'image' - icon: 'fa-file-image-o' - zip: - extensions: ['zip', 'tar.gz', 'tar'] - name: 'archive' - icon: 'fa-file-zip-o' - - # - # Error handling; check if empty files - # - throw Error "No files provided to uploader" if $scope.files?.length is 0 - - # - # Whether or not clearEnqueuedFiles is enabled - # - $scope.clearEnqueuedUpload = (upload) -> - upload.model = null - refreshShownUploadZones() - - # - # Default showName - # - $scope.showName ?= true - - # - # Default singleDropZone - # - $scope.singleDropZone ?= false - - # - # Default asButton - # - $scope.asButton ?= false - - # - # Only initially show uploader if not presenting as button - # - $scope.showUploader = !$scope.asButton - - # - # Default show upload button - # - $scope.showUploadButton ?= true - - # - # Default resetAfterUpload to true - # - $scope.resetAfterUpload ?= true - - # - # When a file is dropped, if there has been rejected files - # warn the user that that file is not okay - # - checkForError = (upload) -> - if upload.rejects?.length > 0 - upload.display.error = yes - upload.rejects = null - $timeout (-> upload.display.error = no), 4000 - return true - false - - # Called when the model has changed - $scope.modelChanged = (newFiles, upload) -> - return unless newFiles.length > 0 || upload.rejects.length > 0 - gotError = checkForError(upload) - unless gotError - $scope.filesSelected = _.flatten(_.map($scope.uploadZones, 'model')) - if $scope.singleDropZone - $scope.selectedFiles = $scope.uploadZones - refreshShownUploadZones() - - # - # Will refresh which shown drop zones are shown - # Only changes if showing one drop zone - # - refreshShownUploadZones = -> - if $scope.singleDropZone - # Find the first-most empty model in each zone - firstEmptyZone = _.find($scope.uploadZones, (zone) -> !zone.model? || zone.model.length == 0) - if firstEmptyZone? - $scope.shownUploadZones = [firstEmptyZone] - else - $scope.shownUploadZones = [] - - # - # Whether or not drop is supported by this browser - assume - # true initially, but the drop zone will alter this - # - $scope.dropSupported = true - - # - # Data required for each upload zone - # - createUploadZones = (files) -> - zones = _.map(files, (uploadData, uploadName) -> - type = uploadData.type - typeData = ACCEPTED_TYPES[type] - # No typeData found? - unless typeData? - throw Error "Invalid type provided to File Uploader #{type}" - zone = - name: uploadName - model: null - accept: "'." + typeData.extensions.join(',.') + "'" - # Rejected files - rejects: null - display: - name: uploadData.name - # Font awesome supports PDF (from Document), - # CSV, Code and Image icons - icon: typeData.icon - type: typeData.name - # Whether or not a reject error is shown - error: false - zone - ) - # Remove all but the active drop zone - if $scope.singleDropZone - $scope.shownUploadZones = [_.first(zones)] - else - $scope.shownUploadZones = zones - $scope.uploadZones = zones - createUploadZones($scope.files) - - # - # Watch for changes in the files, and recreate the zones when - # they do change - # - $scope.$watch 'files', (files, oldFiles) -> - createUploadZones(files) - - # - # Checks if okay to upload (i.e., file models exist for each drop zone) - # - $scope.readyToUpload = -> - $scope.isReady = _.compact(_.flatten (upload.model for upload in $scope.uploadZones)).length is _.keys($scope.files).length - - # - # Resets the uploader and call it - # - $scope.resetUploader = -> - # No upload info and we're not uploading - $scope.uploadingInfo = null - $scope.isUploading = false - $scope.showUploader = !$scope.asButton - for upload in $scope.uploadZones - $scope.clearEnqueuedUpload(upload) - $scope.resetUploader() - - # - # Override on click failure cancel if not set to just reset uploader - # - $scope.onClickFailureCancel ?= $scope.resetUploader - - - # - # Initiates the upload - # - $scope.initiateUpload = -> - return unless $scope.readyToUpload() - $scope.onBeforeUpload?() - - xhr = new XMLHttpRequest() - form = new FormData() - # Append data - files = ({ name: zone.name; data: zone.model[0] } for zone in $scope.uploadZones) - form.append file.name, file.data for file in files - # Append payload - payload = ({ key: k; value: v } for k, v of $scope.payload) - for payloadItem in payload - payloadItem.value = JSON.stringify(payloadItem.value) if _.isObject payloadItem.value - form.append payloadItem.key, payloadItem.value - # Set the percent - $scope.uploadingInfo = - progress: 5 - success: null - error: null - complete: false - $scope.isUploading = true - # Callbacks - xhr.onreadystatechange = -> - if xhr.readyState is 4 - $timeout (-> - # Upload is now complete - $scope.uploadingInfo.complete = true - response = null - try - response = JSON.parse xhr.responseText - catch e - if xhr.status is 0 - response = { error: 'Could not connect to the Doubtfire server' } - else - response = xhr.responseText - # Success (20x success range) - if xhr.status >= 200 and xhr.status < 300 - $scope.onSuccess?(response) - $scope.uploadingInfo.success = true - $timeout((-> - $scope.onComplete?() - if $scope.resetAfterUpload - $scope.resetUploader() - ), 2500) - # Fail - else - $scope.onFailure?(response) - $scope.uploadingInfo.success = false - $scope.uploadingInfo.error = response.error or "Unknown error" - $scope.$apply() - ), 2000 - xhr.upload.onprogress = (event) -> - $scope.uploadingInfo.progress = parseInt(100.0 * event.position / event.totalSize) - $scope.$apply() - # Default the method to POST if it was not defined - $scope.method = 'POST' unless $scope.method? - - # Send it - xhr.open $scope.method, $scope.url, true - - # Add auth details - xhr.setRequestHeader('Auth-Token', newUserService.currentUser.authenticationToken) - xhr.setRequestHeader('Username', newUserService.currentUser.username) - - xhr.send form diff --git a/src/app/common/file-uploader/file-uploader.scss b/src/app/common/file-uploader/file-uploader.scss deleted file mode 100644 index 4ca5cb6988..0000000000 --- a/src/app/common/file-uploader/file-uploader.scss +++ /dev/null @@ -1,139 +0,0 @@ -.file-uploader { - display: block; - // Add some margin like a

    - margin: 2.5em 0; - - // Colors to make it easy to understand - $hover-color: $brand-primary; - $accept-color: $brand-success; - $reject-color: $brand-danger; - - // Extra additional icons - $ban-icon: $fa-var-ban; - $download-icon: $fa-var-download; - - .upload-commit-actions { - margin-top: 1em; - .btn-upload { - margin-right: 1.5ex; - } - } - - .well.drop { - border: 2px #bbb dotted; - font-size: larger; - font-weight: bold; - color: #aaa; - text-align: center; - &, i { - @include transition(all 0.25s ease); - } - p small { - display: block; - } - &:hover { - cursor: pointer; - border-color: $hover-color; - color: $hover-color; - p small { - text-decoration: underline; - } - } - } - - // Wells which have file over - .well.drop.file-over { - cursor: copy; - border-color: $accept-color; - color: $accept-color; - // Switch the icon over - p.fa::before { - content: $download-icon; - } - } - // Rejected file over - .well.drop.file-rejected { - border-color: $reject-color; - color: $reject-color; - // Switch the icon over - p.fa::before { - content: $ban-icon; - } - } - - // File header - .selected-files { - &:not(.list-group) { - display: inline-block; - } - .selected-file { - display: block; - font-size: 1.2em; - i.file-type { - margin-right: 1ex; - font-size: 1.2em; - } - &.highlight { - animation: highlight-selected-file-animation; - animation-duration: 0.75s; - @keyframes highlight-selected-file-animation { - 0% { background: rgba(33, 150, 243, 0.4); } - 0% { box-shadow: 0 0 6px rgba(33, 150, 243, 1); } - 100% { box-shadow: 0 0 0px rgba(255, 255, 255, 0); } - } - } - } - } - a.clear-upload { - margin-left: 1ex; - &:hover i { - font-size: 1.15em; - color: $reject-color; - } - display: inline-block; - } - // Upload area/result - .upload-area { - .progress-area { - .progress { - margin-bottom: 0; - } - .icons { - width: 100%; - display: flex; - justify-content: center; - } - i.fa-arrow-right { - @include animation-wobble(); - } - i { - flex-basis: auto !important; - margin-right: 1ex; - font-size: 2em; - margin-bottom: 0.5em; - } - } - .result-area { - .result-text { - margin-bottom: 0; - display: flex; - justify-content: center; - align-items: center; - min-height: 34px; - } - i { - font-size: 2em; - @include animation-grow; - margin-right: 1ex; - } - .retry-options { - font-weight: bolder; - font-size: 1.2em; - a:first-child { - display: inline-block; - margin-right: 2ex; - } - } - } - } -} diff --git a/src/app/common/file-uploader/file-uploader.tpl.html b/src/app/common/file-uploader/file-uploader.tpl.html deleted file mode 100644 index 368f53380c..0000000000 --- a/src/app/common/file-uploader/file-uploader.tpl.html +++ /dev/null @@ -1,104 +0,0 @@ -

    -
    - -
    -
    -
    -
    - {{uploadZones.length == 1 ? '' : $index + 1 + ' -'}} {{upload.display.name}} -
    -
    - Select {{upload.display.name}} -
    -
    -

    -

    - Invalid file provided - Accepted files: {{upload.accept.split(',').join(', ')}} -

    -

    - Drop {{upload.display.type}} file here - or click to select one -

    -

    - Click to select {{upload.display.type}} file -

    -
    -
    - - - {{upload.model[0].name}} - - - - -
    -
    -
    -
    Upload Summary
    -
    -
    -
    - - {{upload.display.name}} -
    -
    - {{upload.model[0].name}} - File Pending - - - -
    -
    -
    -
    -
    -
    - - -
    -
    -
    -
    - - - -
    - -
    -
    -

    - - File Upload {{uploadingInfo.success === true ? 'Successful' : 'Failed'}} -

    -
    -
    -

    - Error Message: - {{uploadingInfo.error}} -

    -

    - Retry Upload - Cancel -

    -
    -
    -
    -
    From c7bcc89d799e1827096ca37e937ac1468070bbdd Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 17 Nov 2025 13:32:45 +1100 Subject: [PATCH 0736/1280] chore: update migration progress --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 7885b47a9b..a754982870 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,10 @@ MIGRATED: - [x] ./src/app/common/modals/comments-modal/comments-modal.coffee (IN 10.0.x) - [x] ./src/app/groups/group-selector/group-selector.coffee - [x] ./src/app/groups/group-set-manager/group-set-manager.coffee +- [x] ./src/app/common/file-uploader/file-uploader.coffee +- [x] ./src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee +- [x] ./src/app/sessions/auth/http-auth-injector.coffee +- [x] ./src/app/sessions/sessions.coffee TODO: @@ -187,7 +191,6 @@ TODO: - [ ] ./src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.coffee - [ ] ./src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.coffee - [ ] ./src/app/projects/states/portfolio/directives/portfolio-tasks-step/portfolio-tasks-step.coffee -- [ ] ./src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee - [ ] ./src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.coffee - [ ] ./src/app/projects/states/portfolio/portfolio.coffee - [ ] ./src/app/projects/states/index/index.coffee @@ -217,7 +220,6 @@ TODO: - [ ] ./src/app/units/states/students-list/students-list.coffee - [ ] ./src/app/common/modals/modals.coffee - [ ] ./src/app/common/modals/csv-result-modal/csv-result-modal.coffee -- [ ] ./src/app/common/file-uploader/file-uploader.coffee - [ ] ./src/app/common/common.coffee - [ ] ./src/app/common/content-editable/content-editable.coffee - [ ] ./src/app/common/services/media-service.coffee @@ -227,8 +229,6 @@ TODO: - [ ] ./src/app/common/services/services.coffee - [ ] ./src/app/common/services/date-service.coffee - [ ] ./src/app/common/services/analytics-service.coffee -- [ ] ./src/app/sessions/auth/http-auth-injector.coffee -- [ ] ./src/app/sessions/sessions.coffee - [ ] ./src/app/errors/errors.coffee - [ ] ./src/app/errors/states/states.coffee - [ ] ./src/app/errors/states/timeout/timeout.coffee From ec6c2ee621f95e23036fcf94ae92908761be5e22 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 17 Nov 2025 13:37:59 +1100 Subject: [PATCH 0737/1280] chore: remove unused files (#1044) --- src/app/doubtfire-angularjs.module.ts | 3 -- .../sessions/auth/http-auth-injector.coffee | 37 ------------------- src/app/sessions/sessions.coffee | 3 -- src/app/sessions/states/states.coffee | 0 4 files changed, 43 deletions(-) delete mode 100644 src/app/sessions/auth/http-auth-injector.coffee delete mode 100644 src/app/sessions/sessions.coffee delete mode 100644 src/app/sessions/states/states.coffee diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index c7c44c76e3..78bf107b5b 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -111,8 +111,6 @@ import 'build/src/app/common/services/outcome-service.js'; import 'build/src/app/common/services/services.js'; import 'build/src/app/common/services/recorder-service.js'; import 'build/src/app/common/services/analytics-service.js'; -import 'build/src/app/sessions/auth/http-auth-injector.js'; -import 'build/src/app/sessions/sessions.js'; import 'build/src/app/errors/errors.js'; import 'build/src/app/errors/states/timeout/timeout.js'; import 'build/src/app/errors/states/states.js'; @@ -225,7 +223,6 @@ import {FileUploaderComponent} from './common/file-uploader/file-uploader.compon export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', - 'doubtfire.sessions', 'doubtfire.common', 'doubtfire.errors', 'doubtfire.units', diff --git a/src/app/sessions/auth/http-auth-injector.coffee b/src/app/sessions/auth/http-auth-injector.coffee deleted file mode 100644 index 56ef98961e..0000000000 --- a/src/app/sessions/auth/http-auth-injector.coffee +++ /dev/null @@ -1,37 +0,0 @@ -angular.module("doubtfire.sessions.auth.http-auth-injector", []) -# -# This module is responsible for injecting the auth credentials to -# all -# -.config(($httpProvider) -> - $httpProvider.interceptors.push ($q, $rootScope, DoubtfireConstants, newUserService) -> - # - # Inject authentication token for requests - # - injectAuthForRequest = (request) -> - # Intercept API requests and inject the auth token. - if _.startsWith(request.url, DoubtfireConstants.API_URL) and newUserService.currentUser.authenticationToken? - request.headers = {} unless _.has(request, "headers") - request.headers.Auth_Token = newUserService.currentUser.authenticationToken - request.headers.Username = newUserService.currentUser.username - request or $q.when request - - # - # Inject handlers for 419 and 401 response errors - # - injectAuthForResponseWithError = (response) -> - # Intercept unauthorised API responses and fire an event. - if response.config && response.config.url and _.startsWith(response.config.url, DoubtfireConstants.API_URL) - # Timeout? - if response.status is 419 - $rootScope.$broadcast "tokenTimeout" - # Unauthorised? - else if response.status is 401 - $rootScope.$broadcast "unauthorisedRequestIntercepted" - $q.reject response - - { - request: injectAuthForRequest - responseError: injectAuthForResponseWithError - } -) diff --git a/src/app/sessions/sessions.coffee b/src/app/sessions/sessions.coffee deleted file mode 100644 index ccf6e6b5f1..0000000000 --- a/src/app/sessions/sessions.coffee +++ /dev/null @@ -1,3 +0,0 @@ -angular.module('doubtfire.sessions', [ - "doubtfire.sessions.auth.http-auth-injector" -]) diff --git a/src/app/sessions/states/states.coffee b/src/app/sessions/states/states.coffee deleted file mode 100644 index e69de29bb2..0000000000 From a8a29fae3f5bb0a47ba2d13e225f339fe2756dd0 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 17 Nov 2025 18:20:33 +1100 Subject: [PATCH 0738/1280] refactor: portfolio welcome step migration (#1045) * refactor: init portfolio welcome step migration * chore: remove old portfolio welcome step component * chore: remove whitespace * chore: add todo * chore: increase padding --- src/app/doubtfire-angular.module.ts | 2 ++ src/app/doubtfire-angularjs.module.ts | 7 ++++- .../portfolio/directives/directives.coffee | 1 - .../portfolio-welcome-step.coffee | 10 ------- .../portfolio-welcome-step.component.html | 24 +++++++++++++++++ .../portfolio-welcome-step.component.scss | 0 .../portfolio-welcome-step.component.ts | 27 +++++++++++++++++++ .../portfolio-welcome-step.tpl.html | 21 --------------- .../states/portfolio/portfolio.tpl.html | 2 +- 9 files changed, 60 insertions(+), 34 deletions(-) delete mode 100644 src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.coffee create mode 100644 src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.html create mode 100644 src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.scss create mode 100644 src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.ts delete mode 100644 src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.tpl.html diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 2456aef045..9f40010a1b 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -284,6 +284,7 @@ import {GroupMemberListComponent} from './groups/group-member-list/group-member- import {GroupSelectorComponent} from './groups/group-selector/group-selector.component'; import {GroupSetManagerComponent} from './groups/group-set-manager/group-set-manager.component'; import {FileUploaderComponent} from './common/file-uploader/file-uploader.component'; +import {PortfolioWelcomeStepComponent} from './projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component'; @NgModule({ // Components we declare @@ -416,6 +417,7 @@ import {FileUploaderComponent} from './common/file-uploader/file-uploader.compon GroupSelectorComponent, GroupSetManagerComponent, FileUploaderComponent, + PortfolioWelcomeStepComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 78bf107b5b..70c45bfc8e 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -71,7 +71,6 @@ import 'build/src/app/projects/states/outcomes/outcomes.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.js'; -import 'build/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-tasks-step/portfolio-tasks-step.js'; import 'build/src/app/projects/states/portfolio/directives/directives.js'; import 'build/src/app/projects/states/portfolio/portfolio.js'; @@ -220,6 +219,7 @@ import {GroupMemberListComponent} from './groups/group-member-list/group-member- import {GroupSelectorComponent} from './groups/group-selector/group-selector.component'; import {GroupSetManagerComponent} from './groups/group-set-manager/group-set-manager.component'; import {FileUploaderComponent} from './common/file-uploader/file-uploader.component'; +import {PortfolioWelcomeStepComponent} from './projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -541,3 +541,8 @@ DoubtfireAngularJSModule.directive( 'fFileUploader', downgradeComponent({component: FileUploaderComponent}), ); + +DoubtfireAngularJSModule.directive( + 'fPortfolioWelcomeStep', + downgradeComponent({component: PortfolioWelcomeStepComponent}), +); diff --git a/src/app/projects/states/portfolio/directives/directives.coffee b/src/app/projects/states/portfolio/directives/directives.coffee index 661acd16e7..d8ee720f68 100644 --- a/src/app/projects/states/portfolio/directives/directives.coffee +++ b/src/app/projects/states/portfolio/directives/directives.coffee @@ -3,5 +3,4 @@ angular.module('doubtfire.projects.states.portfolio.directives', [ 'doubtfire.projects.states.portfolio.directives.portfolio-learning-summary-report-step' 'doubtfire.projects.states.portfolio.directives.portfolio-review-step' 'doubtfire.projects.states.portfolio.directives.portfolio-tasks-step' - 'doubtfire.projects.states.portfolio.directives.portfolio-welcome-step' ]) diff --git a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.coffee b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.coffee deleted file mode 100644 index c34f31b354..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.coffee +++ /dev/null @@ -1,10 +0,0 @@ -angular.module('doubtfire.projects.states.portfolio.directives.portfolio-welcome-step', []) - -# -# Welcome introductory step -# -.directive('portfolioWelcomeStep', -> - restrict: 'E' - replace: true - templateUrl: 'projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.tpl.html' -) diff --git a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.html new file mode 100644 index 0000000000..c5fd1a5cf8 --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.html @@ -0,0 +1,24 @@ + + + Portfolio Preparation + + +

    Preparing your portfolio involves 5 steps:

    +
      +
    1. Select your Grade you are applying for
    2. +
    3. Upload your Learning Summary Report
    4. +
    5. Select the Tasks you want included
    6. +
    7. Upload any Other Resources you want to add
    8. +
    9. Compile your resources into your portfolio and review
    10. +
    +

    + Once you have completed all of these steps, your portfolio will be prepared by + {{ externalName }} and you will be notified when it is ready. You can then check your work, + and if you want to make any corrections repeat these steps to create a new version of your + portfolio. +

    +
    + + + +
    diff --git a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.scss b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.ts new file mode 100644 index 0000000000..41f953ea73 --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.ts @@ -0,0 +1,27 @@ +import {Component, OnInit, Injector} from '@angular/core'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; + +@Component({ + selector: 'f-portfolio-welcome-step', + templateUrl: 'portfolio-welcome-step.component.html', + styleUrls: ['portfolio-welcome-step.component.scss'], +}) +export class PortfolioWelcomeStepComponent implements OnInit { + public externalName: string = 'OnTrack'; + + constructor( + private constants: DoubtfireConstants, + private injector: Injector, + ) {} + + ngOnInit(): void { + this.constants.ExternalName.subscribe((name) => { + this.externalName = name; + }); + } + + goNextStep() { + // TODO: remove this once parent component is migrated + this.injector.get('$scope').advanceActiveTab(1); + } +} diff --git a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.tpl.html b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.tpl.html deleted file mode 100644 index 524101329b..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.tpl.html +++ /dev/null @@ -1,21 +0,0 @@ -
    -
    -

    Portfolio Preparation

    -
    -
    -

    Preparing your portfolio involves 5 steps:

    -
      -
    1. Select your Grade you are applying for
    2. -
    3. Upload your Learning Summary Report
    4. -
    5. Select the Tasks you want included
    6. -
    7. Upload any Other Resources you want to add
    8. -
    9. Compile your resources into your portfolio and review
    10. -
    -

    - Once you have completed all of these steps, your portfolio will be prepared by {{externalName.value}} and you will be notified when it is ready. You can then check your work, and if you want to make any corrections repeat these steps to create a new version of your portfolio. -

    -
    - -
    diff --git a/src/app/projects/states/portfolio/portfolio.tpl.html b/src/app/projects/states/portfolio/portfolio.tpl.html index ae536e081f..e6a7bee0da 100644 --- a/src/app/projects/states/portfolio/portfolio.tpl.html +++ b/src/app/projects/states/portfolio/portfolio.tpl.html @@ -6,7 +6,7 @@ - + Date: Tue, 18 Nov 2025 11:46:05 +1100 Subject: [PATCH 0739/1280] refactor: migrate portfolio learning summary report step (#1046) * refactor: migrate portfolio learning summary report step * fix: typo * refactor: remove unused code * chore: update placeholder * refactor: check if draft task definition was submitted * chore: add type * refactor: add caption * refactor: add warning to ensure justification * chore: remove old learning summary report step component * chore: unlink old learning summary report step component * docs: update migration progress * chore: add typing --- README.md | 2 +- src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire-angularjs.module.ts | 7 +- .../portfolio/directives/directives.coffee | 1 - ...tfolio-learning-summary-report-step.coffee | 29 ------ ...earning-summary-report-step.component.html | 91 +++++++++++++++++++ ...earning-summary-report-step.component.scss | 5 + ...-learning-summary-report-step.component.ts | 67 ++++++++++++++ ...olio-learning-summary-report-step.tpl.html | 73 --------------- .../states/portfolio/portfolio.tpl.html | 2 +- 10 files changed, 173 insertions(+), 106 deletions(-) delete mode 100644 src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.coffee create mode 100644 src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.html create mode 100644 src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.scss create mode 100644 src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.ts delete mode 100644 src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.tpl.html diff --git a/README.md b/README.md index a754982870..c7e9ed92e3 100644 --- a/README.md +++ b/README.md @@ -147,6 +147,7 @@ MIGRATED: - [x] ./src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee - [x] ./src/app/sessions/auth/http-auth-injector.coffee - [x] ./src/app/sessions/sessions.coffee +- [x] ./src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.coffee TODO: @@ -188,7 +189,6 @@ TODO: - [ ] ./src/app/projects/states/outcomes/outcomes.coffee - [ ] ./src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.coffee - [ ] ./src/app/projects/states/portfolio/directives/directives.coffee -- [ ] ./src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.coffee - [ ] ./src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.coffee - [ ] ./src/app/projects/states/portfolio/directives/portfolio-tasks-step/portfolio-tasks-step.coffee - [ ] ./src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.coffee diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 9f40010a1b..470dc35f8c 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -285,6 +285,7 @@ import {GroupSelectorComponent} from './groups/group-selector/group-selector.com import {GroupSetManagerComponent} from './groups/group-set-manager/group-set-manager.component'; import {FileUploaderComponent} from './common/file-uploader/file-uploader.component'; import {PortfolioWelcomeStepComponent} from './projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component'; +import {PortfolioLearningSummaryReportStepComponent} from './projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component'; @NgModule({ // Components we declare @@ -418,6 +419,7 @@ import {PortfolioWelcomeStepComponent} from './projects/states/portfolio/directi GroupSetManagerComponent, FileUploaderComponent, PortfolioWelcomeStepComponent, + PortfolioLearningSummaryReportStepComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 70c45bfc8e..f7335be1fa 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -69,7 +69,6 @@ import 'build/src/app/projects/states/dashboard/directives/task-dashboard/task-d import 'build/src/app/projects/states/dashboard/dashboard.js'; import 'build/src/app/projects/states/outcomes/outcomes.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.js'; -import 'build/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-tasks-step/portfolio-tasks-step.js'; import 'build/src/app/projects/states/portfolio/directives/directives.js'; @@ -220,6 +219,7 @@ import {GroupSelectorComponent} from './groups/group-selector/group-selector.com import {GroupSetManagerComponent} from './groups/group-set-manager/group-set-manager.component'; import {FileUploaderComponent} from './common/file-uploader/file-uploader.component'; import {PortfolioWelcomeStepComponent} from './projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component'; +import {PortfolioLearningSummaryReportStepComponent} from './projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -546,3 +546,8 @@ DoubtfireAngularJSModule.directive( 'fPortfolioWelcomeStep', downgradeComponent({component: PortfolioWelcomeStepComponent}), ); + +DoubtfireAngularJSModule.directive( + 'fPortfolioLearningSummaryReportStep', + downgradeComponent({component: PortfolioLearningSummaryReportStepComponent}), +); diff --git a/src/app/projects/states/portfolio/directives/directives.coffee b/src/app/projects/states/portfolio/directives/directives.coffee index d8ee720f68..a20b4f1dde 100644 --- a/src/app/projects/states/portfolio/directives/directives.coffee +++ b/src/app/projects/states/portfolio/directives/directives.coffee @@ -1,6 +1,5 @@ angular.module('doubtfire.projects.states.portfolio.directives', [ 'doubtfire.projects.states.portfolio.directives.portfolio-add-extra-files-step' - 'doubtfire.projects.states.portfolio.directives.portfolio-learning-summary-report-step' 'doubtfire.projects.states.portfolio.directives.portfolio-review-step' 'doubtfire.projects.states.portfolio.directives.portfolio-tasks-step' ]) diff --git a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.coffee b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.coffee deleted file mode 100644 index f2f27caaf7..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.coffee +++ /dev/null @@ -1,29 +0,0 @@ -angular.module('doubtfire.projects.states.portfolio.directives.portfolio-learning-summary-report-step', []) - -# -# Step to justify the portfolio with a Learning Summary Report -# -.directive('portfolioLearningSummaryReportStep', -> - restrict: 'E' - replace: true - templateUrl: 'projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.tpl.html' - controller: ($scope) -> - $scope.forceLSRSubmit = false - $scope.acceptUploadNewLearningSummary = false - - $scope.learningSummaryReportFileUploadData = { - type: { - file0: { name: "Learning Summary Report", type: "document" } - }, - payload: { - name: "LearningSummaryReport" # DO NOT MODIFY - case senstitive on API - kind: "document" - } - } - - $scope.addNewFile = (newFile) -> - $scope.addNewFilesToPortfolio(newFile) - $scope.projectHasDraftLearningSummaryReport = false - $scope.acceptUploadNewLearningSummary = false - $scope.forceLSRSubmit = false -) diff --git a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.html new file mode 100644 index 0000000000..3ef553e787 --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.html @@ -0,0 +1,91 @@ + + + Learning Summary Report + + +

    + Upload the Learning Summary Report, the primary porfolio document which justifies your desired + grade. +

    +

    + Your Learning Summary Report is a + summary of what you have learnt in this unit. It consists of two sections: +

    + +
      +
    1. a self-assessment, and
    2. +
    3. your reflections on the unit.
    4. +
    + +

    + The self-assessment indicates how your portfolio aligns with the assessment + criteria, and which grade you are applying for. +

    + +

    + Your reflections are a personal comment on what you have learnt in the unit, + and how your knowledge and skills have developed. +

    + + @if ( + projectHasDraftLearningSummaryReport && !forceLSRSubmit && !acceptUploadNewLearningSummary + ) { +
    + + @if (draftTaskDefinitionWasUsed()) { +
    + Your learning summary report was automatically submitted from your + {{ unit.draftTaskDefinition.abbreviation }} {{ unit.draftTaskDefinition.name }} + submission. +
    + } + + + +
    + } +
    +
    + warning + + Remember to provide a justification for why you believe you have achieved a + {{ targetGradeLabel }} in {{ unit.code }} {{ unit.name }}. +
    + +
    +
    + + +
    + @if (!projectHasDraftLearningSummaryReport) { +
    + You're missing a Learning Summary Report. Upload one to continue. +
    + } + +
    +
    +
    diff --git a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.scss b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.scss new file mode 100644 index 0000000000..fde6acc603 --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.scss @@ -0,0 +1,5 @@ +.submitted .mat-icon { + font-size: 50px; + width: 50px; + height: 50px; +} diff --git a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.ts new file mode 100644 index 0000000000..2f7744af06 --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.ts @@ -0,0 +1,67 @@ +import {Component, Injector, Input} from '@angular/core'; +import {Project} from 'src/app/api/models/project'; +import {Unit} from 'src/app/api/models/unit'; +import {GradeService} from 'src/app/common/services/grade.service'; + +@Component({ + selector: 'f-portfolio-learning-summary-report-step', + templateUrl: 'portfolio-learning-summary-report-step.component.html', + styleUrls: ['portfolio-learning-summary-report-step.component.scss'], +}) +export class PortfolioLearningSummaryReportStepComponent { + @Input() unit: Unit; + @Input() project: Project; + + public learningSummaryReportFileUploadData = { + type: { + file0: {name: 'Learning Summary Report', type: 'document'}, + }, + payload: { + name: 'LearningSummaryReport', // DO NOT MODIFY - case sensitive on API + kind: 'document', + }, + }; + + public forceLSRSubmit: boolean = false; + public acceptUploadNewLearningSummary: boolean = false; + + constructor( + private injector: Injector, + private gradeService: GradeService, + ) {} + + public get projectHasDraftLearningSummaryReport() { + return ( + this.project?.usesDraftLearningSummary || + this.project?.portfolioFiles.find((f) => f.idx === 0) + ); + } + + public get targetGradeLabel(): string { + return this.gradeService.grades[this.project.targetGrade]; + } + + // TODO: remove this once parent component is migrated + advanceActiveTab(index: 1 | -1) { + this.injector.get('$scope').advanceActiveTab(index); + } + + addNewFile(newFile: {kind: string; name: string; idx: number}) { + this.project.portfolioFiles.push(newFile); + this.acceptUploadNewLearningSummary = false; + this.forceLSRSubmit = false; + } + + draftTaskDefinitionWasUsed(): boolean { + const draftTaskDef = this.unit.draftTaskDefinition; + if (draftTaskDef) { + const task = this.project.findTaskForDefinition(draftTaskDef.id); + if (task && task.inSubmittedState()) { + return true; + } + } + return false; + } + + // downloadLearningSummaryReport(){} +} diff --git a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.tpl.html b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.tpl.html deleted file mode 100644 index b190d6f35c..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.tpl.html +++ /dev/null @@ -1,73 +0,0 @@ -
    -
    -

    - {{activeTab.title}} -

    -
    -
    -

    - Upload the Learning Summary Report, the primary porfolio document which - justifies your desired grade. -

    -

    - Your Learning Summary Report is a summary of what you have learnt in this unit. - It consists of two sections: -

      -
    1. a self-assessment, and
    2. -
    3. your reflections on the unit.
    4. -
    -

    -

    - The self-assessment indicates how your portfolio aligns - with the assessment criteria, and which grade you are applying for. -

    -

    - Your reflections are a personal comment on what you have - learnt in the unit, and how your knowledge and skills have developed. -

    -
    -
    -

    - Before you submit your portfolio... -

    - Your draft learning summary has already been copied over, - it is advised you upload a revised copy. -
    -
    - - -
    -
    - -
    -
    -

    - Learning Summary Report Submitted -

    - Click here to re-upload a new Learning Summary Report -
    - -
    -

    - Before you submit the Learning Summary Report... -

    - Remember to provide a justification for why you believe - you have achieved a {{targetGrade}} in {{unit.name}}. -
    -
    - -
    -
    -
    - -
    diff --git a/src/app/projects/states/portfolio/portfolio.tpl.html b/src/app/projects/states/portfolio/portfolio.tpl.html index e6a7bee0da..d60898e344 100644 --- a/src/app/projects/states/portfolio/portfolio.tpl.html +++ b/src/app/projects/states/portfolio/portfolio.tpl.html @@ -12,7 +12,7 @@ [unit]="unit" ng-if="activeTab == tabs.gradeStep">
    - + From a0f3a73e130de7615a3de399a0951ca588ae00b6 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Tue, 18 Nov 2025 13:27:56 +1100 Subject: [PATCH 0740/1280] refactor: migrate portfolio add extra files step component (#1047) * refactor: migrate portfolio add extra files step component * chore: cleanup whitespace * chore: remove unused class * chore: remove debug * chore: remove old portfolio add extra files step component * chore: update migration progress --- README.md | 2 +- src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire-angularjs.module.ts | 7 +- .../portfolio/directives/directives.coffee | 1 - .../portfolio-add-extra-files-step.coffee | 25 ----- ...tfolio-add-extra-files-step.component.html | 51 ++++++++++ ...tfolio-add-extra-files-step.component.scss | 0 ...ortfolio-add-extra-files-step.component.ts | 96 +++++++++++++++++++ .../portfolio-add-extra-files-step.scss | 10 -- .../portfolio-add-extra-files-step.tpl.html | 58 ----------- .../states/portfolio/portfolio.tpl.html | 2 +- 11 files changed, 157 insertions(+), 97 deletions(-) delete mode 100644 src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.coffee create mode 100644 src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html create mode 100644 src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.scss create mode 100644 src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts delete mode 100644 src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.scss delete mode 100644 src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.tpl.html diff --git a/README.md b/README.md index c7e9ed92e3..04c76a2b2e 100644 --- a/README.md +++ b/README.md @@ -148,6 +148,7 @@ MIGRATED: - [x] ./src/app/sessions/auth/http-auth-injector.coffee - [x] ./src/app/sessions/sessions.coffee - [x] ./src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.coffee +- [x] ./src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.coffee TODO: @@ -189,7 +190,6 @@ TODO: - [ ] ./src/app/projects/states/outcomes/outcomes.coffee - [ ] ./src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.coffee - [ ] ./src/app/projects/states/portfolio/directives/directives.coffee -- [ ] ./src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.coffee - [ ] ./src/app/projects/states/portfolio/directives/portfolio-tasks-step/portfolio-tasks-step.coffee - [ ] ./src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.coffee - [ ] ./src/app/projects/states/portfolio/portfolio.coffee diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 470dc35f8c..cd3886f895 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -286,6 +286,7 @@ import {GroupSetManagerComponent} from './groups/group-set-manager/group-set-man import {FileUploaderComponent} from './common/file-uploader/file-uploader.component'; import {PortfolioWelcomeStepComponent} from './projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component'; import {PortfolioLearningSummaryReportStepComponent} from './projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component'; +import {PortfolioAddExtraFilesStepComponent} from './projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component'; @NgModule({ // Components we declare @@ -420,6 +421,7 @@ import {PortfolioLearningSummaryReportStepComponent} from './projects/states/por FileUploaderComponent, PortfolioWelcomeStepComponent, PortfolioLearningSummaryReportStepComponent, + PortfolioAddExtraFilesStepComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index f7335be1fa..9bac403698 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -69,7 +69,6 @@ import 'build/src/app/projects/states/dashboard/directives/task-dashboard/task-d import 'build/src/app/projects/states/dashboard/dashboard.js'; import 'build/src/app/projects/states/outcomes/outcomes.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.js'; -import 'build/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.js'; import 'build/src/app/projects/states/portfolio/directives/portfolio-tasks-step/portfolio-tasks-step.js'; import 'build/src/app/projects/states/portfolio/directives/directives.js'; import 'build/src/app/projects/states/portfolio/portfolio.js'; @@ -220,6 +219,7 @@ import {GroupSetManagerComponent} from './groups/group-set-manager/group-set-man import {FileUploaderComponent} from './common/file-uploader/file-uploader.component'; import {PortfolioWelcomeStepComponent} from './projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component'; import {PortfolioLearningSummaryReportStepComponent} from './projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component'; +import {PortfolioAddExtraFilesStepComponent} from './projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -551,3 +551,8 @@ DoubtfireAngularJSModule.directive( 'fPortfolioLearningSummaryReportStep', downgradeComponent({component: PortfolioLearningSummaryReportStepComponent}), ); + +DoubtfireAngularJSModule.directive( + 'fPortfolioAddExtraFilesStep', + downgradeComponent({component: PortfolioAddExtraFilesStepComponent}), +); diff --git a/src/app/projects/states/portfolio/directives/directives.coffee b/src/app/projects/states/portfolio/directives/directives.coffee index a20b4f1dde..239280567d 100644 --- a/src/app/projects/states/portfolio/directives/directives.coffee +++ b/src/app/projects/states/portfolio/directives/directives.coffee @@ -1,5 +1,4 @@ angular.module('doubtfire.projects.states.portfolio.directives', [ - 'doubtfire.projects.states.portfolio.directives.portfolio-add-extra-files-step' 'doubtfire.projects.states.portfolio.directives.portfolio-review-step' 'doubtfire.projects.states.portfolio.directives.portfolio-tasks-step' ]) diff --git a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.coffee b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.coffee deleted file mode 100644 index f62984ff63..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.coffee +++ /dev/null @@ -1,25 +0,0 @@ -angular.module('doubtfire.projects.states.portfolio.directives.portfolio-add-extra-files-step', []) - -# -# Allow students to add additional files to the end of their portfolio -# They can choose any file they want to upload -# -.directive('portfolioAddExtraFilesStep', -> - restrict: 'E' - replace: true - templateUrl: 'projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.tpl.html' - controller: ($scope) -> - otherFileFileUploadData = (type) -> - type: { - file0: { name: "Other", type: type } - }, - payload: { - name: "Other" - kind: type - } - - $scope.uploadType = 'document' - $scope.$watch 'uploadType', (newType) -> - return unless newType? - $scope.uploadFileData = otherFileFileUploadData newType -) diff --git a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html new file mode 100644 index 0000000000..53707b6891 --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html @@ -0,0 +1,51 @@ + + + Upload Other Files + + +

    + Now is your chance to upload any extra files to include in your portfolio. They'll appear at + the very top of your portfolio, before your tasks. +

    +
    +
      + @for (file of extraFiles; track file) { +
    1. +
      + {{ icons[file.kind] }} + {{ file.name }} +
      + +
    2. + } @empty { +

      If you do not have any files to add, you can skip this step.

      + } +
    +
    +
    + + Select type of file: + + Document File + Code File + Image File + + +
    + + +
    + + + + +
    diff --git a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.scss b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts new file mode 100644 index 0000000000..93b49f47a1 --- /dev/null +++ b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts @@ -0,0 +1,96 @@ +import {Component, Injector, Input, OnInit} from '@angular/core'; +import {MatSelectChange} from '@angular/material/select'; +import {Project} from 'src/app/api/models/project'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-portfolio-add-extra-files-step', + templateUrl: 'portfolio-add-extra-files-step.component.html', + styleUrls: ['portfolio-add-extra-files-step.component.scss'], +}) +export class PortfolioAddExtraFilesStepComponent implements OnInit { + @Input() project: Project; + + public uploadType: 'document' | 'code' | 'image' = 'document'; + + public isUploading: boolean; + + public uploadFileType = { + file0: { + name: 'Other', + type: 'document', + }, + }; + + public uploadFilePayload = { + name: 'Other', + kind: 'document', + }; + + constructor( + private injector: Injector, + private alertService: AlertService, + ) {} + + public readonly icons = { + document: 'article_outlined', + code: 'integration_instructions_outlined', + image: 'image_outlined', + zip: 'zip_outlined', + }; + + ngOnInit(): void { + this.uploadType = 'document'; + + this.uploadFileType = { + file0: { + name: 'Other', + type: 'document', + }, + }; + + this.uploadFilePayload = { + name: 'Other', + kind: 'document', + }; + } + onTypeChange(event: MatSelectChange) { + console.log('on type change', event); + this.uploadFileType = { + file0: { + name: 'Other', + type: event.value, + }, + }; + + this.uploadFilePayload = { + name: 'Other', + kind: event.value, + }; + } + + public get extraFiles() { + // If file.idx === 0, then it's the Learning Summary Report, so we ignore it here + return this.project?.portfolioFiles.filter((file) => file.idx !== 0); + } + + deleteFileFromPortfolio(file: {idx: number; kind: string; name: string}) { + this.project.deleteFileFromPortfolio(file).subscribe({ + next: () => { + this.alertService.success('Succesfully delete file', 3000); + }, + error: (error) => { + this.alertService.error(`Failed to delete file: ${error}`, 6000); + }, + }); + } + + // TODO: remove this once parent component is migrated + advanceActiveTab(index: 1 | -1) { + this.injector.get('$scope').advanceActiveTab(index); + } + + addNewFilesToPortfolio(newFile: {kind: string; name: string; idx: number}) { + this.project.portfolioFiles.push(newFile); + } +} diff --git a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.scss b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.scss deleted file mode 100644 index 47c481a372..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.scss +++ /dev/null @@ -1,10 +0,0 @@ -.portfolio-add-extra-files-step { - a.clear-upload { - margin-left: 1ex; - &:hover i { - font-size: 1.15em; - color: $brand-danger; - } - display: inline-block; - } -} diff --git a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.tpl.html b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.tpl.html deleted file mode 100644 index 136b5f5330..0000000000 --- a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.tpl.html +++ /dev/null @@ -1,58 +0,0 @@ -
    -
    -

    {{activeTab.title}}

    -
    -
    -

    - Now is your chance to upload extra files to include in your portfolio. - These files will be added at to your portfolio before your selected tasks - from the previous step. -

    -
    -
    -

    No files to add?

    -

    If you do not have any files to add you can skip this step.

    -
    -
    -

    Extra file{{extraFiles().length > 1 ? 's' : ''}} added

    -

    - {{extraFiles().length > 1 ? 'The files you add will appear in the portfolio in the order shown below.' : ''}} - If you want to delete a file, click the cross beside the file's name. -

    -
      -
    1. - {{file.name}} - - - -
    2. -
    -
    -
    -
    - -
    - -
    -
    - - -
    -
    -
    - -
    diff --git a/src/app/projects/states/portfolio/portfolio.tpl.html b/src/app/projects/states/portfolio/portfolio.tpl.html index d60898e344..2cc7b69080 100644 --- a/src/app/projects/states/portfolio/portfolio.tpl.html +++ b/src/app/projects/states/portfolio/portfolio.tpl.html @@ -14,6 +14,6 @@ - +
    From b04ee273aa17ef037ee580bacc80e7870c82aa3a Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 19 Nov 2025 16:44:41 +1100 Subject: [PATCH 0741/1280] refactor: unit portfolios state migration (#1048) * chore: init unit portfolios state migration * chore: init portfolios directives * refactor: init tab view * refactor: migrate select student portfolio list * refactor: hook student selection * chore: ensure pdf viewer takes up screen * chore: init project progress dashboard * chore: view progress on project selection * refactor: impove project progress layout * refactor: init portfolio assessment view * refactor: portfolio list pagination * fix: prevent vertical in tab groups * refactor: add padding in child components * refactor: add target and submitted grade card ui * refactor: improve assessment layout * refactor: add student search and filtering * feat: add tab headings * fix: set correct tutorial filter * chore: change paginator options * fix: distribute layout evenly * chore: add loading text * chore: remove todo * feat: download grades button * chore: add placeholders todo * fix: update method call * refactor: improve graph layout * refactor: add route error handling * chore: update todo * chore: update todos * feat: has portfolio column * feat: view project in new tab * chore: add todo * refactor: display no portfolio if doesnt exist * fix: typo * chore: consistent gap * chore: remove old portfolios component * chore: update task stats on grade change * chore: remove old project progress dashboard * chore: display error alert * chore: remove old project progress dashboard * chore: update migration progress * refactor: improve assessment scores responsiveness --- README.md | 4 +- src/app/common/header/header.component.ts | 24 +- src/app/doubtfire-angular.module.ts | 10 + src/app/doubtfire-angularjs.module.ts | 2 - src/app/doubtfire.states.ts | 26 ++ .../project-progress-dashboard.coffee | 46 --- .../project-progress-dashboard.tpl.html | 126 ------- src/app/projects/projects.coffee | 1 - .../portfolios-assessment.component.html | 40 +++ .../portfolios-assessment.component.scss | 0 .../portfolios-assessment.component.ts | 42 +++ .../portfolios-list.component.html | 210 ++++++++++++ .../portfolios-list.component.scss | 0 .../portfolios-list.component.ts | 211 ++++++++++++ .../portfolios-portfolio-view.component.html | 14 + .../portfolios-portfolio-view.component.scss | 0 .../portfolios-portfolio-view.component.ts | 11 + ...portfolios-project-progress.component.html | 100 ++++++ ...portfolios-project-progress.component.scss | 0 .../portfolios-project-progress.component.ts | 82 +++++ .../units/states/portfolios/portfolios.coffee | 129 ------- .../portfolios/portfolios.component.html | 39 +++ .../portfolios/portfolios.component.scss | 0 .../states/portfolios/portfolios.component.ts | 71 ++++ .../units/states/portfolios/portfolios.scss | 26 -- .../states/portfolios/portfolios.tpl.html | 319 ------------------ src/app/units/states/states.coffee | 1 - .../progressburndownchart.component.html | 3 +- .../taskstatuspiechart.component.html | 4 +- 29 files changed, 884 insertions(+), 657 deletions(-) delete mode 100644 src/app/projects/project-progress-dashboard/project-progress-dashboard.coffee delete mode 100644 src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html create mode 100644 src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.html create mode 100644 src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.scss create mode 100644 src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.ts create mode 100644 src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html create mode 100644 src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.scss create mode 100644 src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts create mode 100644 src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.html create mode 100644 src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.scss create mode 100644 src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.ts create mode 100644 src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html create mode 100644 src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.scss create mode 100644 src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts delete mode 100644 src/app/units/states/portfolios/portfolios.coffee create mode 100644 src/app/units/states/portfolios/portfolios.component.html create mode 100644 src/app/units/states/portfolios/portfolios.component.scss create mode 100644 src/app/units/states/portfolios/portfolios.component.ts delete mode 100644 src/app/units/states/portfolios/portfolios.scss delete mode 100644 src/app/units/states/portfolios/portfolios.tpl.html diff --git a/README.md b/README.md index 04c76a2b2e..3dfbd9c89c 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,8 @@ MIGRATED: - [x] ./src/app/sessions/sessions.coffee - [x] ./src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.coffee - [x] ./src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.coffee +- [x] ./src/app/projects/project-progress-dashboard/project-progress-dashboard.coffee +- [x] ./src/app/units/states/portfolios/portfolios.coffee TODO: @@ -179,7 +181,6 @@ TODO: - [ ] ./src/app/config/routing/routing.coffee - [ ] ./src/app/config/analytics/analytics.coffee - [ ] ./src/app/projects/projects.coffee -- [ ] ./src/app/projects/project-progress-dashboard/project-progress-dashboard.coffee - [ ] ./src/app/projects/states/states.coffee - [ ] ./src/app/projects/states/groups/groups.coffee - [ ] ./src/app/projects/states/feedback/feedback.coffee @@ -208,7 +209,6 @@ TODO: - [ ] ./src/app/units/states/states.coffee - [ ] ./src/app/units/states/tasks/tasks.coffee - [ ] ./src/app/units/states/tasks/definition/definition.coffee -- [ ] ./src/app/units/states/portfolios/portfolios.coffee - [ ] ./src/app/units/states/analytics/analytics.coffee - [ ] ./src/app/units/states/edit/directives/directives.coffee - [ ] ./src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.coffee diff --git a/src/app/common/header/header.component.ts b/src/app/common/header/header.component.ts index 842287b92e..7d1fb3bc65 100644 --- a/src/app/common/header/header.component.ts +++ b/src/app/common/header/header.component.ts @@ -87,14 +87,20 @@ export class HeaderComponent implements OnInit, OnDestroy { if (this.currentView == ViewType.PROJECT) { this.updateSelectedProject(currentViewAndEntity.entity as Project); } else if (this.currentView == ViewType.UNIT) { - this.updateSelectedUnitRole(currentViewAndEntity.entity as UnitRole); + if (currentViewAndEntity.entity instanceof UnitRole) { + this.updateSelectedUnitRole(currentViewAndEntity.entity as UnitRole); + } else if (currentViewAndEntity.entity instanceof Unit) { + this.updateSelectedUnit(currentViewAndEntity.entity as Unit); + } } else { this.currentUnit = null; this.currentProject = null; } }, // eslint-disable-next-line @typescript-eslint/no-unused-vars - error: (_err) => {}, + error: (_err) => { + console.error(_err); + }, }), ); } @@ -122,6 +128,20 @@ export class HeaderComponent implements OnInit, OnDestroy { this.currentUnit = unitRole.unit; } + updateSelectedUnit(unit: Unit): void { + this.currentUnit = unit; + this.currentProject = null; + + this.currentUnitRole = unit.staff.find( + (ur) => ur.user?.id === this.userService.currentUser?.id, + ); + + if (this.currentUnitRole) { + // Re-map Unit onto UnitRole object + this.currentUnitRole.unit = unit; + } + } + update(): void { this.checkForUpdateService.checkForUpdate(); } diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index cd3886f895..939c0a9c83 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -287,6 +287,11 @@ import {FileUploaderComponent} from './common/file-uploader/file-uploader.compon import {PortfolioWelcomeStepComponent} from './projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component'; import {PortfolioLearningSummaryReportStepComponent} from './projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component'; import {PortfolioAddExtraFilesStepComponent} from './projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component'; +import {PortfoliosComponent} from './units/states/portfolios/portfolios.component'; +import {PortfoliosListComponent} from './units/states/portfolios/directives/portfolios-list/portfolios-list.component'; +import {PortfoliosProjectProgressComponent} from './units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component'; +import {PortfoliosPortfolioViewComponent} from './units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component'; +import {PortfoliosAssessmentComponent} from './units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component'; @NgModule({ // Components we declare @@ -422,6 +427,11 @@ import {PortfolioAddExtraFilesStepComponent} from './projects/states/portfolio/d PortfolioWelcomeStepComponent, PortfolioLearningSummaryReportStepComponent, PortfolioAddExtraFilesStepComponent, + PortfoliosComponent, + PortfoliosListComponent, + PortfoliosProjectProgressComponent, + PortfoliosPortfolioViewComponent, + PortfoliosAssessmentComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 9bac403698..0a40d4e43e 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -59,7 +59,6 @@ import 'build/src/app/config/routing/routing.js'; import 'build/src/app/config/vendor-dependencies/vendor-dependencies.js'; import 'build/src/app/config/analytics/analytics.js'; import 'build/src/app/projects/projects.js'; -import 'build/src/app/projects/project-progress-dashboard/project-progress-dashboard.js'; import 'build/src/app/projects/states/groups/groups.js'; import 'build/src/app/projects/states/feedback/feedback.js'; import 'build/src/app/projects/states/states.js'; @@ -83,7 +82,6 @@ import 'build/src/app/units/units.js'; import 'build/src/app/units/states/tasks/inbox/inbox.js'; import 'build/src/app/units/states/tasks/tasks.js'; import 'build/src/app/units/states/tasks/definition/definition.js'; -import 'build/src/app/units/states/portfolios/portfolios.js'; import 'build/src/app/units/states/groups/groups.js'; import 'build/src/app/units/states/states.js'; import 'build/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.js'; diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index d2a7226cb2..28da9ec3aa 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -15,6 +15,7 @@ import { TaskViewerState } from './units/task-viewer/task-viewer-state.component import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component'; import { Ng2ViewDeclaration } from '@uirouter/angular'; import { TutorialsComponent } from './projects/states/tutorials/tutorials.component'; +import {PortfoliosComponent} from './units/states/portfolios/portfolios.component'; /* * Use this file to store any states that are sourced by angular components. @@ -430,6 +431,30 @@ const TutorialState: NgHybridStateDeclaration = { }, }; +// TODO 10.0.x: this will need to go under the unit parent state +const PortfoliosState: NgHybridStateDeclaration = { + name: 'units/students/portfolios', + url: '/units/:unitId/students/portfolios', + resolve: { + unitId: [ + '$stateParams', + function ($stateParams) { + return $stateParams.unitId; + }, + ], + }, + views: { + main: { + component: PortfoliosComponent, + }, + }, + data: { + task: 'Student Portfolios', + pageTitle: 'Student Portfolios', + roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Auditor'], + }, +}; + /** * Export the list of states we have created in angular */ @@ -453,4 +478,5 @@ export const doubtfireStates = [ ScormPlayerReviewState, ScormPlayerStudentReviewState, TutorialState, + PortfoliosState, ]; diff --git a/src/app/projects/project-progress-dashboard/project-progress-dashboard.coffee b/src/app/projects/project-progress-dashboard/project-progress-dashboard.coffee deleted file mode 100644 index d28a0d31b5..0000000000 --- a/src/app/projects/project-progress-dashboard/project-progress-dashboard.coffee +++ /dev/null @@ -1,46 +0,0 @@ -angular.module('doubtfire.projects.project-progress-dashboard',[]) - -# -# Progress tab for the student's project -# -# Basically a dashboard where students can see everything about their -# project in one area including burndown chart, tasks to work on -# and their target grade -# -.directive('projectProgressDashboard', -> - restrict: 'E' - templateUrl: 'projects/project-progress-dashboard/project-progress-dashboard.tpl.html' - controller: ($scope, $state, $rootScope, $stateParams, newProjectService, alertService, gradeService, newTaskService, listenerService) -> - if $stateParams.projectId? - $scope.studentProjectId = $stateParams.projectId - else if $scope.project? - $scope.studentProjectId = $scope.project.id - - $scope.grades = gradeService.grades - - $scope.currentVisualisation = 'burndown' - - $scope.chooseGrade = (idx) -> - $scope.project.targetGrade = idx - newProjectService.update($scope.project).subscribe( - (response) -> - alertService.success( "Target updated") - ) - updateTaskCompletionStats() - - $scope.taskCount = -> - $scope.unit.taskDefinitionCount - - $scope.taskStats = {} - - # Update move to task and project... - updateTaskCompletionStats = -> - $scope.taskStats.numberOfTasksCompleted = $scope.project.tasksByStatus(newTaskService.completeStatus).length - $scope.taskStats.numberOfTasksRemaining = $scope.project.activeTasks().length - $scope.taskStats.numberOfTasksCompleted - - $scope.$on 'TaskStatusUpdated', -> - updateTaskCompletionStats() - - - updateTaskCompletionStats() -) diff --git a/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html b/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html deleted file mode 100644 index 1c28a9eb6f..0000000000 --- a/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html +++ /dev/null @@ -1,126 +0,0 @@ -
    -
    -
    -
    -
    -
    -
    -

    Task List

    -
    -
    -
    - -
    -
    -
    -
    -
    -
    -

    Target Grade

    - Select the grade you wish to achieve in the unit. -
    -
    -

    - - - -

    -
    -
    -
    -
    -
    - -
    -
    -
    -
    -
    -

    Burndown Chart

    - The Burndown chart shows how much work remains for you to achieve your target grade. -
    -
    -

    Task Summary Chart

    - Summary of each of your task statuses -
    -
    -
    -
    -
    - - -
    -
    -
    -
    -
    -
    - -
    -
    - - -
    -

    - -

    - -
    -
    - -
    -
    -
    - -
    -
    - -
    -
    - -
    -
    diff --git a/src/app/projects/projects.coffee b/src/app/projects/projects.coffee index 8499f03af4..1874378696 100644 --- a/src/app/projects/projects.coffee +++ b/src/app/projects/projects.coffee @@ -1,5 +1,4 @@ angular.module('doubtfire.projects', [ 'doubtfire.projects.states' 'doubtfire.projects.project-outcome-alignment' - 'doubtfire.projects.project-progress-dashboard' ]) diff --git a/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.html b/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.html new file mode 100644 index 0000000000..79a17e8cdb --- /dev/null +++ b/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.html @@ -0,0 +1,40 @@ +
    +

    Grade for {{ project.student.name }}

    +

    Assign grade for this project.

    + + Rationale + + + @for (group of gradeResults; track group) { +
    +
    + {{ group.name }} +
    + +
    + @for (score of group.scores; track score) { + + } +
    +
    + } +
    + +
    +
    diff --git a/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.scss b/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.ts b/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.ts new file mode 100644 index 0000000000..5cb990243d --- /dev/null +++ b/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.ts @@ -0,0 +1,42 @@ +import {Component, Input} from '@angular/core'; +import {Project} from 'src/app/api/models/project'; +import {Unit} from 'src/app/api/models/unit'; + +@Component({ + selector: 'f-portfolios-assessment', + templateUrl: './portfolios-assessment.component.html', + styleUrl: './portfolios-assessment.component.scss', +}) +export class PortfoliosAssessmentComponent { + @Input() project: Project; + @Input() unit: Unit; + + public gradeResults = [ + { + name: 'Fail', + scores: [0, 10, 20, 30, 40, 44], + }, + { + name: 'Pass', + scores: [50, 53, 55, 57], + }, + { + name: 'Credit', + scores: [60, 63, 65, 67], + }, + { + name: 'Distinction', + scores: [70, 73, 75, 77], + }, + { + name: 'High Distinction', + scores: [80, 83, 85, 87], + }, + { + name: 'High Distinction', + scores: [90, 93, 95, 97, 100], + }, + ]; + + public maxScoresPerRow = Math.max(...this.gradeResults.map((g) => g.scores.length)); +} diff --git a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html new file mode 100644 index 0000000000..ad42aac12f --- /dev/null +++ b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html @@ -0,0 +1,210 @@ +
    +

    Mark portfolios

    +

    Assess student portfolios

    +
    +
    + + + + + @if (hasD2lMapping()) { + + } +
    +
    + + Filter + + + + public + menu_book + + + + account_balance + edit + + + + + All + + @for (grade of gradeValues; track grade) { + + + + } + +
    +
    + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Student + {{ project.student.studentId || project.student.username }} + Name + {{ project.student.name }} + Tutor + {{ project.tutorNames() }} + Tutorial + {{ project.shortTutorialDescription() }} + Target + + Submitted as + + Has Portfolio + {{ project.hasPortfolio ? 'Yes' : 'No' }} + Stats +
    + @for (bar of project.taskStats; track bar) { +
    + @if (bar.key === 'not_started') { + {{ bar.value }}% + } + @if (bar.key === 'complete') { + {{ bar.value }}% + } +
    + } +
    +
    Grade + {{ project.grade }} + View + +
    No students found
    + + +
    diff --git a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.scss b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts new file mode 100644 index 0000000000..28062f9372 --- /dev/null +++ b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts @@ -0,0 +1,211 @@ +import { + AfterViewInit, + Component, + EventEmitter, + Input, + OnInit, + Output, + ViewChild, +} from '@angular/core'; +import {MatButtonToggleChange} from '@angular/material/button-toggle'; +import {MatPaginator} from '@angular/material/paginator'; +import {MatSort, Sort} from '@angular/material/sort'; +import {MatTableDataSource} from '@angular/material/table'; +import {Project} from 'src/app/api/models/project'; +import {TaskStatusEnum} from 'src/app/api/models/task-status'; +import {Unit} from 'src/app/api/models/unit'; +import {TaskService} from 'src/app/api/services/task.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {GradeService} from 'src/app/common/services/grade.service'; + +@Component({ + selector: 'f-portfolios-list', + templateUrl: './portfolios-list.component.html', + styleUrl: './portfolios-list.component.scss', +}) +export class PortfoliosListComponent implements OnInit, AfterViewInit { + @Input() unit: Unit; + + @Output() + public studentSelected = new EventEmitter(); + + displayedColumns: string[] = []; + + @ViewChild(MatPaginator) paginator!: MatPaginator; + @ViewChild(MatSort) sort: MatSort; + + dataSource = new MatTableDataSource([]); + + public portfolioFilter: 'all' | 'submitted_only' = 'submitted_only'; + public tutorialFilter: 'all' | 'mine' = 'all'; + public gradeFilter: number | null = null; + + constructor( + private taskService: TaskService, + private userService: UserService, + private gradeService: GradeService, + private fileDownloaderService: FileDownloaderService, + ) {} + + ngAfterViewInit() { + this.dataSource.paginator = this.paginator; + this.dataSource.sort = this.sort; + } + + ngOnInit(): void { + this.updateDataSource(); + } + + openProject(event: Event, project: Project) { + event.stopPropagation(); + window.open(`/#/projects/${project.id}/dashboard/?tutor=true`, '_blank'); + } + + downloadGrades() { + this.fileDownloaderService.downloadFile(this.unit.gradesUrl, `${this.unit.code}-grades.csv`); + } + + downloadPortfolios() { + // TODO 10.0.x: Download portfolios via sidekiq job + } + + public hasD2lMapping() { + // TODO 10.0.x: fetch this.unit.hasD2lMapping() + return false; + } + + transferToD2l() { + // TODO 10.0.x: Open D2lTransferModal for this.unit + } + + public get gradeValues() { + return this.gradeService.gradeValues; + } + + public gradeLabel(grade) { + return this.gradeService.grades[grade]; + } + + updateDataSource() { + const currentUser = this.userService.currentUser; + + const students = this.unit.students + .filter((p) => (this.portfolioFilter === 'submitted_only' ? p.hasPortfolio : true)) + .filter((p) => (this.tutorialFilter === 'mine' ? p.hasTutor(currentUser) : true)) + .filter((p) => (this.gradeFilter !== null ? p.submittedGrade === this.gradeFilter : true)); + + this.displayedColumns = [ + 'student', + 'name', + 'tutor', + 'tutorial', + 'target', + 'submitted-as', + ...(this.portfolioFilter === 'all' ? ['has-portfolio'] : []), + 'stats', + 'grade', + 'actions', + ]; + + this.dataSource.data = students; + this.dataSource.paginator?.firstPage(); + } + + onPortfolioFilterChange(event: MatButtonToggleChange) { + this.portfolioFilter = event.value; + this.updateDataSource(); + } + + onTutorialFilterChange(event: MatButtonToggleChange) { + this.tutorialFilter = event.value; + this.updateDataSource(); + } + + onGradeFilterChange(event: MatButtonToggleChange) { + this.gradeFilter = event.value; + this.updateDataSource(); + } + + applyFilter(event: Event) { + const filterValue = (event.target as HTMLInputElement).value; + this.dataSource.filter = filterValue.trim().toLowerCase(); + + if (this.dataSource.paginator) { + this.dataSource.paginator.firstPage(); + } + + this.dataSource.filterPredicate = (project, filter) => { + const text = [ + project.student.studentId, + project.student.username, + project.student.name, + project.tutorNames(), + project.shortTutorialDescription(), + String(project.grade), + ] + .join(' ') + .toLowerCase(); + + return text.includes(filter); + }; + } + + selectStudent(project: Project) { + this.studentSelected.emit(project); + } + + public statusColor(status: TaskStatusEnum): string { + return this.taskService.statusColors.get(status); + } + + public statusLabel(status: TaskStatusEnum): string { + return this.taskService.statusLabels.get(status); + } + + private sortCompare(aValue: number | string, bValue: number | string, isAsc: boolean) { + return (aValue < bValue ? -1 : 1) * (isAsc ? 1 : -1); + } + + sortTableData(sort: Sort) { + if (!sort.active || sort.direction === '') { + return; + } + this.dataSource.data = this.dataSource.data.sort((a, b) => { + switch (sort.active) { + case 'student': + return this.sortCompare( + a.student.studentId || a.student.username, + b.student.studentId || b.student.username, + sort.direction === 'asc', + ); + case 'name': + return this.sortCompare(a.student?.name, b.student?.name, sort.direction === 'asc'); + case 'tutor': { + return this.sortCompare(a.tutorNames(), b.tutorNames(), sort.direction === 'asc'); + } + case 'tutorial': + return this.sortCompare( + a.shortTutorialDescription(), + b.shortTutorialDescription(), + sort.direction === 'asc', + ); + + case 'target': + return this.sortCompare(a.targetGrade, b.targetGrade, sort.direction === 'asc'); + case 'submitted-as': + return this.sortCompare(a.submittedGrade, b.submittedGrade, sort.direction === 'asc'); + case 'has-portfolio': + return this.sortCompare( + a.hasPortfolio.toString(), + b.hasPortfolio.toString(), + sort.direction === 'asc', + ); + case 'grade': + return this.sortCompare(a.grade, b.grade, sort.direction === 'asc'); + default: + return 0; + } + }); + } +} diff --git a/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.html b/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.html new file mode 100644 index 0000000000..c88222fa7c --- /dev/null +++ b/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.html @@ -0,0 +1,14 @@ +
    +

    Review portfolio of {{ project.student.name }}

    +

    View or download portfolio for assessment.

    + + @if (project.portfolioAvailable) { + + + } @else { +
    + menu_book +

    No Portfolio Submitted

    +
    + } +
    diff --git a/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.scss b/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.ts b/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.ts new file mode 100644 index 0000000000..48fca4e3ea --- /dev/null +++ b/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.ts @@ -0,0 +1,11 @@ +import {Component, Input} from '@angular/core'; +import {Project} from 'src/app/api/models/project'; + +@Component({ + selector: 'f-portfolios-portfolio-view', + templateUrl: './portfolios-portfolio-view.component.html', + styleUrl: './portfolios-portfolio-view.component.scss', +}) +export class PortfoliosPortfolioViewComponent { + @Input() project: Project; +} diff --git a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html new file mode 100644 index 0000000000..062b08b966 --- /dev/null +++ b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html @@ -0,0 +1,100 @@ +
    +

    Review progress of {{ project.student.name }}

    +

    Review the students progress through the unit's tasks.

    +
    +
    + + + Target Grade + + +
    +
    + + @for (grade of gradeValues; track grade) { + + + + } + +
    + {{ gradeWord(project.targetGrade) ?? 'N/A' }} +
    +
    +
    + + + Submitted Grade + + +
    +
    + + @for (grade of gradeValues; track grade) { + + + + } + +
    + {{ gradeWord(project.submittedGrade) ?? 'N/A' }} +
    +
    +
    +
    + + + Task List + + + + + +
    + + + Task Summary Chart + + + + + + + + Burndown Chart + + +
    + {{ project.student.name }} has completed {{ taskStats.numberOfTasksCompleted }} tasks + and have {{ taskStats.numberOfTasksRemaining }} left to complete to achieve their target + of a + {{ grades[project.targetGrade] }} +
    + +
    +
    +
    +
    +
    diff --git a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.scss b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts new file mode 100644 index 0000000000..b075d10c3f --- /dev/null +++ b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts @@ -0,0 +1,82 @@ +import {Component, Input} from '@angular/core'; +import {Project} from 'src/app/api/models/project'; +import {Unit} from 'src/app/api/models/unit'; +import {ProjectService} from 'src/app/api/services/project.service'; +import {TaskService} from 'src/app/api/services/task.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {GradeService} from 'src/app/common/services/grade.service'; + +@Component({ + selector: 'f-portfolios-project-progress', + templateUrl: './portfolios-project-progress.component.html', + styleUrl: './portfolios-project-progress.component.scss', +}) +export class PortfoliosProjectProgressComponent { + @Input() project: Project; + @Input() unit: Unit; + + public taskStats: {numberOfTasksCompleted: number; numberOfTasksRemaining: number} = { + numberOfTasksCompleted: 0, + numberOfTasksRemaining: 0, + }; + + constructor( + private gradeService: GradeService, + private projectService: ProjectService, + private alertService: AlertService, + private taskService: TaskService, + ) {} + + public get gradeValues() { + return this.gradeService.gradeValues; + } + public get grades() { + return this.gradeService.grades; + } + + public gradeWord(grade) { + return this.gradeService.grades[grade]; + } + + updateTaskCompletionStats() { + this.taskStats.numberOfTasksCompleted = this.project.tasksByStatus( + this.taskService.completeStatus, + ).length; + this.taskStats.numberOfTasksRemaining = + this.project.activeTasks().length - this.taskStats.numberOfTasksCompleted; + } + + updateSubmittedGrade(newGrade: number): void { + const previousSubmittedGrade = this.project.submittedGrade; + this.project.submittedGrade = newGrade; + + this.projectService.update(this.project).subscribe({ + next: (project) => { + project.refreshBurndownChartData?.(); + this.alertService.success(`Updated project's submitted grade`); + this.updateTaskCompletionStats(); + }, + error: (error) => { + this.project.submittedGrade = previousSubmittedGrade; + this.alertService.error(`Failed to update submitted grade: ${error}`); + }, + }); + } + + updatedTargetGrade(newGrade: number): void { + const previousTargetGrade = this.project.targetGrade; + this.project.targetGrade = newGrade; + + this.projectService.update(this.project).subscribe({ + next: (project) => { + project.refreshBurndownChartData?.(); + this.alertService.success(`Updated project's target grade`); + this.updateTaskCompletionStats(); + }, + error: (error) => { + this.project.targetGrade = previousTargetGrade; + this.alertService.error(`Failed to update target grade: ${error}`); + }, + }); + } +} diff --git a/src/app/units/states/portfolios/portfolios.coffee b/src/app/units/states/portfolios/portfolios.coffee deleted file mode 100644 index c0837ba517..0000000000 --- a/src/app/units/states/portfolios/portfolios.coffee +++ /dev/null @@ -1,129 +0,0 @@ -angular.module('doubtfire.units.states.portfolios', []) -# -# State for staff viewing portfolios -# -.config(($stateProvider) -> - $stateProvider.state 'units/students/portfolios', { - parent: 'units/index' - url: '/students/portfolios' - templateUrl: "units/states/portfolios/portfolios.tpl.html" - controller: "UnitPortfoliosStateCtrl" - data: - task: "Student Portfolios" - pageTitle: "_Home_" - roleWhitelist: ['Tutor', 'Convenor', 'Admin', 'Auditor'] - } -) -.controller("UnitPortfoliosStateCtrl", ($scope, alertService, analyticsService, gradeService, newProjectService, Visualisation, newTaskService, fileDownloaderService, newUserService) -> - # TODO: (@alexcu) Break this down into smaller directives/substates - - $scope.downloadGrades = -> fileDownloaderService.downloadFile($scope.unit.gradesUrl, "#{$scope.unit.code}-grades.csv") - $scope.downloadPortfolios = -> fileDownloaderService.downloadFile($scope.unit.portfoliosUrl, "#{$scope.unit.code}-portfolios.zip") - - $scope.studentFilter = 'allStudents' - $scope.portfolioFilter = 'withPortfolio' - - $scope.statusClass = newTaskService.statusClass - $scope.statusText = newTaskService.statusText - - refreshCharts = Visualisation.refreshAll - - # - # Sets the active tab - # - $scope.setActiveTab = (tab) -> - # Do nothing if we're switching to the same tab - return if tab is $scope.activeTab - $scope.activeTab?.active = false - $scope.activeTab = tab - $scope.activeTab.active = true - - if $scope.activeTab == $scope.tabs.viewProgress - refreshCharts() - - # - # Active task tab group - # - $scope.tabs = - selectStudent: - title: "Select Student" - subtitle: "Select the student to assess" - seq: 0 - viewProgress: - title: "View Progress" - subtitle: "See the progress of the student" - seq: 1 - viewPortfolio: - title: "View Portfolio" - subtitle: "See the portfolio of the student" - seq: 2 - assessPortfolio: - title: "Assess Portfolio" - subtitle: "Enter a grade for the student" - seq: 3 - - $scope.setActiveTab($scope.tabs.selectStudent) - - $scope.tutor = newUserService.currentUser - - $scope.search = "" - - # Pagination details - $scope.currentPage = 1 - $scope.maxSize = 5 - $scope.pageSize = 10 - - $scope.filterOptions = {selectedGrade: -1} - $scope.gradeValues = gradeService.gradeValues - $scope.grades = gradeService.grades - $scope.gradeAcronyms = gradeService.gradeAcronyms - - $scope.selectedStudent = null - - $scope.gradeResults = [ - { - name: 'Fail', - scores: [ 0, 10, 20, 30, 40, 44 ] - } - { - name: 'Pass', - scores: [ 50, 53, 55, 57 ] - } - { - name: 'Credit', - scores: [ 60, 63, 65, 67 ] - } - { - name: 'Distinction', - scores: [ 70, 73, 75, 77 ] - } - { - name: 'High Distinction', - scores: [ 80, 83, 85, 87 ] - } - { - name: 'High Distinction', - scores: [ 90, 93, 95, 97, 100 ] - } - ] - - $scope.editingRationale = false - - $scope.toggleEditRationale = -> - $scope.editingRationale = !$scope.editingRationale - - - analyticsService.watchEvent $scope, 'studentFilter', 'Teacher View - Grading Tab' - analyticsService.watchEvent $scope, 'sortOrder', 'Teacher View - Grading Tab' - analyticsService.watchEvent $scope, 'currentPage', 'Teacher View - Grading Tab', 'Selected Page' - - $scope.selectStudent = (student) -> - $scope.selectedStudent = student - $scope.project = null - newProjectService.loadProject(student, $scope.unit).subscribe({ - next: (project) -> - $scope.project = project - $scope.project.preloadedUrl = $scope.project.portfolioUrl() - error: (message) -> alertService.error( message, 6000) - }) -) diff --git a/src/app/units/states/portfolios/portfolios.component.html b/src/app/units/states/portfolios/portfolios.component.html new file mode 100644 index 0000000000..c9c70c8497 --- /dev/null +++ b/src/app/units/states/portfolios/portfolios.component.html @@ -0,0 +1,39 @@ +
    +

    Student Portfolios

    + @if (unit) { + + + + + + @if (selectedProject) { + + } + + + + + @if (selectedProject) { + + } + + + @if (selectedProject) { + + } + + + } @else { + +
    Loading unit...
    + } +
    diff --git a/src/app/units/states/portfolios/portfolios.component.scss b/src/app/units/states/portfolios/portfolios.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/portfolios/portfolios.component.ts b/src/app/units/states/portfolios/portfolios.component.ts new file mode 100644 index 0000000000..4ebd79eccd --- /dev/null +++ b/src/app/units/states/portfolios/portfolios.component.ts @@ -0,0 +1,71 @@ +import {Component, Input, OnInit, ViewChild} from '@angular/core'; +import {MatTabGroup} from '@angular/material/tabs'; +import {StateService} from '@uirouter/core'; +import {Project} from 'src/app/api/models/project'; +import {Unit} from 'src/app/api/models/unit'; +import {ProjectService} from 'src/app/api/services/project.service'; +import {UnitService} from 'src/app/api/services/unit.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global-state.service'; + +@Component({ + selector: 'f-portfolios', + templateUrl: './portfolios.component.html', + styleUrl: './portfolios.component.scss', +}) +export class PortfoliosComponent implements OnInit { + // Passed from doubtfire.states.ts + @Input() unitId: number; + + // Exposed to child components + public unit: Unit = null; + public selectedProject: Project; + + @ViewChild('tabs') tabs!: MatTabGroup; + + constructor( + private globalStateService: GlobalStateService, + private unitService: UnitService, + private projectService: ProjectService, + private stateService: StateService, + private alertService: AlertService, + ) {} + + studentSelected(project: Project) { + this.selectedProject = null; + + this.projectService.loadProject(project, this.unit).subscribe({ + next: (project) => { + this.selectedProject = project; + this.tabs.selectedIndex = 1; + }, + error: (error) => { + this.alertService.error(`Failed to load project: ${error}`, 6000); + console.error(error); + }, + }); + } + + ngOnInit(): void { + // TODO 10.0.x: Unit and student loading needs to be moved to the parent controller (units/{unitId}) when everything is migrated + this.unitService.get(this.unitId).subscribe({ + next: (unit) => { + this.globalStateService.setView(ViewType.UNIT, unit); + + this.projectService.loadStudents(unit, false).subscribe({ + next: () => { + this.unit = unit; + }, + error: (error) => { + this.alertService.error(`Failed to load unit: ${error}`, 6000); + this.stateService.go('home'); + }, + }); + }, + error: (error) => { + this.alertService.error(`Failed to load unit: ${error}`, 6000); + this.stateService.go('home'); + }, + }); + } +} diff --git a/src/app/units/states/portfolios/portfolios.scss b/src/app/units/states/portfolios/portfolios.scss deleted file mode 100644 index 0e1e97b594..0000000000 --- a/src/app/units/states/portfolios/portfolios.scss +++ /dev/null @@ -1,26 +0,0 @@ -.unit-student-portfolio-list { - .select-portfolio-grade.btn-group { - @media (min-width: $screen-sm-max) { - margin: auto 1.2ex; - } - label.btn { - padding: 4px 7px; - font-size: 0.9em; - height: 34px; - } - } -} - -.grade-icon { - color: #fff; - font-size: 1em; - border-radius: 100%; - width: 2.25em; - height: 2.25em; - font-weight: 100; - margin: 0 auto; - display: flex; - align-items: center; - justify-content: center; - background-color: #333333; -} diff --git a/src/app/units/states/portfolios/portfolios.tpl.html b/src/app/units/states/portfolios/portfolios.tpl.html deleted file mode 100644 index 75b9a955ee..0000000000 --- a/src/app/units/states/portfolios/portfolios.tpl.html +++ /dev/null @@ -1,319 +0,0 @@ -
    - - - {{tab.title}} - - - -
    -
    -
    -

    Mark Portfolios

    - Assess student portfolios -
    -
    -
    -
    - - -
    -
    - - -
    -
    - -
    -
    - -
    -
    - - - -
    - -
    - -
    -
    - -

    No portfolios found

    -
    - - - - - - - - - - - - - - - - - - - - - - - - - - - -
    - - Student - - - - - Name - - - - - Tutor - - - - - Tutorial - - - - - Target - - - - - Submitted as - - - - - Stats - - - - Portfolio? - - - - - Grade - - -
    {{student.student.studentId || student.student.username}}{{student.student.name}}{{student.tutorNames()}}{{student.shortTutorialDescription()}} - - - - - - - {{bar.value}}% - - - - {{student.hasPortfolio ? "Yes" : "No"}} - {{student.grade}}
    -
    - -
    -
    -
    -
    -

    Portfolio Details

    - Review portfolio and assign grade. -
    -
    -
    - -

    Select student to view portfolio and assign grade

    -
    -
    -
    -
    -
    -
    -

    Review Progress of {{selectedStudent.student.name}}

    - Review the students progress through the unit's tasks. -
    -
    -
    - -
    -
    - -
    -
    -
    -

    Review Portfolio of {{selectedStudent.student.name}}

    - View or download portfolio for assessment. -
    -
    -
    - -

    No Portfolio Submitted

    -
    -
    - - -
    -
    - -
    -
    -
    -

    Grade for {{selectedStudent.student.name}}

    - Assign Grade for this work. -
    -
    -
    -
    - -
    - -
    -
    {{results.name}}
    -

    - -

    -
    -
    - -
    -
    -
    -
    -
    diff --git a/src/app/units/states/states.coffee b/src/app/units/states/states.coffee index 7d68872f4a..cd08e56e0c 100644 --- a/src/app/units/states/states.coffee +++ b/src/app/units/states/states.coffee @@ -6,6 +6,5 @@ angular.module('doubtfire.units.states', [ 'doubtfire.units.states.groups' 'doubtfire.units.states.students' 'doubtfire.units.states.analytics' - 'doubtfire.units.states.portfolios' 'doubtfire.units.states.rollover' ]) diff --git a/src/app/visualisations/progress-burndown-chart/progressburndownchart.component.html b/src/app/visualisations/progress-burndown-chart/progressburndownchart.component.html index 374cee4ce8..039c289a6b 100644 --- a/src/app/visualisations/progress-burndown-chart/progressburndownchart.component.html +++ b/src/app/visualisations/progress-burndown-chart/progressburndownchart.component.html @@ -1,4 +1,4 @@ -
    +
    diff --git a/src/app/visualisations/task-status-pie-chart/taskstatuspiechart.component.html b/src/app/visualisations/task-status-pie-chart/taskstatuspiechart.component.html index 02f2e78dee..0364d01766 100644 --- a/src/app/visualisations/task-status-pie-chart/taskstatuspiechart.component.html +++ b/src/app/visualisations/task-status-pie-chart/taskstatuspiechart.component.html @@ -1,4 +1,4 @@ -
    +
    From 09ca9b040c31629e94dd48ee57b2483c38c96bf0 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 19 Nov 2025 16:58:47 +1100 Subject: [PATCH 0742/1280] chore: update migration progress --- README.md | 128 +++++++++++++++++++++++++++--------------------------- 1 file changed, 64 insertions(+), 64 deletions(-) diff --git a/README.md b/README.md index 3dfbd9c89c..a6a2b4bfbc 100644 --- a/README.md +++ b/README.md @@ -14,12 +14,12 @@ A modern, lightweight learning management system. Important: When completing a frontend migration, please update the below list regarding the component you have migrated. -SUMMARY: +### SUMMARY: - `89 / 183` components migrated - `19` components no longer in the doubtfire-lms/9.x branch -NO LONGER IN doubtfire-lms/9.x +### NO LONGER IN doubtfire-lms/9.x - [x] ./src/app/projects/states/all/directives/all-projects-list/all-projects-list.coffee - [x] ./src/app/projects/states/all/all.coffee @@ -41,7 +41,7 @@ NO LONGER IN doubtfire-lms/9.x - [x] ./src/app/common/modals/progress-modal/progress-modal.coffee - [x] ./src/app/errors/states/not-found/not-found.coffee -MIGRATED: +### MIGRATED: - [x] ./src/app/home/splash-screen/splash-screen.component.ts - [x] ./src/app/home/states/home/home.component.ts @@ -151,88 +151,88 @@ MIGRATED: - [x] ./src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.coffee - [x] ./src/app/projects/project-progress-dashboard/project-progress-dashboard.coffee - [x] ./src/app/units/states/portfolios/portfolios.coffee +- [x] ./src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.coffee +- [x] ./src/app/config/local-storage/local-storage.coffee (Removed in 10.0.x) +- [x] ./src/app/projects/states/tutorials/tutorials.coffee +- [x] ./src/app/admin/modals/modals.coffee -TODO: +### TODO: -- [ ] ./src/app/visualisations/alignment-bar-chart.coffee -- [ ] ./src/app/visualisations/summary-task-status-scatter.coffee -- [ ] ./src/app/visualisations/target-grade-pie-chart.coffee -- [ ] ./src/app/visualisations/achievement-custom-bar-chart.coffee -- [ ] ./src/app/visualisations/student-task-status-pie-chart.coffee -- [ ] ./src/app/visualisations/alignment-bullet-chart.coffee -- [ ] ./src/app/visualisations/task-status-pie-chart.coffee -- [ ] ./src/app/visualisations/achievement-box-plot.coffee -- [ ] ./src/app/visualisations/task-completion-box-plot.coffee -- [ ] ./src/app/visualisations/visualisations.coffee -- [ ] ./src/app/tasks/tasks.coffee -- [ ] ./src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee -- [ ] ./src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/task-ilo-alignment-modal.coffee -- [ ] ./src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment.coffee -- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.coffee -- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment.coffee -- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.coffee -- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-rater/task-ilo-alignment-rater.coffee -- [ ] ./src/app/tasks/modals/modals.coffee +- [ ] ./src/app/common/common.coffee +- [ ] ./src/app/common/content-editable/content-editable.coffee +- [ ] ./src/app/common/filters/filters.coffee +- [ ] ./src/app/common/modals/csv-result-modal/csv-result-modal.coffee +- [ ] ./src/app/common/modals/modals.coffee +- [ ] ./src/app/common/services/analytics-service.coffee +- [ ] ./src/app/common/services/date-service.coffee +- [ ] ./src/app/common/services/listener-service.coffee +- [ ] ./src/app/common/services/media-service.coffee +- [ ] ./src/app/common/services/outcome-service.coffee +- [ ] ./src/app/common/services/recorder-service.coffee +- [ ] ./src/app/common/services/services.coffee +- [ ] ./src/app/config/analytics/analytics.coffee - [ ] ./src/app/config/config.coffee -- [ ] ./src/app/config/runtime/runtime.coffee - [ ] ./src/app/config/root-controller/root-controller.coffee -- [ ] ./src/app/config/local-storage/local-storage.coffee -- [ ] ./src/app/config/vendor-dependencies/vendor-dependencies.coffee - [ ] ./src/app/config/routing/routing.coffee -- [ ] ./src/app/config/analytics/analytics.coffee +- [ ] ./src/app/config/runtime/runtime.coffee +- [ ] ./src/app/config/vendor-dependencies/vendor-dependencies.coffee +- [ ] ./src/app/errors/errors.coffee +- [ ] ./src/app/errors/states/states.coffee +- [ ] ./src/app/errors/states/timeout/timeout.coffee +- [ ] ./src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.coffee +- [ ] ./src/app/groups/groups.coffee +- [ ] ./src/app/groups/tutor-group-manager/tutor-group-manager.coffee +- [ ] ./src/app/projects/project-outcome-alignment/project-outcome-alignment.coffee - [ ] ./src/app/projects/projects.coffee -- [ ] ./src/app/projects/states/states.coffee -- [ ] ./src/app/projects/states/groups/groups.coffee -- [ ] ./src/app/projects/states/feedback/feedback.coffee +- [ ] ./src/app/projects/states/dashboard/dashboard.coffee - [ ] ./src/app/projects/states/dashboard/directives/directives.coffee - [ ] ./src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.coffee - [ ] ./src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee -- [ ] ./src/app/projects/states/dashboard/dashboard.coffee +- [ ] ./src/app/projects/states/feedback/feedback.coffee +- [ ] ./src/app/projects/states/groups/groups.coffee +- [ ] ./src/app/projects/states/index/index.coffee - [ ] ./src/app/projects/states/outcomes/outcomes.coffee -- [ ] ./src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.coffee - [ ] ./src/app/projects/states/portfolio/directives/directives.coffee -- [ ] ./src/app/projects/states/portfolio/directives/portfolio-tasks-step/portfolio-tasks-step.coffee -- [ ] ./src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.coffee +- [ ] ./src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.coffee (Wait until merged in with 10.0.x) +- [ ] ./src/app/projects/states/portfolio/directives/portfolio-tasks-step/portfolio-tasks-step.coffee (Wait until merged in with 10.0.x) - [ ] ./src/app/projects/states/portfolio/portfolio.coffee -- [ ] ./src/app/projects/states/index/index.coffee -- [ ] ./src/app/projects/project-outcome-alignment/project-outcome-alignment.coffee -- [ ] ./src/app/projects/states/tutorials/tutorials.coffee -- [ ] ./src/app/admin/modals/modals.coffee -- [ ] ./src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.coffee -- [ ] ./src/app/groups/tutor-group-manager/tutor-group-manager.coffee -- [ ] ./src/app/groups/groups.coffee -- [ ] ./src/app/units/states/groups/groups.coffee -- [ ] ./src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.coffee +- [ ] ./src/app/projects/states/states.coffee +- [ ] ./src/app/tasks/modals/modals.coffee +- [ ] ./src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee +- [ ] ./src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/task-ilo-alignment-modal.coffee +- [ ] ./src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment.coffee +- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.coffee +- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-rater/task-ilo-alignment-rater.coffee +- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.coffee +- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment.coffee +- [ ] ./src/app/tasks/tasks.coffee - [ ] ./src/app/units/modals/modals.coffee - [ ] ./src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.coffee -- [ ] ./src/app/units/units.coffee -- [ ] ./src/app/units/states/states.coffee -- [ ] ./src/app/units/states/tasks/tasks.coffee -- [ ] ./src/app/units/states/tasks/definition/definition.coffee -- [ ] ./src/app/units/states/analytics/analytics.coffee +- [ ] ./src/app/units/states/analytics/analytics.coffee (Just the routing, since the TypeScript f-analytics component has been expanded in 10.0.x) - [ ] ./src/app/units/states/edit/directives/directives.coffee +- [ ] ./src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.coffee - [ ] ./src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.coffee - [ ] ./src/app/units/states/edit/edit.coffee +- [ ] ./src/app/units/states/groups/groups.coffee +- [ ] ./src/app/units/states/index/index.coffee - [ ] ./src/app/units/states/rollover/directives/directives.coffee - [ ] ./src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee - [ ] ./src/app/units/states/rollover/rollover.coffee -- [ ] ./src/app/units/states/index/index.coffee +- [ ] ./src/app/units/states/states.coffee - [ ] ./src/app/units/states/students-list/students-list.coffee -- [ ] ./src/app/common/modals/modals.coffee -- [ ] ./src/app/common/modals/csv-result-modal/csv-result-modal.coffee -- [ ] ./src/app/common/common.coffee -- [ ] ./src/app/common/content-editable/content-editable.coffee -- [ ] ./src/app/common/services/media-service.coffee -- [ ] ./src/app/common/services/recorder-service.coffee -- [ ] ./src/app/common/services/outcome-service.coffee -- [ ] ./src/app/common/services/listener-service.coffee -- [ ] ./src/app/common/services/services.coffee -- [ ] ./src/app/common/services/date-service.coffee -- [ ] ./src/app/common/services/analytics-service.coffee -- [ ] ./src/app/errors/errors.coffee -- [ ] ./src/app/errors/states/states.coffee -- [ ] ./src/app/errors/states/timeout/timeout.coffee -- [ ] ./src/app/common/filters/filters.coffee +- [ ] ./src/app/units/states/tasks/definition/definition.coffee +- [ ] ./src/app/units/states/tasks/tasks.coffee +- [ ] ./src/app/units/units.coffee +- [ ] ./src/app/visualisations/achievement-box-plot.coffee +- [ ] ./src/app/visualisations/achievement-custom-bar-chart.coffee +- [ ] ./src/app/visualisations/alignment-bar-chart.coffee +- [ ] ./src/app/visualisations/alignment-bullet-chart.coffee +- [ ] ./src/app/visualisations/student-task-status-pie-chart.coffee +- [ ] ./src/app/visualisations/summary-task-status-scatter.coffee +- [ ] ./src/app/visualisations/target-grade-pie-chart.coffee +- [ ] ./src/app/visualisations/task-completion-box-plot.coffee +- [ ] ./src/app/visualisations/task-status-pie-chart.coffee +- [ ] ./src/app/visualisations/visualisations.coffee ## Table of Contents From 5968f64644fa14505f65aea0f73f5dcfa117cc1a Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 19 Nov 2025 16:59:27 +1100 Subject: [PATCH 0743/1280] chore: remove admin modals coffeescript --- src/app/admin/modals/modals.coffee | 1 - src/app/doubtfire-angularjs.module.ts | 1 - 2 files changed, 2 deletions(-) delete mode 100644 src/app/admin/modals/modals.coffee diff --git a/src/app/admin/modals/modals.coffee b/src/app/admin/modals/modals.coffee deleted file mode 100644 index f05f3bf26b..0000000000 --- a/src/app/admin/modals/modals.coffee +++ /dev/null @@ -1 +0,0 @@ -angular.module('doubtfire.admin.modals', []) \ No newline at end of file diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 0a40d4e43e..f6e596f918 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -73,7 +73,6 @@ import 'build/src/app/projects/states/portfolio/directives/directives.js'; import 'build/src/app/projects/states/portfolio/portfolio.js'; import 'build/src/app/projects/states/index/index.js'; import 'build/src/app/projects/project-outcome-alignment/project-outcome-alignment.js'; -import 'build/src/app/admin/modals/modals.js'; import 'build/src/app/groups/groups.js'; import 'build/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.js'; import 'build/src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.js'; From 0e9223cc94ab96a07127c1523cbd36d4ccbaf972 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 19 Nov 2025 17:01:48 +1100 Subject: [PATCH 0744/1280] chore: update migration progress --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a6a2b4bfbc..0102408209 100644 --- a/README.md +++ b/README.md @@ -155,6 +155,7 @@ Important: When completing a frontend migration, please update the below list re - [x] ./src/app/config/local-storage/local-storage.coffee (Removed in 10.0.x) - [x] ./src/app/projects/states/tutorials/tutorials.coffee - [x] ./src/app/admin/modals/modals.coffee +- [x] ./src/app/common/services/date-service.coffee ### TODO: @@ -164,7 +165,6 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/common/modals/csv-result-modal/csv-result-modal.coffee - [ ] ./src/app/common/modals/modals.coffee - [ ] ./src/app/common/services/analytics-service.coffee -- [ ] ./src/app/common/services/date-service.coffee - [ ] ./src/app/common/services/listener-service.coffee - [ ] ./src/app/common/services/media-service.coffee - [ ] ./src/app/common/services/outcome-service.coffee From dde1e7697f8a9a93577bb0e18e3e81a3ebd1ace2 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 19 Nov 2025 17:12:38 +1100 Subject: [PATCH 0745/1280] fix: display groups only when a group set is selected --- .../groups/group-selector/group-selector.component.html | 7 ++++++- src/app/groups/group-selector/group-selector.component.ts | 2 +- .../group-set-manager/group-set-manager.component.html | 1 + 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/app/groups/group-selector/group-selector.component.html b/src/app/groups/group-selector/group-selector.component.html index b0984e69f3..b2878507d9 100644 --- a/src/app/groups/group-selector/group-selector.component.html +++ b/src/app/groups/group-selector/group-selector.component.html @@ -187,7 +187,12 @@ } - @if (selectedGroupSet.keepGroupsInSameClass && selectedGroupSet.groups.length > 0 && !unitRole) { + @if ( + selectedGroupSet && + selectedGroupSet.keepGroupsInSameClass && + selectedGroupSet.groups.length > 0 && + !unitRole + ) {

    Can't see the group you need to join? Groups shown are limited to those in your allocated tutorials. Use the diff --git a/src/app/groups/group-selector/group-selector.component.ts b/src/app/groups/group-selector/group-selector.component.ts index f4847ba263..54cde0a36d 100644 --- a/src/app/groups/group-selector/group-selector.component.ts +++ b/src/app/groups/group-selector/group-selector.component.ts @@ -87,7 +87,7 @@ export class GroupSelectorComponent refreshGroups() { this.groupsSub?.unsubscribe(); - this.groupsSub = this.selectedGroupSet.groupsCache.values.subscribe((values) => { + this.groupsSub = this.selectedGroupSet?.groupsCache.values.subscribe((values) => { this.groups = [...values]; }); this.applyFilters(); diff --git a/src/app/groups/group-set-manager/group-set-manager.component.html b/src/app/groups/group-set-manager/group-set-manager.component.html index 1f209b3870..0c114326a8 100644 --- a/src/app/groups/group-set-manager/group-set-manager.component.html +++ b/src/app/groups/group-set-manager/group-set-manager.component.html @@ -7,6 +7,7 @@ [selectedGroup]="selectedGroup" [selectedGroupSet]="selectedGroupSet" [onSelect]="groupSelectHandler" + [hidden]="!selectedGroupSet" > From e964d1edcd5a37f7ea5ee9db928348dac231e13b Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 19 Nov 2025 17:32:21 +1100 Subject: [PATCH 0746/1280] chore: revert hidden condition --- .../groups/group-set-manager/group-set-manager.component.html | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/groups/group-set-manager/group-set-manager.component.html b/src/app/groups/group-set-manager/group-set-manager.component.html index 0c114326a8..4dc322bbe2 100644 --- a/src/app/groups/group-set-manager/group-set-manager.component.html +++ b/src/app/groups/group-set-manager/group-set-manager.component.html @@ -1,4 +1,4 @@ -

    +
    From a79dd46e2e4c57ce4b9c529b673e441da5370994 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 20 Nov 2025 15:33:33 +1100 Subject: [PATCH 0747/1280] chore: update migration progress --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 0102408209..df97cc67e5 100644 --- a/README.md +++ b/README.md @@ -156,6 +156,12 @@ Important: When completing a frontend migration, please update the below list re - [x] ./src/app/projects/states/tutorials/tutorials.coffee - [x] ./src/app/admin/modals/modals.coffee - [x] ./src/app/common/services/date-service.coffee +- [ ] ./src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/task-ilo-alignment-modal.coffee (Removed in 10.0.x) +- [ ] ./src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment.coffee (Removed in 10.0.x) +- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.coffee (Removed in 10.0.x) +- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-rater/task-ilo-alignment-rater.coffee (Removed in 10.0.x) +- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.coffee (Removed in 10.0.x) +- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment.coffee (Removed in 10.0.x) ### TODO: @@ -199,12 +205,6 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/projects/states/states.coffee - [ ] ./src/app/tasks/modals/modals.coffee - [ ] ./src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee -- [ ] ./src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/task-ilo-alignment-modal.coffee -- [ ] ./src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment.coffee -- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.coffee -- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-rater/task-ilo-alignment-rater.coffee -- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.coffee -- [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment.coffee - [ ] ./src/app/tasks/tasks.coffee - [ ] ./src/app/units/modals/modals.coffee - [ ] ./src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.coffee From 15bbecf57552c59330ec06289a7e622203aec38b Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 20 Nov 2025 15:34:24 +1100 Subject: [PATCH 0748/1280] chore: update migration progress --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index df97cc67e5..4a060d55af 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,7 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-rater/task-ilo-alignment-rater.coffee (Removed in 10.0.x) - [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.coffee (Removed in 10.0.x) - [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment.coffee (Removed in 10.0.x) +- [ ] ./src/app/projects/project-outcome-alignment/project-outcome-alignment.coffee (Removed in 10.0.x) ### TODO: @@ -188,7 +189,6 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.coffee - [ ] ./src/app/groups/groups.coffee - [ ] ./src/app/groups/tutor-group-manager/tutor-group-manager.coffee -- [ ] ./src/app/projects/project-outcome-alignment/project-outcome-alignment.coffee - [ ] ./src/app/projects/projects.coffee - [ ] ./src/app/projects/states/dashboard/dashboard.coffee - [ ] ./src/app/projects/states/dashboard/directives/directives.coffee From f505823498bd52f6282d613512c085f8978f48b7 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 25 Nov 2025 12:58:21 +1100 Subject: [PATCH 0749/1280] chore(release): 10.0.0-64 --- CHANGELOG.md | 8 ++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 25972b520c..e1e42ecd66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-64](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-63...v10.0.0-64) (2025-11-25) + + +### Bug Fixes + +* avoid calling window to open project in new tab ([9ab015d](https://github.com/b0ink/doubtfire-deploy/commit/9ab015d168cf7e421500910766b9e6fb0bf907f5)) +* use new google fonts api for proper weight loading ([#1039](https://github.com/b0ink/doubtfire-deploy/issues/1039)) ([40f2640](https://github.com/b0ink/doubtfire-deploy/commit/40f2640e6579536cef8e82e9476733083b82bac1)) + ## [10.0.0-63](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-62...v10.0.0-63) (2025-11-10) diff --git a/package-lock.json b/package-lock.json index ac840fcd6d..99a5447d53 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-63", + "version": "10.0.0-64", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-63", + "version": "10.0.0-64", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 47621b97b8..2945358894 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-63", + "version": "10.0.0-64", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From bdcd75d91d5ddc7d9a60317bd91289a7242251e1 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 25 Nov 2025 13:11:37 +1100 Subject: [PATCH 0750/1280] fix: typo --- .../upload-submission-modal/upload-submission-modal.tpl.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html index 65695e16ec..bfda995467 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html @@ -101,7 +101,7 @@

    Final comments

    -
    Character count: {{comment.length}} (Min. 25)
    +
    Character count: {{comment.length}} (Min. 25)
    From 665d6ae86b65e9e8ba83df1ad3d4a053a4553851 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 25 Nov 2025 13:11:44 +1100 Subject: [PATCH 0751/1280] chore(release): 10.0.0-65 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1e42ecd66..6935c31476 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-65](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-64...v10.0.0-65) (2025-11-25) + + +### Bug Fixes + +* typo ([bdcd75d](https://github.com/b0ink/doubtfire-deploy/commit/bdcd75d91d5ddc7d9a60317bd91289a7242251e1)) + ## [10.0.0-64](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-63...v10.0.0-64) (2025-11-25) diff --git a/package-lock.json b/package-lock.json index 99a5447d53..c30263893b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-64", + "version": "10.0.0-65", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-64", + "version": "10.0.0-65", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 2945358894..fb458e4b24 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-64", + "version": "10.0.0-65", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From c7776f489b68f97ab93b5f1faf19095bdec18558 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Fri, 28 Nov 2025 14:30:30 +1100 Subject: [PATCH 0752/1280] refactor: migrate rollover state (#1050) * refactor: init rollover migration * refactor: add rollover functionality * refactor: remove comment * chore: remove old rollover component * chore: revert formatting * chore: revert formatting * chore: update migration progress * chore: update migration progress * chore: update migration progress * chore: update migration progress * chore: update migration progress * chore: update migration progress --- README.md | 22 +++--- src/app/api/models/unit.ts | 8 +- src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire-angularjs.module.ts | 3 - src/app/doubtfire.states.ts | 26 ++++++ .../unit-details-editor.tpl.html | 2 +- .../rollover/directives/directives.coffee | 3 - .../unit-dates-selector.coffee | 79 ------------------- .../unit-dates-selector.tpl.html | 65 --------------- src/app/units/states/rollover/rollover.coffee | 40 ---------- .../states/rollover/rollover.component.html | 57 +++++++++++++ .../states/rollover/rollover.component.scss | 0 .../states/rollover/rollover.component.ts | 77 ++++++++++++++++++ .../units/states/rollover/rollover.tpl.html | 3 - src/app/units/states/states.coffee | 1 - 15 files changed, 179 insertions(+), 209 deletions(-) delete mode 100644 src/app/units/states/rollover/directives/directives.coffee delete mode 100644 src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee delete mode 100644 src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.tpl.html delete mode 100644 src/app/units/states/rollover/rollover.coffee create mode 100644 src/app/units/states/rollover/rollover.component.html create mode 100644 src/app/units/states/rollover/rollover.component.scss create mode 100644 src/app/units/states/rollover/rollover.component.ts delete mode 100644 src/app/units/states/rollover/rollover.tpl.html diff --git a/README.md b/README.md index 4a060d55af..b97274b557 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ Important: When completing a frontend migration, please update the below list re - [x] ./src/app/common/alert-list/alert-list.coffee - [x] ./src/app/common/modals/progress-modal/progress-modal.coffee - [x] ./src/app/errors/states/not-found/not-found.coffee +- [x] ./src/app/groups/tutor-group-manager/tutor-group-manager.coffee ### MIGRATED: @@ -163,6 +164,14 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.coffee (Removed in 10.0.x) - [ ] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment.coffee (Removed in 10.0.x) - [ ] ./src/app/projects/project-outcome-alignment/project-outcome-alignment.coffee (Removed in 10.0.x) +- [ ] ./src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.coffee (Removed in 10.0.x) +- [ ] ./src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.coffee (Removed in 10.0.x) +- [ ] ./src/app/projects/states/outcomes/outcomes.coffee (Removed in 10.0.x) +- [ ] ./src/app/projects/states/portfolio/directives/portfolio-tasks-step/portfolio-tasks-step.coffee (Removed in 10.0.x) +- [x] ./src/app/units/states/rollover/directives/directives.coffee +- [x] ./src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee +- [x] ./src/app/units/states/rollover/rollover.coffee +- [x] ./src/app/visualisations/task-status-pie-chart.coffee ### TODO: @@ -188,7 +197,6 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/errors/states/timeout/timeout.coffee - [ ] ./src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.coffee - [ ] ./src/app/groups/groups.coffee -- [ ] ./src/app/groups/tutor-group-manager/tutor-group-manager.coffee - [ ] ./src/app/projects/projects.coffee - [ ] ./src/app/projects/states/dashboard/dashboard.coffee - [ ] ./src/app/projects/states/dashboard/directives/directives.coffee @@ -197,29 +205,22 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/projects/states/feedback/feedback.coffee - [ ] ./src/app/projects/states/groups/groups.coffee - [ ] ./src/app/projects/states/index/index.coffee -- [ ] ./src/app/projects/states/outcomes/outcomes.coffee - [ ] ./src/app/projects/states/portfolio/directives/directives.coffee -- [ ] ./src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.coffee (Wait until merged in with 10.0.x) -- [ ] ./src/app/projects/states/portfolio/directives/portfolio-tasks-step/portfolio-tasks-step.coffee (Wait until merged in with 10.0.x) +- [ ] ./src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.coffee (Migrate this in 10.0.x) - [ ] ./src/app/projects/states/portfolio/portfolio.coffee - [ ] ./src/app/projects/states/states.coffee - [ ] ./src/app/tasks/modals/modals.coffee - [ ] ./src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee - [ ] ./src/app/tasks/tasks.coffee - [ ] ./src/app/units/modals/modals.coffee -- [ ] ./src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.coffee - [ ] ./src/app/units/states/analytics/analytics.coffee (Just the routing, since the TypeScript f-analytics component has been expanded in 10.0.x) - [ ] ./src/app/units/states/edit/directives/directives.coffee - [ ] ./src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.coffee -- [ ] ./src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.coffee - [ ] ./src/app/units/states/edit/edit.coffee - [ ] ./src/app/units/states/groups/groups.coffee - [ ] ./src/app/units/states/index/index.coffee -- [ ] ./src/app/units/states/rollover/directives/directives.coffee -- [ ] ./src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee -- [ ] ./src/app/units/states/rollover/rollover.coffee - [ ] ./src/app/units/states/states.coffee -- [ ] ./src/app/units/states/students-list/students-list.coffee +- [ ] ./src/app/units/states/students-list/students-list.coffee (Refer to the unit-students-editor component) - [ ] ./src/app/units/states/tasks/definition/definition.coffee - [ ] ./src/app/units/states/tasks/tasks.coffee - [ ] ./src/app/units/units.coffee @@ -231,7 +232,6 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/visualisations/summary-task-status-scatter.coffee - [ ] ./src/app/visualisations/target-grade-pie-chart.coffee - [ ] ./src/app/visualisations/task-completion-box-plot.coffee -- [ ] ./src/app/visualisations/task-status-pie-chart.coffee - [ ] ./src/app/visualisations/visualisations.coffee ## Table of Contents diff --git a/src/app/api/models/unit.ts b/src/app/api/models/unit.ts index 9d8ed9fa3f..59bbca86d0 100644 --- a/src/app/api/models/unit.ts +++ b/src/app/api/models/unit.ts @@ -253,9 +253,11 @@ export class Unit extends Entity { return Math.round((startToNow / totalDuration) * 100); } - public rolloverTo(body: {new_unit_code?: string, start_date: Date; end_date: Date}): Observable; - public rolloverTo(body: {new_unit_code?: string, teaching_period_id: number}): Observable; - public rolloverTo(body: any): Observable { + public rolloverTo( + body: + | {new_unit_code?: string; start_date: Date; end_date: Date} + | {new_unit_code?: string; teaching_period_id: number}, + ): Observable { const unitService = AppInjector.get(UnitService); return unitService.create( diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 939c0a9c83..0c0b4e2411 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -292,6 +292,7 @@ import {PortfoliosListComponent} from './units/states/portfolios/directives/port import {PortfoliosProjectProgressComponent} from './units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component'; import {PortfoliosPortfolioViewComponent} from './units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component'; import {PortfoliosAssessmentComponent} from './units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component'; +import {RolloverComponent} from './units/states/rollover/rollover.component'; @NgModule({ // Components we declare @@ -432,6 +433,7 @@ import {PortfoliosAssessmentComponent} from './units/states/portfolios/directive PortfoliosProjectProgressComponent, PortfoliosPortfolioViewComponent, PortfoliosAssessmentComponent, + RolloverComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index f6e596f918..c1f82e13e7 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -88,9 +88,6 @@ import 'build/src/app/units/states/edit/directives/unit-details-editor/unit-deta import 'build/src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.js'; import 'build/src/app/units/states/edit/directives/directives.js'; import 'build/src/app/units/states/edit/edit.js'; -import 'build/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.js'; -import 'build/src/app/units/states/rollover/directives/directives.js'; -import 'build/src/app/units/states/rollover/rollover.js'; import 'build/src/app/units/states/index/index.js'; import 'build/src/app/units/states/students-list/students-list.js'; import 'build/src/app/units/states/analytics/analytics.js'; diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index 28da9ec3aa..9f3da83c84 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -16,6 +16,7 @@ import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component import { Ng2ViewDeclaration } from '@uirouter/angular'; import { TutorialsComponent } from './projects/states/tutorials/tutorials.component'; import {PortfoliosComponent} from './units/states/portfolios/portfolios.component'; +import { RolloverComponent } from './units/states/rollover/rollover.component'; /* * Use this file to store any states that are sourced by angular components. @@ -455,6 +456,30 @@ const PortfoliosState: NgHybridStateDeclaration = { }, }; + +const RolloverState: NgHybridStateDeclaration = { + name: 'units/rollover', + url: '/units/:unitId/rollover', + resolve: { + unitId: [ + '$stateParams', + function ($stateParams) { + return $stateParams.unitId; + }, + ], + }, + views: { + main: { + component: RolloverComponent, + }, + }, + data: { + task: 'Unit Rollover', + pageTitle: 'Unit Rollover', + roleWhitelist: ['Convenor', 'Admin'], + }, +}; + /** * Export the list of states we have created in angular */ @@ -479,4 +504,5 @@ export const doubtfireStates = [ ScormPlayerStudentReviewState, TutorialState, PortfoliosState, + RolloverState, ]; diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html index 3cd81f09c4..1fd0ab346b 100644 --- a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html +++ b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.tpl.html @@ -429,4 +429,4 @@

    Update Unit

    -
    +
    \ No newline at end of file diff --git a/src/app/units/states/rollover/directives/directives.coffee b/src/app/units/states/rollover/directives/directives.coffee deleted file mode 100644 index 4f892f1291..0000000000 --- a/src/app/units/states/rollover/directives/directives.coffee +++ /dev/null @@ -1,3 +0,0 @@ -angular.module('doubtfire.units.states.rollover.directives', [ - 'doubtfire.units.states.rollover.directives.unit-dates-selector' -]) \ No newline at end of file diff --git a/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee b/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee deleted file mode 100644 index 07569a20a0..0000000000 --- a/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee +++ /dev/null @@ -1,79 +0,0 @@ -angular.module('doubtfire.units.states.rollover.directives.unit-dates-selector', []) - -# -# Editor for the basic details of a unit, such as the name, code -# start and end dates etc. -# -.directive('unitDatesSelector', -> - replace: true - restrict: 'E' - templateUrl: 'units/states/rollover/directives/unit-dates-selector/unit-dates-selector.tpl.html' - controller: ($scope, $state, $rootScope, DoubtfireConstants, alertService, newTeachingPeriodService) -> - $scope.calOptions = { - startOpened: false - endOpened: false - } - - # Get the configurable, external name of Doubtfire - $scope.externalName = DoubtfireConstants.ExternalName - - $scope.saveData = { - id: $scope.unit.id, - toPeriod: null, - startDate: null, - endDate: null - } - - # get the teaching periods- gets an object with the loaded teaching periods - newTeachingPeriodService.cache.values.subscribe( - (periods) -> - $scope.teachingPeriodValues = [{value: undefined, text: "None"}] - other = periods.filter((tp) -> tp.endDate > Date.now()).map((p) -> {value: p, text: "#{p.year} #{p.period}"}) - _.each other, (d) -> $scope.teachingPeriodValues.push(d) - - if (periods.length > 0) - $scope.saveData.toPeriod = periods[periods.length - 1] - ) - - $scope.teachingPeriodSelected = ($event) -> - $scope.saveData.toPeriod = $event - - # Datepicker opener - $scope.open = ($event, pickerData) -> - $event.preventDefault() - $event.stopPropagation() - - if pickerData == 'start' - $scope.calOptions.startOpened = ! $scope.calOptions.startOpened - $scope.calOptions.endOpened = false - else - $scope.calOptions.startOpened = false - $scope.calOptions.endOpened = ! $scope.calOptions.endOpened - - $scope.dateOptions = { - formatYear: 'yy', - startingDay: 1 - } - - $scope.saveUnit = -> - if $scope.saveData.toPeriod - body = { - teaching_period_id: $scope.saveData.toPeriod.id - } - else - body = { - start_date: $scope.saveData.startDate - end_date: $scope.saeData.endDate - } - $scope.unit.rolloverTo(body).subscribe({ - next: (response) -> - alertService.success( "Unit created.", 2000) - $state.go("units/admin", {unitId: response.id}) - error: (response) -> - alertService.error "Error creating unit - #{response}" - - }) - - - -) diff --git a/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.tpl.html b/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.tpl.html deleted file mode 100644 index 08d6a1a87d..0000000000 --- a/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.tpl.html +++ /dev/null @@ -1,65 +0,0 @@ -
    -
    -
    -

    Create Unit

    - Duplicate an existing unit by specifying the time period. -
    -
    -
    -
    - -
    - -
    -
    - -
    - -
    -
    - - - - - -
    -
    -
    - -
    - -
    -
    - - - - - -
    -
    -
    -
    - -
    -
    -
    diff --git a/src/app/units/states/rollover/rollover.coffee b/src/app/units/states/rollover/rollover.coffee deleted file mode 100644 index afc82b1dc9..0000000000 --- a/src/app/units/states/rollover/rollover.coffee +++ /dev/null @@ -1,40 +0,0 @@ -angular.module('doubtfire.units.states.rollover', [ - 'doubtfire.units.states.rollover.directives' -]) - -.config(($stateProvider) -> - $stateProvider.state 'units/rollover', { - parent: 'units/index' - url: '/rollover' - controller: 'RolloverUnitState' - templateUrl: 'units/states/rollover/rollover.tpl.html' - data: - task: 'Unit Rollover' - pageTitle: "_Unit Rollover_" - roleWhitelist: ['Convenor', 'Admin'] - } -) -.controller("RolloverUnitState", ($scope, $state, $stateParams, newUserService, alertService, newUnitService, globalStateService) -> - unitId = +$stateParams.unitId - return $state.go('home') unless unitId - - globalStateService.onLoad () -> - # Load assessing unit role - $scope.unitRole = globalStateService.loadedUnitRoles.currentValues.find((unitRole) -> unitRole.unit.id == unitId) - - if (! $scope.unitRole?) && ( newUserService.currentUser.role == "Admin" ) - $scope.unitRole = newUserService.adminRoleFor(unitId, newUserService.currentUser) - - # Go home if no unit role was found - return $state.go('home') unless $scope.unitRole? - - globalStateService.setView("UNIT", $scope.unitRole) - - newUnitService.get(unitId).subscribe({ - next: (unit)-> $scope.unit = unit - error: (err)-> - alertService.error( "Error loading unit: " + err, 8000) - setTimeout((()-> $state.go('home')), 5000) - }) - -) diff --git a/src/app/units/states/rollover/rollover.component.html b/src/app/units/states/rollover/rollover.component.html new file mode 100644 index 0000000000..f9ac373ed0 --- /dev/null +++ b/src/app/units/states/rollover/rollover.component.html @@ -0,0 +1,57 @@ +
    + + + Copy {{ unit?.code }} {{ unit?.nameAndPeriod }} + + + +

    + Duplicate this unit by copying it to the indicated teaching period, or a custom start and + end date. +

    + +
    + + Teaching Period + + Custom Date + @for (period of teachingPeriods; track period) { + {{ period.year }} {{ period.period }} + } + + + +
    + @if (!teachingPeriod) { + + Start Date + + DD/MM/YYYY + + + + + End Date + + DD/MM/YYYY + + + + } @else { + + {{ teachingPeriod.name }} Start Date + + + + {{ teachingPeriod.name }} End Date + + + } +
    +
    + + + +
    +
    +
    diff --git a/src/app/units/states/rollover/rollover.component.scss b/src/app/units/states/rollover/rollover.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/rollover/rollover.component.ts b/src/app/units/states/rollover/rollover.component.ts new file mode 100644 index 0000000000..f577daa588 --- /dev/null +++ b/src/app/units/states/rollover/rollover.component.ts @@ -0,0 +1,77 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {StateService} from '@uirouter/core'; +import {TeachingPeriod} from 'src/app/api/models/teaching-period'; +import {Unit} from 'src/app/api/models/unit'; +import {TeachingPeriodService} from 'src/app/api/services/teaching-period.service'; +import {UnitService} from 'src/app/api/services/unit.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global-state.service'; + +@Component({ + selector: 'f-rollover', + templateUrl: './rollover.component.html', + styleUrl: './rollover.component.scss', +}) +export class RolloverComponent implements OnInit { + @Input() unitId: number; + + public unit: Unit; + + public teachingPeriods: TeachingPeriod[] = []; + + public teachingPeriod: TeachingPeriod; + + public newStartDate: Date; + public newEndDate: Date; + + constructor( + private globalStateService: GlobalStateService, + private unitService: UnitService, + private alertService: AlertService, + private state: StateService, + private teachingPeriodService: TeachingPeriodService, + ) {} + ngOnInit(): void { + this.globalStateService.onLoad(() => { + this.unitService.get(this.unitId).subscribe({ + next: (unit) => { + this.unit = unit; + this.globalStateService.setView(ViewType.UNIT, unit); + setTimeout(() => { + this.initUnit(); + }); + }, + error: (error) => { + this.alertService.error(`Failed to load unit: ${error}`, 6000); + this.state.go('home'); + }, + }); + }); + } + + initUnit() { + this.teachingPeriodService.cache.values.subscribe((periods) => { + this.teachingPeriods = periods; + this.teachingPeriods = periods.filter((p) => p.endDate.getTime() > Date.now()); + if (this.teachingPeriods.length) { + this.teachingPeriod = this.teachingPeriods[this.teachingPeriods.length - 1]; + } + }); + } + + createUnit() { + const body = this.teachingPeriod + ? {teaching_period_id: this.teachingPeriod.id} + : {start_date: this.newStartDate, end_date: this.newEndDate}; + + this.unit.rolloverTo(body).subscribe({ + next: (response) => { + this.alertService.success(`Unit created`, 2000); + this.state.go('units/admin', {unitId: response.id}); + }, + error: (error) => { + this.alertService.error(`Error creating unit: ${error}`, 6000); + }, + }); + } +} diff --git a/src/app/units/states/rollover/rollover.tpl.html b/src/app/units/states/rollover/rollover.tpl.html deleted file mode 100644 index aa2a80abe2..0000000000 --- a/src/app/units/states/rollover/rollover.tpl.html +++ /dev/null @@ -1,3 +0,0 @@ -
    - -
    diff --git a/src/app/units/states/states.coffee b/src/app/units/states/states.coffee index cd08e56e0c..6860c0f2a0 100644 --- a/src/app/units/states/states.coffee +++ b/src/app/units/states/states.coffee @@ -6,5 +6,4 @@ angular.module('doubtfire.units.states', [ 'doubtfire.units.states.groups' 'doubtfire.units.states.students' 'doubtfire.units.states.analytics' - 'doubtfire.units.states.rollover' ]) From 0611be04e8fe7e75ae07504945a2984839475e3a Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 28 Nov 2025 15:27:41 +1100 Subject: [PATCH 0753/1280] fix: correctly set rollover end date --- .../directives/unit-dates-selector/unit-dates-selector.coffee | 4 ++-- .../unit-dates-selector/unit-dates-selector.tpl.html | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee b/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee index 07569a20a0..1542d89d20 100644 --- a/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee +++ b/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee @@ -62,8 +62,8 @@ angular.module('doubtfire.units.states.rollover.directives.unit-dates-selector', } else body = { - start_date: $scope.saveData.startDate - end_date: $scope.saeData.endDate + start_date: $scope.saveData.startDate, + end_date: $scope.saveData.endDate } $scope.unit.rolloverTo(body).subscribe({ next: (response) -> diff --git a/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.tpl.html b/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.tpl.html index c3be994325..fdfe7f5f21 100644 --- a/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.tpl.html +++ b/src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.tpl.html @@ -39,11 +39,11 @@

    Copy {{unit.code}} {{unit.nameAndPeriod}}

    - + Date: Fri, 28 Nov 2025 15:47:58 +1100 Subject: [PATCH 0754/1280] refactor: migrate unit groups (#1049) * refactor: migrate unit groups * chore: update migration progress * chore: update migration progress * chore: add comment --- README.md | 4 ++-- src/app/doubtfire-angular.module.ts | 2 ++ src/app/doubtfire-angularjs.module.ts | 6 +++++ src/app/units/states/groups/groups.tpl.html | 24 ++++--------------- .../unit-groups/unit-groups.component.html | 21 ++++++++++++++++ .../unit-groups/unit-groups.component.scss | 5 ++++ .../unit-groups/unit-groups.component.ts | 17 +++++++++++++ 7 files changed, 58 insertions(+), 21 deletions(-) create mode 100644 src/app/units/states/groups/unit-groups/unit-groups.component.html create mode 100644 src/app/units/states/groups/unit-groups/unit-groups.component.scss create mode 100644 src/app/units/states/groups/unit-groups/unit-groups.component.ts diff --git a/README.md b/README.md index b97274b557..7b478bcf16 100644 --- a/README.md +++ b/README.md @@ -203,7 +203,7 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.coffee - [ ] ./src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee - [ ] ./src/app/projects/states/feedback/feedback.coffee -- [ ] ./src/app/projects/states/groups/groups.coffee +- [ ] ./src/app/projects/states/groups/groups.coffee (-> "project-groups") - [ ] ./src/app/projects/states/index/index.coffee - [ ] ./src/app/projects/states/portfolio/directives/directives.coffee - [ ] ./src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.coffee (Migrate this in 10.0.x) @@ -217,7 +217,7 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/units/states/edit/directives/directives.coffee - [ ] ./src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.coffee - [ ] ./src/app/units/states/edit/edit.coffee -- [ ] ./src/app/units/states/groups/groups.coffee +- [ ] ./src/app/units/states/groups/groups.coffee (State only -> "unit-groups") - [ ] ./src/app/units/states/index/index.coffee - [ ] ./src/app/units/states/states.coffee - [ ] ./src/app/units/states/students-list/students-list.coffee (Refer to the unit-students-editor component) diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 0c0b4e2411..f794925283 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -292,6 +292,7 @@ import {PortfoliosListComponent} from './units/states/portfolios/directives/port import {PortfoliosProjectProgressComponent} from './units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component'; import {PortfoliosPortfolioViewComponent} from './units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component'; import {PortfoliosAssessmentComponent} from './units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component'; +import {UnitGroupsComponent} from './units/states/groups/unit-groups/unit-groups.component'; import {RolloverComponent} from './units/states/rollover/rollover.component'; @NgModule({ @@ -433,6 +434,7 @@ import {RolloverComponent} from './units/states/rollover/rollover.component'; PortfoliosProjectProgressComponent, PortfoliosPortfolioViewComponent, PortfoliosAssessmentComponent, + UnitGroupsComponent, RolloverComponent, ], // Services we provide diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index c1f82e13e7..698deda67a 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -214,6 +214,7 @@ import {FileUploaderComponent} from './common/file-uploader/file-uploader.compon import {PortfolioWelcomeStepComponent} from './projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component'; import {PortfolioLearningSummaryReportStepComponent} from './projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component'; import {PortfolioAddExtraFilesStepComponent} from './projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component'; +import {UnitGroupsComponent} from './units/states/groups/unit-groups/unit-groups.component'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -550,3 +551,8 @@ DoubtfireAngularJSModule.directive( 'fPortfolioAddExtraFilesStep', downgradeComponent({component: PortfolioAddExtraFilesStepComponent}), ); + +DoubtfireAngularJSModule.directive( + 'fUnitGroups', + downgradeComponent({component: UnitGroupsComponent}), +); diff --git a/src/app/units/states/groups/groups.tpl.html b/src/app/units/states/groups/groups.tpl.html index 6d79bdb9a3..987218beb6 100644 --- a/src/app/units/states/groups/groups.tpl.html +++ b/src/app/units/states/groups/groups.tpl.html @@ -1,19 +1,5 @@ -
    - - -
    - -
    -
    - -

    No Groupwork Enabled

    -
    -
    -

    - There is no group work enabled for this unit. Convenors should create at - least one group set first for groups to be created. This can be found under - the groups tab in the unit administration settings. -

    - Unit Administration -
    -
    + diff --git a/src/app/units/states/groups/unit-groups/unit-groups.component.html b/src/app/units/states/groups/unit-groups/unit-groups.component.html new file mode 100644 index 0000000000..bde04e582a --- /dev/null +++ b/src/app/units/states/groups/unit-groups/unit-groups.component.html @@ -0,0 +1,21 @@ +@if (unit.hasGroupwork()) { +
    + + +
    +} @else { +
    + groups + +

    No Groupwork Enabled

    + +

    + There is no group work enabled for this unit. Convenors should create at least one group set + first for groups to be created. This can be found under the groups tab in the unit + administration settings. +

    + +
    +} diff --git a/src/app/units/states/groups/unit-groups/unit-groups.component.scss b/src/app/units/states/groups/unit-groups/unit-groups.component.scss new file mode 100644 index 0000000000..542e68a366 --- /dev/null +++ b/src/app/units/states/groups/unit-groups/unit-groups.component.scss @@ -0,0 +1,5 @@ +.mat-icon { + font-size: 75px; + width: 75px; + height: 75px; +} diff --git a/src/app/units/states/groups/unit-groups/unit-groups.component.ts b/src/app/units/states/groups/unit-groups/unit-groups.component.ts new file mode 100644 index 0000000000..c9378bf5e0 --- /dev/null +++ b/src/app/units/states/groups/unit-groups/unit-groups.component.ts @@ -0,0 +1,17 @@ +import {Component, Input} from '@angular/core'; +import {GroupSet} from 'src/app/api/models/doubtfire-model'; +import {Unit} from 'src/app/api/models/unit'; +import {UnitRole} from 'src/app/api/models/unit-role'; + +// This component is only displayed to staff +// Students will be shown the projects/states/groups (project-groups) component +@Component({ + selector: 'f-unit-groups', + templateUrl: './unit-groups.component.html', + styleUrl: './unit-groups.component.scss', +}) +export class UnitGroupsComponent { + @Input() unit: Unit; + @Input() unitRole: UnitRole; + @Input() selectedGroupSet: GroupSet; +} From 67159985d84ddc3cff9b2863b41591b66c360128 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 28 Nov 2025 22:37:35 +1100 Subject: [PATCH 0755/1280] refactor: rename chart components --- src/app/doubtfire-angular.module.ts | 6 ++--- src/app/doubtfire-angularjs.module.ts | 6 ++--- ...=> progress-burndown-chart.component.html} | 0 ...=> progress-burndown-chart.component.scss} | 0 ...s => progress-burndown-chart.component.ts} | 4 +-- ...l => task-status-pie-chart.component.html} | 0 ...s => task-status-pie-chart.component.scss} | 0 ....ts => task-status-pie-chart.component.ts} | 4 +-- ...html => task-visualisation.component.html} | 0 ...scss => task-visualisation.component.scss} | 0 ...ent.ts => task-visualisation.component.ts} | 26 +++++++++++-------- 11 files changed, 25 insertions(+), 21 deletions(-) rename src/app/visualisations/progress-burndown-chart/{progressburndownchart.component.html => progress-burndown-chart.component.html} (100%) rename src/app/visualisations/progress-burndown-chart/{progressburndownchart.component.scss => progress-burndown-chart.component.scss} (100%) rename src/app/visualisations/progress-burndown-chart/{progressburndownchart.component.ts => progress-burndown-chart.component.ts} (97%) rename src/app/visualisations/task-status-pie-chart/{taskstatuspiechart.component.html => task-status-pie-chart.component.html} (100%) rename src/app/visualisations/task-status-pie-chart/{taskstatuspiechart.component.scss => task-status-pie-chart.component.scss} (100%) rename src/app/visualisations/task-status-pie-chart/{taskstatuspiechart.component.ts => task-status-pie-chart.component.ts} (95%) rename src/app/visualisations/task-visualisation/{taskvisualisation.component.html => task-visualisation.component.html} (100%) rename src/app/visualisations/task-visualisation/{taskvisualisation.component.scss => task-visualisation.component.scss} (100%) rename src/app/visualisations/task-visualisation/{taskvisualisation.component.ts => task-visualisation.component.ts} (72%) diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index f794925283..2ed284691b 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -247,8 +247,8 @@ import {UnitRootStateComponent} from './units/unit-root-state.component'; import {TaskViewerStateComponent} from './units/task-viewer/task-viewer-state.component'; import {ProjectRootStateComponent} from './projects/states/project-root-state.component'; import {ProjectProgressDashboardComponent} from './projects/project-progress-dashboard/project-progress-dashboard.component'; -import {ProgressBurndownChartComponent} from './visualisations/progress-burndown-chart/progressburndownchart.component'; -import {TaskVisualisationComponent} from './visualisations/task-visualisation/taskvisualisation.component'; +import {ProgressBurndownChartComponent} from './visualisations/progress-burndown-chart/progress-burndown-chart.component'; +import {TaskVisualisationComponent} from './visualisations/task-visualisation/task-visualisation.component'; import {ChartBaseComponent} from './common/chart-base/chart-base-component/chart-base-component.component'; import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component'; import {ScormAdapterService} from './api/services/scorm-adapter.service'; @@ -279,7 +279,7 @@ const MY_DATE_FORMAT = { }; import {TutorialsComponent} from './projects/states/tutorials/tutorials.component'; import {UnitStudentEnrolmentModalComponent} from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component'; -import {TaskStatusPieChartComponent} from './visualisations/task-status-pie-chart/taskstatuspiechart.component'; +import {TaskStatusPieChartComponent} from './visualisations/task-status-pie-chart/task-status-pie-chart.component'; import {GroupMemberListComponent} from './groups/group-member-list/group-member-list.component'; import {GroupSelectorComponent} from './groups/group-selector/group-selector.component'; import {GroupSetManagerComponent} from './groups/group-set-manager/group-set-manager.component'; diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 698deda67a..7fdba35560 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -147,7 +147,7 @@ import {fPdfViewerComponent} from './common/pdf-viewer/pdf-viewer.component'; import {PdfViewerPanelComponent} from './common/pdf-viewer-panel/pdf-viewer-panel.component'; import {StaffTaskListComponent} from './units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component'; import {StatusIconComponent} from './common/status-icon/status-icon.component'; -import {TaskStatusPieChartComponent} from './visualisations/task-status-pie-chart/taskstatuspiechart.component'; +import {TaskStatusPieChartComponent} from './visualisations/task-status-pie-chart/task-status-pie-chart.component'; import { GroupSetService, LearningOutcomeService, @@ -192,8 +192,8 @@ import {FUsersComponent} from './admin/states/users/users.component'; import {FUnitTaskListComponent} from './units/task-viewer/directives/unit-task-list/unit-task-list.component'; import {FTaskDetailsViewComponent} from './units/task-viewer/directives/task-details-view/task-details-view.component'; import {FTaskSheetViewComponent} from './units/task-viewer/directives/task-sheet-view/task-sheet-view.component'; -import {ProgressBurndownChartComponent} from './visualisations/progress-burndown-chart/progressburndownchart.component'; -import {TaskVisualisationComponent} from './visualisations/task-visualisation/taskvisualisation.component'; +import {ProgressBurndownChartComponent} from './visualisations/progress-burndown-chart/progress-burndown-chart.component'; +import {TaskVisualisationComponent} from './visualisations/task-visualisation/task-visualisation.component'; import {TutorialsComponent} from './projects/states/tutorials/tutorials.component'; import {ProgressDashboardComponent} from './projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component'; import {FUnitsComponent} from './admin/states/units/units.component'; diff --git a/src/app/visualisations/progress-burndown-chart/progressburndownchart.component.html b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html similarity index 100% rename from src/app/visualisations/progress-burndown-chart/progressburndownchart.component.html rename to src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html diff --git a/src/app/visualisations/progress-burndown-chart/progressburndownchart.component.scss b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.scss similarity index 100% rename from src/app/visualisations/progress-burndown-chart/progressburndownchart.component.scss rename to src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.scss diff --git a/src/app/visualisations/progress-burndown-chart/progressburndownchart.component.ts b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.ts similarity index 97% rename from src/app/visualisations/progress-burndown-chart/progressburndownchart.component.ts rename to src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.ts index e49ca853dc..cec3c2c3bf 100644 --- a/src/app/visualisations/progress-burndown-chart/progressburndownchart.component.ts +++ b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.ts @@ -6,8 +6,8 @@ import {ChartBaseComponent} from 'src/app/common/chart-base/chart-base-component @Component({ selector: 'f-progress-burndown-chart', - templateUrl: './progressburndownchart.component.html', - styleUrls: ['./progressburndownchart.component.scss'], + templateUrl: './progress-burndown-chart.component.html', + styleUrls: ['./progress-burndown-chart.component.scss'], }) export class ProgressBurndownChartComponent extends ChartBaseComponent implements OnInit { @Input() project: Project; diff --git a/src/app/visualisations/task-status-pie-chart/taskstatuspiechart.component.html b/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.html similarity index 100% rename from src/app/visualisations/task-status-pie-chart/taskstatuspiechart.component.html rename to src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.html diff --git a/src/app/visualisations/task-status-pie-chart/taskstatuspiechart.component.scss b/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.scss similarity index 100% rename from src/app/visualisations/task-status-pie-chart/taskstatuspiechart.component.scss rename to src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.scss diff --git a/src/app/visualisations/task-status-pie-chart/taskstatuspiechart.component.ts b/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.ts similarity index 95% rename from src/app/visualisations/task-status-pie-chart/taskstatuspiechart.component.ts rename to src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.ts index 1e9bb142d8..27a9fcd8c4 100644 --- a/src/app/visualisations/task-status-pie-chart/taskstatuspiechart.component.ts +++ b/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.ts @@ -4,8 +4,8 @@ import {ChartBaseComponent} from 'src/app/common/chart-base/chart-base-component @Component({ selector: 'f-task-status-pie-chart', - templateUrl: './taskstatuspiechart.component.html', - styleUrls: ['./taskstatuspiechart.component.scss'], + templateUrl: './task-status-pie-chart.component.html', + styleUrls: ['./task-status-pie-chart.component.scss'], }) export class TaskStatusPieChartComponent extends ChartBaseComponent implements OnInit { @Input() project: Project; diff --git a/src/app/visualisations/task-visualisation/taskvisualisation.component.html b/src/app/visualisations/task-visualisation/task-visualisation.component.html similarity index 100% rename from src/app/visualisations/task-visualisation/taskvisualisation.component.html rename to src/app/visualisations/task-visualisation/task-visualisation.component.html diff --git a/src/app/visualisations/task-visualisation/taskvisualisation.component.scss b/src/app/visualisations/task-visualisation/task-visualisation.component.scss similarity index 100% rename from src/app/visualisations/task-visualisation/taskvisualisation.component.scss rename to src/app/visualisations/task-visualisation/task-visualisation.component.scss diff --git a/src/app/visualisations/task-visualisation/taskvisualisation.component.ts b/src/app/visualisations/task-visualisation/task-visualisation.component.ts similarity index 72% rename from src/app/visualisations/task-visualisation/taskvisualisation.component.ts rename to src/app/visualisations/task-visualisation/task-visualisation.component.ts index 8b5c1e1f50..c90fc32759 100644 --- a/src/app/visualisations/task-visualisation/taskvisualisation.component.ts +++ b/src/app/visualisations/task-visualisation/task-visualisation.component.ts @@ -1,24 +1,22 @@ -import { Component, OnInit, Input, SimpleChanges } from '@angular/core'; -import { Color } from 'd3'; -import { Project, TaskStatus, TaskStatusEnum } from 'src/app/api/models/doubtfire-model'; +import {Component, OnInit, Input, SimpleChanges} from '@angular/core'; +import {Color} from 'd3'; +import {Project, TaskStatus, TaskStatusEnum} from 'src/app/api/models/doubtfire-model'; @Component({ selector: 'f-task-visualisation', - templateUrl: './taskvisualisation.component.html', - styleUrls: ['./taskvisualisation.component.scss'] + templateUrl: './task-visualisation.component.html', + styleUrls: ['./task-visualisation.component.scss'], }) - export class TaskVisualisationComponent implements OnInit { @Input() project: Project; @Input() grade: number; - data: {name: string, value: number}[] = []; - colors: {name: string, value: string}[]; + data: {name: string; value: number}[] = []; + colors: {name: string; value: string}[]; view: number[] = [700, 400]; // options textColor: string = '#F5F5F5'; - ngOnInit(): void { this.updateData(); } @@ -39,7 +37,13 @@ export class TaskVisualisationComponent implements OnInit { } }); - const sortOrder = ['Complete', 'Discuss', 'Awaiting Feedback', 'Working On It', 'Not Started']; + const sortOrder = [ + 'Complete', + 'Discuss', + 'Awaiting Feedback', + 'Working On It', + 'Not Started', + ]; this.data = Array.from(taskCounts) .map(([status, count]) => { @@ -60,7 +64,7 @@ export class TaskVisualisationComponent implements OnInit { }); this.colors = Array.from(TaskStatus.STATUS_COLORS).map(([status, color]) => { - return { name: TaskStatus.STATUS_LABELS.get(status), value: color }; + return {name: TaskStatus.STATUS_LABELS.get(status), value: color}; }); // console.log('Data:', this.data); From 6965c96f75f40c0423d606411c9aeef16f3f0a93 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 28 Nov 2025 22:39:50 +1100 Subject: [PATCH 0756/1280] chore: remove unused visualisations --- README.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 7b478bcf16..fc8827a0bd 100644 --- a/README.md +++ b/README.md @@ -172,6 +172,11 @@ Important: When completing a frontend migration, please update the below list re - [x] ./src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee - [x] ./src/app/units/states/rollover/rollover.coffee - [x] ./src/app/visualisations/task-status-pie-chart.coffee +- [x] ./src/app/visualisations/student-task-status-pie-chart.coffee +- [ ] ./src/app/visualisations/achievement-box-plot.coffee (ILO Alignments removed) +- [ ] ./src/app/visualisations/achievement-custom-bar-chart.coffee (ILO Alignments removed) +- [ ] ./src/app/visualisations/alignment-bar-chart.coffee (ILO Alignments removed) +- [ ] ./src/app/visualisations/alignment-bullet-chart.coffee (ILO Alignments removed) ### TODO: @@ -224,12 +229,7 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/units/states/tasks/definition/definition.coffee - [ ] ./src/app/units/states/tasks/tasks.coffee - [ ] ./src/app/units/units.coffee -- [ ] ./src/app/visualisations/achievement-box-plot.coffee -- [ ] ./src/app/visualisations/achievement-custom-bar-chart.coffee -- [ ] ./src/app/visualisations/alignment-bar-chart.coffee -- [ ] ./src/app/visualisations/alignment-bullet-chart.coffee -- [ ] ./src/app/visualisations/student-task-status-pie-chart.coffee -- [ ] ./src/app/visualisations/summary-task-status-scatter.coffee +- [ ] ./src/app/visualisations/summary-task-status-scatter.coffee (Unit task status summary) - [ ] ./src/app/visualisations/target-grade-pie-chart.coffee - [ ] ./src/app/visualisations/task-completion-box-plot.coffee - [ ] ./src/app/visualisations/visualisations.coffee From 9be2044886742a2aa78e5aed6da53f2837c49346 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 28 Nov 2025 22:40:09 +1100 Subject: [PATCH 0757/1280] chore: remove unused visualisations --- .../achievement-box-plot.coffee | 67 -- .../achievement-custom-bar-chart.coffee | 677 ------------------ .../visualisations/alignment-bar-chart.coffee | 41 -- .../alignment-bullet-chart.coffee | 591 --------------- .../student-task-status-pie-chart.coffee | 41 -- 5 files changed, 1417 deletions(-) delete mode 100644 src/app/visualisations/achievement-box-plot.coffee delete mode 100644 src/app/visualisations/achievement-custom-bar-chart.coffee delete mode 100644 src/app/visualisations/alignment-bar-chart.coffee delete mode 100644 src/app/visualisations/alignment-bullet-chart.coffee delete mode 100644 src/app/visualisations/student-task-status-pie-chart.coffee diff --git a/src/app/visualisations/achievement-box-plot.coffee b/src/app/visualisations/achievement-box-plot.coffee deleted file mode 100644 index 7ef7646829..0000000000 --- a/src/app/visualisations/achievement-box-plot.coffee +++ /dev/null @@ -1,67 +0,0 @@ -angular.module('doubtfire.visualisations.achievement-box-plot', []) -.directive 'achievementBoxPlot', -> - replace: true - restrict: 'E' - templateUrl: 'visualisations/visualisation.tpl.html' - scope: - rawData: '=data' - type: '=' - unit: '=' - pctHolder: '=' - height: '=?' - showLegend: '=?' - controller: ($scope, $timeout, Visualisation, outcomeService, $sce) -> - $scope.showLegend = unless $scope.showLegend? then true else $scope.showLegend - $scope.height = unless $scope.height? then 600 else $scope.height - - iloValues = outcomeService.calculateTargets($scope.unit, $scope.unit, $scope.unit.taskStatusFactor) - iloMaxes = _.mapValues iloValues, (d, k) -> _.reduce d, ((memo, value) -> memo + value), 0 - rangeMax = _.max _.values(iloMaxes) - - refreshData = (newData) -> - isPct = ($scope.pctHolder? and $scope.pctHolder.pct) - if isPct - $scope.options.chart.yDomain = [0, 1] - else - $scope.options.chart.yDomain = [0, rangeMax] - - $scope.data = _.map newData, (d, id) -> - max = iloMaxes[id] - if (! max?) or max == 0 or ! isPct - max = 1 - label = _.find($scope.unit.ilos, { id: +id }).abbreviation - { - label: $sce.getTrustedHtml(label), - values: { - Q1: d.lower / max - Q2: d.median / max - Q3: d.upper / max - whisker_low: d.min / max - whisker_high: d.max / max - } - } - $timeout -> - if $scope.api?.refresh? - $scope.api.refresh() - - [$scope.options, $scope.config] = Visualisation 'boxPlotChart', 'ILO Achievement Box Plot', { - x: (d) -> d.label - height: $scope.height - showXAxis: $scope.showLegend - margin: - top: if $scope.showLegend then 20 else 20 - right: if $scope.showLegend then 10 else 10 - bottom: if $scope.showLegend then 60 else 20 - left: if $scope.showLegend then 80 else 40 - yAxis: - axisLabel: if $scope.showLegend then "ILO Achievement" - tooltip: - enabled: $scope.showLegend - maxBoxWidth: 75 - yDomain: [0, 1] - }, {}, 'Achievement Box Plot' - - # $scope.$watch 'rawData', refreshData($scope.rawData) - $scope.$watch 'pctHolder.pct', (newData, oldData) -> if newData != oldData then refreshData($scope.rawData) - - refreshData($scope.rawData) diff --git a/src/app/visualisations/achievement-custom-bar-chart.coffee b/src/app/visualisations/achievement-custom-bar-chart.coffee deleted file mode 100644 index 6eafad4c6d..0000000000 --- a/src/app/visualisations/achievement-custom-bar-chart.coffee +++ /dev/null @@ -1,677 +0,0 @@ -angular.module('doubtfire.visualisations.achievement-custom-bar-chart', []) -.directive 'achievementCustomBarChart', -> - replace: true - restrict: 'E' - templateUrl: 'visualisations/visualisation.tpl.html' - scope: - project: '=' - unit: '=' - - controller: ($scope, Visualisation, outcomeService, gradeService, $sce) -> - $scope.showLegend = if $scope.showLegend? then $scope.showLegend else true - unless nv.models.achievementBar? - nv.models.achievementBar = -> - chart = (selection) -> - renderWatch.reset() - selection.each (data) -> - availableWidth = width - (margin.left) - (margin.right) - availableHeight = height - (margin.top) - (margin.bottom) - container = d3.select(this) - nv.utils.initSVG container - #add series index to each data point for reference - data.forEach (series, i) -> - series.values.forEach (point) -> - point.series = i - return - return - # Setup Scales - # remap and flatten the data for use in calculating the scales' domains - seriesData = if xDomain and yDomain then [] else data.map(((d) -> - d.values.map ((d, i) -> - { - x: getX(d, i) - y: getY(d, i) - y0: d.y0 - } - ) - )) - x.domain(xDomain or d3.merge(seriesData).map((d) -> - d.x - )).rangeBands xRange or [ - 0 - availableWidth - ], .1 - y.domain yDomain or d3.extent(d3.merge(seriesData).map((d) -> - d.y - ).concat(forceY)) - # If showValues, pad the Y axis range to account for label height - if showValues - y.range yRange or [ - availableHeight - (if y.domain()[0] < 0 then 12 else 0) - if y.domain()[1] > 0 then 12 else 0 - ] - else - y.range yRange or [ - availableHeight - 0 - ] - #store old scales if they exist - x0 = x0 or x - y0 = y0 or y.copy().range([ - y(0) - y(0) - ]) - # Setup containers and skeleton of chart - wrap = container.selectAll('g.nv-wrap.nv-discretebar').data([ data ]) - wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-discretebar') - gEnter = wrapEnter.append('g') - g = wrap.select('g') - gEnter.append('g').attr 'class', 'nv-groups' - wrap.attr 'transform', 'translate(' + margin.left + ',' + margin.top + ')' - # TODO: (@macite) by definition, the discrete bar should not have multiple groups, will modify/remove later - groups = wrap.select('.nv-groups').selectAll('.nv-group').data(((d) -> - d - ), (d) -> - d.key - ) - groups.enter().append('g').style('stroke-opacity', 1e-6).style 'fill-opacity', 1e-6 - groups.exit().watchTransition(renderWatch, 'discreteBar: exit groups').style('stroke-opacity', 1e-6).style('fill-opacity', 1e-6).remove() - groups.attr('class', (d, i) -> - 'nv-group nv-series-' + i - ) - groups.watchTransition(renderWatch, 'discreteBar: groups').style('stroke-opacity', 1).style 'fill-opacity', .75 - - if targets? && _.size(targets) > 0 - # Create the background bars... match one set per ILO - backBarSeries = groups.selectAll('g.nv-backBarSeries').data((d) -> - d.values - ) - backBarSeries.exit().remove() - backBarSeries.enter().append('g') - backBarSeries.attr('class', (d, i) -> - 'nv-backBarSeries nv-backSeries-' + i - ).classed 'hover', (d) -> - d.hover - - backBars = backBarSeries.selectAll('g.nv-backBar').data( (d,i) -> _.map(_.values(d.targets), (v) -> { value: v, key: d.label } ) ) - backBars.exit().remove() - backBarsEnter = backBars.enter().append('g') - - backBarsEnter.append('rect').attr('height', 10).attr 'width', x.rangeBand() * 0.9 / data.length - backBarsEnter.on('mouseover', (d, i) -> - d3.select(this).classed 'hover', true - dispatch.elementMouseover - data: gradeService.grades[i] - index: i - color: d.value.color - return - ).on('mouseout', (d, i) -> - d3.select(this).classed 'hover', false - dispatch.elementMouseout - data: gradeService.grades[i] - index: i - color: d.value.color - return - ).on('mousemove', (d, i) -> - dispatch.elementMousemove - data: gradeService.grades[i] - index: i - color: d.value.color - return - ).on('click', (d, i) -> - element = this - dispatch.elementClick - data: gradeService.grades[i] - index: i - color: d.value.color - event: d3.event - element: element - d3.event.stopPropagation() - return - ).on('dblclick', (d, i) -> - dispatch.elementDblClick - data: gradeService.grades[i] - index: i - color: d.value.color - d3.event.stopPropagation() - return - ) - - backBars.attr('class', (d, i, j) -> - if d.value.height < 0 then 'nv-backBar negative' else 'nv-backBar positive' - ).select('rect').attr('class', rectClass).style('fill-opacity', '0.2'). - style('fill', (d) -> d.value.color). - watchTransition(renderWatch, 'discreteBar: backBars rect').attr 'width', x.rangeBand() * .9 / data.length - backBars.watchTransition(renderWatch, 'discreteBar: backBars').attr('transform', (d, i, j) -> - left = x(d.key) + x.rangeBand() * .05 - top = y(d.value.height + d.value.offset) - 'translate(' + left + ', ' + top + ')' - ).select('rect').attr 'height', (d, i, j) -> - Math.max Math.abs(y(d.value.height) - y(0)), 1 - - bars = groups.selectAll('g.nv-bar').data((d) -> - d.values - ) - bars.exit().remove() - barsEnter = bars.enter().append('g').on('mouseover', (d, i) -> - # TODO: (@macite) figure out why j works above, but not here - d3.select(this).classed 'hover', true - dispatch.elementMouseover - data: d - index: i - color: d3.select(this).style('fill') - return - ).on('mouseout', (d, i) -> - d3.select(this).classed 'hover', false - dispatch.elementMouseout - data: d - index: i - color: d3.select(this).style('fill') - return - ).on('mousemove', (d, i) -> - dispatch.elementMousemove - data: d - index: i - color: d3.select(this).style('fill') - return - ).on('click', (d, i) -> - element = this - dispatch.elementClick - data: d - index: i - color: d3.select(this).style('fill') - event: d3.event - element: element - d3.event.stopPropagation() - return - ).on('dblclick', (d, i) -> - dispatch.elementDblClick - data: d - index: i - color: d3.select(this).style('fill') - d3.event.stopPropagation() - return - ) - - barsEnter.append('rect').attr('height', 0).attr 'width', x.rangeBand() * .5 / data.length - if showValues - barsEnter.append('text').attr 'text-anchor', 'middle' - bars.select('text').text((d, i) -> - valueFormat getY(d, i) - ).watchTransition(renderWatch, 'discreteBar: bars text').attr('x', x.rangeBand() * .5 / 2).attr 'y', (d, i) -> - if getY(d, i) < 0 then y(getY(d, i)) - y(0) + 12 else -4 - else - bars.selectAll('text').remove() - bars.attr('class', (d, i) -> - if getY(d, i) < 0 then 'nv-bar negative' else 'nv-bar positive' - ).style('fill', (d, i) -> - d.color or color(d, i) - ).style('stroke', (d, i) -> - d.color or color(d, i) - ).select('rect').attr('class', rectClass).watchTransition(renderWatch, 'discreteBar: bars rect').attr 'width', x.rangeBand() * .5 / data.length - bars.watchTransition(renderWatch, 'discreteBar: bars').attr('transform', (d, i) -> - left = x(getX(d, i)) + x.rangeBand() * .25 - top = if getY(d, i) < 0 then y(0) else if y(0) - y(getY(d, i)) < 1 then y(0) - 1 else y(getY(d, i)) - 'translate(' + left + ', ' + top + ')' - ).select('rect').attr 'height', (d, i) -> - Math.max Math.abs(y(getY(d, i)) - y(0)), 1 - #store old scales for use in transitions on update - x0 = x.copy() - y0 = y.copy() - return - renderWatch.renderEnd 'achievementBar immediate' - chart - - 'use strict' - #============================================================ - # Public Variables with Default Settings - #------------------------------------------------------------ - margin = - top: 0 - right: 0 - bottom: 0 - left: 0 - width = 960 - height = 500 - id = Math.floor(Math.random() * 10000) - container = undefined - x = d3.scale.ordinal() - y = d3.scale.linear() - - getX = (d) -> - d.x - - getY = (d) -> - d.y - - forceY = [ 0 ] - color = nv.utils.defaultColor() - showValues = false - valueFormat = d3.format(',.2f') - xDomain = undefined - yDomain = undefined - xRange = undefined - yRange = undefined - dispatch = d3.dispatch('chartClick', 'elementClick', 'elementDblClick', 'elementMouseover', 'elementMouseout', 'elementMousemove', 'renderEnd') - rectClass = 'discreteBar' - duration = 250 - #============================================================ - # Private Variables - #------------------------------------------------------------ - x0 = undefined - y0 = undefined - renderWatch = nv.utils.renderWatch(dispatch, duration) - #============================================================ - # Expose Public Variables - #------------------------------------------------------------ - chart.dispatch = dispatch - chart.options = nv.utils.optionsFunc.bind(chart) - chart._options = Object.create({}, - width: - get: -> - width - set: (_) -> - width = _ - return - height: - get: -> - height - set: (_) -> - height = _ - return - forceY: - get: -> - forceY - set: (_) -> - forceY = _ - return - showValues: - get: -> - showValues - set: (_) -> - showValues = _ - return - x: - get: -> - getX - set: (_) -> - getX = _ - return - y: - get: -> - getY - set: (_) -> - getY = _ - return - xScale: - get: -> - x - set: (_) -> - x = _ - return - yScale: - get: -> - y - set: (_) -> - y = _ - return - xDomain: - get: -> - xDomain - set: (_) -> - xDomain = _ - return - yDomain: - get: -> - yDomain - set: (_) -> - yDomain = _ - return - xRange: - get: -> - xRange - set: (_) -> - xRange = _ - return - yRange: - get: -> - yRange - set: (_) -> - yRange = _ - return - valueFormat: - get: -> - valueFormat - set: (_) -> - valueFormat = _ - return - id: - get: -> - id - set: (_) -> - id = _ - return - rectClass: - get: -> - rectClass - set: (_) -> - rectClass = _ - return - margin: - get: -> - margin - set: (_) -> - margin.top = if _.top != undefined then _.top else margin.top - margin.right = if _.right != undefined then _.right else margin.right - margin.bottom = if _.bottom != undefined then _.bottom else margin.bottom - margin.left = if _.left != undefined then _.left else margin.left - return - color: - get: -> - color - set: (_) -> - color = nv.utils.getColor(_) - return - duration: - get: -> - duration - set: (_) -> - duration = _ - renderWatch.reset duration - return - ) - nv.utils.initOptions chart - chart - - # - # Chart that contains stacked bars in the background, overlaid by other bars... - # - nv.models.achievementBarChart = -> - chart = (selection) -> - renderWatch.reset() - renderWatch.models achievementbar - if showXAxis - renderWatch.models xAxis - if showYAxis - renderWatch.models yAxis - selection.each (data) -> - container = d3.select(this) - that = this - nv.utils.initSVG container - availableWidth = nv.utils.availableWidth(width, container, margin) - availableHeight = nv.utils.availableHeight(height, container, margin) - - chart.update = -> - dispatch.beforeUpdate() - container.transition().duration(duration).call chart - return - - chart.container = this - - # Display No Data message if there's nothing to show. - if (!data) or (!data.length) or data.filter(((d) -> d.values.length)).length <= 0 - nv.utils.noData chart, container - return chart - else - container.selectAll('.nv-noData').remove() - - # Setup Scales - x = achievementbar.xScale() - y = achievementbar.yScale().clamp(true) - # Setup containers and skeleton of chart - wrap = container.selectAll('g.nv-wrap.nv-discreteBarWithAxes').data([ data ]) - gEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-discreteBarWithAxes').append('g') - defsEnter = gEnter.append('defs') - g = wrap.select('g') - gEnter.append('g').attr 'class', 'nv-x nv-axis' - gEnter.append('g').attr('class', 'nv-y nv-axis').append('g').attr('class', 'nv-zeroLine').append 'line' - gEnter.append('g').attr 'class', 'nv-barsWrap' - gEnter.append('g').attr 'class', 'nv-legendWrap' - g.attr 'transform', 'translate(' + margin.left + ',' + margin.top + ')' - if showLegend - legend.width availableWidth - g.select('.nv-legendWrap').datum(data).call legend - if margin.top != legend.height() - margin.top = legend.height() - availableHeight = nv.utils.availableHeight(height, container, margin) - wrap.select('.nv-legendWrap').attr 'transform', 'translate(0,' + -margin.top + ')' - if rightAlignYAxis - g.select('.nv-y.nv-axis').attr 'transform', 'translate(' + availableWidth + ',0)' - if rightAlignYAxis - g.select('.nv-y.nv-axis').attr 'transform', 'translate(' + availableWidth + ',0)' - # Main Chart Component(s) - achievementbar.width(availableWidth).height availableHeight - barsWrap = g.select('.nv-barsWrap').datum(data.filter((d) -> - !d.disabled - )) - barsWrap.transition().call achievementbar - defsEnter.append('clipPath').attr('id', 'nv-x-label-clip-' + achievementbar.id()).append 'rect' - g.select('#nv-x-label-clip-' + achievementbar.id() + ' rect').attr('width', x.rangeBand() * (if staggerLabels then 2 else 1)).attr('height', 16).attr 'x', -x.rangeBand() / (if staggerLabels then 1 else 2) - # Setup Axes - if showXAxis - xAxis.scale(x)._ticks(nv.utils.calcTicksX(availableWidth / 100, data)).tickSize -availableHeight, 0 - g.select('.nv-x.nv-axis').attr 'transform', 'translate(0,' + (y.range()[0] + (if achievementbar.showValues() and y.domain()[0] < 0 then 16 else 0)) + ')' - g.select('.nv-x.nv-axis').call xAxis - xTicks = g.select('.nv-x.nv-axis').selectAll('g') - if staggerLabels - xTicks.selectAll('text').attr 'transform', (d, i, j) -> - 'translate(0,' + (if j % 2 == 0 then '5' else '17') + ')' - if rotateLabels - xTicks.selectAll('.tick text').attr('transform', 'rotate(' + rotateLabels + ' 0,0)').style 'text-anchor', if rotateLabels > 0 then 'start' else 'end' - if wrapLabels - g.selectAll('.tick text').call nv.utils.wrapTicks, chart.xAxis.rangeBand() - if showYAxis - yAxis.scale(y)._ticks(nv.utils.calcTicksY(availableHeight / 36, data)).tickSize -availableWidth, 0 - g.select('.nv-y.nv-axis').call yAxis - # Zero line - g.select('.nv-zeroLine line').attr('x1', 0).attr('x2', if rightAlignYAxis then -availableWidth else availableWidth).attr('y1', y(0)).attr 'y2', y(0) - return - renderWatch.renderEnd 'achievementBar chart immediate' - chart - - 'use strict' - #============================================================ - # Public Variables with Default Settings - #------------------------------------------------------------ - achievementbar = nv.models.achievementBar() - xAxis = nv.models.axis() - yAxis = nv.models.axis() - legend = nv.models.legend() - tooltip = nv.models.tooltip() - margin = - top: 15 - right: 10 - bottom: 50 - left: 60 - width = null - height = null - color = nv.utils.getColor() - showLegend = false - showXAxis = true - showYAxis = true - rightAlignYAxis = false - staggerLabels = false - wrapLabels = false - rotateLabels = 0 - x = undefined - y = undefined - noData = null - dispatch = d3.dispatch('beforeUpdate', 'renderEnd') - duration = 250 - xAxis.orient('bottom').showMaxMin(false).tickFormat (d) -> - d - yAxis.orient(if rightAlignYAxis then 'right' else 'left').tickFormat d3.format(',.1f') - tooltip.duration(0).headerEnabled(false).keyFormatter (d, i) -> - xAxis.tickFormat() d, i - #============================================================ - # Private Variables - #------------------------------------------------------------ - renderWatch = nv.utils.renderWatch(dispatch, duration) - #============================================================ - # Event Handling/Dispatching (out of chart's scope) - #------------------------------------------------------------ - achievementbar.dispatch.on 'elementMouseover.tooltip', (evt) -> - key = chart.x()(evt.data) - unless key? - key = "#{evt.data} task range" - else - key = "Your progress with #{key}" - evt['series'] = - key: key - # value: chart.y()(evt.data) - color: evt.color - tooltip.data(evt).hidden false - return - achievementbar.dispatch.on 'elementMouseout.tooltip', (evt) -> - tooltip.hidden true - return - achievementbar.dispatch.on 'elementMousemove.tooltip', (evt) -> - tooltip() - return - #============================================================ - # Expose Public Variables - #------------------------------------------------------------ - chart.dispatch = dispatch - chart.achievementbar = achievementbar - chart.legend = legend - chart.xAxis = xAxis - chart.yAxis = yAxis - chart.tooltip = tooltip - chart.options = nv.utils.optionsFunc.bind(chart) - chart._options = Object.create({}, - width: - get: -> - width - set: (_) -> - width = _ - return - height: - get: -> - height - set: (_) -> - height = _ - return - showLegend: - get: -> - showLegend - set: (_) -> - showLegend = _ - return - staggerLabels: - get: -> - staggerLabels - set: (_) -> - staggerLabels = _ - return - rotateLabels: - get: -> - rotateLabels - set: (_) -> - rotateLabels = _ - return - wrapLabels: - get: -> - wrapLabels - set: (_) -> - wrapLabels = ! !_ - return - showXAxis: - get: -> - showXAxis - set: (_) -> - showXAxis = _ - return - showYAxis: - get: -> - showYAxis - set: (_) -> - showYAxis = _ - return - noData: - get: -> - noData - set: (_) -> - noData = _ - return - margin: - get: -> - margin - set: (_) -> - margin.top = if _.top != undefined then _.top else margin.top - margin.right = if _.right != undefined then _.right else margin.right - margin.bottom = if _.bottom != undefined then _.bottom else margin.bottom - margin.left = if _.left != undefined then _.left else margin.left - return - duration: - get: -> - duration - set: (_) -> - duration = _ - renderWatch.reset duration - achievementbar.duration duration - xAxis.duration duration - yAxis.duration duration - return - color: - get: -> - color - set: (_) -> - color = nv.utils.getColor(_) - achievementbar.color color - legend.color color - return - rightAlignYAxis: - get: -> - rightAlignYAxis - set: (_) -> - rightAlignYAxis = _ - yAxis.orient if _ then 'right' else 'left' - return - ) - nv.utils.inheritOptions chart, achievementbar - nv.utils.initOptions chart - chart - - - # - # Get the data and options for the chart... - # - targets = outcomeService.calculateTargets($scope.unit, $scope.unit, $scope.unit.taskStatusFactor) - currentProgress = outcomeService.calculateProgress($scope.unit, $scope.project) - - achievementData = { - key: "Learning Achievement" - values: [] - } - - max = 0 - - _.each $scope.unit.ilos, (ilo) -> - iloTargets = { } - iloTargets[0] = { offset: 0, height: targets[ilo.id][0], color: gradeService.gradeColors.P } - iloTargets[1] = { offset: iloTargets[0].offset + iloTargets[0].height, height: targets[ilo.id][1], color: gradeService.gradeColors.C } - iloTargets[2] = { offset: iloTargets[1].offset + iloTargets[1].height, height: targets[ilo.id][2], color: gradeService.gradeColors.D } - iloTargets[3] = { offset: iloTargets[2].offset + iloTargets[2].height, height: targets[ilo.id][3], color: gradeService.gradeColors.HD } - - if iloTargets[3].offset + iloTargets[3].height > max - max = iloTargets[3].offset + iloTargets[3].height - - achievementData.values.push { - label: $sce.getTrustedHtml(ilo.name) - value: currentProgress[0][ilo.id] # 0 = staff value - targets: iloTargets - } - - [$scope.options, $scope.config] = Visualisation 'achievementBarChart', 'ILO Achievement Bar Chart', { - height: 600 - duration: 500 - yDomain: [0, max] - showValues: false - showYAxis: false - showLegend: false - x: (d) -> d.label - y: (d) -> d.value - color: (d) -> '#373737' - }, {} - - $scope.data = [ achievementData ] diff --git a/src/app/visualisations/alignment-bar-chart.coffee b/src/app/visualisations/alignment-bar-chart.coffee deleted file mode 100644 index b137cb1dbe..0000000000 --- a/src/app/visualisations/alignment-bar-chart.coffee +++ /dev/null @@ -1,41 +0,0 @@ -angular.module('doubtfire.visualisations.alignment-bar-chart', []) -.directive 'alignmentBarChart', -> - replace: true - restrict: 'E' - templateUrl: 'visualisations/visualisation.tpl.html' - scope: - project: '=' - unit: '=' - source: '=' - taskStatusFactor: '=' - controller: ($scope, Visualisation, gradeService, outcomeService) -> - xFn = (d) -> d.label - yFn = (d) -> d.value - - [$scope.options, $scope.config] = Visualisation 'multiBarChart', 'ILO Alignment Bar Chart', { - clipEdge: yes - stacked: no - height: 200 - duration: 500 - color: (d) -> - gradeService.gradeColors[gradeService.gradeAcronyms[d.key]] - x: xFn - y: yFn - forceY: 0 - showYAxis: no - }, {} - - $scope.data = [] - - $scope.calculateAlignmentVisualisation = (source, taskStatusFactor) -> - unit = $scope.unit - _.extend $scope.data, outcomeService.targetsByGrade($scope.unit, source) - - if $scope.api? - $scope.api.update() - - $scope.calculateAlignmentVisualisation($scope.source, $scope.taskStatusFactor) - - $scope.$on('UpdateAlignmentChart', -> - $scope.calculateAlignmentVisualisation($scope.source, $scope.taskStatusFactor) - ) diff --git a/src/app/visualisations/alignment-bullet-chart.coffee b/src/app/visualisations/alignment-bullet-chart.coffee deleted file mode 100644 index 9ef1f3f9e1..0000000000 --- a/src/app/visualisations/alignment-bullet-chart.coffee +++ /dev/null @@ -1,591 +0,0 @@ -angular.module('doubtfire.visualisations.alignment-bullet-chart', []) -.directive 'alignmentBulletChart', -> - replace: true - restrict: 'E' - templateUrl: 'visualisations/visualisation.tpl.html' - scope: - project: '=' - unit: '=' - ilo: '=' - targets: '=' - currentProgress: '=' - classStats: '=' - showLegend: '=?' - - controller: ($scope, gradeService, Visualisation, $sce) -> - $scope.showLegend = if $scope.showLegend? then $scope.showLegend else true - unless nv.models.iloBullet? - # Chart design based on the recommendations of Stephen Few. Implementation - # based on the work of Clint Ivy, Jamie Love, and Jason Davies. - # http://projects.instantcognition.com/protovis/bulletchart/ - nv.models.iloBullet = -> - chart = (selection) -> - selection.each (d, i) -> - availableWidth = width - (if $scope.legend then margin.left else 0) - (if $scope.legend then margin.right else 0) - availableHeight = height - (margin.top) - (margin.bottom) - container = d3.select(this) - nv.utils.initSVG container - rangez = ranges.call(this, d, i).slice().reverse() - markerz = markers.call(this, d, i).slice().sort(d3.descending) - measurez = measures.call(this, d, i) - rangeLabelz = rangeLabels.call(this, d, i).slice().reverse() - markerLabelz = markerLabels.call(this, d, i).slice() - measureLabelz = measureLabels.call(this, d, i).slice() - - # Setup Scales - # Compute the new x-scale. - x1 = d3.scale.linear().domain(d3.extent(d3.merge([ - forceX - rangez - ]))).range(if reverse then [ - availableWidth - 0 - ] else [ - 0 - availableWidth - ]) - # Retrieve the old x-scale, if this is an update. - x0 = @__chart__ or d3.scale.linear().domain([ - 0 - Infinity - ]).range(x1.range()) - - # Stash the new scale. - @__chart__ = x1 - - # Get the range values - rangeHD = rangez[0] - rangeD = rangez[1] - rangeC = rangez[2] - rangeP = rangez[3] - - # Setup containers and skeleton of chart - wrap = container.selectAll('g.nv-wrap.nv-bullet').data([ d ]) - wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bullet') - gEnter = wrapEnter.append('g') - g = wrap.select('g') - gEnter.append('rect').attr('class', 'nv-range nv-rangeHD').style('fill-opacity', '0.2').style('fill', gradeService.gradeColors.HD) - gEnter.append('rect').attr('class', 'nv-range nv-rangeD' ).style('fill-opacity', '0.2').style('fill', gradeService.gradeColors.D) - gEnter.append('rect').attr('class', 'nv-range nv-rangeC' ).style('fill-opacity', '0.2').style('fill', gradeService.gradeColors.C) - gEnter.append('rect').attr('class', 'nv-range nv-rangeP' ).style('fill-opacity', '0.2').style('fill', gradeService.gradeColors.P) - gEnter.append('rect').attr 'class', 'nv-measure' - gEnter.append('rect').attr('class', 'nv-median').style('fill-opacity', '1.0').style('fill','#ffffff') - wrap.attr 'transform', 'translate(' + margin.left + ',' + margin.top + ')' - - w0 = (d) -> - Math.abs x0(d) - x0(0) - - w1 = (d) -> - Math.abs x1(d) - x1(0) - - xp0 = (d) -> - if d > 0 then x0(d) else x0(0) - - xp1 = (d) -> - if d > 0 then x1(d) else x1(0) - - g.select('rect.nv-rangeHD') - .attr('height', availableHeight) - .attr('width', w1(rangeHD - rangeD) ) - .attr('x', xp1(rangeD)) - .datum rangeHD - - g.select('rect.nv-rangeD') - .attr('height', availableHeight) - .attr('width', w1(rangeD - rangeC)) - .attr('x', xp1(rangeC)) - .datum rangeD - - g.select('rect.nv-rangeC') - .attr('height', availableHeight) - .attr('width', w1(rangeC - rangeP)) - .attr('x', xp1(rangeP)) - .datum rangeC - - g.select('rect.nv-rangeP') - .attr('height', availableHeight) - .attr('width', w1(rangeP)) - .attr('x', xp1(0)) - .datum rangeP - - if measurez? - g.select('rect.nv-median') - .style('fill', "#373737") - .style('fill-opacity',0.6) - .attr('height', availableHeight) - .attr('y', 0) - .attr('width', 2) - .attr('x', xp1(measurez.median)) - .on('mouseover', -> - dispatch.elementMouseover - value: measurez.median - label: 'The average student is here' - color: d3.select(this).style('fill') - return) - .on('mousemove', -> - dispatch.elementMousemove - value: measurez.median - label: 'Class Median' - color: d3.select(this).style('fill') - return) - .on 'mouseout', -> - dispatch.elementMouseout - value: measurez.median - label: 'Class Median' - color: d3.select(this).style('fill') - return - - g.select('rect.nv-measure') - .style('fill', "#373737") - .style('fill-opacity',0.6) - .attr('height', availableHeight * 2 / 3) - .attr('y', availableHeight / 6) - .attr('width', xp1(measurez.upper) - xp1(measurez.lower)) - .attr('x', xp1(measurez.lower)) - .on('mouseover', -> - dispatch.elementMouseover - value: measurez[0] - label: measureLabelz[0] or 'Current' - color: d3.select(this).style('fill') - return) - .on('mousemove', -> - dispatch.elementMousemove - value: measurez[0] - label: measureLabelz[0] or 'Current' - color: d3.select(this).style('fill') - return) - .on 'mouseout', -> - dispatch.elementMouseout - value: measurez[0] - label: measureLabelz[0] or 'Current' - color: d3.select(this).style('fill') - return - - h3 = availableHeight / 6 - markerData = markerz.map((marker, index) -> - { - value: marker - label: markerLabelz[index] - } - ) - gEnter.selectAll('path.nv-markerTriangle') - .data(markerData) - .enter() - .append('path') - .attr('class', 'nv-markerTriangle') - .attr('d', (d,i) -> - if i % 2 == 0 - 'M0,' + h3 + 'L' + h3 + ',' + -h3 + ' ' + -h3 + ',' + -h3 + 'Z' - else - 'M0,' + -h3 + 'L' + -h3 + ',0L0,' + h3 + 'L' + h3 + ',0Z' - ) - .on('mouseover', (d) -> - dispatch.elementMouseover( - value: d.value - label: d.label or 'Previous' - color: d3.select(this).style('fill') - pos: [ - x1(d.value) - availableHeight / 2 - ]) - return ) - .on('mousemove', (d) -> - dispatch.elementMousemove( - value: d.value - label: d.label or 'Previous' - color: d3.select(this).style('fill') ) - return ) - .on 'mouseout', (d, i) -> - dispatch.elementMouseout( - value: d.value - label: d.label or 'Previous' - color: d3.select(this).style('fill')) - return - - g.selectAll('path.nv-markerTriangle') - .data(markerData).attr 'transform', (d) -> - 'translate(' + x1(d.value) + ',' + availableHeight / 2 + ')' - - wrap.selectAll('.nv-range').on('mouseover', (d, i) -> - label = rangeLabelz[i] or (if !i then 'Maximum' else if i == 1 then 'Mean' else 'Minimum') - dispatch.elementMouseover - value: d - label: label - color: d3.select(this).style('fill') - return - ).on('mousemove', -> - dispatch.elementMousemove - value: measurez[0] - label: measureLabelz[0] or 'Previous' - color: d3.select(this).style('fill') - return - ).on 'mouseout', (d, i) -> - label = rangeLabelz[i] or (if !i then 'Maximum' else if i == 1 then 'Mean' else 'Minimum') - dispatch.elementMouseout - value: d - label: label - color: d3.select(this).style('fill') - return - return - chart - - 'use strict' - #============================================================ - # Public Variables with Default Settings - #------------------------------------------------------------ - margin = - top: 0 - right: 0 - bottom: 0 - left: 0 - orient = 'left' - reverse = false - - ranges = (d) -> - d.ranges - - markers = (d) -> - if d.markers then d.markers else [] - - measures = (d) -> - d.measures - - rangeLabels = (d) -> - if d.rangeLabels then d.rangeLabels else [] - - markerLabels = (d) -> - if d.markerLabels then d.markerLabels else [] - - measureLabels = (d) -> - if d.measureLabels then d.measureLabels else [] - - forceX = [ 0 ] - width = 380 - height = 30 - container = null - tickFormat = null - color = nv.utils.getColor([ '#1f77b4' ]) - dispatch = d3.dispatch('elementMouseover', 'elementMouseout', 'elementMousemove') - #============================================================ - # Expose Public Variables - #------------------------------------------------------------ - chart.dispatch = dispatch - chart.options = nv.utils.optionsFunc.bind(chart) - chart._options = Object.create({}, - ranges: - get: -> - ranges - set: (_) -> - ranges = _ - return - markers: - get: -> - markers - set: (_) -> - markers = _ - return - measures: - get: -> - measures - set: (_) -> - measures = _ - return - forceX: - get: -> - forceX - set: (_) -> - forceX = _ - return - width: - get: -> - width - set: (_) -> - width = _ - return - height: - get: -> - height - set: (_) -> - height = _ - return - tickFormat: - get: -> - tickFormat - set: (_) -> - tickFormat = _ - return - margin: - get: -> - margin - set: (_) -> - margin.top = if _.top != undefined then _.top else margin.top - margin.right = if _.right != undefined then _.right else margin.right - margin.bottom = if _.bottom != undefined then _.bottom else margin.bottom - margin.left = if _.left != undefined then _.left else margin.left - return - orient: - get: -> - orient - set: (_) -> - # left, right, top, bottom - orient = _ - reverse = orient == 'right' or orient == 'bottom' - return - color: - get: -> - color - set: (_) -> - color = nv.utils.getColor(_) - return - ) - nv.utils.initOptions chart - chart - - # --- - # generated by js2coffee 2.1.0 - - - # Chart design based on NVD3 bullet chart. - nv.models.iloChart = -> - #============================================================ - # Public Variables with Default Settings - #------------------------------------------------------------ - - bullet = nv.models.iloBullet() - tooltip = nv.models.tooltip() - - # TODO: (@macite) top & bottom - orient = 'left' - reverse = false - margin = if $scope.legend then { top: 5, right: 40, bottom: 5, left: 120 } else { top: 5, right: 5, bottom: 5, left: 5 } - - ranges = (d) -> d.ranges - rangeLabels = (d) -> d.rangeLabels - markers = (d) -> if d.markers then d.markers else [] - measures = (d) -> d.measures - - width = null - height = 55 - tickFormat = null - ticks = null - noData = null - dispatch = d3.dispatch - - tooltip - .duration(0) - .headerEnabled(false) - - chart = (selection) -> - selection.each (d, i) -> - container = d3.select(this) - nv.utils.initSVG(container) - - availableWidth = nv.utils.availableWidth(width, container, margin) - availableHeight = height - margin.top - margin.bottom - that = this - - chart.update = -> chart(selection) - chart.container = this - - # Display No Data message if there's nothing to show. - if (!d || !ranges.call(this, d, i)) - nv.utils.noData(chart, container) - return chart - else - container.selectAll('.nv-noData').remove() - - rangez = ranges.call(this, d, i).slice().sort(d3.descending) - markerz = markers.call(this, d, i).slice().sort(d3.descending) - measurez = measures.call(this, d, i) - - # Setup containers and skeleton of chart - wrap = container.selectAll('g.nv-wrap.nv-bulletChart').data([d]) - wrapEnter = wrap.enter().append('g').attr('class', 'nvd3 nv-wrap nv-bulletChart') - gEnter = wrapEnter.append('g') - g = wrap.select('g') - - gEnter.append('g').attr('class', 'nv-bulletWrap') - gEnter.append('g').attr('class', 'nv-titles') if $scope.legend - - wrap.attr('transform', 'translate(' + (if $scope.legend then margin.left else 10) + ',' + margin.top + ')') - - # Compute the new x-scale. - # TODO: (@macite) need to allow forceX and forceY, and xDomain, yDomain - x1 = d3.scale.linear() - .domain([0, Math.max(rangez[0], (markerz[0] || 0), measurez[0])]) - .range(if reverse then [availableWidth, 0] else [0, availableWidth]) - - # Retrieve the old x-scale, if this is an update. - x0 = this.__chart__ || d3.scale.linear() - .domain([0, Infinity]) - .range(x1.range()) - - # Stash the new scale. - this.__chart__ = x1 - - # TODO: (@macite) could optimize by precalculating x0(0) and x1(0) - w0 = (d) -> Math.abs(x0(d) - x0(0)) - w1 = (d) -> Math.abs(x1(d) - x1(0)) - - if $scope.legend - title = gEnter.select('.nv-titles').append('g') - .attr('text-anchor', 'end') - .attr('transform', 'translate(-6,' + (height - margin.top - margin.bottom) / 2 + ')') - - title.append('text') - .attr('class', 'nv-title') - .text((d) -> d.title ) - - title.append('text') - .attr('class', 'nv-subtitle') - .attr('dy', '1em') - .text( (d) -> d.subtitle ) - - bullet - .width(availableWidth) - .height(availableHeight) - - bulletWrap = g.select('.nv-bulletWrap') - d3.transition(bulletWrap).call(bullet) - - # # Compute the tick format. - # format = tickFormat || x1.tickFormat( availableWidth / 100 ) - - # # Update the tick groups. - # tick = g.selectAll('g.nv-tick') - # .data x1.ticks( if ticks then ticks else (availableWidth / 50) ), (d) -> - # this.textContent || format(d) - - # # Initialize the ticks with the old scale, x0. - # tickEnter = tick.enter().append('g') - # .attr('class', 'nv-tick') - # .attr('transform', (d) -> 'translate(' + x0(d) + ',0)' ) - # .style('opacity', 1e-6) - - # tickEnter.append('line') - # .attr('y1', availableHeight) - # .attr('y2', availableHeight * 7 / 6) - - # tickEnter.append('text') - # .attr('text-anchor', 'middle') - # .attr('dy', '1em') - # .attr('y', availableHeight * 7 / 6) - # .text(format) - - # # Transition the updating ticks to the new scale, x1. - # tickUpdate = d3.transition(tick) - # .attr('transform', (d) -> 'translate(' + x1(d) + ',0)') - # .style('opacity', 1) - - # tickUpdate.select('line') - # .attr('y1', availableHeight) - # .attr('y2', availableHeight * 7 / 6) - - # tickUpdate.select('text') - # .attr('y', availableHeight * 7 / 6) - - # #Transition the exiting ticks to the new scale, x1. - # d3.transition(tick.exit()) - # .attr('transform', (d) -> 'translate(' + x1(d) + ',0)' ) - # .style('opacity', 1e-6 ) - # .remove( ) - # end selection each - - d3.timer.flush() - chart - - #============================================================ - # Event Handling/Dispatching (out of chart's scope) - #------------------------------------------------------------ - bullet.dispatch.on 'elementMouseover.tooltip', (evt) -> - evt['series'] = { - key: evt.label - # value: evt.value - color: evt.color - } - tooltip.data(evt).hidden(false) - - bullet.dispatch.on 'elementMouseout.tooltip', (evt) -> - tooltip.hidden(true) - - bullet.dispatch.on 'elementMousemove.tooltip', (evt) -> - tooltip() - - #============================================================ - # Expose Public Variables - #------------------------------------------------------------ - - chart.bullet = bullet - chart.dispatch = dispatch - chart.tooltip = tooltip - - chart.options = nv.utils.optionsFunc.bind(chart) - - chart._options = Object.create({}, { - # simple options, just get/set the necessary values - ranges: {get: (-> ranges), set: ((_)-> ranges=_) }, # ranges (bad, satisfactory, good) - rangeLabels: {get: (-> rangeLabels), set: ((_)-> rangeLabels=_) }, # ranges (bad, satisfactory, good) - markers: {get: (-> markers), set: ((_) -> markers=_) }, # markers (previous, goal) - measures: {get: (-> measures), set: ((_) -> measures=_) }, # measures (actual, forecast) - width: {get: (-> width), set: ((_) -> width=_) }, - height: {get: (-> height), set: ((_) -> height=_) }, - tickFormat: {get: (-> tickFormat), set: ((_) -> tickFormat=_) }, - ticks: {get: (-> ticks), set: ((_) -> ticks=_) }, - noData: {get: (-> noData), set: ((_) -> noData=_) }, - - # options that require extra logic in the setter - margin: {get: (-> margin), set: (_) -> - margin.top = if _.top? then _.top else margin.top - margin.right = if _.right? then _.right else margin.right - margin.bottom = if _.bottom? then _.bottom else margin.bottom - margin.left = if _.left? then _.left else margin.left - }, - orient: {get: (-> orient), set: (_) -> # left, right, top, bottom - orient = _ - reverse = orient == 'right' || orient == 'bottom' - } - }) - - nv.utils.inheritOptions(chart, bullet) - nv.utils.initOptions(chart) - - chart - - [$scope.options, $scope.config] = Visualisation 'iloChart', 'ILO Alignment Bullet Chart', { - height: 60 - duration: 500 - }, {} - - targetP = $scope.targets[$scope.ilo.id][0] - targetC = targetP + $scope.targets[$scope.ilo.id][1] - targetD = targetC + $scope.targets[$scope.ilo.id][2] - targetHD = targetD + $scope.targets[$scope.ilo.id][3] - - $scope.data = { - "title": $sce.getTrustedHtml($scope.ilo.abbreviation), #Label the bullet chart - "subtitle": $sce.getTrustedHtml($scope.ilo.name), #sub-label for bullet chart - "ranges":[targetP,targetC,targetD,targetHD], #Minimum, mean and maximum values. - "rangeLabels":['Pass','Credit','Distinction','High Distinction'], #Minimum, mean and maximum values. - "measures": {}, #Value representing current measurement (the thick blue line in the example) - "measureLabels": ['Most of the class are in this area'] - "markers":[] #Place a marker on the chart (the white triangle marker) - "markerLabels": ['Your Suggested Progress - Staff Suggestion', 'Your Current Progress - Self Reflection'] - } - - if $scope.classStats? && $scope.classStats.title? - $scope.data.measureLabels[0] = $scope.classStats.title - - updateProgress = -> - if $scope.currentProgress? - _.each $scope.currentProgress, (d, i) -> - $scope.data.markers[i] = $scope.currentProgress[i][$scope.ilo.id] - if $scope.currentProgress[i].title? - $scope.data.markerLabels[i] = $scope.currentProgress[i].title - - $scope.data.measures = if $scope.classStats? && $scope.classStats[$scope.ilo.id]? then $scope.classStats[$scope.ilo.id] else 0 - - updateProgress() - - $scope.$on('ProgressUpdated', -> - updateProgress() - ) diff --git a/src/app/visualisations/student-task-status-pie-chart.coffee b/src/app/visualisations/student-task-status-pie-chart.coffee deleted file mode 100644 index 12a8ce47ad..0000000000 --- a/src/app/visualisations/student-task-status-pie-chart.coffee +++ /dev/null @@ -1,41 +0,0 @@ -angular.module('doubtfire.visualisations.student-task-status-pie-chart', []) -.directive 'studentTaskStatusPieChart', -> - replace: true - restrict: 'E' - templateUrl: 'visualisations/visualisation.tpl.html' - scope: - project: '=' - updateData: '=?' - controller: ($scope, newTaskService, Visualisation) -> - colors = newTaskService.statusColors - $scope.data = [] - - $scope.updateData = -> - $scope.data.length = 0 - newTaskService.statusLabels.forEach( (label, key) -> - count = $scope.project.tasksByStatus(key).length - $scope.data.push { key: label, y: count, statusKey: key } - ) - - if $scope.api - $scope.api.update() - - $scope.$on 'TaskStatusUpdated', $scope.updateData - - $scope.updateData() - - [$scope.options, $scope.config] = Visualisation 'pieChart', 'Student Task Status Pie Chart', { - color: (d, i) -> - colors.get(d.statusKey) - x: (d) -> d.key - y: (d) -> d.y - showLabels: no - tooltip: - valueFormatter: (d) -> - fixed = d.toFixed() - pct = Math.round((d / $scope.project.activeTasks().length) * 100) - task = if fixed is "1" then "task" else "tasks" - "#{fixed} #{task} (#{pct}%)" - keyFormatter: (d) -> - d - }, {} From 504a26e9c003880bee711d61287b111773b0c09a Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 28 Nov 2025 22:50:13 +1100 Subject: [PATCH 0758/1280] chore: remove unused visualisations --- src/app/doubtfire-angularjs.module.ts | 6 ------ src/app/visualisations/visualisations.coffee | 6 ------ 2 files changed, 12 deletions(-) diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 7fdba35560..2de407b9fe 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -32,16 +32,10 @@ import 'angular-md5/angular-md5.js'; import 'build/templates-app.js'; import 'build/assets/wav-worker.js'; import 'build/src/app/visualisations/summary-task-status-scatter.js'; -import 'build/src/app/visualisations/student-task-status-pie-chart.js'; -import 'build/src/app/visualisations/progress-burndown-chart.js'; import 'build/src/app/visualisations/target-grade-pie-chart.js'; import 'build/src/app/visualisations/task-status-pie-chart.js'; import 'build/src/app/visualisations/task-completion-box-plot.js'; import 'build/src/app/visualisations/visualisations.js'; -import 'build/src/app/visualisations/alignment-bullet-chart.js'; -import 'build/src/app/visualisations/achievement-custom-bar-chart.js'; -import 'build/src/app/visualisations/alignment-bar-chart.js'; -import 'build/src/app/visualisations/achievement-box-plot.js'; import 'build/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.js'; import 'build/src/app/tasks/modals/modals.js'; import 'build/src/app/tasks/tasks.js'; diff --git a/src/app/visualisations/visualisations.coffee b/src/app/visualisations/visualisations.coffee index f7882be92e..2e90fd66d2 100644 --- a/src/app/visualisations/visualisations.coffee +++ b/src/app/visualisations/visualisations.coffee @@ -1,14 +1,8 @@ angular.module('doubtfire.visualisations', [ 'doubtfire.visualisations.summary-task-status-scatter' - 'doubtfire.visualisations.progress-burndown-chart' - 'doubtfire.visualisations.alignment-bar-chart' - 'doubtfire.visualisations.alignment-bullet-chart' - 'doubtfire.visualisations.student-task-status-pie-chart' 'doubtfire.visualisations.task-status-pie-chart' 'doubtfire.visualisations.target-grade-pie-chart' 'doubtfire.visualisations.task-completion-box-plot' - 'doubtfire.visualisations.achievement-box-plot' - 'doubtfire.visualisations.achievement-custom-bar-chart' ]) .factory('Visualisation', ($interval, analyticsService) -> From 730ffd0c3f79a5ad42c0c59c2f2c2a901ab0d702 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 1 Dec 2025 13:50:42 +1100 Subject: [PATCH 0759/1280] feat: discussion prompts (#1042) * feat: init discussion prompts ui * refactor: improve tutor discussion ui * refactor: display discussion prompts in tutor discussion view * refactor: reword weight to priority --- src/app/api/models/discussion-prompt.ts | 59 +++++++ src/app/api/models/task-definition.ts | 5 + .../api/services/discussion-prompt.service.ts | 128 +++++++++++++++ .../api/services/task-definition.service.ts | 1 + src/app/common/footer/footer.component.html | 13 ++ src/app/common/footer/footer.component.ts | 4 + src/app/doubtfire-angular.module.ts | 9 + .../discussion-prompts-view.component.html | 11 ++ .../discussion-prompts-view.component.scss | 0 .../discussion-prompts-view.component.ts | 11 ++ .../task-dashboard.component.html | 7 + .../states/dashboard/selected-task.service.ts | 5 + .../discussion-prompts.component.html | 21 +++ .../discussion-prompts.component.scss | 0 .../discussion-prompts.component.ts | 50 ++++++ .../tutor-discussion.component.html | 15 +- .../tutor-discussion.component.ts | 7 + ...finition-discussion-prompts.component.html | 107 ++++++++++++ ...finition-discussion-prompts.component.scss | 0 ...definition-discussion-prompts.component.ts | 155 ++++++++++++++++++ .../task-definition-editor.component.html | 12 ++ 21 files changed, 614 insertions(+), 6 deletions(-) create mode 100644 src/app/api/models/discussion-prompt.ts create mode 100644 src/app/api/services/discussion-prompt.service.ts create mode 100644 src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html create mode 100644 src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.scss create mode 100644 src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts create mode 100644 src/app/projects/states/discussion-prompts/discussion-prompts.component.html create mode 100644 src/app/projects/states/discussion-prompts/discussion-prompts.component.scss create mode 100644 src/app/projects/states/discussion-prompts/discussion-prompts.component.ts create mode 100644 src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.html create mode 100644 src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.scss create mode 100644 src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts diff --git a/src/app/api/models/discussion-prompt.ts b/src/app/api/models/discussion-prompt.ts new file mode 100644 index 0000000000..e984847084 --- /dev/null +++ b/src/app/api/models/discussion-prompt.ts @@ -0,0 +1,59 @@ +import {Entity} from 'ngx-entity-service'; +import {AppInjector} from 'src/app/app-injector'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {DiscussionPromptService} from '../services/discussion-prompt.service'; +import {Project, TaskDefinition, Unit, User} from './doubtfire-model'; + +export class DiscussionPrompt extends Entity { + id: number; + unit: Unit; + taskDefinition: TaskDefinition; + project: Project | null; + createdBy: User; + content: string; + priority: number; + discussedAt: Date; + + public readonly PRIORITY = { + 1: 'Low', + 2: 'Medium', + 3: 'High', + } as const; + + constructor(data?: Project | TaskDefinition | Unit) { + super(); + if (data) { + if (data instanceof Project) { + this.project = data; + } else if (data instanceof TaskDefinition) { + this.taskDefinition = data; + } else if (data instanceof Unit) { + this.unit = data; + } + } else { + console.error('Failed to get project'); + } + } + + public get priorityLabel() { + return this.PRIORITY[this.priority] ?? this.priority; + } + + public delete() { + const discussionPromptService: DiscussionPromptService = + AppInjector.get(DiscussionPromptService); + discussionPromptService + .delete( + {task_definition_id: this.taskDefinition.id, id: this.id}, + {cache: this.taskDefinition.discussionPromptsCache}, + ) + .subscribe({ + next: (_response: object) => { + AppInjector.get(AlertService).success('Successfully deleted discussion note', 4000); + }, + error: (error: any) => { + AppInjector.get(AlertService).error(error?.message || error || 'Unknown error', 2000); + }, + }); + } +} diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index 814c7a9c53..d3aa2a4317 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -8,6 +8,7 @@ import {TaskDefinitionService} from '../services/task-definition.service'; import {Grade, GroupSet, LearningOutcome, Project, TutorialStream, Unit} from './doubtfire-model'; import {Task} from './doubtfire-model'; import {TaskPrerequisite} from './task-prerequisite'; +import {DiscussionPrompt} from './discussion-prompt'; export type UploadRequirement = { key: string; @@ -57,10 +58,14 @@ export class TaskDefinition extends Entity { assessInPortfolioOnly: boolean; useResourcesForJplagBaseCode: boolean; lockAssessmentsToTutorialStream: boolean; + discussionPromptsCount: number; public readonly taskPrerequisitesCache: EntityCache = new EntityCache(); + public readonly discussionPromptsCache: EntityCache = + new EntityCache(); + public readonly learningOutcomesCache: EntityCache = new EntityCache(); diff --git a/src/app/api/services/discussion-prompt.service.ts b/src/app/api/services/discussion-prompt.service.ts new file mode 100644 index 0000000000..c102fbcbf1 --- /dev/null +++ b/src/app/api/services/discussion-prompt.service.ts @@ -0,0 +1,128 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; +import { + Project, + ProjectService, + TaskDefinition, + Unit, + UserService, +} from 'src/app/api/models/doubtfire-model'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {DiscussionPrompt} from '../models/discussion-prompt'; + +@Injectable() +export class DiscussionPromptService extends CachedEntityService { + protected readonly endpointFormat = + 'task_definitions/:task_definition_id:/discussion_prompts/:id:'; + + protected readonly projectEndpointFormat = 'projects/:projectId:/discussion_prompts'; + protected readonly taskDefinitionProjectEndpointFormat = + 'projects/:projectId:/discussion_prompts'; + protected readonly taskDefinitionEndpointFormat = + 'task_definitions/:taskDefinitionId:/discussion_prompts'; + + constructor( + httpClient: HttpClient, + private userService: UserService, + private projectService: ProjectService, + ) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'content', + 'priority', + { + keys: ['createdBy', 'created_by_id'], + toEntityFn: (data: object, key: string, prompt: DiscussionPrompt) => { + if (prompt.project) { + return prompt.project.unit.staff.find((s) => s.user.id === data['created_by_id']).user; + } else if (prompt.taskDefinition) { + return prompt.taskDefinition.unit.staff.find((s) => s.user.id === data['created_by_id']) + ?.user; + } else if (prompt.unit) { + return prompt.unit.staff.find((s) => s.user.id === data['created_by_id'])?.user; + } + }, + }, + { + keys: ['taskDefinition', 'task_definition_id'], + toEntityFn: (data: object, key: string, entity: DiscussionPrompt) => { + if (entity.project) { + return entity.project.unit.taskDef(data[key]); + } else if (entity.unit) { + return entity.unit.taskDef(data[key]); + } + return entity.taskDefinition; + }, + toJsonFn: (entity: DiscussionPrompt, key: string) => { + return entity.taskDefinition?.id; + }, + }, + ); + + this.mapping.addJsonKey('project', 'taskDefinition', 'unit', 'createdBy'); + } + + public createInstanceFrom( + _json: object, + other?: Project | Unit | TaskDefinition, + ): DiscussionPrompt { + return new DiscussionPrompt(other); + } + + // TODO: loadDiscussionPromptsForProject and overload for loadTaskDefinitionDiscussionPrompts() + + public loadDiscussionPromptsForPoject(project: Project) { + const options: RequestOptions = { + endpointFormat: this.taskDefinitionProjectEndpointFormat, + cacheBehaviourOnGet: 'cacheQuery', + constructorParams: project, + }; + + return super.fetchAll( + { + projectId: project?.id, + }, + options, + ); + } + + public loadDiscussionPrompts( + project: Project, + taskDefinition?: TaskDefinition, + useFetch: boolean = true, + ): Observable { + const options: RequestOptions = { + endpointFormat: project + ? taskDefinition + ? this.taskDefinitionProjectEndpointFormat + : this.projectEndpointFormat + : this.taskDefinitionEndpointFormat, + cache: taskDefinition.discussionPromptsCache, + sourceCache: taskDefinition.discussionPromptsCache, + // cacheBehaviourOnGet: 'cacheQuery', + constructorParams: project ? project : taskDefinition, + }; + + if (useFetch) { + return super.fetchAll( + { + projectId: project?.id, + taskDefinitionId: taskDefinition?.id, + }, + options, + ); + } else { + return super.query( + { + projectId: project?.id, + taskDefinitionId: taskDefinition?.id, + }, + options, + ); + } + } +} diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index cb36d3cc32..59664c143a 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -125,6 +125,7 @@ export class TaskDefinitionService extends CachedEntityService { 'maxQualityPts', 'overseerImageId', 'assessmentEnabled', + 'discussionPromptsCount', { keys: 'ilos', toEntityOp: (data: object, key: string, taskDefinition: TaskDefinition) => { diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index 8fd9e50a33..e7d84ac5e5 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -128,6 +128,19 @@
    } @if (selectedTask?.project) { + @if (selectedTask?.definition.discussionPromptsCount) { + + } +
    @if (selectedTask.project.staffNoteCount > 0) {
    diff --git a/src/app/common/footer/footer.component.ts b/src/app/common/footer/footer.component.ts index 7e38438381..295b8612ee 100644 --- a/src/app/common/footer/footer.component.ts +++ b/src/app/common/footer/footer.component.ts @@ -107,6 +107,10 @@ export class FooterComponent implements OnInit { this.selectedTaskService.showStaffNotes(); } + viewDiscussionPrompts() { + this.selectedTaskService.showDiscussionPrompts(); + } + getJplagReport() { if (!this.selectedTask?.definition) { return; diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 318c601b35..7938a4e274 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -297,6 +297,10 @@ import {PortfolioIncludedTasksComponent} from './projects/states/portfolio/direc import {OverseerScriptEditorModalComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component'; import {CodeEditorModule} from '@ngstack/code-editor'; import {UploadGradesComponent} from './units/states/portfolios/upload-grades/upload-grades.component'; +import {DiscussionPromptService} from './api/services/discussion-prompt.service'; +import {DiscussionPromptsComponent} from './projects/states/discussion-prompts/discussion-prompts.component'; +import {TaskDefinitionDiscussionPromptsComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component'; +import {DiscussionPromptsViewComponent} from './projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { @@ -452,6 +456,10 @@ const MY_DATE_FORMAT = { AnalyticsTutorTimesComponent, PortfolioIncludedTasksComponent, OverseerScriptEditorModalComponent, + UploadGradesComponent, + DiscussionPromptsComponent, + TaskDefinitionDiscussionPromptsComponent, + DiscussionPromptsViewComponent, ], providers: [ // Services we provide @@ -541,6 +549,7 @@ const MY_DATE_FORMAT = { LtiService, TaskPrerequisiteService, MarkingSessionService, + DiscussionPromptService, ], imports: [ FlexLayoutModule, diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html new file mode 100644 index 0000000000..8cc634a7fd --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html @@ -0,0 +1,11 @@ +
    +
    + comment +

    Discussion Prompts for {{ project?.student?.name }}

    +
    + + +
    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.scss b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts new file mode 100644 index 0000000000..6156a4b191 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts @@ -0,0 +1,11 @@ +import {Component, Input} from '@angular/core'; + +@Component({ + selector: 'f-discussion-prompts-view', + templateUrl: './discussion-prompts-view.component.html', + styleUrls: ['./discussion-prompts-view.component.scss'], +}) +export class DiscussionPromptsViewComponent { + @Input() project; + @Input() taskDefinition; +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html index 705ab5b6d3..df91328f92 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html @@ -19,6 +19,13 @@ + + + + diff --git a/src/app/projects/states/dashboard/selected-task.service.ts b/src/app/projects/states/dashboard/selected-task.service.ts index 31b5dd8716..204714694e 100644 --- a/src/app/projects/states/dashboard/selected-task.service.ts +++ b/src/app/projects/states/dashboard/selected-task.service.ts @@ -9,6 +9,7 @@ export enum DashboardViews { task, similarity, staff_notes, + discussion_prompts, } @Injectable({ @@ -66,6 +67,10 @@ export class SelectedTaskService { this.currentView$.next(DashboardViews.staff_notes); } + public showDiscussionPrompts() { + this.currentView$.next(DashboardViews.discussion_prompts); + } + public showSubmission() { if (!this.task$.value) return; this.currentPdfUrl$.next(this.task$.value.submissionUrl(false)); diff --git a/src/app/projects/states/discussion-prompts/discussion-prompts.component.html b/src/app/projects/states/discussion-prompts/discussion-prompts.component.html new file mode 100644 index 0000000000..5dcbbf84ff --- /dev/null +++ b/src/app/projects/states/discussion-prompts/discussion-prompts.component.html @@ -0,0 +1,21 @@ +
    + @for (prompt of discussionPrompts; track prompt) { + + +
    + {{ prompt.taskDefinition.abbreviation }} +
    +
    + {{ prompt.content }} +
    +
    + {{ prompt.priorityLabel }} +
    +
    +
    + } +
    diff --git a/src/app/projects/states/discussion-prompts/discussion-prompts.component.scss b/src/app/projects/states/discussion-prompts/discussion-prompts.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts b/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts new file mode 100644 index 0000000000..2e384498af --- /dev/null +++ b/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts @@ -0,0 +1,50 @@ +import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core'; +import {DiscussionPrompt} from 'src/app/api/models/discussion-prompt'; +import {Project, TaskDefinition, UserService} from 'src/app/api/models/doubtfire-model'; +import {StaffNote} from 'src/app/api/models/staff-note'; +import {DiscussionPromptService} from 'src/app/api/services/discussion-prompt.service'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-discussion-prompts', + templateUrl: './discussion-prompts.component.html', + styleUrl: './discussion-prompts.component.scss', +}) +export class DiscussionPromptsComponent implements OnInit { + @ViewChild('staffNotesContainer') staffNotesContainer!: ElementRef; + @ViewChild('staffNoteEditor', {static: false}) staffNoteEditor!: ElementRef; + + @Input() project: Project; + @Input() taskDefinition: TaskDefinition; + + loadingStaffNotes: boolean = true; + + noteText: string = ''; + + editingNote?: StaffNote; + editingNoteText?: string = ''; + + replyingToNote?: StaffNote; + + hoveredNoteId: number | null = null; + + discussionPrompts: DiscussionPrompt[] = []; + + constructor( + private userService: UserService, + private discussionPromptService: DiscussionPromptService, + private alertService: AlertService, + private confirmationModalService: ConfirmationModalService, + ) {} + ngOnInit(): void { + console.log('task def?', this.taskDefinition); + this.loadingStaffNotes = true; + this.discussionPromptService + .loadDiscussionPromptsForPoject(this.project) + .subscribe((prompts) => { + console.log(prompts); + this.discussionPrompts = prompts; + }); + } +} diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html index 89cf35865f..f38d42764b 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html @@ -79,7 +79,7 @@ -
    -

    {{ task.definition.name }}

    -
    +
    +

    {{ task.definition.name }}

    + {{ task.definition.abbreviation }} - {{ getTargetTradeString(task.definition.targetGrade) }} Task -
    +
    @if (task.hasGrade()) {
    @@ -215,7 +215,8 @@

    {{ task.definition.name }}

    - + + @if (footerTabView === TutorDiscussionTabView.SHOW_COMMENTS) { @@ -235,6 +236,8 @@

    {{ task.definition.name }}

    } @else if (footerTabView === TutorDiscussionTabView.SHOW_STAFF_NOTES) { + } @else if (footerTabView === TutorDiscussionTabView.SHOW_DISCUSSION_PROMPTS) { + } }
    diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts index 567988d53d..801482ec4d 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts @@ -23,6 +23,7 @@ import {GradeService} from 'src/app/common/services/grade.service'; enum TutorDiscussionTabView { SHOW_COMMENTS, SHOW_STAFF_NOTES, + SHOW_DISCUSSION_PROMPTS, } @Component({ selector: 'f-tutor-discussion', @@ -88,6 +89,8 @@ export class TutorDiscussionComponent implements AfterViewInit { this.showComments(); } else if (event.index === 1) { this.showStaffNotes(); + } else if (event.index === 2) { + this.showDiscussionPrompts(); } } @@ -99,6 +102,10 @@ export class TutorDiscussionComponent implements AfterViewInit { this.footerTabView = TutorDiscussionTabView.SHOW_STAFF_NOTES; } + public showDiscussionPrompts() { + this.footerTabView = TutorDiscussionTabView.SHOW_DISCUSSION_PROMPTS; + } + public ngAfterViewInit(): void { this.authService.afterAuthCall((result) => { if (!result) { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.html new file mode 100644 index 0000000000..86d762974e --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.html @@ -0,0 +1,107 @@ +
    +
    + + + + + + + + + + + + + + + + + + +
    Discussion Prompt + @if (!editing(prompt)) { + {{ prompt.content }} + } @else { + + Discussion Prompt + + + } + Priority + @if (!editing(prompt)) { + {{ prompt.priorityLabel }} + } @else { +
    + + Priority + + + High + Medium + Low + + +
    + } +
    Actions +
    + @if (editing(prompt)) { + + + } @else { + + + } +
    +
    + @if (!dataSource.data.length) { +
    No discussion prompts
    + } +
    + @if (!creatingNewDiscussionPrompt) { +
    + +
    + } + + @if (creatingNewDiscussionPrompt) { + + +
    + + Discussion Prompt + + + + Priority + + + High + Medium + Low + + +
    +
    + + +
    +
    +
    + } +
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts new file mode 100644 index 0000000000..149682d55d --- /dev/null +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts @@ -0,0 +1,155 @@ +import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import {UntypedFormControl, Validators} from '@angular/forms'; +import {MatTableDataSource} from '@angular/material/table'; +import {Observable, Subscription} from 'rxjs'; +import {DiscussionPrompt} from 'src/app/api/models/discussion-prompt'; +import {Task} from 'src/app/api/models/task'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {TaskPrerequisite} from 'src/app/api/models/task-prerequisite'; +import {Unit} from 'src/app/api/models/unit'; +import {DiscussionPromptService} from 'src/app/api/services/discussion-prompt.service'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {TaskPrerequisiteService} from 'src/app/api/services/task-prerequisite.service'; +import {EntityFormComponent} from 'src/app/common/entity-form/entity-form.component'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-task-definition-discussion-prompts', + templateUrl: 'task-definition-discussion-prompts.component.html', + styleUrls: ['task-definition-discussion-prompts.component.scss'], +}) +export class TaskDefinitionDiscussionPromptsComponent + extends EntityFormComponent + implements OnInit, OnChanges +{ + @Input() taskDefinition: TaskDefinition; + @Input() staffView: boolean; + @Input() task: Task; + + displayedColumns: string[] = ['content', 'priority', 'actions']; + + private prereqSub?: Subscription; + + public dataSource = new MatTableDataSource(); + + creatingNewDiscussionPrompt: boolean = false; + + newDiscussionPromptContent: string; + newDiscussionPromptWeight: number = 2; + + constructor( + private taskDefinitionService: TaskDefinitionService, + private alertService: AlertService, + private taskPrerequisiteService: TaskPrerequisiteService, + private discussionPromptService: DiscussionPromptService, + ) { + super( + { + content: new UntypedFormControl('', [Validators.required]), + priority: new UntypedFormControl('', [Validators.required]), + }, + 'Discussion Prompt', + ); + } + public get unit(): Unit { + return this.taskDefinition?.unit; + } + + public get prerequisites(): Observable { + return this.taskDefinition.taskPrerequisitesCache.values; + } + + ngOnInit(): void { + this.prereqSub = this.taskDefinition.discussionPromptsCache.values.subscribe((values) => { + this.dataSource.data = values; + }); + } + + ngOnChanges(changes: SimpleChanges): void { + if ( + changes.taskDefinition && + changes.taskDefinition.previousValue?.id !== changes.taskDefinition.currentValue?.id + ) { + this.prereqSub?.unsubscribe(); + this.prereqSub = this.taskDefinition.discussionPromptsCache.values.subscribe((values) => { + this.dataSource.data = values; + }); + this.fetchDiscussionPrompts(); + } + } + + private fetchDiscussionPrompts() { + const taskDefinition = this.taskDefinition; + this.discussionPromptService.loadDiscussionPrompts(null, taskDefinition).subscribe({ + next: (data) => { + this.dataSource.data = data; + }, + error: (error) => { + this.alertService.error(`Failed to load discussion promnpts: ${error}`); + }, + }); + } + + public addNewPrompt() { + const content = this.newDiscussionPromptContent; + const priority = this.newDiscussionPromptWeight; + this.discussionPromptService + .create( + { + task_definition_id: this.taskDefinition.id, + content: content, + priority: priority, + }, + { + cache: this.taskDefinition.discussionPromptsCache, + constructorParams: this.taskDefinition, + }, + ) + .subscribe({ + next: (_result) => { + this.cancelNewDiscussionPrompt(); + this.prereqSub?.unsubscribe(); + this.prereqSub = this.taskDefinition.discussionPromptsCache.values.subscribe((values) => { + this.dataSource.data = values; + }); + this.alertService.success(`Succesfully created prompt`, 3000); + }, + error: (error) => { + this.alertService.error(`Failed to create prompt: ${error}`, 6000); + }, + }); + } + + public deletePrompt(prompt: DiscussionPrompt) { + prompt.delete(); + } + + createNewDiscussionPrompt() { + this.creatingNewDiscussionPrompt = true; + } + + cancelNewDiscussionPrompt() { + this.creatingNewDiscussionPrompt = false; + this.newDiscussionPromptContent = ''; + this.newDiscussionPromptWeight = 2; + } + + submit() { + this.discussionPromptService + .put({ + id: this.selected.id, + task_definition_id: this.taskDefinition.id, + content: this.selected.content, + priority: this.selected.priority, + }) + .subscribe({ + next: (_response) => { + this.cancelEdit(); + this.alertService.success('Successfully saved prompt', 3000); + }, + error: (error) => { + this.alertService.error(`Failed to update prompt: ${error}`, 6000); + }, + }); + } +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html index 7744269ca5..a13d096675 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html @@ -68,6 +68,18 @@

    Details for {{ taskDefinition.abbreviation }} - {{ taskDefinition.name }} + + Discussion Prompts +
    +

    + Discussion prompts for tutors to use when discussing student tasks in class +

    + + + +
    +
    + @if (overseerEnabled) { Task Assessment Automation From 2db24183d551559414d8e1c7eee4ecdaf032ccb6 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 1 Dec 2025 14:54:28 +1100 Subject: [PATCH 0760/1280] refactor: migrate project groups (#1056) * refactor: migrate project groups component * chore: ensure callback is not null * chore: update migration progress --- README.md | 2 +- src/app/doubtfire-angular.module.ts | 2 ++ src/app/doubtfire-angularjs.module.ts | 6 ++++++ .../group-member-list.component.ts | 2 +- .../projects/states/groups/groups.tpl.html | 19 +++++-------------- .../project-groups.component.html | 12 ++++++++++++ .../project-groups.component.scss | 5 +++++ .../project-groups.component.ts | 15 +++++++++++++++ 8 files changed, 47 insertions(+), 16 deletions(-) create mode 100644 src/app/projects/states/groups/project-groups/project-groups.component.html create mode 100644 src/app/projects/states/groups/project-groups/project-groups.component.scss create mode 100644 src/app/projects/states/groups/project-groups/project-groups.component.ts diff --git a/README.md b/README.md index fc8827a0bd..fe61c8d20f 100644 --- a/README.md +++ b/README.md @@ -208,7 +208,7 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.coffee - [ ] ./src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee - [ ] ./src/app/projects/states/feedback/feedback.coffee -- [ ] ./src/app/projects/states/groups/groups.coffee (-> "project-groups") +- [ ] ./src/app/projects/states/groups/groups.coffee (State only -> "project-groups") - [ ] ./src/app/projects/states/index/index.coffee - [ ] ./src/app/projects/states/portfolio/directives/directives.coffee - [ ] ./src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.coffee (Migrate this in 10.0.x) diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 2ed284691b..634304b171 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -294,6 +294,7 @@ import {PortfoliosPortfolioViewComponent} from './units/states/portfolios/direct import {PortfoliosAssessmentComponent} from './units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component'; import {UnitGroupsComponent} from './units/states/groups/unit-groups/unit-groups.component'; import {RolloverComponent} from './units/states/rollover/rollover.component'; +import {ProjectGroupsComponent} from './projects/states/groups/project-groups/project-groups.component'; @NgModule({ // Components we declare @@ -436,6 +437,7 @@ import {RolloverComponent} from './units/states/rollover/rollover.component'; PortfoliosAssessmentComponent, UnitGroupsComponent, RolloverComponent, + ProjectGroupsComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 2de407b9fe..ddfe5a39c9 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -209,6 +209,7 @@ import {PortfolioWelcomeStepComponent} from './projects/states/portfolio/directi import {PortfolioLearningSummaryReportStepComponent} from './projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component'; import {PortfolioAddExtraFilesStepComponent} from './projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component'; import {UnitGroupsComponent} from './units/states/groups/unit-groups/unit-groups.component'; +import {ProjectGroupsComponent} from './projects/states/groups/project-groups/project-groups.component'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -550,3 +551,8 @@ DoubtfireAngularJSModule.directive( 'fUnitGroups', downgradeComponent({component: UnitGroupsComponent}), ); + +DoubtfireAngularJSModule.directive( + 'fProjectGroups', + downgradeComponent({component: ProjectGroupsComponent}), +); diff --git a/src/app/groups/group-member-list/group-member-list.component.ts b/src/app/groups/group-member-list/group-member-list.component.ts index 3e71170de3..b83199407c 100644 --- a/src/app/groups/group-member-list/group-member-list.component.ts +++ b/src/app/groups/group-member-list/group-member-list.component.ts @@ -50,7 +50,7 @@ export class GroupMemberListComponent implements OnInit, OnChanges { this.selectedGroup.getMembers().subscribe({ next: (members) => { this.loading = false; - this.onMembersLoaded(); + this.onMembersLoaded?.(); this.canRemoveMembers = !!this.unitRole || (this.selectedGroup.groupSet.allowStudentsToManageGroups && !this.selectedGroup.locked); diff --git a/src/app/projects/states/groups/groups.tpl.html b/src/app/projects/states/groups/groups.tpl.html index 804d268d35..47114d023d 100644 --- a/src/app/projects/states/groups/groups.tpl.html +++ b/src/app/projects/states/groups/groups.tpl.html @@ -1,14 +1,5 @@ -
    - - -
    - -
    -
    - -

    No Group Work

    -
    -
    - There is no group work enabled for this unit. -
    -
    + diff --git a/src/app/projects/states/groups/project-groups/project-groups.component.html b/src/app/projects/states/groups/project-groups/project-groups.component.html new file mode 100644 index 0000000000..6468b85e39 --- /dev/null +++ b/src/app/projects/states/groups/project-groups/project-groups.component.html @@ -0,0 +1,12 @@ +
    + @if (unit.hasGroupwork()) { + + + } @else { +
    + groups +

    No Group Work

    +

    There is no group work enabled for this unit.

    +
    + } +
    diff --git a/src/app/projects/states/groups/project-groups/project-groups.component.scss b/src/app/projects/states/groups/project-groups/project-groups.component.scss new file mode 100644 index 0000000000..542e68a366 --- /dev/null +++ b/src/app/projects/states/groups/project-groups/project-groups.component.scss @@ -0,0 +1,5 @@ +.mat-icon { + font-size: 75px; + width: 75px; + height: 75px; +} diff --git a/src/app/projects/states/groups/project-groups/project-groups.component.ts b/src/app/projects/states/groups/project-groups/project-groups.component.ts new file mode 100644 index 0000000000..9969bd6ceb --- /dev/null +++ b/src/app/projects/states/groups/project-groups/project-groups.component.ts @@ -0,0 +1,15 @@ +import {Component, Input} from '@angular/core'; +import {GroupSet, Project} from 'src/app/api/models/doubtfire-model'; +import {Unit} from 'src/app/api/models/unit'; + +// This component is only displayed to students (projects) +@Component({ + selector: 'f-project-groups', + templateUrl: './project-groups.component.html', + styleUrl: './project-groups.component.scss', +}) +export class ProjectGroupsComponent { + @Input() unit: Unit; + @Input() project: Project; + @Input() selectedGroupSet: GroupSet; +} From ec5376255a0c69dc887a5508e80ca4f614291b48 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Tue, 2 Dec 2025 12:41:57 +1100 Subject: [PATCH 0761/1280] refactor: migrate group member contribution assigner component (#1057) * feat: migrate group-member-contribution-assigner component * refactor: use mat table * refactor: add table sorting * chore: update migration progress * chore: avoid defaulting group * fix: check if overseer test submission * refactor: remove groups module * refactor: improve hover rating effect * refactor: use modern for-loop directive * chore: default sort by student name * refactor: ensure confrating is set - used in other logic for statistics * refactor: remove unused code * refactor: remove confrating * chore: allow nullable overstar property * chore: remove class --------- Co-authored-by: EkamBhullar --- README.md | 4 +- src/app/api/models/groups/group.ts | 33 ++-- src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire-angularjs.module.ts | 9 +- .../group-member-contribution-assigner.coffee | 74 --------- ...ember-contribution-assigner.component.html | 51 ++++++ ...ember-contribution-assigner.component.scss | 0 ...-member-contribution-assigner.component.ts | 157 ++++++++++++++++++ .../group-member-contribution-assigner.scss | 19 --- ...roup-member-contribution-assigner.tpl.html | 41 ----- src/app/groups/groups.coffee | 3 - .../upload-submission-modal.coffee | 2 +- .../upload-submission-modal.tpl.html | 12 +- 13 files changed, 240 insertions(+), 167 deletions(-) delete mode 100644 src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.coffee create mode 100644 src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.html create mode 100644 src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.scss create mode 100644 src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.ts delete mode 100644 src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.scss delete mode 100644 src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.tpl.html delete mode 100644 src/app/groups/groups.coffee diff --git a/README.md b/README.md index fe61c8d20f..37ecf811c2 100644 --- a/README.md +++ b/README.md @@ -177,6 +177,8 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/visualisations/achievement-custom-bar-chart.coffee (ILO Alignments removed) - [ ] ./src/app/visualisations/alignment-bar-chart.coffee (ILO Alignments removed) - [ ] ./src/app/visualisations/alignment-bullet-chart.coffee (ILO Alignments removed) +- [x] ./src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.coffee +- [x] ./src/app/groups/groups.coffee ### TODO: @@ -200,8 +202,6 @@ Important: When completing a frontend migration, please update the below list re - [ ] ./src/app/errors/errors.coffee - [ ] ./src/app/errors/states/states.coffee - [ ] ./src/app/errors/states/timeout/timeout.coffee -- [ ] ./src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.coffee -- [ ] ./src/app/groups/groups.coffee - [ ] ./src/app/projects/projects.coffee - [ ] ./src/app/projects/states/dashboard/dashboard.coffee - [ ] ./src/app/projects/states/dashboard/directives/directives.coffee diff --git a/src/app/api/models/groups/group.ts b/src/app/api/models/groups/group.ts index 5abbb9f0ff..fd00bdf0e4 100644 --- a/src/app/api/models/groups/group.ts +++ b/src/app/api/models/groups/group.ts @@ -6,6 +6,13 @@ import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {Unit, GroupSet, Project, Tutorial, ProjectService} from '../doubtfire-model'; import {AlertService} from 'src/app/common/services/alert.service'; +export interface MemberContribution { + project: Project; + rating: number; + percent: number; + overStar?: number | null; +} + export class Group extends Entity { public id: number; public name: string; @@ -152,23 +159,13 @@ export class Group extends Entity { } } - public contributionSum( - contrib: {project: Project; rating: number; confRating: number; percent: number}[], - member?: Project, - value?: number, - ): number { - return contrib.reduce( - ( - prevValue: number, - current: {project: Project; rating: number; confRating: number; percent: number}, - ) => { - if (current.project === member) { - return prevValue + value; - } else { - return prevValue + current.rating; - } - }, - 0, - ); + public contributionSum(contrib: MemberContribution[], member?: Project, value?: number): number { + return contrib.reduce((prevValue: number, current) => { + if (current.project === member) { + return prevValue + value; + } else { + return prevValue + current.rating; + } + }, 0); } } diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 634304b171..fa5708f4d9 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -264,6 +264,7 @@ import {PrivacyPolicy} from './config/privacy-policy/privacy-policy'; // import {PrivacyPolicy} from './config/privacy-policy/privacy-policy'; import {UnitStaffEditorComponent} from './units/states/edit/directives/unit-staff-editor/unit-staff-editor.component'; import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component'; +import {GroupMemberContributionAssignerComponent} from './groups/group-member-contribution-assigner/group-member-contribution-assigner.component'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { @@ -438,6 +439,7 @@ import {ProjectGroupsComponent} from './projects/states/groups/project-groups/pr UnitGroupsComponent, RolloverComponent, ProjectGroupsComponent, + GroupMemberContributionAssignerComponent, ], // Services we provide providers: [ diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index ddfe5a39c9..4855d04ad6 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -67,8 +67,6 @@ import 'build/src/app/projects/states/portfolio/directives/directives.js'; import 'build/src/app/projects/states/portfolio/portfolio.js'; import 'build/src/app/projects/states/index/index.js'; import 'build/src/app/projects/project-outcome-alignment/project-outcome-alignment.js'; -import 'build/src/app/groups/groups.js'; -import 'build/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.js'; import 'build/src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.js'; import 'build/src/app/units/modals/modals.js'; import 'build/src/app/units/units.js'; @@ -210,6 +208,7 @@ import {PortfolioLearningSummaryReportStepComponent} from './projects/states/por import {PortfolioAddExtraFilesStepComponent} from './projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component'; import {UnitGroupsComponent} from './units/states/groups/unit-groups/unit-groups.component'; import {ProjectGroupsComponent} from './projects/states/groups/project-groups/project-groups.component'; +import {GroupMemberContributionAssignerComponent} from './groups/group-member-contribution-assigner/group-member-contribution-assigner.component'; export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.config', @@ -218,7 +217,6 @@ export const DoubtfireAngularJSModule = angular.module('doubtfire', [ 'doubtfire.units', 'doubtfire.tasks', 'doubtfire.projects', - 'doubtfire.groups', 'doubtfire.visualisations', ]); @@ -556,3 +554,8 @@ DoubtfireAngularJSModule.directive( 'fProjectGroups', downgradeComponent({component: ProjectGroupsComponent}), ); + +DoubtfireAngularJSModule.directive( + 'fGroupMemberContributionAssigner', + downgradeComponent({component: GroupMemberContributionAssignerComponent}), +); diff --git a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.coffee b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.coffee deleted file mode 100644 index b949a95d98..0000000000 --- a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.coffee +++ /dev/null @@ -1,74 +0,0 @@ -angular.module('doubtfire.groups.group-member-contribution-assigner', []) - -# -# Directive to rate each student's contributions -# in a group task assessment -# -.directive('groupMemberContributionAssigner', -> - restrict: 'E' - templateUrl: 'groups/group-member-contribution-assigner/group-member-contribution-assigner.tpl.html' - replace: true - scope: - task: '=' - project: '=' - team: '=' #out parameter - - controller: ($scope, gradeService) -> - $scope.selectedGroupSet = $scope.task.definition.groupSet - unless $scope.task.isTestSubmission - $scope.selectedGroup = $scope.project.getGroupForTask($scope.task) - - $scope.memberSortOrder = 'project.student.name' - $scope.numStars = 5 - $scope.initialStars = 3 - - $scope.percentages = { - danger: 0, - warning: 25, - info: 50, - success: 100 - } - - $scope.checkClearRating = (contrib) -> - if contrib.confRating == 1 && contrib.overStar == 1 && contrib.rating == 0 - contrib.rating = contrib.percent = 0 - else if contrib.confRating == 1 && contrib.overStar == 1 && contrib.rating == 0 - contrib.rating = 1 - contrib.confRating = contrib.rating - - memberPercentage = (contrib, rating) -> - (100 * (rating / $scope.selectedGroup.contributionSum($scope.team.memberContributions, contrib, rating))).toFixed() - - $scope.hoveringOver = (contrib, value) -> - contrib.overStar = value - contrib.percent = memberPercentage(contrib, value) - - $scope.gradeFor = gradeService.gradeFor - - if $scope.selectedGroup && $scope.selectedGroupSet - $scope.selectedGroup.getMembers().subscribe({ - next: (members) -> - $scope.team.memberContributions = _.map(members, (member) -> - result = { - project: member, - rating: $scope.initialStars, - confRating: $scope.initialStars, - percent: 0 - } - result.percent = memberPercentage(result, $scope.initialStars) - result - ) - # Need the '+' to convert to number - $scope.percentages.warning = +(25 / members.length).toFixed() - $scope.percentages.info = +(50 / members.length).toFixed() - $scope.percentages.success = +(95 / members.length).toFixed() - }) - else - $scope.team.memberContributions = [] - - $scope.percentClass = (pct) -> - return 'label-success' if pct >= $scope.percentages.success - return 'label-info' if $scope.percentages.info <= pct < $scope.percentages.success - return 'label-warning' if $scope.percentages.warning <= pct < $scope.percentages.info - return 'label-danger' if $scope.percentages.danger <= pct < $scope.percentages.warning -) diff --git a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.html b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.html new file mode 100644 index 0000000000..d799655b00 --- /dev/null +++ b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.html @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + +
    Team Member + {{ member.project.student.name }} + Target Grade + + Contribution + @for (i of [].constructor(numStars); track $index) { + + person + + } +
    diff --git a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.scss b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.ts b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.ts new file mode 100644 index 0000000000..15129a953f --- /dev/null +++ b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.ts @@ -0,0 +1,157 @@ +import { + Component, + EventEmitter, + Input, + OnChanges, + OnInit, + Output, + SimpleChanges, +} from '@angular/core'; +import {Sort} from '@angular/material/sort'; +import {MatTableDataSource} from '@angular/material/table'; +import {GroupSet} from 'src/app/api/models/doubtfire-model'; +import {Group, MemberContribution} from 'src/app/api/models/groups/group'; +import {Project} from 'src/app/api/models/project'; +import {Task} from 'src/app/api/models/task'; + +@Component({ + selector: 'f-group-member-contribution-assigner', + templateUrl: './group-member-contribution-assigner.component.html', + styleUrls: ['./group-member-contribution-assigner.component.scss'], +}) +export class GroupMemberContributionAssignerComponent implements OnInit, OnChanges { + @Input() isTestSubmission: boolean; + + @Input() task: Task; + @Input() project: Project; + @Input() team = {memberContributions: [] as MemberContribution[]}; + @Output() teamChange = new EventEmitter<{memberContributions: MemberContribution[]}>(); + + selectedGroupSet: GroupSet; + selectedGroup: Group; + + numStars = 5; + initialStars = 3; + + percentages = { + danger: 0, + warning: 25, + info: 50, + success: 100, + }; + + displayedColumns = ['name', 'target-grade', 'contribution']; + dataSource = new MatTableDataSource([]); + + ngOnInit(): void { + this.initializeGroupData(); + this.loadMembers(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['task'] || changes['project']) { + this.initializeGroupData(); + this.loadMembers(); + } + } + + private initializeGroupData(): void { + this.selectedGroupSet = this.task?.definition?.groupSet; + // Check if this is an overseer test submission + if (!this.isTestSubmission) { + const group = this.project?.getGroupForTask(this.task); + this.selectedGroup = group; + if (!this.selectedGroup && this.selectedGroupSet?.groups?.length > 0) { + this.selectedGroup = this.selectedGroupSet.groups[0]; + } + } + } + + private loadMembers(): void { + if (!this.selectedGroup && this.selectedGroupSet?.groups?.length > 0) { + console.error(`Could not find project's group`); + this.team.memberContributions = []; + return; + } + if (this.selectedGroup && this.selectedGroupSet) { + this.selectedGroup.getMembers().subscribe({ + next: (members) => { + this.team.memberContributions = members.map((member) => { + const result: MemberContribution = { + project: member, + rating: this.initialStars, + percent: 0, + overStar: null, + }; + result.percent = this.memberPercentage(result, this.initialStars); + return result; + }); + + // Update percentages based on member count + this.percentages.warning = +(25 / members.length).toFixed(); + this.percentages.info = +(50 / members.length).toFixed(); + this.percentages.success = +(95 / members.length).toFixed(); + + this.teamChange.emit(this.team); + this.dataSource.data = [...this.team.memberContributions]; + }, + }); + } else { + this.team.memberContributions = []; + this.teamChange.emit(this.team); + } + } + + private memberPercentage(contrib: MemberContribution, rating: number): number { + return +( + 100 * + (rating / + this.selectedGroup.contributionSum(this.team.memberContributions, contrib.project, rating)) + ).toFixed(); + } + + selectRating(contrib: MemberContribution, rating: number) { + if (contrib.rating !== rating) { + contrib.rating = rating; + this.hoveringOver(contrib, rating); + } else { + contrib.rating = 0; + this.hoveringOver(contrib, 0); + } + } + + hoveringOver(contrib: MemberContribution, value: number): void { + contrib.overStar = value; + contrib.percent = this.memberPercentage(contrib, value); + } + + private sortCompare(aValue: number | string, bValue: number | string, isAsc: boolean) { + return (aValue < bValue ? -1 : 1) * (isAsc ? 1 : -1); + } + + sortTableData(sort: Sort) { + if (!sort.active || sort.direction === '') { + return; + } + this.dataSource.data = this.dataSource.data.sort((a, b) => { + switch (sort.active) { + case 'name': + return this.sortCompare( + a.project.student.name, + b.project.student.name, + sort.direction === 'asc', + ); + case 'target-grade': + return this.sortCompare( + a.project.targetGrade, + b.project.targetGrade, + sort.direction === 'asc', + ); + case 'contribution': + return this.sortCompare(a.rating, b.rating, sort.direction === 'asc'); + default: + return 0; + } + }); + } +} diff --git a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.scss b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.scss deleted file mode 100644 index 8199fd2757..0000000000 --- a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.scss +++ /dev/null @@ -1,19 +0,0 @@ -.group-member-contribution-assigner { - .group-member-contribution-rating { - &:focus { - outline: none; - } - i { - font-size: 2em; - cursor: pointer; - } - .icon-colorful { - color: rgb(255, 247, 141); - -webkit-text-stroke-width: 1px; - -webkit-text-stroke-color: orange; - } - .icon-disable { - color: #ccc; - } - } -} diff --git a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.tpl.html b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.tpl.html deleted file mode 100644 index 1fa8194d11..0000000000 --- a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.tpl.html +++ /dev/null @@ -1,41 +0,0 @@ -
    - - - - - - - - - - - - - - - -
    Team MemberTarget GradeContribution
    {{member.student_name}} - - - - - - - {{member.percent}} % effort - - - No effort - - -
    -
    diff --git a/src/app/groups/groups.coffee b/src/app/groups/groups.coffee deleted file mode 100644 index feae90ec11..0000000000 --- a/src/app/groups/groups.coffee +++ /dev/null @@ -1,3 +0,0 @@ -angular.module('doubtfire.groups', [ - 'doubtfire.groups.group-member-contribution-assigner' -]) diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee index 7646c70ff4..b0a94257ab 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee @@ -166,7 +166,7 @@ angular.module('doubtfire.tasks.modals.upload-submission-modal', []) shouldDisableByState = { # Disable group if group members not allocated anything group: -> - _.chain($scope.team.memberContributions).map('confRating').compact().value().length == 0 + _.chain($scope.team.memberContributions).map('rating').compact().value().length == 0 # Disable alignment if no alignments made (need at least 1) and # if description is blank alignment: -> diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html index 9b96abcd0b..f8019a3011 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.tpl.html @@ -35,12 +35,12 @@

    - - + +
    - @if (comment.assessment_result && comment.assessment_result.is_successful) { -
    -
    -
    {{ comment.text }}
    + +
    +
    +
    {{ comment.text }}
    - -
    -
    - } @else { + +
    +
    +
    diff --git a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts index 44e22eea8b..ed2e404b26 100644 --- a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts @@ -46,7 +46,7 @@ export class TaskAssessmentCommentComponent implements OnInit { } ngOnInit() { - this.update(); + // this.update(); } get message() { From e454166455d0af105bd9ef037ff7a19c2180e915 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Dec 2025 11:56:10 +1100 Subject: [PATCH 0764/1280] chore(release): 10.0.0-66 --- CHANGELOG.md | 12 ++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6935c31476..aa893a612a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-66](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-65...v10.0.0-66) (2025-12-03) + + +### Features + +* discussion prompts ([#1042](https://github.com/b0ink/doubtfire-deploy/issues/1042)) ([730ffd0](https://github.com/b0ink/doubtfire-deploy/commit/730ffd0c3f79a5ad42c0c59c2f2c2a901ab0d702)) + + +### Bug Fixes + +* correctly set rollover end date ([0611be0](https://github.com/b0ink/doubtfire-deploy/commit/0611be04e8fe7e75ae07504945a2984839475e3a)) + ## [10.0.0-65](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-64...v10.0.0-65) (2025-11-25) diff --git a/package-lock.json b/package-lock.json index c30263893b..184b9874da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-65", + "version": "10.0.0-66", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-65", + "version": "10.0.0-66", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index fb458e4b24..307e43542b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-65", + "version": "10.0.0-66", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 6651279c49f431dbddf6fd5d810440ae7b3b9898 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Dec 2025 14:33:08 +1100 Subject: [PATCH 0765/1280] feat: allow sidekiq web access (#1053) --- ngsw-config.json | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/ngsw-config.json b/ngsw-config.json index 8c80cd0891..5c8069284f 100644 --- a/ngsw-config.json +++ b/ngsw-config.json @@ -47,5 +47,14 @@ } } ], - "navigationUrls": ["/**", "!/**/*.*", "!/**/*__*", "!/**/*__*/**", "!/JPlag/**", "!/JPlag"] + "navigationUrls": [ + "/**", + "!/**/*.*", + "!/**/*__*", + "!/**/*__*/**", + "!/JPlag/**", + "!/JPlag", + "!/sidekiq/**", + "!/sidekiq" + ] } From 8db864661ec58c111bd611e9a33c65f11db59f3d Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Dec 2025 14:33:23 +1100 Subject: [PATCH 0766/1280] chore(release): 10.0.0-67 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa893a612a..eb4dacb6a1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-67](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-66...v10.0.0-67) (2025-12-03) + + +### Features + +* allow sidekiq web access ([#1053](https://github.com/b0ink/doubtfire-deploy/issues/1053)) ([6651279](https://github.com/b0ink/doubtfire-deploy/commit/6651279c49f431dbddf6fd5d810440ae7b3b9898)) + ## [10.0.0-66](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-65...v10.0.0-66) (2025-12-03) diff --git a/package-lock.json b/package-lock.json index 184b9874da..452c2770cb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-66", + "version": "10.0.0-67", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-66", + "version": "10.0.0-67", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 307e43542b..377855c416 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-66", + "version": "10.0.0-67", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From fbc63b0308d87d921e1d74788e8da6031443e57e Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 8 Dec 2025 15:40:42 +1100 Subject: [PATCH 0767/1280] fix: only trim if valid --- src/app/api/models/user/user.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/models/user/user.ts b/src/app/api/models/user/user.ts index 03a281bf12..b11826505a 100644 --- a/src/app/api/models/user/user.ts +++ b/src/app/api/models/user/user.ts @@ -54,7 +54,7 @@ export class User extends Entity { } public get preferredName(): string { - const nickname = this.nickname.trim(); + const nickname = this.nickname?.trim(); const firstName = this.firstName.trim(); if (nickname) { return nickname; From 520be4a74735e9dd9fe9ab511208b48e2fcff152 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 8 Dec 2025 15:43:11 +1100 Subject: [PATCH 0768/1280] chore(release): 10.0.0-68 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index eb4dacb6a1..6bf63acef3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-68](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-67...v10.0.0-68) (2025-12-08) + + +### Bug Fixes + +* only trim if valid ([fbc63b0](https://github.com/b0ink/doubtfire-deploy/commit/fbc63b0308d87d921e1d74788e8da6031443e57e)) + ## [10.0.0-67](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-66...v10.0.0-67) (2025-12-03) diff --git a/package-lock.json b/package-lock.json index 452c2770cb..7d80fd42ec 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-67", + "version": "10.0.0-68", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-67", + "version": "10.0.0-68", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 377855c416..5bd6fc814f 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-67", + "version": "10.0.0-68", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 2674d4e5ade26e5420b87518f4cd9da909ec7246 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 9 Dec 2025 11:20:45 +1100 Subject: [PATCH 0769/1280] feat: display number of stuff notes in tutor discussion --- .../states/tutor-discussion/tutor-discussion.component.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html index f38d42764b..87703c8b6b 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html @@ -215,7 +215,10 @@

    {{ task.definition.name }}

    - + From 15365ed4f42af790af9a9ae24dae42f041dff1df Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Fri, 12 Dec 2025 12:26:45 +1100 Subject: [PATCH 0770/1280] feat: attention required task status (#1061) * feat: init discuss check task status * refactor: add discuss check status * refactor: add discuss and check marking button * refactor: add warning badge to discuss check tasks * refactor: update discuss check status description * refactor: update discuss check description * chore: ensure discuss check status does not unlock requisite tasks * refactor: rename to off track * refactor: rename to attention required * refactor: update status colors * refactor: rename to attention required internally * chore: update assess in portfolio color --- src/app/api/models/task-prerequisite.ts | 1 + src/app/api/models/task-status.ts | 84 +++++++++++++++---- src/app/common/footer/footer.component.html | 45 ++++++---- .../status-icon/status-icon.component.scss | 3 + .../tutor-discussion.component.html | 6 +- .../tutor-discussion.component.ts | 1 + ...task-definition-prerequisites.component.ts | 1 + src/styles/common/task-status-colors.scss | 12 ++- src/styles/mixins/task-list.scss | 6 ++ .../mixins/task-status-colors-generator.scss | 3 + src/styles/modules/project-task-bar.scss | 6 ++ src/styles/modules/task-status.scss | 14 ++++ 12 files changed, 144 insertions(+), 38 deletions(-) diff --git a/src/app/api/models/task-prerequisite.ts b/src/app/api/models/task-prerequisite.ts index 510d6ce3b6..9645adfe5b 100644 --- a/src/app/api/models/task-prerequisite.ts +++ b/src/app/api/models/task-prerequisite.ts @@ -23,6 +23,7 @@ export class TaskPrerequisite extends Entity { ready_for_feedback: 1, assess_in_portfolio: 1, discuss: 2, + attention_required: 0, demonstrate: 2, complete: 3, }; diff --git a/src/app/api/models/task-status.ts b/src/app/api/models/task-status.ts index 4bff84e86c..0933627924 100644 --- a/src/app/api/models/task-status.ts +++ b/src/app/api/models/task-status.ts @@ -1,4 +1,4 @@ -import { Task } from './task'; +import {Task} from './task'; export type TaskStatusEnum = | 'not_started' @@ -13,14 +13,15 @@ export type TaskStatusEnum = | 'complete' | 'fail' | 'time_exceeded' - | 'assess_in_portfolio'; + | 'assess_in_portfolio' + | 'attention_required'; export type TaskStatusUiData = { status: TaskStatusEnum; icon: string; label: string; class: string; - help: { detail: string; reason: string; action: string }; + help: {detail: string; reason: string; action: string}; }; export class TaskStatus { @@ -38,6 +39,7 @@ export class TaskStatus { 'fail', 'time_exceeded', 'assess_in_portfolio', + 'attention_required', ]; public static readonly VALID_TOP_TASKS: TaskStatusEnum[] = [ @@ -48,6 +50,7 @@ export class TaskStatus { 'fix_and_resubmit', 'ready_for_feedback', 'discuss', + 'attention_required', 'demonstrate', ]; @@ -60,6 +63,7 @@ export class TaskStatus { 'fail', 'time_exceeded', 'assess_in_portfolio', + 'attention_required', ]; public static readonly FINAL_STATUSES: TaskStatusEnum[] = [ @@ -70,11 +74,25 @@ export class TaskStatus { 'assess_in_portfolio', ]; - public static readonly GRADEABLE_STATUSES: TaskStatusEnum[] = ['fail', 'discuss', 'demonstrate', 'complete']; + public static readonly GRADEABLE_STATUSES: TaskStatusEnum[] = [ + 'fail', + 'discuss', + 'demonstrate', + 'complete', + ]; - public static readonly TO_BE_WORKED_ON: TaskStatusEnum[] = ['not_started', 'redo', 'need_help', 'working_on_it']; + public static readonly TO_BE_WORKED_ON: TaskStatusEnum[] = [ + 'not_started', + 'redo', + 'need_help', + 'working_on_it', + ]; - public static readonly DISCUSSION_STATES: TaskStatusEnum[] = ['discuss', 'demonstrate']; + public static readonly DISCUSSION_STATES: TaskStatusEnum[] = [ + 'discuss', + 'attention_required', + 'demonstrate', + ]; public static readonly STATE_THAT_ALLOWS_EXTENSION: TaskStatusEnum[] = [ 'not_started', @@ -112,6 +130,7 @@ export class TaskStatus { 'discuss', 'demonstrate', 'complete', + 'attention_required', ]; public static readonly FEEDBACK_TEMPLATE_STATUSES: TaskStatusEnum[] = [ @@ -120,9 +139,13 @@ export class TaskStatus { 'fix_and_resubmit', 'redo', 'feedback_exceeded', + 'attention_required', ]; - public static readonly LEARNING_WEIGHT: Map = new Map([ + public static readonly LEARNING_WEIGHT: Map = new Map< + TaskStatusEnum, + number + >([ ['fail', 0.0], ['not_started', 0.0], ['working_on_it', 0.0], @@ -135,10 +158,14 @@ export class TaskStatus { ['demonstrate', 0.8], ['complete', 1.0], ['time_exceeded', 0.3], - ['assess_in_portfolio', 0.0], + ['assess_in_portfolio', 1.0], + ['attention_required', 0.1], ]); - public static readonly STATUS_ACRONYM: Map = new Map([ + public static readonly STATUS_ACRONYM: Map = new Map< + TaskStatusEnum, + string + >([ ['ready_for_feedback', 'RFF'], ['not_started', 'NOS'], ['working_on_it', 'WRK'], @@ -152,6 +179,7 @@ export class TaskStatus { ['fail', 'FAL'], ['time_exceeded', 'TIE'], ['assess_in_portfolio', 'AIP'], + ['attention_required', 'AR'], ]); // Which status should not show up in the task status drop down... for students @@ -172,6 +200,7 @@ export class TaskStatus { ['time_exceeded', ['ready_for_feedback', 'not_started', 'working_on_it', 'need_help']], ['fail', ['ready_for_feedback', 'not_started', 'working_on_it', 'need_help']], ['assess_in_portfolio', ['not_started']], + ['attention_required', ['ready_for_feedback', 'not_started', 'working_on_it', 'need_help']], ]); public static readonly STATUS_LABELS = new Map([ @@ -188,6 +217,7 @@ export class TaskStatus { ['fail', 'Fail'], ['time_exceeded', 'Time Exceeded'], ['assess_in_portfolio', 'Assess in Portfolio'], + ['attention_required', 'Attention Required'], ]); public static readonly STATUS_ICONS = new Map([ @@ -204,6 +234,7 @@ export class TaskStatus { ['fail', 'fa fa-times'], ['time_exceeded', 'fa fa-clock-o'], ['assess_in_portfolio', 'fa fa-folder-open'], + ['attention_required', 'fa fa-commenting'], ]); // Please make sure this matches task-status-colors.less @@ -220,7 +251,8 @@ export class TaskStatus { ['complete', '#5BB75B'], ['fail', '#d93713'], ['time_exceeded', '#d93713'], - ['assess_in_portfolio', '#91b891'], + ['assess_in_portfolio', '#f2d85c'], + ['attention_required', '#f1814d'], ]); public static readonly STATUS_SEQ = new Map([ @@ -237,6 +269,7 @@ export class TaskStatus { ['demonstrate', 11], ['complete', 12], ['assess_in_portfolio', 13], + ['attention_required', 14], ]); public static readonly SWITCHABLE_STATES = { @@ -244,6 +277,7 @@ export class TaskStatus { tutor: [ 'complete', 'discuss', + 'attention_required', 'demonstrate', 'fix_and_resubmit', 'redo', @@ -258,14 +292,16 @@ export class TaskStatus { // action = action student can take public static readonly HELP_DESCRIPTIONS = new Map< TaskStatusEnum, - { detail: string; reason: string; action: string } + {detail: string; reason: string; action: string} >([ [ 'ready_for_feedback', { detail: 'Submitted this task for feedback', - reason: 'You have finished working on the task and have uploaded it for your tutor to assess.', - action: 'No further action is required. Your tutor will change this task status once they have assessed it.', + reason: + 'You have finished working on the task and have uploaded it for your tutor to assess.', + action: + 'No further action is required. Your tutor will change this task status once they have assessed it.', }, ], [ @@ -289,7 +325,8 @@ export class TaskStatus { { detail: 'Need help for the task', reason: 'You are working on the task but would like some help to get it complete.', - action: 'Upload the task with what you have completed so far and add a comment on what you would like help on.', + action: + 'Upload the task with what you have completed so far and add a comment on what you would like help on.', }, ], [ @@ -306,7 +343,8 @@ export class TaskStatus { 'feedback_exceeded', { detail: 'Feedback will no longer be given', - reason: 'This work is not complete to an acceptable standard and your tutor will not reassess it again.', + reason: + 'This work is not complete to an acceptable standard and your tutor will not reassess it again.', action: "It is now your responsibility to ensure this task is at an adequate standard in your portfolio. You should fix your work according to your tutor's prior feedback and include a corrected version in your portfolio.", }, @@ -329,6 +367,16 @@ export class TaskStatus { action: 'For this to be marked as complete, attend class and discuss it with your tutor.', }, ], + [ + 'attention_required', + { + detail: 'Your work is off track and needs focused discussion.', + reason: + 'It seems you have misunderstood some key requirements for this task. Previous feedback has not led to sufficient progress.', + action: + 'Attend class so your tutor can go through your work in detail and help you get back on track.', + }, + ], [ 'demonstrate', { @@ -343,7 +391,8 @@ export class TaskStatus { { detail: 'You are finished with this task 🎉', reason: 'Your tutor is happy with your work and it has been discussed with them.', - action: 'No further action required. Move onto the next task, or go party if everything is done.', + action: + 'No further action required. Move onto the next task, or go party if everything is done.', }, ], [ @@ -359,7 +408,8 @@ export class TaskStatus { 'time_exceeded', { detail: 'Time limit exceeded', - reason: 'This work was submitted after the deadline, having missed both the target date and deadline.', + reason: + 'This work was submitted after the deadline, having missed both the target date and deadline.', action: 'Work submitted after the feedback deadline will not be checked by tutors prior to the portfolio assessment. You will need to ensure this task is at an adequate standard in your portfolio.', }, diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index e7d84ac5e5..a31bf9fac8 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -14,18 +14,32 @@
    - - + +
    + + + +
    - + @if (selectedTask && selectedTask.suggestedTaskStatus) { - } @if (selectedTask?.definition?.assessInPortfolioOnly) { -
    + + +

    } diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts index 801482ec4d..f08edf198c 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts @@ -352,6 +352,7 @@ export class TutorDiscussionComponent implements AfterViewInit { 'demonstrate', 'ready_for_feedback', 'discuss', + 'attention_required', 'need_help', // 'complete', 'fix_and_resubmit', diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts index eff30b4bd3..2528ffcd6d 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts @@ -37,6 +37,7 @@ export class TaskDefinitionPrerequisitesComponent implements OnInit, OnChanges { ready_for_feedback: 1, assess_in_portfolio: 1, discuss: 2, + attention_required: 0, demonstrate: 2, complete: 3, }; diff --git a/src/styles/common/task-status-colors.scss b/src/styles/common/task-status-colors.scss index 563e2cf038..3e045a4406 100644 --- a/src/styles/common/task-status-colors.scss +++ b/src/styles/common/task-status-colors.scss @@ -85,9 +85,15 @@ $task-status-colors: ( fore: $task-status-foreground-color-light, ), assess-in-portfolio: ( - base: #91b891, - dark: darken(#91b891, 15%), - light: lighten(#91b891, 15%), + base: #f2d85c, + dark: darken(#f2d85c, 15%), + light: lighten(#f2d85c, 15%), + fore: $task-status-foreground-color-dark, + ), + attention-required: ( + base: #f1814d, + dark: darken(#f1814d, 15%), + light: lighten(#f1814d, 15%), fore: $task-status-foreground-color-light, ), ); diff --git a/src/styles/mixins/task-list.scss b/src/styles/mixins/task-list.scss index 5684822871..63af66d655 100644 --- a/src/styles/mixins/task-list.scss +++ b/src/styles/mixins/task-list.scss @@ -81,6 +81,9 @@ &.assess-in-portfolio { @include custom-box-shadow(lighten(task-status-color('assess-in-portfolio'), 15%)); } + &.attention-required { + @include custom-box-shadow(lighten(task-status-color('attention-required'), 15%)); + } } &.selected { &.ready-for-feedback { @@ -122,6 +125,9 @@ &.assess-in-portfolio { @include custom-box-shadow(task-status-color('assess-in-portfolio')); } + &.attention-required { + @include custom-box-shadow(task-status-color('attention-required')); + } } .task-badges { width: 50px; diff --git a/src/styles/mixins/task-status-colors-generator.scss b/src/styles/mixins/task-status-colors-generator.scss index 4d0646ecd6..6f2b97e2c5 100644 --- a/src/styles/mixins/task-status-colors-generator.scss +++ b/src/styles/mixins/task-status-colors-generator.scss @@ -62,3 +62,6 @@ @mixin task-status-color-assess-in-portfolio { @include task-status-color('assess-in-portfolio'); } +@mixin task-status-color-attention-required { + @include task-status-color('attention-required'); +} diff --git a/src/styles/modules/project-task-bar.scss b/src/styles/modules/project-task-bar.scss index 78d15e07f6..d3af788607 100644 --- a/src/styles/modules/project-task-bar.scss +++ b/src/styles/modules/project-task-bar.scss @@ -76,6 +76,12 @@ .progress-bar-complete { @include task-status-color-complete; } +.progress-bar-assess-in-portfolio { + @include task-status-color-assess-in-portfolio; +} +.progress-bar-attention-required { + @include task-status-color-attention-required; +} .progress-bar-not-started { @include task-status-color-not-started; diff --git a/src/styles/modules/task-status.scss b/src/styles/modules/task-status.scss index ba7252f899..6ed7ea0f57 100644 --- a/src/styles/modules/task-status.scss +++ b/src/styles/modules/task-status.scss @@ -41,6 +41,9 @@ &.assess-in-portfolio { @include task-status-color-assess-in-portfolio; } + &.attention-required { + @include task-status-color-attention-required; + } &.ready-for-feedback:hover { background-color: task-status-color('ready-for-feedback'); @@ -81,6 +84,9 @@ &.assess-in-portfolio:hover { background-color: task-status-color('assess-in-portfolio'); } + &.attention-required:hover { + background-color: task-status-color('attention-required'); + } } .task-status > .btn-default { @@ -149,6 +155,11 @@ &.assess-in-portfolio:hover { @include task-status-color-assess-in-portfolio; } + &.attention-required, + &.attention-required.active, + &.attention-required:hover { + @include task-status-color-attention-required; + } &.ready-for-feedback { background-color: lighten(task-status-color('ready-for-feedback'), 15%); @@ -189,6 +200,9 @@ &.assess-in-portfolio { background-color: lighten(task-status-color('assess-in-portfolio'), 15%); } + &.attention-required { + background-color: lighten(task-status-color('attention-required'), 15%); + } } i.task-status-icon { From 7cb8fc7471f0402c562fb8a0b87df672ceb22ea3 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 5 Jan 2026 15:01:53 +1100 Subject: [PATCH 0771/1280] feat: overseer pipeline (#1064) * feat: init overseer pipeline ui * chore: init drag and drop steps panel * feat: init overseer-step crud * feat: use new monaco editor package * refactor: clean up ui * feat: get list of overseer resource files * chore: allow no input file * feat: allow partial input output diff check * feat: allow deleting of overseer steps * feat: overseer step result model * refactor: improve overseer report view * refactor: organise imports * refactor: retrieve feedback message * refactor: expose overseer assessment details to task comment * feat: dropdown for command language * fix: set fixed height size * chore: show overseer reports to students * build: ensure monaco editor is packed correctly * refactor: lazy load step results for overseer assessments * refactor: align default feedback messages with the backend * refactor: improve assessment comment ui * chore: ignore old assessment script * refactor: hide test result until report is ready * fix: use new overseer report component for test submission history * chore: allow for overseer report refresh * refactor: reduce icon size * refactor: auto expand selected overseer report * chore: enable submission history if project is valid * chore: delete new step * chore: set correct overseer steps when changing task definition * feat: add overseer task status result * chore: add hint explaining test submissions can be used before enabling overseer * refactor: hide overseer steps until docker image has been selected * chore: move overseer editor to original place * refactor: ensure task definition is saved before adding overseer steps * chore: show delete and save buttons when step is selected * refactor: use seconds for overseer timeout * refactor: show status dropdown only when halting step * refactor: cleanup * chore: render diff if overseer step is null * refactor: remove debug * chore: show empty overseer reports --- angular.json | 8 + package-lock.json | 47 +-- package.json | 3 +- .../models/overseer/overseer-assessment.ts | 23 +- .../models/overseer/overseer-step-result.ts | 35 ++ src/app/api/models/overseer/overseer-step.ts | 75 ++++ src/app/api/models/task-definition.ts | 4 + src/app/api/models/task.ts | 6 +- .../services/overseer-assessment.service.ts | 28 +- .../services/overseer-step-result.service.ts | 52 +++ src/app/api/services/overseer-step.service.ts | 47 +++ src/app/api/services/task-comment.service.ts | 5 + .../api/services/task-definition.service.ts | 18 + src/app/common/footer/footer.component.ts | 6 +- .../task-assessment-modal.component.html | 16 +- .../task-assessment-modal.component.ts | 7 +- .../task-assessment-modal.service.ts | 35 +- src/app/doubtfire-angular.module.ts | 13 +- src/app/doubtfire-angularjs.module.ts | 6 + .../task-overseer-report.component.html | 167 ++++++++ .../task-overseer-report.component.scss | 0 .../task-overseer-report.component.ts | 145 +++++++ .../task-dashboard/task-dashboard.coffee | 2 +- .../task-dashboard.component.html | 4 + .../task-dashboard/task-dashboard.tpl.html | 14 +- .../states/dashboard/selected-task.service.ts | 5 + .../task-assessment-comment.component.html | 58 ++- .../task-assessment-comment.component.scss | 56 --- .../task-assessment-comment.component.ts | 24 +- .../task-definition-overseer.component.html | 376 +++++++++++++++++- .../task-definition-overseer.component.scss | 50 +++ .../task-definition-overseer.component.ts | 206 +++++++++- 32 files changed, 1383 insertions(+), 158 deletions(-) create mode 100644 src/app/api/models/overseer/overseer-step-result.ts create mode 100644 src/app/api/models/overseer/overseer-step.ts create mode 100644 src/app/api/services/overseer-step-result.service.ts create mode 100644 src/app/api/services/overseer-step.service.ts create mode 100644 src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html create mode 100644 src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.scss create mode 100644 src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts diff --git a/angular.json b/angular.json index cf6bc6bd32..0d892151bd 100644 --- a/angular.json +++ b/angular.json @@ -29,8 +29,16 @@ "input": "./JPlag-Report-Viewer", "output": "/JPlag", "glob": "**/!(*.gitignore|README.md|.git)" + }, + { + "glob": "**/*", + "input": "./node_modules/monaco-editor/min", + "output": "/assets/monaco/min/" } ], + "loader": { + ".ttf": "binary" + }, "styles": [ "src/theme.scss", "src/styles.scss", diff --git a/package-lock.json b/package-lock.json index 7d80fd42ec..05dae886a7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -61,7 +61,7 @@ "lottie-web": "^5.12.2", "marked": "^11.1.0", "moment": "^2.29.4", - "monaco-editor": "^0.54.0", + "monaco-editor": "^0.44.0", "ng-csv": "0.2.3", "ng-file-upload": "~5.0.9", "ng-flex-layout": "^17.3.7-beta.1", @@ -69,6 +69,7 @@ "ngx-bootstrap": "^6.1.0", "ngx-entity-service": "^0.0.41", "ngx-lottie": "^11.0.2", + "ngx-monaco-editor-v2": "^17.0.1", "nvd3": "1.8.6", "qrcode": "^1.5.4", "rxjs": "~7.4.0", @@ -9254,12 +9255,6 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, - "node_modules/dompurify": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.7.tgz", - "integrity": "sha512-VaTstWtsneJY8xzy7DekmYWEOZcmzIe3Qb3zPd4STve1OBTa+e+WmS1ITQec1fZYXI3HCsOZZiSMpG6oxoWMWQ==", - "license": "(MPL-2.0 OR Apache-2.0)" - }, "node_modules/domutils": { "version": "3.1.0", "dev": true, @@ -15766,26 +15761,10 @@ } }, "node_modules/monaco-editor": { - "version": "0.54.0", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.54.0.tgz", - "integrity": "sha512-hx45SEUoLatgWxHKCmlLJH81xBo0uXP4sRkESUpmDQevfi+e7K1VuiSprK6UpQ8u4zOcKNiH0pMvHvlMWA/4cw==", - "license": "MIT", - "dependencies": { - "dompurify": "3.1.7", - "marked": "14.0.0" - } - }, - "node_modules/monaco-editor/node_modules/marked": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", - "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", - "license": "MIT", - "bin": { - "marked": "bin/marked.js" - }, - "engines": { - "node": ">= 18" - } + "version": "0.44.0", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.44.0.tgz", + "integrity": "sha512-5SmjNStN6bSuSE5WPT2ZV+iYn1/yI9sd4Igtk23ChvqB7kDk9lZbB9F5frsuvpB+2njdIeGGFf2G4gbE6rCC9Q==", + "license": "MIT" }, "node_modules/morgan": { "version": "1.10.0", @@ -16126,6 +16105,20 @@ "lottie-web": ">=5.9.2" } }, + "node_modules/ngx-monaco-editor-v2": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/ngx-monaco-editor-v2/-/ngx-monaco-editor-v2-17.0.1.tgz", + "integrity": "sha512-GP+Ni6zKFQjF/ve5ZQtfE9eRLKL4GxMvdmDTrla1x6F5pSIcYGCcjZ4gQ1/AHMa5dgarfs+Et+1bBtAOJtI6KA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.1.0" + }, + "peerDependencies": { + "@angular/common": "^17.0.3", + "@angular/core": "^17.0.3", + "monaco-editor": "^0.44.0" + } + }, "node_modules/nice-napi": { "version": "1.0.2", "dev": true, diff --git a/package.json b/package.json index 5bd6fc814f..d3eeccad5d 100644 --- a/package.json +++ b/package.json @@ -80,7 +80,7 @@ "lottie-web": "^5.12.2", "marked": "^11.1.0", "moment": "^2.29.4", - "monaco-editor": "^0.54.0", + "monaco-editor": "^0.44.0", "ng-csv": "0.2.3", "ng-file-upload": "~5.0.9", "ng-flex-layout": "^17.3.7-beta.1", @@ -88,6 +88,7 @@ "ngx-bootstrap": "^6.1.0", "ngx-entity-service": "^0.0.41", "ngx-lottie": "^11.0.2", + "ngx-monaco-editor-v2": "^17.0.1", "nvd3": "1.8.6", "qrcode": "^1.5.4", "rxjs": "~7.4.0", diff --git a/src/app/api/models/overseer/overseer-assessment.ts b/src/app/api/models/overseer/overseer-assessment.ts index dcffd8fd4f..005b6be09f 100644 --- a/src/app/api/models/overseer/overseer-assessment.ts +++ b/src/app/api/models/overseer/overseer-assessment.ts @@ -1,20 +1,28 @@ -import {Entity, EntityMapping} from 'ngx-entity-service'; +import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; import {Task} from '../doubtfire-model'; +import {OverseerStepResult} from './overseer-step-result'; export class OverseerAssessment extends Entity { id: number; + // overseerStepId: number; timestamp: Date; timestampString: string; content?: [{label: string; result: string}]; task?: Task; taskStatus?: string; - submissionStatus?: string; + submissionStatus?: 'queued' | 'executing' | 'passed' | 'failed' | 'error'; createdAt?: Date; updatedAt?: Date; taskId?: number; + totalSteps: number; + passedSteps: number; + label: string; + public readonly stepResultsCache: EntityCache = + new EntityCache(); + constructor(task?: Task) { super(); @@ -31,4 +39,15 @@ export class OverseerAssessment extends Entity { overseer_assessment: super.toJson(mappingData, ignoreKeys), }; } + + public get stepsSkipped() { + return this.task?.definition.overseerStepsCache.currentValues.filter( + (step) => + !this.stepResultsCache.currentValues.find((result) => result.overseerStepId === step.id), + ); + } + + public get reportReady() { + return this.submissionStatus === 'passed' || this.submissionStatus === 'failed'; + } } diff --git a/src/app/api/models/overseer/overseer-step-result.ts b/src/app/api/models/overseer/overseer-step-result.ts new file mode 100644 index 0000000000..2a44371825 --- /dev/null +++ b/src/app/api/models/overseer/overseer-step-result.ts @@ -0,0 +1,35 @@ +import {Entity, EntityMapping} from 'ngx-entity-service'; +import {OverseerAssessment} from './overseer-assessment'; +import {OverseerStep} from './overseer-step'; + +export class OverseerStepResult extends Entity { + id: number; + overseerAssessment: OverseerAssessment; + overseerStep: OverseerStep; + overseerStepId: number; + + exitStatus: number; + pass: boolean; + stdout: string; + stdin: string; + expectedOutput: string; + stdoutSha256: string; + stdinSha256: string; + expectedOutputSha256: string; + feedbackMessage: string; + + constructor(oa?: OverseerAssessment, os?: OverseerStep) { + super(); + this.overseerAssessment = oa; + // this.overseerStep = os; + } + + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { + return { + overseer_step_result: super.toJson(mappingData, ignoreKeys), + }; + } +} diff --git a/src/app/api/models/overseer/overseer-step.ts b/src/app/api/models/overseer/overseer-step.ts new file mode 100644 index 0000000000..5d2a03ee28 --- /dev/null +++ b/src/app/api/models/overseer/overseer-step.ts @@ -0,0 +1,75 @@ +import {Entity, EntityMapping} from 'ngx-entity-service'; +import {TaskDefinition} from '../task-definition'; +import {TaskStatus, TaskStatusEnum} from '../task-status'; +import {OverseerStepService} from '../../services/overseer-step.service'; +import {AppInjector} from 'src/app/app-injector'; +import {AlertService} from 'src/app/common/services/alert.service'; + +export class OverseerStep extends Entity { + id: number; + taskDefinition: TaskDefinition; + + name: string; + description: string; + + // Shown to the student's + displayName: string; + displayDescription: string; + + runCommand: string; + commandLanguage: string; + timeout: number; + sortOrder: number; + stepType: 'status_check' | 'output_diff'; + partialOutputDiff: boolean; + stdinInputFile: string; + expectedOutputFile: string; + + feedbackMessage: string; + statusOnSuccess: TaskStatusEnum | 'no_change'; + statusOnFailure: TaskStatusEnum | 'no_change'; + + haltOnSuccess: boolean; + haltOnFailure: boolean; + + showExpectedOutput: boolean; + showStdin: boolean; + showStdout: boolean; + + enabled: boolean; + + // showStdOutToStudent: boolean + + constructor(td?: TaskDefinition) { + super(); + this.taskDefinition = td; + } + + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { + return { + overseer_step: super.toJson(mappingData, ignoreKeys), + }; + } + + public delete() { + const overseerStepService: OverseerStepService = AppInjector.get(OverseerStepService); + overseerStepService + .delete( + { + id: this.id, + }, + {cache: this.taskDefinition.overseerStepsCache, endpointFormat: 'overseer_steps/:id:'}, + ) + .subscribe({ + next: (_response: object) => { + AppInjector.get(AlertService).success('Successfully deleted overseer step', 4000); + }, + error: (error) => { + AppInjector.get(AlertService).error(error?.message || error || 'Unknown error', 2000); + }, + }); + } +} diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index d3aa2a4317..4a47a7ab96 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -9,6 +9,7 @@ import {Grade, GroupSet, LearningOutcome, Project, TutorialStream, Unit} from '. import {Task} from './doubtfire-model'; import {TaskPrerequisite} from './task-prerequisite'; import {DiscussionPrompt} from './discussion-prompt'; +import {OverseerStep} from './overseer/overseer-step'; export type UploadRequirement = { key: string; @@ -59,6 +60,7 @@ export class TaskDefinition extends Entity { useResourcesForJplagBaseCode: boolean; lockAssessmentsToTutorialStream: boolean; discussionPromptsCount: number; + overseerResourceFiles: string[] = []; public readonly taskPrerequisitesCache: EntityCache = new EntityCache(); @@ -69,6 +71,8 @@ export class TaskDefinition extends Entity { public readonly learningOutcomesCache: EntityCache = new EntityCache(); + public readonly overseerStepsCache: EntityCache = new EntityCache(); + readonly unit: Unit; constructor(unit: Unit) { diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index c920e985a7..d624a8285d 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -579,11 +579,7 @@ export class Task extends Entity { } public get overseerEnabled(): boolean { - return ( - this.unit.overseerEnabled && - this.definition.assessmentEnabled && - this.definition.hasTaskAssessmentResources - ); + return this.unit.overseerEnabled && this.definition.assessmentEnabled; } public get scormEnabled(): boolean { diff --git a/src/app/api/services/overseer-assessment.service.ts b/src/app/api/services/overseer-assessment.service.ts index 2226887caf..df897e43be 100644 --- a/src/app/api/services/overseer-assessment.service.ts +++ b/src/app/api/services/overseer-assessment.service.ts @@ -5,6 +5,7 @@ import {HttpClient} from '@angular/common/http'; import API_URL from 'src/app/config/constants/apiUrl'; import {OverseerAssessment} from '../models/overseer/overseer-assessment'; import {Task} from '../models/doubtfire-model'; +import {OverseerStepResultService} from './overseer-step-result.service'; @Injectable() export class OverseerAssessmentService extends EntityService { @@ -13,7 +14,10 @@ export class OverseerAssessmentService extends EntityService protected readonly triggerEndpointFormat = 'projects/:project_id:/task_def_id/:td_id:/overseer_assessment/:id:/trigger'; - constructor(httpClient: HttpClient) { + constructor( + httpClient: HttpClient, + private overseerStepResultService: OverseerStepResultService, + ) { super(httpClient, API_URL); this.mapping.addKeys( @@ -31,6 +35,24 @@ export class OverseerAssessmentService extends EntityService }, }, ['timestampString', 'submission_timestamp'], + { + keys: 'overseerStepResults', + toEntityOp: (data: object, key: string, overseerAssesment: OverseerAssessment) => { + data[key]?.forEach((overseerStep) => { + overseerAssesment.stepResultsCache.getOrCreate( + overseerStep['id'], + this.overseerStepResultService, + overseerStep, + { + constructorParams: overseerAssesment, + }, + ); + }); + }, + }, + 'overseerStepId', + 'totalSteps', + 'passedSteps', ); } @@ -44,7 +66,9 @@ export class OverseerAssessmentService extends EntityService td_id: task.definition.id, }; - return this.query(pathIds); + return this.query(pathIds, { + constructorParams: task, + }); } public triggerOverseer(assessment: OverseerAssessment): Observable { diff --git a/src/app/api/services/overseer-step-result.service.ts b/src/app/api/services/overseer-step-result.service.ts new file mode 100644 index 0000000000..f7e873281b --- /dev/null +++ b/src/app/api/services/overseer-step-result.service.ts @@ -0,0 +1,52 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {OverseerAssessment} from '../models/doubtfire-model'; +import {OverseerStepResult} from '../models/overseer/overseer-step-result'; +import {Observable} from 'rxjs'; + +@Injectable() +export class OverseerStepResultService extends CachedEntityService { + protected readonly endpointFormat = + 'units/:unitId:/task_definitions/:taskDefId:/overseer_step_results/:id:'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'overseerStepId', + 'exitStatus', + 'pass', + 'feedbackMessage', + 'stdout', + 'stdin', + 'expectedOutput', + 'stdoutSha256', + 'stdinSha256', + 'expectedOutputSha256', + ); + + this.mapping.mapAllKeysToJsonExcept('id'); + } + + public createInstanceFrom(json: object, other?: any): OverseerStepResult { + return new OverseerStepResult(other as OverseerAssessment); + } + + public getOverseerStepResults(assessment: OverseerAssessment): Observable { + const pathIds = { + projectId: assessment.task.project.id, + taskDefId: assessment.task.definition.id, + id: assessment.id, + }; + + return this.query(pathIds, { + endpointFormat: + 'projects/:projectId:/task_definitions/:taskDefId:/overseer_assessments_results/:id:', + constructorParams: assessment.task, + cache: assessment.stepResultsCache, + }); + } +} diff --git a/src/app/api/services/overseer-step.service.ts b/src/app/api/services/overseer-step.service.ts new file mode 100644 index 0000000000..6df6323294 --- /dev/null +++ b/src/app/api/services/overseer-step.service.ts @@ -0,0 +1,47 @@ +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CachedEntityService} from 'ngx-entity-service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {OverseerStep} from '../models/overseer/overseer-step'; +import {TaskDefinition} from '../models/task-definition'; + +@Injectable() +export class OverseerStepService extends CachedEntityService { + protected readonly endpointFormat = + 'units/:unitId:/task_definitions/:taskDefId:/overseer_steps/:id:'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + // 'taskDefinition', + 'name', + 'description', + 'displayName', + 'displayDescription', + 'runCommand', + 'timeout', + 'sortOrder', + 'stepType', + 'partialOutputDiff', + 'stdinInputFile', + 'expectedOutputFile', + 'feedbackMessage', + 'statusOnSuccess', + 'statusOnFailure', + 'haltOnSuccess', + 'haltOnFailure', + 'showExpectedOutput', + 'showStdin', + 'showStdout', + 'enabled', + ); + + this.mapping.mapAllKeysToJsonExcept('id'); + } + + public createInstanceFrom(json: object, other?: any): OverseerStep { + return new OverseerStep(other as TaskDefinition); + } +} diff --git a/src/app/api/services/task-comment.service.ts b/src/app/api/services/task-comment.service.ts index b804b164b4..6761bc715c 100644 --- a/src/app/api/services/task-comment.service.ts +++ b/src/app/api/services/task-comment.service.ts @@ -120,6 +120,11 @@ export class TaskCommentService extends CachedEntityService { // Scorm Extension Comments ['taskScormExtensions', 'scorm_extensions'], + 'overseerAssessmentId', + 'overseerPassedSteps', + 'overseerTotalSteps', + 'overseerInProgress', + 'overseerStatus', ); this.mapping.addJsonKey('granted'); diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index 59664c143a..8e98e8175d 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -15,6 +15,7 @@ import {TaskPrerequisiteService} from './task-prerequisite.service'; import {TaskPrerequisite} from '../models/task-prerequisite'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {SidekiqJob} from '../models/sidekiq-job'; +import {OverseerStepService} from './overseer-step.service'; @Injectable() export class TaskDefinitionService extends CachedEntityService { @@ -24,6 +25,7 @@ export class TaskDefinitionService extends CachedEntityService { httpClient: HttpClient, private learningOutcomeService: LearningOutcomeService, private taskPrerequisiteService: TaskPrerequisiteService, + private overseerStepService: OverseerStepService, ) { super(httpClient, API_URL); @@ -140,6 +142,22 @@ export class TaskDefinitionService extends CachedEntityService { }, 'useResourcesForJplagBaseCode', 'lockAssessmentsToTutorialStream', + { + keys: 'overseerSteps', + toEntityOp: (data: object, key: string, taskDefinition: TaskDefinition) => { + data[key]?.forEach((overseerStep) => { + taskDefinition.overseerStepsCache.getOrCreate( + overseerStep['id'], + this.overseerStepService, + overseerStep, + { + constructorParams: taskDefinition, + }, + ); + }); + }, + }, + 'overseerResourceFiles', ); this.mapping.mapAllKeysToJsonExcept( diff --git a/src/app/common/footer/footer.component.ts b/src/app/common/footer/footer.component.ts index 295b8612ee..fa44839024 100644 --- a/src/app/common/footer/footer.component.ts +++ b/src/app/common/footer/footer.component.ts @@ -99,8 +99,12 @@ export class FooterComponent implements OnInit { this.selectedTaskService.showSimilarity(); } + // viewOverseer() { + // this.taskAssessmentModal.show(this.selectedTask); + // } + viewOverseer() { - this.taskAssessmentModal.show(this.selectedTask); + this.selectedTaskService.showOverseerReports(); } viewStaffNotes() { diff --git a/src/app/common/modals/task-assessment-modal/task-assessment-modal.component.html b/src/app/common/modals/task-assessment-modal/task-assessment-modal.component.html index 080a65cfd6..4ac4445bfb 100644 --- a/src/app/common/modals/task-assessment-modal/task-assessment-modal.component.html +++ b/src/app/common/modals/task-assessment-modal/task-assessment-modal.component.html @@ -1,14 +1,20 @@

    Overseer Assessment

    - - + +
    @if (noDataFlag) { - + }
    diff --git a/src/app/common/modals/task-assessment-modal/task-assessment-modal.component.ts b/src/app/common/modals/task-assessment-modal/task-assessment-modal.component.ts index 06c8fb3246..13bd6e9236 100644 --- a/src/app/common/modals/task-assessment-modal/task-assessment-modal.component.ts +++ b/src/app/common/modals/task-assessment-modal/task-assessment-modal.component.ts @@ -2,6 +2,7 @@ import {Component, OnInit, Inject, Input} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {Subject} from 'rxjs'; import {Task} from 'src/app/api/models/doubtfire-model'; +import {TaskAssessmentModalData} from './task-assessment-modal.service'; @Component({ selector: 'task-assessment-modal', @@ -10,16 +11,18 @@ import {Task} from 'src/app/api/models/doubtfire-model'; }) export class TaskAssessmentModalComponent implements OnInit { @Input() task: Task; + @Input() overseerAssessmentId?: number; noDataFlag: boolean; refreshTrigger: Subject = new Subject(); constructor( public dialogRef: MatDialogRef, - @Inject(MAT_DIALOG_DATA) public data: any, + @Inject(MAT_DIALOG_DATA) public data: TaskAssessmentModalData, ) {} ngOnInit() { - this.task = this.data; + this.task = this.data.task; + this.overseerAssessmentId = this.data.overseerAssessmentId; } setNoDataFlag($event) { diff --git a/src/app/common/modals/task-assessment-modal/task-assessment-modal.service.ts b/src/app/common/modals/task-assessment-modal/task-assessment-modal.service.ts index 927c861a04..31e9bc54c9 100644 --- a/src/app/common/modals/task-assessment-modal/task-assessment-modal.service.ts +++ b/src/app/common/modals/task-assessment-modal/task-assessment-modal.service.ts @@ -1,21 +1,30 @@ -import { Injectable } from '@angular/core'; -import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog'; +import {Injectable} from '@angular/core'; +import {MatDialogRef, MAT_DIALOG_DATA, MatDialog} from '@angular/material/dialog'; import {TaskAssessmentModalComponent} from './task-assessment-modal.component'; +import {Task} from 'src/app/api/models/task'; + +export interface TaskAssessmentModalData { + task: Task; + overseerAssessmentId: number; +} @Injectable({ - providedIn: 'root' + providedIn: 'root', }) export class TaskAssessmentModalService { - constructor( - public dialog: MatDialog, - ) { } + constructor(public dialog: MatDialog) {} - public show(task: any) { - let dialogRef: MatDialogRef; - dialogRef = this.dialog.open(TaskAssessmentModalComponent, { - data: task, - width: '80%', - panelClass: 'submission-history-modal' - }); + public show(task: Task, overseerAssessmentId?: number) { + this.dialog.open( + TaskAssessmentModalComponent, + { + data: { + task: task, + overseerAssessmentId, + }, + width: '80%', + panelClass: 'submission-history-modal', + }, + ); } } diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 7938a4e274..86b5fc459d 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -43,9 +43,13 @@ import {UIRouterUpgradeModule} from '@uirouter/angular-hybrid'; import {MatDialogModule as MatDialogModuleNew} from '@angular/material/dialog'; import {AlertService} from 'src/app/common/services/alert.service'; import {AlertComponent} from 'src/app/common/services/alert.service'; +import {MatSidenavModule} from '@angular/material/sidenav'; import {setTheme} from 'ngx-bootstrap/utils'; +import {CodeEditorModule} from '@ngstack/code-editor'; +import {MonacoEditorModule} from 'ngx-monaco-editor-v2'; + import {AboutDoubtfireModalService} from 'src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.service'; import { D2lUnitDetailsFormComponent, @@ -295,12 +299,14 @@ import {AnalyticsTutorTimesComponent} from './units/states/analytics/directives/ import {MarkingSessionService} from './api/services/marking-session.service'; import {PortfolioIncludedTasksComponent} from './projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component'; import {OverseerScriptEditorModalComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component'; -import {CodeEditorModule} from '@ngstack/code-editor'; import {UploadGradesComponent} from './units/states/portfolios/upload-grades/upload-grades.component'; import {DiscussionPromptService} from './api/services/discussion-prompt.service'; import {DiscussionPromptsComponent} from './projects/states/discussion-prompts/discussion-prompts.component'; import {TaskDefinitionDiscussionPromptsComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component'; import {DiscussionPromptsViewComponent} from './projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component'; +import {OverseerStepService} from './api/services/overseer-step.service'; +import {TaskOverseerReportComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component'; +import {OverseerStepResultService} from './api/services/overseer-step-result.service'; // See https://stackoverflow.com/questions/55721254/how-to-change-mat-datepicker-date-format-to-dd-mm-yyyy-in-simplest-way/58189036#58189036 const MY_DATE_FORMAT = { @@ -460,6 +466,7 @@ const MY_DATE_FORMAT = { DiscussionPromptsComponent, TaskDefinitionDiscussionPromptsComponent, DiscussionPromptsViewComponent, + TaskOverseerReportComponent, ], providers: [ // Services we provide @@ -550,6 +557,8 @@ const MY_DATE_FORMAT = { TaskPrerequisiteService, MarkingSessionService, DiscussionPromptService, + OverseerStepService, + OverseerStepResultService, ], imports: [ FlexLayoutModule, @@ -613,6 +622,8 @@ const MY_DATE_FORMAT = { MatDialogModuleNew, CalendarModule.forRoot({provide: CalendarDateAdapter, useFactory: adapterFactory}), CodeEditorModule.forRoot(), + MatSidenavModule, + MonacoEditorModule.forRoot(), ], }) diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 8187457400..8d0fee5456 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -233,6 +233,7 @@ import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/dir import {PortfolioIncludedTasksComponent} from './projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component'; import {TaskSimilarityViewComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component'; import {UploadGradesComponent} from './units/states/portfolios/upload-grades/upload-grades.component'; +import {TaskOverseerReportComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component'; export const DoubtfireAngularJSModule = angular .module('doubtfire', [ @@ -575,3 +576,8 @@ DoubtfireAngularJSModule.directive( 'fUploadGrades', downgradeComponent({component: UploadGradesComponent}), ); + +DoubtfireAngularJSModule.directive( + 'fTaskOverseerReport', + downgradeComponent({component: TaskOverseerReportComponent}), +); diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html new file mode 100644 index 0000000000..5609881791 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html @@ -0,0 +1,167 @@ +
    + +
    + + @for (oa of overseerAssessments; track oa; let idx = $index) { + + + + + Submission {{ idx + 1 }}: {{ oa.timestamp | humanizedDate }} + @if (idx === 0) { + (Most recent) + } + + @if (oa.reportReady) { +
    + {{ oa.passedSteps }} / {{ oa.totalSteps }} + @if (oa.passedSteps === oa.totalSteps) { + done + } @else { + cancel + } +
    + } @else { +
    + Tests In Progress + +
    + } +
    + + + @for (result of oa.stepResultsCache.values | async; track result.id; let idx = $index) { + + + + Step {{ idx + 1 }}: {{ result.overseerStep?.displayName }} + @if (result.pass) { + done + } @else { + cancel + } + + + + + + @if (!result.pass) { +

    + {{ result.feedbackMessage }} +

    + } + + @if ( + result.expectedOutput && + result.expectedOutput !== result.stdout && + (result.overseerStep?.stepType === 'output_diff' || !result.overseerStep) + ) { +
    + + + + + + +
    + @if (viewOutput === 'diff' || viewOutput === 'split_diff') { + @if (result.expectedOutput !== result.stdout) { + + } + } @else if (viewOutput === 'your_output') { + + } @else if (viewOutput === 'expected_output') { + + } + } @else if (result.stdout) { +
    {{result.stdout}}
    + } @else if (result.pass) { +
    SUCCESS
    +
    + (No Output) +
    + } +
    + } + @if (loadingAssessments.has(oa.id)) { +
    + +
    + } @else { + @for (skipped of oa.stepsSkipped; track skipped.id; let idx = $index) { + + + + + + Step {{ oa.stepResultsCache.currentValues.length + idx + 1 }}: + {{ skipped?.displayName ?? '-' }} + (Skipped) + + + pause + + + } + } +
    +
    + } @empty { +
    + subtitles_off +
    No submission reports for this task.
    +
    + } +
    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.scss b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts new file mode 100644 index 0000000000..cf4c5a86ed --- /dev/null +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts @@ -0,0 +1,145 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {OverseerAssessment} from 'src/app/api/models/doubtfire-model'; +import {Task} from 'src/app/api/models/task'; +import {OverseerAssessmentService} from 'src/app/api/services/overseer-assessment.service'; +import {OverseerStepResultService} from 'src/app/api/services/overseer-step-result.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {TaskSubmissionService} from 'src/app/common/services/task-submission.service'; + +@Component({ + selector: 'f-task-overseer-report', + templateUrl: './task-overseer-report.component.html', + styleUrl: './task-overseer-report.component.scss', +}) +export class TaskOverseerReportComponent implements OnInit { + @Input() task: Task; + @Input() loadOverseerAssessmentId?: number; + + constructor( + private alerts: AlertService, + private submissions: TaskSubmissionService, + private overseerAssessmentService: OverseerAssessmentService, + private overseerStepResultsService: OverseerStepResultService, + ) {} + + public viewOutput: 'your_output' | 'expected_output' | 'diff' | 'split_diff' = 'your_output'; + + stdoutOptions = { + theme: 'vs-dark', + language: 'plaintext', + renderMinimap: false, + lineNumbers: false, + + minimap: { + enabled: false, + }, + }; + editorOptions = { + theme: 'vs', + language: 'text', + renderMinimap: false, + minimap: { + enabled: false, + }, + readOnly: true, + }; + + diffEditorOptions = { + theme: 'vs', + language: 'plaintext', + renderMinimap: false, + readOnly: true, + domReadOnly: true, + renderMarginRevertIcon: false, + enableSplitViewResizing: false, + useInlineViewWhenSpaceIsLimited: false, + renderSideBySideInlineBreakpoint: 1000, + renderSideBySide: true, + compactMode: true, + minimap: { + enabled: false, + }, + lineNumbers: 'off', + }; + + diff() { + this.diffEditorOptions.renderSideBySide = false; + this.diffEditorOptions.compactMode = true; + this.diffEditorOptions = {...this.diffEditorOptions}; + this.viewOutput = 'diff'; + } + + splitDiff() { + this.diffEditorOptions.renderSideBySide = true; + this.diffEditorOptions.compactMode = false; + this.diffEditorOptions = {...this.diffEditorOptions}; + setTimeout(() => { + this.viewOutput = 'split_diff'; + }, 100); + } + + submissionOutput() { + this.viewOutput = 'your_output'; + } + + expectedOutput() { + this.viewOutput = 'expected_output'; + } + + public overseerAssessments: OverseerAssessment[] = []; + + ngOnInit(): void { + this.loadAssessments(); + } + + loadAssessments(isRefresh: boolean = false) { + if (isRefresh) { + this.loadOverseerAssessmentId = null; + } + this.overseerAssessmentService.queryForTask(this.task).subscribe({ + next: (assessments) => { + this.overseerAssessments = assessments; + for (const oa of this.overseerAssessments) { + for (const result of oa.stepResultsCache.currentValues) { + result.overseerStep = this.task.definition.overseerStepsCache.currentValues.find( + (step) => step.id === result.overseerStepId, + ); + } + } + }, + error: (error) => { + this.alerts.error(`Failed to load overseer reports: ${error}`, 6000); + }, + }); + } + + loadingAssessments = new Set(); + + onAssessmentOpen(overseerAssesment: OverseerAssessment) { + if (this.loadOverseerAssessmentId === overseerAssesment.id) { + setTimeout(() => { + const el = document.getElementById(`oa-panel-${overseerAssesment.id}`); + el?.scrollIntoView({behavior: 'smooth', block: 'start'}); + }, 250); + } + + this.loadingAssessments.add(overseerAssesment.id); + + this.overseerStepResultsService.getOverseerStepResults(overseerAssesment).subscribe({ + next: () => { + for (const oa of this.overseerAssessments) { + for (const result of oa.stepResultsCache.currentValues) { + result.overseerStep = this.task.definition.overseerStepsCache.currentValues.find( + (step) => step.id === result.overseerStepId, + ); + } + } + this.loadingAssessments.delete(overseerAssesment.id); + }, + error: (error) => { + console.error(error); + this.loadingAssessments.delete(overseerAssesment.id); + }, + }); + } +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee index f70113800c..a5d9df4511 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee @@ -25,7 +25,7 @@ angular.module('doubtfire.projects.states.dashboard.directives.task-dashboard', # Is the current user a tutor? $scope.tutor = $stateParams.tutor # the ways in which the dashboard can be viewed - $scope.dashboardViews = ["details", "submission", "task", "similarities"] + $scope.dashboardViews = ["details", "submission", "task", "similarities", "overseer"] # set the current dashboard view to details by default updateCurrentView = -> diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html index df91328f92..fc861e5b34 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html @@ -16,6 +16,10 @@ + + + + diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html index 16d998bc0a..45893297a0 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.tpl.html @@ -2,7 +2,9 @@
    {{task.definition.name}} - {{task.definition.name}} + {{task.definition.name}} + @@ -94,6 +99,9 @@
    +
    + +
    diff --git a/src/app/projects/states/dashboard/selected-task.service.ts b/src/app/projects/states/dashboard/selected-task.service.ts index 204714694e..3385019a77 100644 --- a/src/app/projects/states/dashboard/selected-task.service.ts +++ b/src/app/projects/states/dashboard/selected-task.service.ts @@ -10,6 +10,7 @@ export enum DashboardViews { similarity, staff_notes, discussion_prompts, + overseer, } @Injectable({ @@ -67,6 +68,10 @@ export class SelectedTaskService { this.currentView$.next(DashboardViews.staff_notes); } + public showOverseerReports() { + this.currentView$.next(DashboardViews.overseer); + } + public showDiscussionPrompts() { this.currentView$.next(DashboardViews.discussion_prompts); } diff --git a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.html b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.html index d6d344fc06..4feda189a2 100644 --- a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.html +++ b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.html @@ -1,15 +1,49 @@ -
    -
    - -
    -
    -
    {{ comment.text }}
    - - -
    +
    + +
    +
    + +
    + @if (comment.overseerStatus === 'pre_queued') { + Tests In Progress + } @else if (comment.overseerStatus === 'passed') { + Tests Passed {{ comment.overseerPassedSteps }} / {{ comment.overseerTotalSteps }} + } @else if (comment.overseerStatus === 'failed') { + Tests Failed {{ comment.overseerPassedSteps }} / {{ comment.overseerTotalSteps }} + }
    - + +
    + + @if (comment.overseerStatus === 'passed') { + check_circle + } @else if (comment.overseerStatus === 'failed') { + highlight_off_outline + } @else if (comment.overseerStatus === 'pre_queued') { + + } + + @if (comment.overseerStatus !== 'pre_queued') { + + }
    diff --git a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.scss b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.scss index 816d3724e7..e69de29bb2 100644 --- a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.scss +++ b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.scss @@ -1,56 +0,0 @@ -div { - width: 100%; -} - -p { - color: #2c2c2c; - text-align: center; -} - -hr { - width: 100%; -} - -.hr-fade { - background: linear-gradient(to right, transparent, #9696969d, transparent); - width: 100%; - margin-top: 1px; -} - -.fade-text { - color: #9696969d; - opacity: 0.8; -} - -.hr-text { - margin: 0; - line-height: 1em; - position: relative; - outline: 0; - border: 0; - color: black; - text-align: center; - height: 1.5em; - opacity: 0.8; - &:before { - content: ""; - background: linear-gradient(to right, transparent, #9696969d, transparent); - position: absolute; - left: 0; - top: 50%; - width: 100%; - height: 1px; - } - &:after { - content: attr(data-content); - position: relative; - display: inline-block; - color: black; - - padding: 0 0.5em; - line-height: 1.5em; - - color: #9696969d; - background-color: #fff; - } -} diff --git a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts index ed2e404b26..a57f866649 100644 --- a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts @@ -1,8 +1,11 @@ -import { Component, OnInit, Input, Inject } from '@angular/core'; -import { TaskSubmissionService, TaskAssessmentResult } from 'src/app/common/services/task-submission.service'; -import { TaskAssessmentModalService } from 'src/app/common/modals/task-assessment-modal/task-assessment-modal.service'; -import { Task } from 'src/app/api/models/doubtfire-model'; -import { AlertService } from 'src/app/common/services/alert.service'; +import {Component, OnInit, Input, Inject} from '@angular/core'; +import { + TaskSubmissionService, + TaskAssessmentResult, +} from 'src/app/common/services/task-submission.service'; +import {TaskAssessmentModalService} from 'src/app/common/modals/task-assessment-modal/task-assessment-modal.service'; +import {Task} from 'src/app/api/models/doubtfire-model'; +import {AlertService} from 'src/app/common/services/alert.service'; export interface User { id: number; @@ -23,6 +26,11 @@ export interface TaskAssessmentComment { recipient_read_time?: Date; // new fields that extend regular Comment Interface. TODO: create a separate Comment entity and extend it. assessment_result?: TaskAssessmentResult; + overseerAssessmentId: number; + overseerPassedSteps: number; + overseerTotalSteps: number; + overseerInProgress: boolean; + overseerStatus: string; } @Component({ @@ -53,12 +61,12 @@ export class TaskAssessmentCommentComponent implements OnInit { return this.comment.assessment_result.assessment_output; } - showTaskAssessmentResult() { - this.modalService.show(this.task); + showTaskAssessmentResult(overseerAssessmentId?: number) { + this.modalService.show(this.task, overseerAssessmentId); } scroll(el: HTMLElement) { - el.scrollIntoView({ behavior: 'smooth' }); + el.scrollIntoView({behavior: 'smooth'}); } update(): void { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html index 0e5c521bcb..fb78832932 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html @@ -1,12 +1,19 @@
    - - Automation Enabled - +
    + + Automation Enabled + +
    + + You can add or modify Overseer steps while keeping this unchecked and use the test submission + feature. Once everything is ready, enable automation to apply it to all student submissions. + +
    Docker Image @@ -18,10 +25,6 @@ Docker image for Overseer - - upload_file Test Submission -
    + +
    + +@if (taskDefinition.overseerImageId) { + @if (!taskDefinitionHasChanges()) { +
    +
    + @if (this.selectedOverseerStep) { + + + } +
    +
    + + + +
    +
    Overseer Steps
    + @if (!newOverseerStep) { + + } +
    +
    + @for (step of overseerSteps; track step.id) { +
    + drag_indicator + {{ step.sortOrder }}. {{ step.name ?? 'Untitled Step' }} +
    + } + @if (newOverseerStep) { +
    + + {{ newOverseerStep.sortOrder }}. {{ newOverseerStep.name || 'Untitled Step' }} +
    + } + + +
    +
    + + @if (selectedOverseerStep) { + + + +
    + + Step Name + + Visible to staff only + + + Description + + Visible to staff only + +
    + + + Step Type + + Custom Script + Input/Output + + + + @if (selectedOverseerStep.stepType === 'output_diff') { +
    +
    + + Script Input File + + + (none) + @for (file of taskDefinition.overseerResourceFiles; track file) { + {{ file }} + } + + The selected file will be passed as standard input to the program when it + runs. + + + + Show input file to student + +
    +
    + + Expected Output File + + @for (file of taskDefinition.overseerResourceFiles; track file) { + {{ file }} + } + + Program output must exactly match this file to pass. + + + Show expected output file to student + +
    + Partial Output Comparison +
    + + If enabled, test passes if the expected output appears anywhere in the + student's output. Otherwise, only exact matches pass. + +
    +
    + + } + +
    +
    Execution Script
    + + Language + + @for (language of getLanguages; track language) { + {{ + language.id ?? language.aliases?.[0] ?? language.id + }} + } + + Visual use only + +
    + + + +
    + + + @if (selectedOverseerStep.stepType === 'status_check') { + This step passes only if the script exits with status 0. Any non-zero exit code + marks the step as failed. + } @else if (selectedOverseerStep.stepType === 'output_diff') { + The script output is compared against the expected output. If noisy warnings + cause failures, move that logic into a separate step. + } + +
    + + Time Limit (s) + + How long the code can execute for before overseer automatically kills the + process. A timeout will result in a failed test (Exit status 124) + +
    +
    + +
    + Halt on success + + @if (selectedOverseerStep.haltOnSuccess) { + + Status on Success + + No Change + @for (status of statusKeys; track status) { + {{ statusName(status) }} + } + + + } +
    +
    + +
    + +
    + + Halt on failure + + @if (selectedOverseerStep.haltOnFailure) { + + + Status on Fail + + No Change + @for (status of statusKeys; track status) { + {{ statusName(status) }} + } + + + } +
    +
    +
    + + +
    + + + Test Name + + Shown to student in overseer report + + + Description + + Shown to student in overseer report + +
    + + Feedback message + + Feedback to provide to the student if the task failed. You can leave this blank + and a default will message will be used instead. + + + +
    + Enabled +
    + + If disabled, this step will not run and will not appear in the Overseer report for + students. + +
    + +
    + Show output +
    + + When enabled, students can see this step’s standard output, including script + output, program output, and compile errors. + +
    +
    +
    + } @else { +
    + No steps selected + tab_unselected +
    + } +
    +
    + } @else { +
    + Please save the task definition before configuring the overseer steps. +
    + } +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.scss b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.scss index e69de29bb2..ff10c528b0 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.scss +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.scss @@ -0,0 +1,50 @@ +.example-list { + width: 300px; + max-width: 100%; + border: solid 1px #ccc; + min-height: 50px; + height: 100%; + display: block; + background: white; + // border-radius: 4px; + overflow: hidden; +} + +.example-box { + padding: 20px 10px; + border-bottom: solid 1px #ccc; + height: 50px; + color: rgba(0, 0, 0, 0.87); + display: flex; + flex-direction: row; + align-items: center; + // justify-content: space-between; + box-sizing: border-box; + cursor: pointer; + background: white; + font-size: 14px; + font-family: sans-serif; + user-select: none; +} + +.cdk-drag-preview { + border: none; + box-sizing: border-box; + border-radius: 4px; + box-shadow: + 0 5px 5px -3px rgba(0, 0, 0, 0.2), + 0 8px 10px 1px rgba(0, 0, 0, 0.14), + 0 3px 14px 2px rgba(0, 0, 0, 0.12); +} +.cdk-drag-placeholder { + opacity: 0; +} +.cdk-drag-animating { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} +.example-box:last-child { + border: none; +} +.example-list.cdk-drop-list-dragging .example-box:not(.cdk-drag-placeholder) { + transition: transform 250ms cubic-bezier(0, 0, 0.2, 1); +} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts index ea0f92ba89..07f7eb597c 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts @@ -1,32 +1,52 @@ -import {Component, Input, OnChanges} from '@angular/core'; +import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop'; +import {Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from '@angular/core'; import {Observable} from 'rxjs'; import { OverseerAssessment, OverseerImage, OverseerImageService, Task, + TaskService, + TaskStatusEnum, User, UserService, } from 'src/app/api/models/doubtfire-model'; +import {OverseerStep} from 'src/app/api/models/overseer/overseer-step'; import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Unit} from 'src/app/api/models/unit'; +import {OverseerStepService} from 'src/app/api/services/overseer-step.service'; import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; import {TaskAssessmentModalService} from 'src/app/common/modals/task-assessment-modal/task-assessment-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {TaskSubmissionService} from 'src/app/common/services/task-submission.service'; import {OverseerScriptEditorModalService} from './overseer-script-editor-modal/overseer-script-editor-modal.service'; - +import * as monaco from 'monaco-editor'; +import {MatSelectChange} from '@angular/material/select'; @Component({ selector: 'f-task-definition-overseer', templateUrl: 'task-definition-overseer.component.html', styleUrls: ['task-definition-overseer.component.scss'], }) -export class TaskDefinitionOverseerComponent implements OnChanges { +export class TaskDefinitionOverseerComponent implements OnChanges, OnInit { @Input() taskDefinition: TaskDefinition; + @ViewChild('editor') editorComponent; + public currentUserTask: Task; + editorOptions = { + theme: 'vs', + language: 'shell', + renderMinimap: false, + + minimap: { + enabled: false, + }, + }; + + public stepType: 'status_check' | 'output_diff' = 'status_check'; + public visibility = 'public'; constructor( private alerts: AlertService, private overseerImageService: OverseerImageService, @@ -36,8 +56,175 @@ export class TaskDefinitionOverseerComponent implements OnChanges { private taskDefinitionService: TaskDefinitionService, private fileDownloaderService: FileDownloaderService, private overseerScriptEditorModal: OverseerScriptEditorModalService, + private overseerStepService: OverseerStepService, + private taskService: TaskService, ) {} + public get statusKeys() { + return this.taskService.statusKeys; + } + + public statusName(status: TaskStatusEnum) { + return this.taskService.statusLabels.get(status); + } + + public selectedOverseerStep: OverseerStep = null; + public newOverseerStep: OverseerStep = null; + + public overseerSteps: OverseerStep[] = []; + + selectStep(step: OverseerStep) { + this.selectedOverseerStep = step; + setTimeout(() => { + const editor = this.editorComponent?._editor; + if (editor) { + editor.revealLine(1); + editor.setScrollPosition({scrollTop: 0}); + } + }); + } + + addStep() { + this.newOverseerStep = new OverseerStep(this.taskDefinition); + this.newOverseerStep.stepType = 'status_check'; + this.newOverseerStep.timeout = 30; + this.newOverseerStep.enabled = true; + this.newOverseerStep.showStdout = true; + this.newOverseerStep.statusOnFailure = 'no_change'; + this.newOverseerStep.statusOnSuccess = 'no_change'; + this.newOverseerStep.commandLanguage = 'shell'; + this.newOverseerStep.runCommand = '#!/bin/bash\n\n'; + this.newOverseerStep.showExpectedOutput = true; + + this.newOverseerStep.sortOrder = this.taskDefinition.overseerStepsCache.currentValues.length; + this.selectedOverseerStep = this.newOverseerStep; + } + + getFeedbackMessagePlaceholder() { + // If the feedback message is blank, this is what will automatically be used + // (If this changes, ensure to update it in AcceptOverseerJob) + switch (this.selectedOverseerStep.stepType) { + case 'status_check': + return 'This test did not complete successfully. Check the output for any errors.'; + case 'output_diff': + return 'Your output did not match the expected result.'; + } + } + + ngOnInit(): void { + this.taskDefinition.overseerStepsCache.values.subscribe((steps) => { + this.overseerSteps = [...steps]; + }); + } + + public get getLanguages() { + return monaco?.languages.getLanguages() ?? []; + } + + onLanguageChange(event: MatSelectChange) { + const value = event.value; + this.editorOptions.language = value; + this.editorOptions = {...this.editorOptions}; + } + + drop(event: CdkDragDrop) { + if (this.newOverseerStep) { + this.alerts.error('Please save changes before re-ordering steps', 3000); + return; + } + moveItemInArray(this.overseerSteps, event.previousIndex, event.currentIndex); + // TODO: open endpoint to update sort orders in a single request + for (let i = 0; i < this.overseerSteps.length; i++) { + const step = this.taskDefinition.overseerStepsCache.get(this.overseerSteps[i].id); + if (step.sortOrder === i) { + // Ignore if no change + continue; + } + step.sortOrder = i; + this.overseerStepService + .update( + { + id: step.id, + unitId: this.unit.id, + taskDefId: this.taskDefinition.id, + }, + { + entity: step, + constructorParams: this.taskDefinition, + }, + ) + .subscribe({ + next: () => { + // console.log('updated!'); + }, + error: (error) => { + this.alerts.error(`Failed to update order of steps: ${error}`, 6000); + }, + }); + } + } + + deleteStep() { + if (this.selectedOverseerStep && this.selectedOverseerStep === this.newOverseerStep) { + this.newOverseerStep = null; + this.selectedOverseerStep = null; + return; + } + this.selectedOverseerStep?.delete(); + this.selectedOverseerStep = null; + } + + saveStep() { + if (!this.selectedOverseerStep.id) { + // this.newOverseerStep.runCommand = this.model.value; + this.overseerStepService + .create( + { + unitId: this.unit.id, + taskDefId: this.taskDefinition.id, + }, + { + entity: this.newOverseerStep, + }, + ) + .subscribe({ + next: (result) => { + this.alerts.success('Added overseer step', 3000); + result.taskDefinition = this.taskDefinition; + this.taskDefinition.overseerStepsCache.add(result); + this.selectStep(result); + this.newOverseerStep = null; + }, + error: (error) => { + console.error(error); + this.alerts.error(error, 3000); + }, + }); + } else { + this.overseerStepService + .update( + { + id: this.selectedOverseerStep.id, + unitId: this.unit.id, + taskDefId: this.taskDefinition.id, + }, + { + entity: this.selectedOverseerStep, + cache: this.taskDefinition.overseerStepsCache, + }, + ) + .subscribe({ + next: (result) => { + this.alerts.success('Saved overseer step', 3000); + }, + error: (error) => { + console.error(error); + this.alerts.error(error, 3000); + }, + }); + } + } + public get overseerEnabled(): boolean { return this.unit.overseerEnabled; } @@ -54,12 +241,21 @@ export class TaskDefinitionOverseerComponent implements OnChanges { return this.userService.currentUser; } - public ngOnChanges() { + public taskDefinitionHasChanges(): boolean { + return this.taskDefinition.hasChanges(this.taskDefinitionService.mapping); + } + + public ngOnChanges(changes: SimpleChanges) { const proj = this.unit.findProjectForUsername(this.currentUser.username); if (proj) { this.currentUserTask = proj.findTaskForDefinition(this.taskDefinition.id); this.hasAnySubmissions(); } + if (changes['taskDefinition']) { + this.taskDefinition.overseerStepsCache.values.subscribe((steps) => { + this.overseerSteps = [...steps]; + }); + } } testSubmission() { @@ -69,7 +265,7 @@ export class TaskDefinitionOverseerComponent implements OnChanges { this.currentUserTask.definition = this.taskDefinition; this.currentUserTask.status = 'ready_for_feedback'; this.currentUserTask.id = this.taskDefinition.id; // set a default id... - this.hasAnySubmissions(); + // this.hasAnySubmissions(); } this.currentUserTask.presentTaskSubmissionModal(this.currentUserTask.status, false, true); From 4f607926e3ac305316a05607fda7f7bff7faec00 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 5 Jan 2026 15:42:12 +1100 Subject: [PATCH 0772/1280] feat: project task planner gantt chart (#1051) * feat: init project plan gatt chart * chore: set compatible version * chore: update gantt chart package * refactor: display task items and map prerequisites * refactor: add task target start and due date * refactor: show prerequisite for tasks in tooltip * refactor: save target and due dates * feat: display task definition dates as baseline items * chore: remove extension * fix: create unique baseline item * refactor: fix timezone issues * refactor: clean up ui buttons * refactor: ensure timeline view shows the earliest task * chore: always show task planner * refactor: rename project plan * refactor: minify ui * chore: confirm changes * feat: allow target grade changes * refactor: display tasks target grade * feat: link to task details * refactor: remove debug * chore: remove old task sliders * refactor: display show date toggle * chore: add curved links * fix: save target dates * chore: reverse prerequisite links * refactor: reset target dates if task is prerequisite for another task * chore: fix gantt chart config * refactor: display warning if prerequisite task ends after dependent task starts * fix: return false if no linked item * refactor: highlight prerequisite conflicts * refactor: move task planner into its own component * refactor: highlight prerequisites on task hover * chore: fix prerequisite conflicts * feat: add status icon to task list * chore: update bar color * feat: display task prerequisites modal * refactor: display dependent tasks * fix: only use target start and end date if unit allows flexible dates * refactor: ensure prerequisites are mapped * chore: only update z-index of lines when hovering over * feat: task planner card for project dashboard * chore: add more details * chore: add tooltip delay * chore: add description heading * chore: add back watch command * refactor: use single endpoint to reset all target dates * chore: add button to redirect to task planner * chore: only show dates in tooltip * refactor: set gantt view dates to latest possible end date * feat: scroll to and highlight selected task item * refactor: remove unused code * refactor: remove unused code * chore: format * refactor: assign gantt config variable * refactor: add oop logic + cleanup duplicated code * fix: convert correct deadline date string * chore: import task planner card --- angular.json | 3 +- package-lock.json | 68 +++ package.json | 2 + src/app/api/models/project.ts | 13 + src/app/api/models/task.ts | 30 +- src/app/api/models/unit.ts | 10 + .../api/services/task-prerequisite.service.ts | 13 + src/app/api/services/task.service.ts | 8 + .../task-dropdown.component.html | 12 +- .../task-date-slider.component.html | 13 +- src/app/doubtfire-angular.module.ts | 36 ++ src/app/doubtfire-angularjs.module.ts | 18 + src/app/doubtfire.states.ts | 5 +- .../progress-dashboard.tpl.html | 5 + .../task-planner-card.component.html | 28 + .../task-planner-card.component.scss | 0 .../task-planner-card.component.ts | 14 + .../states/plan/project-plan.component.html | 35 +- .../states/plan/project-plan.component.scss | 0 .../states/plan/project-plan.component.ts | 63 +- ...planner-prerequisites-modal.component.html | 79 +++ ...planner-prerequisites-modal.component.scss | 0 ...k-planner-prerequisites-modal.component.ts | 39 ++ ...ask-planner-prerequisites-modal.service.ts | 27 + .../task-planner/task-planner.component.html | 129 +++++ .../task-planner/task-planner.component.scss | 18 + .../task-planner/task-planner.component.ts | 544 ++++++++++++++++++ src/styles.scss | 1 + tsconfig.json | 3 +- 29 files changed, 1184 insertions(+), 32 deletions(-) create mode 100644 src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.html create mode 100644 src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.scss create mode 100644 src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts create mode 100644 src/app/projects/states/plan/project-plan.component.scss create mode 100644 src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html create mode 100644 src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.scss create mode 100644 src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts create mode 100644 src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.service.ts create mode 100644 src/app/projects/states/plan/task-planner/task-planner.component.html create mode 100644 src/app/projects/states/plan/task-planner/task-planner.component.scss create mode 100644 src/app/projects/states/plan/task-planner/task-planner.component.ts diff --git a/angular.json b/angular.json index 0d892151bd..6a528bd8c1 100644 --- a/angular.json +++ b/angular.json @@ -49,7 +49,8 @@ "./build/assets/node_modules/codemirror/lib/codemirror.css", "./build/assets/node_modules/codemirror/theme/xq-light.css", "./build/assets/node_modules/nvd3/build/nv.d3.css", - "node_modules/@ctrl/ngx-emoji-mart/picker.css" + "node_modules/@ctrl/ngx-emoji-mart/picker.css", + "node_modules/@worktile/gantt/styles/index.scss" ], "scripts": [ "node_modules/moment/moment.js", diff --git a/package-lock.json b/package-lock.json index 05dae886a7..53f1d09af5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -31,6 +31,7 @@ "@uirouter/angularjs": "^1.0.30", "@uirouter/core": "^6.1.0", "@uirouter/rx": "^1.0.0", + "@worktile/gantt": "^18.0.5", "angular": "1.5.11", "angular-calendar": "^0.31.1", "angular-filter": "0.5.17", @@ -55,6 +56,7 @@ "es5-shim": "^4.5.12", "file-saver": "^2.0.5", "font-awesome": "~4.7.0", + "html2canvas": "^1.4.1", "html5-qrcode": "^2.3.8", "jquery": "2.1.4", "lodash": "~4.17", @@ -6186,6 +6188,22 @@ "@xtuc/long": "4.2.2" } }, + "node_modules/@worktile/gantt": { + "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@worktile/gantt/-/gantt-18.0.5.tgz", + "integrity": "sha512-LCcWaFBmeg5u9cVDEmREHdR+qJJHE3Ld4VxdoJpTXfhDkx2f19tp0wMR9MkwOLRwwTCx/5gGJ1kTbz4P0Zfc1Q==", + "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/cdk": ">=17.0.0", + "@angular/common": ">=17.0.0", + "@angular/core": ">=17.0.0", + "date-fns": ">=2.0.0", + "rxjs": "^6.5.0 || ^7.0.0" + } + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "dev": true, @@ -7235,6 +7253,15 @@ "node": ">= 0.4" } }, + "node_modules/base64-arraybuffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, "node_modules/base64-js": { "version": "1.5.1", "funding": [ @@ -8704,6 +8731,15 @@ "node": ">= 8" } }, + "node_modules/css-line-break": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/css-loader": { "version": "6.10.0", "dev": true, @@ -8860,6 +8896,7 @@ "version": "3.6.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", + "license": "MIT", "funding": { "type": "github", "url": "https://github.com/sponsors/kossnocorp" @@ -12848,6 +12885,19 @@ "dev": true, "license": "MIT" }, + "node_modules/html2canvas": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", + "license": "MIT", + "dependencies": { + "css-line-break": "^2.1.0", + "text-segmentation": "^1.0.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, "node_modules/html5-qrcode": { "version": "2.3.8", "resolved": "https://registry.npmjs.org/html5-qrcode/-/html5-qrcode-2.3.8.tgz", @@ -21515,6 +21565,15 @@ "node": ">=0.10" } }, + "node_modules/text-segmentation": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", + "license": "MIT", + "dependencies": { + "utrie": "^1.0.2" + } + }, "node_modules/text-table": { "version": "0.2.0", "dev": true, @@ -22306,6 +22365,15 @@ "node": ">= 0.4.0" } }, + "node_modules/utrie": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", + "license": "MIT", + "dependencies": { + "base64-arraybuffer": "^1.0.2" + } + }, "node_modules/uuid": { "version": "3.4.0", "dev": true, diff --git a/package.json b/package.json index d3eeccad5d..4b9234d2b7 100644 --- a/package.json +++ b/package.json @@ -50,6 +50,7 @@ "@uirouter/angularjs": "^1.0.30", "@uirouter/core": "^6.1.0", "@uirouter/rx": "^1.0.0", + "@worktile/gantt": "^18.0.5", "angular": "1.5.11", "angular-calendar": "^0.31.1", "angular-filter": "0.5.17", @@ -74,6 +75,7 @@ "es5-shim": "^4.5.12", "file-saver": "^2.0.5", "font-awesome": "~4.7.0", + "html2canvas": "^1.4.1", "html5-qrcode": "^2.3.8", "jquery": "2.1.4", "lodash": "~4.17", diff --git a/src/app/api/models/project.ts b/src/app/api/models/project.ts index df3c3cda26..2afef9ffa2 100644 --- a/src/app/api/models/project.ts +++ b/src/app/api/models/project.ts @@ -537,4 +537,17 @@ export class Project extends Entity { const httpClient = AppInjector.get(HttpClient); return httpClient.get(this.tasksIncludedInPortfolioUrl()); } + + public resetTargetDates(): Observable { + const projectService: ProjectService = AppInjector.get(ProjectService); + return projectService.update( + { + projectId: this.id, + }, + { + endpointFormat: '/projects/:projectId:/reset_target_dates', + entity: this, + }, + ); + } } diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index d624a8285d..e2d85bf61b 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -53,6 +53,9 @@ export class Task extends Entity { pinned: boolean = false; + targetStartDate: Date; + targetDueDate: Date; + public topWeight: number = 0; public readonly commentCache: EntityCache = new EntityCache(); @@ -167,7 +170,9 @@ export class Task extends Entity { } public localDueDate(): Date { - if (this.dueDate) { + if (this.targetDueDate && this.unit.allowFlexibleDates) { + return this.targetDueDate; + } else if (this.dueDate) { return this.dueDate; } else { return this.definition.localDueDate(); @@ -236,6 +241,25 @@ export class Task extends Entity { ); } + public saveTargetDates(startDate: Date | string, dueDate: Date | string): Observable { + const taskService: TaskService = AppInjector.get(TaskService); + + return taskService.update( + { + projectId: this.project.id, + taskDefId: this.definition.id, + }, + { + endpointFormat: '/projects/:projectId:/task_def_id/:taskDefId:/target_dates', + entity: this, + body: { + target_start_date: startDate, + target_due_date: dueDate, + }, + }, + ); + } + /** * Calculate the time between two dates * @@ -297,7 +321,9 @@ export class Task extends Entity { } public get startDate(): Date { - if (this.extensions < 0) { + if (this.targetStartDate && this.unit.allowFlexibleDates) { + return this.targetStartDate; + } else if (this.extensions < 0) { // If the task has an extension, the start date is the due date minus the extension return MappingFunctions.addWeeks(this.definition.startDate, this.extensions); } else { diff --git a/src/app/api/models/unit.ts b/src/app/api/models/unit.ts index 0caa668085..452bbceb98 100644 --- a/src/app/api/models/unit.ts +++ b/src/app/api/models/unit.ts @@ -34,6 +34,7 @@ import {HttpClient, HttpParams} from '@angular/common/http'; import {TaskPrerequisiteService} from '../services/task-prerequisite.service'; import {MarkingSession} from './marking-session'; import {MarkingSessionService} from '../services/marking-session.service'; +import {TaskPrerequisite} from './task-prerequisite'; export class Unit extends Entity { id: number; @@ -721,4 +722,13 @@ export class Unit extends Entity { }), ); } + + public get taskDefinitionsPrerequisitesUrl(): string { + return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.id}/task_prerequisites`; + } + + public getTaskPrerequisites(): Observable { + const prerequisiteService = AppInjector.get(TaskPrerequisiteService); + return prerequisiteService.getUnitPrerequisites(this.id); + } } diff --git a/src/app/api/services/task-prerequisite.service.ts b/src/app/api/services/task-prerequisite.service.ts index d3906860f8..ffb323b0d1 100644 --- a/src/app/api/services/task-prerequisite.service.ts +++ b/src/app/api/services/task-prerequisite.service.ts @@ -9,6 +9,8 @@ export class TaskPrerequisiteService extends CachedEntityService { keys: 'dueDate', toEntityFn: MappingFunctions.mapDateToEndOfDay, }, + { + keys: 'targetStartDate', + toEntityFn: MappingFunctions.mapDateToEndOfDay, + }, + { + keys: 'targetDueDate', + toEntityFn: MappingFunctions.mapDateToEndOfDay, + }, 'extensions', 'scormExtensions', { diff --git a/src/app/common/header/task-dropdown/task-dropdown.component.html b/src/app/common/header/task-dropdown/task-dropdown.component.html index c5d1d763d4..cc8cec968f 100644 --- a/src/app/common/header/task-dropdown/task-dropdown.component.html +++ b/src/app/common/header/task-dropdown/task-dropdown.component.html @@ -63,13 +63,11 @@ > Dashboard - @if (currentProject.unit.allowFlexibleDates) { - - - } + + + } +
    @if (editMode) { diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 86b5fc459d..33c8db369b 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -300,10 +300,15 @@ import {MarkingSessionService} from './api/services/marking-session.service'; import {PortfolioIncludedTasksComponent} from './projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component'; import {OverseerScriptEditorModalComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component'; import {UploadGradesComponent} from './units/states/portfolios/upload-grades/upload-grades.component'; +import {GANTT_GLOBAL_CONFIG, GanttLinkLineType, NgxGanttModule} from '@worktile/gantt'; import {DiscussionPromptService} from './api/services/discussion-prompt.service'; import {DiscussionPromptsComponent} from './projects/states/discussion-prompts/discussion-prompts.component'; import {TaskDefinitionDiscussionPromptsComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component'; import {DiscussionPromptsViewComponent} from './projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component'; +import {TaskPlannerComponent} from './projects/states/plan/task-planner/task-planner.component'; +import {TaskPlannerPrerequisitesModalComponent} from './projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component'; +import {TaskPlannerPrerequisitesModalService} from './projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.service'; +import {TaskPlannerCardComponent} from './projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component'; import {OverseerStepService} from './api/services/overseer-step.service'; import {TaskOverseerReportComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component'; import {OverseerStepResultService} from './api/services/overseer-step-result.service'; @@ -321,6 +326,31 @@ const MY_DATE_FORMAT = { }, }; +const GANTT_CHART_CONFIG = { + provide: GANTT_GLOBAL_CONFIG, + useValue: { + // locale: 'en-US', + dateFormat: { + // timeZone: 'UTC', + weekStartsOn: 1, + week: 'w', + year: 'yyyy', + month: 'MMMM', + yearMonth: 'yyyy MMM', + yearQuarter: 'yyyy', + }, + linkOptions: { + showArrow: true, + lineType: GanttLinkLineType.curve, + }, + styleOptions: { + // lineHeight: '25', + // barHeight: '23', + // headerHeight: '50px', + }, + }, +}; + @NgModule({ // Components we declare declarations: [ @@ -466,6 +496,9 @@ const MY_DATE_FORMAT = { DiscussionPromptsComponent, TaskDefinitionDiscussionPromptsComponent, DiscussionPromptsViewComponent, + TaskPlannerComponent, + TaskPlannerCardComponent, + TaskPlannerPrerequisitesModalComponent, TaskOverseerReportComponent, ], providers: [ @@ -557,6 +590,8 @@ const MY_DATE_FORMAT = { TaskPrerequisiteService, MarkingSessionService, DiscussionPromptService, + GANTT_CHART_CONFIG, + TaskPlannerPrerequisitesModalService, OverseerStepService, OverseerStepResultService, ], @@ -622,6 +657,7 @@ const MY_DATE_FORMAT = { MatDialogModuleNew, CalendarModule.forRoot({provide: CalendarDateAdapter, useFactory: adapterFactory}), CodeEditorModule.forRoot(), + NgxGanttModule, MatSidenavModule, MonacoEditorModule.forRoot(), ], diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 8d0fee5456..40e8930490 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -233,6 +233,9 @@ import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/dir import {PortfolioIncludedTasksComponent} from './projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component'; import {TaskSimilarityViewComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component'; import {UploadGradesComponent} from './units/states/portfolios/upload-grades/upload-grades.component'; +import {ProjectPlanComponent} from './projects/states/plan/project-plan.component'; +import {TaskPlannerComponent} from './projects/states/plan/task-planner/task-planner.component'; +import {TaskPlannerCardComponent} from './projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component'; import {TaskOverseerReportComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component'; export const DoubtfireAngularJSModule = angular @@ -577,6 +580,21 @@ DoubtfireAngularJSModule.directive( downgradeComponent({component: UploadGradesComponent}), ); +DoubtfireAngularJSModule.directive( + 'fProjectPlan', + downgradeComponent({component: ProjectPlanComponent}), +); + +DoubtfireAngularJSModule.directive( + 'fTaskPlanner', + downgradeComponent({component: TaskPlannerComponent}), +); + +DoubtfireAngularJSModule.directive( + 'fTaskPlannerCard', + downgradeComponent({component: TaskPlannerCardComponent}), +); + DoubtfireAngularJSModule.directive( 'fTaskOverseerReport', downgradeComponent({component: TaskOverseerReportComponent}), diff --git a/src/app/doubtfire.states.ts b/src/app/doubtfire.states.ts index 01b722864a..f1710f6b54 100644 --- a/src/app/doubtfire.states.ts +++ b/src/app/doubtfire.states.ts @@ -429,8 +429,11 @@ const SuccessCloseState: NgHybridStateDeclaration = { const projectPlanState: NgHybridStateDeclaration = { name: 'project/plan', parent: 'projects/index', - url: '/plan', + url: '/plan?:taskDef?', component: ProjectPlanComponent, + params: { + taskDef: {value: null, squash: true, dynamic: true}, + }, // views: { // main: { // // Main body links to angular component diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.tpl.html b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.tpl.html index 93069ef71b..b5859c8b2a 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.tpl.html +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.tpl.html @@ -5,6 +5,11 @@

    +
    +
    + +
    +
    diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.html b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.html new file mode 100644 index 0000000000..da584e5670 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.html @@ -0,0 +1,28 @@ + + + Plan Your Tasks + +

    + The Task Planner shows a timeline of your tasks, their due dates, and prerequisite + relationships. Use it to plan when to start and submit tasks, ensuring prerequisites are + completed early so you have time for feedback. +

    + @if (unit.allowFlexibleDates) { +

    + You can set your own start and target dates. Be mindful of each task’s + Feedback Deadline — submissions after this date will not be checked. Aim + to finish at least one week before the deadline, especially if you are targeting a higher + grade. +

    + } +
    +
    + + + +
    diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.scss b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts new file mode 100644 index 0000000000..3af5379eec --- /dev/null +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts @@ -0,0 +1,14 @@ +import {Component, Input} from '@angular/core'; +import {Project} from 'src/app/api/models/project'; + +@Component({ + selector: 'f-task-planner-card', + templateUrl: './task-planner-card.component.html', + styleUrl: './task-planner-card.component.scss', +}) +export class TaskPlannerCardComponent { + @Input() project: Project; + public get unit() { + return this.project?.unit; + } +} diff --git a/src/app/projects/states/plan/project-plan.component.html b/src/app/projects/states/plan/project-plan.component.html index d8f43331cb..cf49f02ec0 100644 --- a/src/app/projects/states/plan/project-plan.component.html +++ b/src/app/projects/states/plan/project-plan.component.html @@ -1,13 +1,34 @@
    -

    Plan Your Tasks

    +

    Task Planner

    - View and adjust the due dates of tasks. Remember to leave time to get and respond to feedback. + @if (unit.allowFlexibleDates) { + View and adjust the due dates for your tasks. Remember to leave time to get and respond to + feedback. + } @else { + View the task deadlines for your project, so you can organise your work and ensure you meet + all submission requirements on time. + } +

    +

    + Click on a task in the timeline to see how it connects to other tasks. This will show you which + tasks must be completed before it, and which tasks depend on it being completed first.

    - +
    -
    - @for (taskDef of taskDefs(); track $index) { - - } +
    +
    + + Target Grade + + @for (grade of gradeValues; track grade) { + {{ gradeString(grade) }} + } + +
    +
    diff --git a/src/app/projects/states/plan/project-plan.component.scss b/src/app/projects/states/plan/project-plan.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/plan/project-plan.component.ts b/src/app/projects/states/plan/project-plan.component.ts index c3002f3026..d1a9194f75 100644 --- a/src/app/projects/states/plan/project-plan.component.ts +++ b/src/app/projects/states/plan/project-plan.component.ts @@ -1,16 +1,44 @@ -import {Component} from '@angular/core'; +import {Component, OnInit, ViewChild} from '@angular/core'; +import {MatSelectChange} from '@angular/material/select'; +import {Project, ProjectService} from 'src/app/api/models/doubtfire-model'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {GradeService} from 'src/app/common/services/grade.service'; import {GlobalStateService} from '../index/global-state.service'; -import { Project, TaskDefinition } from 'src/app/api/models/doubtfire-model'; +import {TaskPlannerComponent} from './task-planner/task-planner.component'; @Component({ selector: 'f-project-plan', templateUrl: 'project-plan.component.html', - // styleUrls: ['project-plan.component.scss'] + styleUrls: ['project-plan.component.scss'], }) -export class ProjectPlanComponent { +export class ProjectPlanComponent implements OnInit { public project: Project; - constructor(private globalStateService: GlobalStateService) { + @ViewChild(TaskPlannerComponent) planner!: TaskPlannerComponent; + + public get unit() { + return this.project?.unit; + } + + public get gradeValues() { + return this.gradeService.gradeValues; + } + + public get gradeAcronyms() { + return this.gradeService.gradeAcronyms; + } + + public gradeString(grade: number) { + return this.gradeService.grades[grade]; + } + + constructor( + private globalStateService: GlobalStateService, + private gradeService: GradeService, + private projectService: ProjectService, + private alertService: AlertService, + ) { this.globalStateService.currentViewAndEntitySubject$.subscribe((viewAndEntity) => { if (viewAndEntity.viewType === 'PROJECT' && viewAndEntity.entity) { this.project = viewAndEntity.entity as Project; @@ -18,13 +46,26 @@ export class ProjectPlanComponent { }); } - public taskDefs(): TaskDefinition[] { - if (!this.project || !this.project.unit.taskDefinitions) { - return []; - } + public selectedTargetGrade: number; + + ngOnInit(): void { + this.selectedTargetGrade = this.project.targetGrade; + } + + onTargetGradeChange(event: MatSelectChange) { + const previousTargetGrade = this.project.targetGrade; + this.project.targetGrade = event.value; - return this.project.unit.taskDefinitions.filter((taskDef) => { - return taskDef.targetGrade <= this.project.targetGrade; + this.projectService.update(this.project).subscribe({ + next: () => { + this.alertService.success(`Succesfully updated target grade`, 2000); + this.planner.refreshItems(); + }, + error: (error) => { + this.project.targetGrade = previousTargetGrade; + this.selectedTargetGrade = previousTargetGrade; + this.alertService.error(`Failed to update target grade: ${error}`, 6000); + }, }); } } diff --git a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html new file mode 100644 index 0000000000..5ea71774fd --- /dev/null +++ b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html @@ -0,0 +1,79 @@ + + + + {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} + + + + + Task Description: +

    {{ taskDefinition.description }}

    + + @if (!task.hasPrerequisiteTasks()) { +
    This task has no prerequisites.
    + } + + @if (dependents.length) { + + + Required by + + + + + {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} is a + prerequisite for the following tasks. In some cases, + {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} needs to + reach the Discuss or Complete status, which requires + tutor feedback. Plan ahead to avoid being locked out of submission. + + + + + + + + + + + + + + + + + + +
    Task + {{ link.taskDefinition?.abbreviation }} {{ link.taskDefinition?.name }} + Submission Open + @if (link.taskDefinition.projectTask(project).blockedByPrerequisiteTasks()) { + block_outlined + } @else { + check_circle + } + + Required Status + +
    +
    +
    + } @else { +
    + This task is not a prerequisite for any other tasks. +
    + } +
    +
    diff --git a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.scss b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts new file mode 100644 index 0000000000..54f2aaadf0 --- /dev/null +++ b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts @@ -0,0 +1,39 @@ +import {Component, Inject, Input, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {MatTableDataSource} from '@angular/material/table'; +import {Project} from 'src/app/api/models/project'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {TaskPrerequisite} from 'src/app/api/models/task-prerequisite'; + +export interface TaskPlannerPrerequisitesModalData { + taskDefinition: TaskDefinition; + project: Project; + dependents: TaskPrerequisite[]; +} + +@Component({ + selector: 'f-task-planner-prerequisites-modal', + templateUrl: './task-planner-prerequisites-modal.component.html', + styleUrl: './task-planner-prerequisites-modal.component.scss', +}) +export class TaskPlannerPrerequisitesModalComponent implements OnInit { + @Input() taskDefinition: TaskDefinition; + @Input() project: Project; + @Input() dependents: TaskPrerequisite[]; + + public dataSource = new MatTableDataSource(); + public displayedColumns: string[] = ['task-definition', 'current-status', 'required-status']; + + public get task() { + return this.project?.findTaskForDefinition(this.taskDefinition?.id); + } + + constructor(@Inject(MAT_DIALOG_DATA) public data: TaskPlannerPrerequisitesModalData) {} + + ngOnInit(): void { + this.taskDefinition = this.data.taskDefinition; + this.project = this.data.project; + this.dependents = this.data.dependents; + this.dataSource.data = this.dependents; + } +} diff --git a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.service.ts b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.service.ts new file mode 100644 index 0000000000..4f12f4fd1f --- /dev/null +++ b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.service.ts @@ -0,0 +1,27 @@ +import {Injectable} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import {Project, TaskDefinition} from 'src/app/api/models/doubtfire-model'; +import { + TaskPlannerPrerequisitesModalComponent, + TaskPlannerPrerequisitesModalData, +} from './task-planner-prerequisites-modal.component'; +import {TaskPrerequisite} from 'src/app/api/models/task-prerequisite'; + +@Injectable({ + providedIn: 'root', +}) +export class TaskPlannerPrerequisitesModalService { + constructor(public dialog: MatDialog) {} + + public show(project: Project, taskDefinition: TaskDefinition, dependents: TaskPrerequisite[]) { + this.dialog.open( + TaskPlannerPrerequisitesModalComponent, + { + data: {taskDefinition, project, dependents}, + width: '100%', + maxWidth: '900px', + panelClass: 'overflow-y-auto', + }, + ); + } +} diff --git a/src/app/projects/states/plan/task-planner/task-planner.component.html b/src/app/projects/states/plan/task-planner/task-planner.component.html new file mode 100644 index 0000000000..025da92aa5 --- /dev/null +++ b/src/app/projects/states/plan/task-planner/task-planner.component.html @@ -0,0 +1,129 @@ +
    +
    + Show Task Dates +
    + @if (unit.allowFlexibleDates) { +
    + + +
    + } +
    + + + + +
    +
    + +
    + {{ item.title }} +
    +
    + +
    +
    +
    + + @if (showDatesColumn) { + + + {{ toDateString(item.start) }} + + + + + + {{ toDateString(item.end) }} + + + + + + {{ item.task.localDeadlineDate() ? toDateString(item.task.localDeadlineDate()) : 'N/A' }} + + + } + + +
    +
    + @if (unsavedChanges(item)) { + change_circle + } + @if (prerequisiteConflict(item)) { + warning + } @else if (isBlockedByPrerequisite(item)) { + warning + } + @if (isPastFeedbackDeadline(item)) { + dangerous + } + @if (isCloseToFeedbackDeadline(item)) { + query_builder + } +
    + +   {{ item.title }} +
    +
    +
    +
    +
    diff --git a/src/app/projects/states/plan/task-planner/task-planner.component.scss b/src/app/projects/states/plan/task-planner/task-planner.component.scss new file mode 100644 index 0000000000..ddf668e57b --- /dev/null +++ b/src/app/projects/states/plan/task-planner/task-planner.component.scss @@ -0,0 +1,18 @@ +:host ::ng-deep .flexible-dates .gantt-links-overlay svg { + z-index: 999 !important; + pointer-events: none; +} + +:host ::ng-deep .flexible-dates .gantt-links-overlay-main { + height: 1px; + overflow: visible !important; + pointer-events: none; +} + +.gantt-bar { + background-color: var(--bar-bg); +} + +.flash { + transition: background-color 500ms ease-in-out; +} diff --git a/src/app/projects/states/plan/task-planner/task-planner.component.ts b/src/app/projects/states/plan/task-planner/task-planner.component.ts new file mode 100644 index 0000000000..097b0e6b92 --- /dev/null +++ b/src/app/projects/states/plan/task-planner/task-planner.component.ts @@ -0,0 +1,544 @@ +import {Component, Input, OnInit, ViewChild} from '@angular/core'; +import {UIRouter} from '@uirouter/core'; +import { + GanttBaselineItem, + GanttDate, + GanttItem, + GanttLink, + GanttLinkType, + GanttViewOptions, + GanttViewType, + NgxGanttComponent, +} from '@worktile/gantt'; +import {Project} from 'src/app/api/models/project'; +import {Task} from 'src/app/api/models/task'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {TaskPrerequisite} from 'src/app/api/models/task-prerequisite'; +import {TaskPrerequisiteService} from 'src/app/api/services/task-prerequisite.service'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {GradeService} from 'src/app/common/services/grade.service'; +import {TaskPlannerPrerequisitesModalService} from './task-planner-prerequisites-modal/task-planner-prerequisites-modal.service'; + +interface TaskGanttItem extends GanttItem { + highlighted?: boolean; + taskDefinition: TaskDefinition; + task: Task; + originalLinks: GanttLink[]; +} + +@Component({ + selector: 'f-task-planner', + templateUrl: './task-planner.component.html', + styleUrl: './task-planner.component.scss', +}) +export class TaskPlannerComponent implements OnInit { + // Show a warning if the task's target end date is within this many days of the feedback deadline + public readonly CLOSE_TO_FEEDBACK_DEADLINE_THRESHOLD = 7; + + @Input() project: Project; + @ViewChild('gantt') ganttComponent: NgxGanttComponent; + + public viewType: GanttViewType = GanttViewType.day; + public viewOptions: GanttViewOptions; + + public allTaskPrerequisites: TaskPrerequisite[]; + public taskPrerequisites: TaskPrerequisite[]; + + public items: TaskGanttItem[] = []; + + // TaskDefinition default dates for reference + public baselineItems: GanttBaselineItem[] = []; + + public animateBackground: boolean = false; + public showDatesColumn: boolean = false; + public overlayLines: boolean = false; + + public get unit() { + return this.project?.unit; + } + + constructor( + private gradeService: GradeService, + private alertService: AlertService, + private confirmationModalService: ConfirmationModalService, + private taskPlannerPrerequisitesModal: TaskPlannerPrerequisitesModalService, + private taskPrerequisiteService: TaskPrerequisiteService, + private router: UIRouter, + ) {} + + public get gradeValues() { + return this.gradeService.gradeValues; + } + + public get gradeAcronyms() { + return this.gradeService.gradeAcronyms; + } + + public gradeString(grade: number) { + return this.gradeService.grades[grade]; + } + + onBarHover(item: TaskGanttItem) { + this.setLinkColors(item, true); + } + + onBarLeave(item: TaskGanttItem) { + this.setLinkColors(item, false); + } + + setLinkColors(item: TaskGanttItem, active: boolean) { + this.overlayLines = active; + + const ganttItem = this.items.find((i) => i.id === item.id); + ganttItem.links.forEach((linkItem) => { + const link = linkItem as GanttLink; + this.toggleLinkOpacity(link, active); + }); + + const prerequisites = this.items.filter((i) => { + const links = i.links; + if (typeof links === 'string') { + return false; + } + + return links.some((l) => typeof l !== 'string' && l.link === item.id); + }); + + prerequisites.forEach((prereq) => { + prereq.links.forEach((linkItem) => { + const link = linkItem as GanttLink; + if (link.link == item.id) { + this.toggleLinkOpacity(link, active); + } + }); + }); + + this.items = [...this.items]; + } + + private toggleLinkOpacity(link: GanttLink, active: boolean) { + const color = link.color as {active: string; default: string}; + + if (!active && !color.default.endsWith('0.1)')) { + // Dim link by lowering alpha + color.default = color.default.slice(0, -2) + '0.1)'; + } else if (active && color.default.endsWith('0.1)')) { + // Restore full opacity + color.default = color.default.slice(0, -4) + '1)'; + } + } + + barClick(item: TaskGanttItem) { + const td = item.taskDefinition; + const prereqs = this.taskPrerequisites.filter((p) => p.prerequisiteId === td.id); + this.taskPlannerPrerequisitesModal.show(this.project, td, prereqs); + } + + private mapPrerequisites() { + for (const prerequisite of this.allTaskPrerequisites) { + prerequisite.taskDefinition = this.unit.taskDefinitions.find( + (td) => td.id === prerequisite.taskDefinitionId, + ); + prerequisite.prerequisite = this.unit.taskDefinitions.find( + (td) => td.id === prerequisite.prerequisiteId, + ); + } + this.allTaskPrerequisites = [...this.allTaskPrerequisites]; + } + + public blockedDependents: Map = new Map(); + + // Check to see if this task is a prerequisite for another task + // If it is, ensure the end date on the task is before the start of its dependent task + prerequisiteConflict(item: TaskGanttItem) { + if (!item.links.length) { + return false; + } + + let isAfterDependentStartDate: boolean = false; + for (const ganttLink of item.links) { + if (typeof ganttLink === 'string') { + continue; + } + + const ganttItem = this.items.find((i) => i.id === ganttLink.link); + if (!ganttItem) { + return false; + } + const diff = this.normalizeDateUTC(item.end) - this.normalizeDateUTC(ganttItem.end); + const color = typeof ganttLink.color === 'string' ? ganttLink.color : ganttLink.color.default; + + if (diff > 0) { + isAfterDependentStartDate = true; + } + + continue; + + if (color === '#0079D8') { + // Ready for feedback + if (diff > 0) { + isAfterDependentStartDate = true; + } + } else if (color === '#31b0d5' || color === '#5BB75B') { + // Discuss or Complete + if (diff >= -7 * 24 * 60 * 60) { + // We need to ensure this task is submitted a week earlier than its dependent so get it in a Discuss state + isAfterDependentStartDate = true; + } + } + } + + return isAfterDependentStartDate; + } + + isBlockedByPrerequisite(item: TaskGanttItem) { + const prerequisites = this.items.filter((i) => { + const links = i.links; + if (typeof links === 'string') { + return false; + } + + return links.some((l) => typeof l !== 'string' && l.link === item.id); + }); + + for (const link of prerequisites) { + if (this.prerequisiteConflict(link)) { + const diff = this.normalizeDateUTC(link.end) - this.normalizeDateUTC(item.end); + if (diff > 0) { + return true; + } + } + } + + return false; + } + + getItemClasses(item: TaskGanttItem): string[] { + const classes: string[] = ['gantt-bar']; + if (this.animateBackground) { + classes.push('flash'); + } + if (item.highlighted) { + classes.push('[--bar-bg:#03c6fc]'); + } else if (this.isPastFeedbackDeadline(item)) { + classes.push('[--bar-bg:#cd3704]', 'text-white'); + } else if (this.isBlockedByPrerequisite(item)) { + classes.push('[--bar-bg:#e88307]', 'text-black'); + } else if (this.isCloseToFeedbackDeadline(item)) { + classes.push('[--bar-bg:#ffc53d]', 'text-black'); + } else { + classes.push('[--bar-bg:#0e467b]', 'text-white'); + } + + return classes; + } + + isPastFeedbackDeadline(item: TaskGanttItem) { + return item.end > item.task.localDeadlineDate().getTime() / 1000; + } + + isCloseToFeedbackDeadline(item: TaskGanttItem) { + if (!this.unit.allowFlexibleDates) { + return false; + } + + const task = item.task; + const diff = + this.normalizeDateUTC(task.localDeadlineDate().getTime() / 1000) - + this.normalizeDateUTC(item.end); + + return diff >= 0 && diff <= this.CLOSE_TO_FEEDBACK_DEADLINE_THRESHOLD * 24 * 60 * 60; + } + + toDateStr = (timestamp: number) => { + const d = new Date(timestamp * 1000); + return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`; + }; + + saveTargetDates() { + for (const item of this.items) { + const td = item.taskDefinition; + if (!td) { + continue; + } + if (this.unsavedChanges(item)) { + this.saveTargetDate(item); + } + } + } + + saveTargetDate(item: TaskGanttItem) { + const td = item.taskDefinition; + const task = item.task; + + task.saveTargetDates(this.toDateStr(item.start), this.toDateStr(item.end)).subscribe({ + next: (data) => { + task.targetDueDate = data.targetDueDate; + task.targetStartDate = data.targetStartDate; + item.start = this.normalizeDateUTC(data.targetStartDate.getTime() / 1000); + item.end = this.normalizeDateUTC(data.targetDueDate.getTime() / 1000); + this.items = [...this.items]; + }, + error: (error) => { + this.alertService.error( + `Failed to save target date for ${td.abbreviation}: ${error}`, + 6000, + ); + }, + }); + } + + anyUnsavedChanges() { + return this.items.some((i) => this.unsavedChanges(i)); + } + + confirmSaveTargetDates() { + this.confirmationModalService.show( + 'Save Task Dates?', + `Do you want to save these new target dates for your tasks? You can always reset them to the unit's default later.`, + () => { + this.saveTargetDates(); + }, + ); + } + + confirmResetTargetDates() { + this.confirmationModalService.show( + 'Reset Task Dates?', + `Are you sure you want to reset all target dates to the unit's default? All modified dates will be reset.`, + () => { + this.project.resetTargetDates().subscribe({ + next: (_project) => { + for (const task of this.project.tasks) { + task.targetDueDate = null; + task.targetStartDate = null; + + const item = this.items.find((item) => item.id === task.definition.id.toString()); + + item.start = this.normalizeDateUTC(task.startDate.getTime() / 1000); + item.end = this.normalizeDateUTC(task.localDueDate().getTime() / 1000); + } + this.items = [...this.items]; + }, + error: (error) => { + this.alertService.error(`Failed to reset target dates: ${error}`, 6000); + }, + }); + }, + ); + } + + normalizeDateUTC = (ts: number) => { + const d = new GanttDate(ts * 1000); + // const utc = Date.UTC(d.getUTCFullYear(), d.getUTCMonth(), d.getUTCDate(), 0, 0, 0, 0); + return Math.floor(d.getUnixTime()); + }; + + toDateString(timestamp: number | Date) { + const date = timestamp instanceof Date ? timestamp : new Date(timestamp * 1000); + return date.toLocaleDateString('en-AU', { + month: 'short', + day: 'numeric', + // year: '2-digit', + }); + } + + unsavedChanges(item: TaskGanttItem) { + const task = item.task; + const start = this.normalizeDateUTC(task.startDate.getTime() / 1000); + const end = this.normalizeDateUTC(task.localDueDate().getTime() / 1000); + return start !== this.normalizeDateUTC(item.start) || end !== this.normalizeDateUTC(item.end); + } + + getTooltip(item: TaskGanttItem) { + return `${this.toDateString(item.start)} — ${this.toDateString(item.end)}`; + } + + public get earliestStartDate() { + const earliestTaskStartDate = Math.min( + ...this.taskDefs().map((t) => t.startDate.getTime() / 1000), + ); + return Math.floor(Math.min(this.unit.startDate.getTime() / 1000, earliestTaskStartDate)); + } + + public get latestEndDate() { + const latestTaskEndDate = Math.max(...this.taskDefs().map((t) => t.dueDate.getTime() / 1000)); + return Math.floor(Math.max(this.unit.endDate.getTime() / 1000, latestTaskEndDate)); + } + + ngOnInit(): void { + this.viewOptions = { + datePrecisionUnit: 'day', + start: new GanttDate(this.earliestStartDate), + end: new GanttDate(this.latestEndDate), + dragPreviewDateFormat: 'MMM dd', + }; + + this.unit.getTaskPrerequisites().subscribe({ + next: (prereqs) => { + this.allTaskPrerequisites = prereqs; + this.mapPrerequisites(); + for (const prerequisite of this.allTaskPrerequisites) { + prerequisite.taskDefinition.taskPrerequisitesCache.getOrCreate( + prerequisite.id, + this.taskPrerequisiteService, + prerequisite, + ); + } + + for (const td of this.unit.taskDefinitions) { + const prerequisites = td.taskPrerequisitesCache.currentValues; + const definitions = this.unit.taskDefinitions; + for (const prerequisite of prerequisites) { + prerequisite.taskDefinition = definitions.find( + (td) => td.id === prerequisite.taskDefinitionId, + ); + prerequisite.prerequisite = definitions.find( + (td) => td.id === prerequisite.prerequisiteId, + ); + } + } + + this.refreshItems(); + }, + error: (error) => { + this.alertService.error(`Failed to get task prerequisites: ${error}`, 6000); + }, + }); + } + + refreshItems() { + this.taskPrerequisites = this.allTaskPrerequisites.filter((pre) => + this.taskDefs().find((td) => td.id === pre.taskDefinitionId), + ); + + const taskDefinitions = this.taskDefs(); + this.items = []; + + for (const td of taskDefinitions) { + const task = this.project.findTaskForDefinition(td.id); + + const item: TaskGanttItem = { + id: td.id.toString(), + title: `${td.abbreviation} ${td.name}`, + start: this.normalizeDateUTC(task.startDate.getTime() / 1000), + end: this.normalizeDateUTC(task.localDueDate().getTime() / 1000), + expandable: false, + draggable: this.project.unit.allowFlexibleDates, + // color: this.gradeService.gradeColors[td.targetGrade], + expanded: false, + color: '#3333ff', + taskDefinition: td, + task: task, + // progress: 0.5, + originalLinks: [], + links: this.taskPrerequisites + .filter((p) => p.prerequisiteId === td.id) + // .filter((p) => p.taskDefinitionId === td.id) + .map((p) => { + let color: string; + + switch (p.taskStatus) { + case 'ready_for_feedback': + color = 'rgba(0, 121, 216, 0.1)'; + break; + case 'complete': + color = 'rgba(91, 183, 91, 0.1)'; + break; + case 'discuss': + color = 'rgba(49, 176, 213, 0.1)'; + break; + case 'demonstrate': + color = 'rgba(49, 176, 213, 0.1)'; + break; + default: + color = 'gray'; + } + const link: GanttLink = { + type: GanttLinkType.fs, + link: p.taskDefinitionId.toString(), + // link: p.prerequisiteId.toString(), + color: { + default: color, + active: color, + }, + }; + + return link; + }), + }; + + // if ( + // item.links.length && + // (this.isCloseToFeedbackDeadline(item) || this.isPastFeedbackDeadline(item)) + // ) { + // const task = this.project.findTaskForDefinition(td.id); + + // item.start = this.normalizeDateUTC(task.startDate.getTime() / 1000); + // item.end = this.normalizeDateUTC(task.localDueDate().getTime() / 1000); + + // // If the task defaults are still invalid, reset them to the task definition default + // if (this.isCloseToFeedbackDeadline(item) || this.isPastFeedbackDeadline(item)) { + // item.start = this.normalizeDateUTC(td.startDate.getTime() / 1000); + // item.end = this.normalizeDateUTC(td.localDueDate().getTime() / 1000); + // } + // } + + const originalItem = {...item}; + item.originalLinks = [...(originalItem.links as GanttLink[])]; + + this.items.push(item); + this.items = [...this.items]; + + // Create baseline item + const baselineItem = {...item}; + baselineItem.start = this.normalizeDateUTC(td.startDate.getTime() / 1000); + baselineItem.end = this.normalizeDateUTC(td.targetDate.getTime() / 1000); + this.baselineItems.push(baselineItem); + this.baselineItems = [...this.baselineItems]; + + // if (this.unsavedChanges(item)) { + // this.saveTargetDate(item); + // } + } + + this.ganttComponent.scrollToToday(); + + if (this.router.globals.params.taskDef) { + const taskItem = this.items.find((item) => item.id === this.router.globals.params.taskDef); + if (taskItem) { + this.ganttComponent.scrollToDate(taskItem.start); + taskItem.highlighted = true; + this.animateBackground = true; + + setTimeout(() => { + const el = document.querySelector(`[data-gantt-id="${taskItem.id}"]`) as HTMLElement; + + el?.scrollIntoView({ + behavior: 'smooth', + block: 'center', + inline: 'nearest', + }); + }); + setTimeout(() => (taskItem.highlighted = false), 1000); + setTimeout(() => (this.animateBackground = false), 2000); + } + this.router.stateService.go( + this.router.globals.current.name, + {taskDef: null}, + {location: 'replace', notify: false, reload: false}, + ); + } + } + + public taskDefs(): TaskDefinition[] { + if (!this.project || !this.project.unit.taskDefinitions) { + return []; + } + + return this.project.unit.taskDefinitions.filter((taskDef) => { + return taskDef.targetGrade <= this.project.targetGrade; + }); + } +} diff --git a/src/styles.scss b/src/styles.scss index 7eec75221c..8b8db3480d 100644 --- a/src/styles.scss +++ b/src/styles.scss @@ -1,5 +1,6 @@ // For more information: https://material.angular.io/guide/theming @use '@angular/material' as mat; +@use '@worktile/gantt/styles/index'; @include mat.core(); diff --git a/tsconfig.json b/tsconfig.json index c1f136d7b7..f062ffbb0f 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -19,7 +19,8 @@ "typeRoots": ["node_modules/@types"], "lib": ["es2020", "dom", "ES2021.String"], "useDefineForClassFields": false, - "allowSyntheticDefaultImports": true + "allowSyntheticDefaultImports": true, + "skipLibCheck": true }, "angularCompilerOptions": { "strictTemplates": false From 6b616fc6de2f58197988c7999005a9abaa79864b Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 5 Jan 2026 15:45:22 +1100 Subject: [PATCH 0773/1280] chore(release): 10.0.0-69 --- CHANGELOG.md | 10 ++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6bf63acef3..51a2cd51da 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,16 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-69](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-68...v10.0.0-69) (2026-01-05) + + +### Features + +* attention required task status ([#1061](https://github.com/b0ink/doubtfire-deploy/issues/1061)) ([15365ed](https://github.com/b0ink/doubtfire-deploy/commit/15365ed4f42af790af9a9ae24dae42f041dff1df)) +* display number of stuff notes in tutor discussion ([2674d4e](https://github.com/b0ink/doubtfire-deploy/commit/2674d4e5ade26e5420b87518f4cd9da909ec7246)) +* overseer pipeline ([#1064](https://github.com/b0ink/doubtfire-deploy/issues/1064)) ([7cb8fc7](https://github.com/b0ink/doubtfire-deploy/commit/7cb8fc7471f0402c562fb8a0b87df672ceb22ea3)) +* project task planner gantt chart ([#1051](https://github.com/b0ink/doubtfire-deploy/issues/1051)) ([4f60792](https://github.com/b0ink/doubtfire-deploy/commit/4f607926e3ac305316a05607fda7f7bff7faec00)) + ## [10.0.0-68](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-67...v10.0.0-68) (2025-12-08) diff --git a/package-lock.json b/package-lock.json index 53f1d09af5..ae33639815 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-68", + "version": "10.0.0-69", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-68", + "version": "10.0.0-69", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 4b9234d2b7..33f6f2b521 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-68", + "version": "10.0.0-69", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 6c6c7f9cd1297d0671231c80fbad77b900be5cba Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 5 Jan 2026 16:44:33 +1100 Subject: [PATCH 0774/1280] chore: allow no expected output file --- .../task-definition-overseer.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html index fb78832932..cde5ed4e7e 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html @@ -194,6 +194,7 @@ Expected Output File + (none) @for (file of taskDefinition.overseerResourceFiles; track file) { {{ file }} } From 7ff9fa3380b58320ed1819f04ac8a258c72ada39 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 6 Jan 2026 08:08:24 +1100 Subject: [PATCH 0775/1280] chore: render correct error --- src/app/home/states/lti-dashboard/lti-dashboard.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/home/states/lti-dashboard/lti-dashboard.component.ts b/src/app/home/states/lti-dashboard/lti-dashboard.component.ts index db081c7375..0c0ad93d57 100644 --- a/src/app/home/states/lti-dashboard/lti-dashboard.component.ts +++ b/src/app/home/states/lti-dashboard/lti-dashboard.component.ts @@ -78,7 +78,7 @@ export class LtiDashboardComponent implements AfterViewInit { this.isLoading = false; }, error: (error) => { - this.alertsService.error(error.error, 6000); + this.alertsService.error(error.error || error, 6000); this.isLoading = false; }, }); From a6bdd22ff864e72c679fae1844345963447fdf08 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 6 Jan 2026 09:02:27 +1100 Subject: [PATCH 0776/1280] fix: skip query for unsaved task definition --- .../task-definition-discussion-prompts.component.ts | 5 ++++- .../task-definition-prerequisites.component.ts | 8 +++++++- 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts index 149682d55d..e22072d433 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts @@ -80,12 +80,15 @@ export class TaskDefinitionDiscussionPromptsComponent private fetchDiscussionPrompts() { const taskDefinition = this.taskDefinition; + if (!taskDefinition.id) { + return; + } this.discussionPromptService.loadDiscussionPrompts(null, taskDefinition).subscribe({ next: (data) => { this.dataSource.data = data; }, error: (error) => { - this.alertService.error(`Failed to load discussion promnpts: ${error}`); + this.alertService.error(`Failed to load discussion prompts: ${error}`, 6000); }, }); } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts index 2528ffcd6d..201e8a35ab 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts @@ -101,6 +101,9 @@ export class TaskDefinitionPrerequisitesComponent implements OnInit, OnChanges { private fetchTaskPrerequisites() { const taskDefinition = this.taskDefinition; + if (!taskDefinition.id) { + return; + } this.taskPrerequisiteService .query( { @@ -127,7 +130,10 @@ export class TaskDefinitionPrerequisitesComponent implements OnInit, OnChanges { this.filterTaskDefs(this.searchCtrl.value ?? ''); }, error: (error) => { - console.error(error); + this.alertService.error( + `Failed to fetch prerequisites for task definition: ${error}`, + 6000, + ); }, }); } From 9317a5477bb27ed59d9c2e29af9e4538c253816c Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 6 Jan 2026 09:13:21 +1100 Subject: [PATCH 0777/1280] chore: remove required fields --- .../task-definition-overseer.component.html | 45 ++----------------- 1 file changed, 3 insertions(+), 42 deletions(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html index cde5ed4e7e..87e44b0754 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html @@ -113,35 +113,14 @@ cdkDragDisabled (click)="selectStep(newOverseerStep)" > - {{ newOverseerStep.sortOrder }}. {{ newOverseerStep.name || 'Untitled Step' }}
    } - -
    @if (selectedOverseerStep) { -
    @@ -193,7 +172,7 @@
    Expected Output File - + (none) @for (file of taskDefinition.overseerResourceFiles; track file) { {{ file }} @@ -220,9 +199,6 @@
    - }
    @@ -231,7 +207,6 @@ Language @for (language of getLanguages; track language) { @@ -244,11 +219,6 @@
    - -
    Status on Success - + No Change @for (status of statusKeys; track status) { {{ statusName(status) }} @@ -318,7 +288,7 @@ Status on Fail - + No Change @for (status of statusKeys; track status) { {{ statusName(status) }} @@ -361,15 +331,6 @@ and a default will message will be used instead. -
    Date: Tue, 6 Jan 2026 09:26:42 +1100 Subject: [PATCH 0778/1280] chore(release): 10.0.0-70 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 51a2cd51da..6121dce31b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [10.0.0-70](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-69...v10.0.0-70) (2026-01-05) + + +### Bug Fixes + +* skip query for unsaved task definition ([a6bdd22](https://github.com/b0ink/doubtfire-deploy/commit/a6bdd22ff864e72c679fae1844345963447fdf08)) + ## [10.0.0-69](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.0-68...v10.0.0-69) (2026-01-05) diff --git a/package-lock.json b/package-lock.json index ae33639815..2eb60f3bef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.0-69", + "version": "10.0.0-70", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.0-69", + "version": "10.0.0-70", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 33f6f2b521..6b4ad8bb97 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.0-69", + "version": "10.0.0-70", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 6dcfe952f0415fb1327b738137f817a0fcfa0488 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 11 Feb 2026 12:06:34 +1100 Subject: [PATCH 0779/1280] feat: download staff notes csv (#1062) * feat: download staff notes csv * chore: restore imports --- src/app/api/models/unit.ts | 11 +++++++++ src/app/doubtfire-angular.module.ts | 2 ++ src/app/doubtfire-angularjs.module.ts | 6 +++++ .../download-staff-notes.component.html | 3 +++ .../download-staff-notes.component.scss | 0 .../download-staff-notes.component.ts | 24 +++++++++++++++++++ .../states/portfolios/portfolios.tpl.html | 1 + 7 files changed, 47 insertions(+) create mode 100644 src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html create mode 100644 src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.scss create mode 100644 src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts diff --git a/src/app/api/models/unit.ts b/src/app/api/models/unit.ts index 452bbceb98..0415a8bda2 100644 --- a/src/app/api/models/unit.ts +++ b/src/app/api/models/unit.ts @@ -723,6 +723,17 @@ export class Unit extends Entity { ); } + public get staffNotesCsvDownloadUrl(): string { + return `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/staff_notes`; + } + + public downloadStaffNotesCsv(): void { + AppInjector.get(FileDownloaderService).downloadFile( + `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/staff_notes`, + `${this.name}-StaffNotes.csv`, + ); + } + public get taskDefinitionsPrerequisitesUrl(): string { return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.id}/task_prerequisites`; } diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 33c8db369b..16e6c15557 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -305,6 +305,7 @@ import {DiscussionPromptService} from './api/services/discussion-prompt.service' import {DiscussionPromptsComponent} from './projects/states/discussion-prompts/discussion-prompts.component'; import {TaskDefinitionDiscussionPromptsComponent} from './units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component'; import {DiscussionPromptsViewComponent} from './projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component'; +import {DownloadStaffNotesComponent} from './units/states/portfolios/download-staff-notes/download-staff-notes.component'; import {TaskPlannerComponent} from './projects/states/plan/task-planner/task-planner.component'; import {TaskPlannerPrerequisitesModalComponent} from './projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component'; import {TaskPlannerPrerequisitesModalService} from './projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.service'; @@ -497,6 +498,7 @@ const GANTT_CHART_CONFIG = { TaskDefinitionDiscussionPromptsComponent, DiscussionPromptsViewComponent, TaskPlannerComponent, + DownloadStaffNotesComponent, TaskPlannerCardComponent, TaskPlannerPrerequisitesModalComponent, TaskOverseerReportComponent, diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index 40e8930490..1fb4868e3c 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -233,6 +233,7 @@ import {PortfolioGradeSelectStepComponent} from './projects/states/portfolio/dir import {PortfolioIncludedTasksComponent} from './projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component'; import {TaskSimilarityViewComponent} from './projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component'; import {UploadGradesComponent} from './units/states/portfolios/upload-grades/upload-grades.component'; +import {DownloadStaffNotesComponent} from './units/states/portfolios/download-staff-notes/download-staff-notes.component'; import {ProjectPlanComponent} from './projects/states/plan/project-plan.component'; import {TaskPlannerComponent} from './projects/states/plan/task-planner/task-planner.component'; import {TaskPlannerCardComponent} from './projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component'; @@ -580,6 +581,11 @@ DoubtfireAngularJSModule.directive( downgradeComponent({component: UploadGradesComponent}), ); +DoubtfireAngularJSModule.directive( + 'fDownloadStaffNotes', + downgradeComponent({component: DownloadStaffNotesComponent}), +); + DoubtfireAngularJSModule.directive( 'fProjectPlan', downgradeComponent({component: ProjectPlanComponent}), diff --git a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html new file mode 100644 index 0000000000..529708f97c --- /dev/null +++ b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html @@ -0,0 +1,3 @@ + diff --git a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.scss b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts new file mode 100644 index 0000000000..eb3e1501bd --- /dev/null +++ b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts @@ -0,0 +1,24 @@ +import {Component, Input, OnInit} from '@angular/core'; +import {Unit} from 'src/app/api/models/unit'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-download-staff-notes', + templateUrl: 'download-staff-notes.component.html', + styleUrl: 'download-staff-notes.component.scss', +}) +export class DownloadStaffNotesComponent implements OnInit { + @Input() unit: Unit; + + constructor(private alertService: AlertService) {} + + public ngOnInit(): void { + if (!this.unit) { + return console.error(`Invalid unit`); + } + } + + public downloadStaffNotesCsv() { + this.unit.downloadStaffNotesCsv(); + } +} diff --git a/src/app/units/states/portfolios/portfolios.tpl.html b/src/app/units/states/portfolios/portfolios.tpl.html index 34d00d5d7f..eaff240d73 100644 --- a/src/app/units/states/portfolios/portfolios.tpl.html +++ b/src/app/units/states/portfolios/portfolios.tpl.html @@ -236,6 +236,7 @@

    Mark Portfolios

    rotate="false" >
    +
    -
    -

    You are not enrolled in any {{ externalName.value }} units.

    -

    Contact your unit convenor or tutor to enrol you in a subject.

    -
    + @if (!notEnrolled && projects?.length === 0 && unitRoles?.length === 0) { +
    +

    You are not enrolled in any {{ externalName.value }} units.

    +

    Contact your unit convenor or tutor to enrol you in a subject.

    +
    + }

    Units you teach

    @@ -19,38 +18,38 @@

    Units you teach

    -
    - - - {{ unitRole.unit?.name }} - {{ unitRole.unit?.code }} - - - - - - - {{ unitRole.teachingPeriod?.name || showDate(unitRole.unit.startDate) }} - - - {{ unitRole.role }} - - - - - - -
    + @if (!unitRole.unit.teachingPeriod || unitRole.unit.teachingPeriod?.active) { +
    + + + {{ unitRole.unit?.name }} + {{ unitRole.unit?.code }} + + + + + + + {{ unitRole.teachingPeriod?.name || showDate(unitRole.unit.startDate) }} + + + {{ unitRole.role }} + + + + + + +
    + }
    Enrolled units
    -
    -
    - - - {{ project.unit.name }} - {{ project.unit.code }} - - - - - - - {{ project.unit.teachingPeriod?.name || showDate(project.unit.startDate) }} - - - - - - + @for (project of projects; track project) { +
    + @if (project.unit.isActive) { +
    + + + {{ project.unit.name }} + {{ project.unit.code }} + + + + + + + {{ project.unit.teachingPeriod?.name || showDate(project.unit.startDate) }} + + + + + + +
    + }
    -
    + } + @if (d2lDataMapping.id) { + + } diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html index 210e1be655..092508da3a 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html @@ -132,9 +132,11 @@

    Unit Staff

    (optionSelected)="addSelectedStaff($event.option.value)" [displayWith]="displayStaffName" > - - {{ staff.name }} - + @for (staff of filteredStaff; track staff) { + + {{ staff.name }} + + } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html index cf4faacbe4..f534b66b97 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html @@ -39,9 +39,11 @@ matTooltipShowDelay="1000" (selectionChange)="updateTaskPrerequisite(link)" > - - {{ state.label }} - + @for (state of stateOptions; track state) { + + {{ state.label }} + + } } } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html index b5250fe675..63c972facf 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html @@ -54,64 +54,66 @@

    Manage Target Dates

    - - -
    - -
    - - -
    - - Start Date - + +
    + +
    + + +
    + - - - - - - Target Date - + Start Date + + + + + - @if (isStartAfterTarget(td, g)) { - Target date must be after start date - } - - - - -
    - - + > + Target Date + + @if (isStartAfterTarget(td, g)) { + + Target date must be after start date + + } + + +
    +
    + +
    + } diff --git a/src/app/units/states/edit/unit-admin-state.component.html b/src/app/units/states/edit/unit-admin-state.component.html index c0414b2692..ebe4a87ca1 100644 --- a/src/app/units/states/edit/unit-admin-state.component.html +++ b/src/app/units/states/edit/unit-admin-state.component.html @@ -10,76 +10,72 @@ } -
    - - @if (unit) { -
    - -
    +
    + @switch (currentTab.routeSegment) { + @case ('details') { + @if (unit) { +
    + +
    + } } - - - - @if (unit) { -
    -
    -

    Unit Learning Outcomes

    -

    Manage unit outcomes and related feedback templates.

    + @case ('learning-outcomes') { + @if (unit) { +
    +
    +

    Unit Learning Outcomes

    +

    Manage unit outcomes and related feedback templates.

    +
    +
    - -
    + } } - - - - @if (unit) { -
    - -
    + @case ('staff') { + @if (unit) { +
    + +
    + } } -
    - - - @if (unit) { -
    -
    -

    Tutorials

    -

    Manage tutorial streams and classes for this unit.

    + @case ('tutorials') { + @if (unit) { +
    +
    +

    Tutorials

    +

    Manage tutorial streams and classes for this unit.

    +
    +
    - -
    + } } - - - - @if (unit) { -
    - -
    + @case ('students') { + @if (unit) { +
    + +
    + } } -
    - - - @if (unit) { -
    - -
    + @case ('tasks') { + @if (unit) { +
    + +
    + } } -
    - - - @if (unit) { -
    -
    -

    Groups

    -

    Configure group sets and manage team-based activities.

    + @case ('groups') { + @if (unit) { +
    +
    +

    Groups

    +

    Configure group sets and manage team-based activities.

    +
    +
    - -
    + } } - + }
    diff --git a/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.html b/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.html index 773d151132..dda733d9bf 100644 --- a/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.html +++ b/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.html @@ -60,56 +60,53 @@
    -
    - -
    - @if (task.hasPdf) { - - } @else { -
    - - description_off - -
    - } -
    -
    - - -
    - @if (task.definition.hasTaskSheet) { - - } @else { -
    - - subtitles_off - -
    - } -
    -
    - - -
    - -
    -
    - - -
    - -
    -
    - - -
    - -
    -
    - - -
    -
    +
    + @switch (currentTab) { + @case (InboxDashboardTab.submission) { +
    + @if (task.hasPdf) { + + } @else { +
    + + description_off + +
    + } +
    + } + @case (InboxDashboardTab.taskSheet) { +
    + @if (task.definition.hasTaskSheet) { + + } @else { +
    + + subtitles_off + +
    + } +
    + } + @case (InboxDashboardTab.staffNotes) { +
    + +
    + } + @case (InboxDashboardTab.tutorNotes) { +
    + +
    + } + @case (InboxDashboardTab.similarities) { +
    + +
    + } + @case (InboxDashboardTab.overseer) { +
    + } + }
    } @else {
    diff --git a/src/app/units/task-viewer/task-viewer-state.component.html b/src/app/units/task-viewer/task-viewer-state.component.html index 8cdf71603b..3b54723add 100644 --- a/src/app/units/task-viewer/task-viewer-state.component.html +++ b/src/app/units/task-viewer/task-viewer-state.component.html @@ -1,56 +1,58 @@ -
    - -
    -
    - -
    +@if (unit$ | async; as unit) { +
    + +
    +
    + +
    + +
    +
    + +
    + @if (selectedTaskDefinition$ | async; as selectedTaskDef) { +
    +
    + +
    + +
    + } +
    +
    +
    + +
    +
    - -
    - - -
    -
    -
    - -
    - +
    +
    +
    +
    + +
    +
    - - -
    -
    - -
    - -
    -
    - -
    - -
    - -
    - -
    -
    -
    +} diff --git a/src/main.ts b/src/main.ts index 9fbcaa2373..75742be059 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,4 +1,4 @@ -import {enableProdMode} from '@angular/core'; +import {enableProdMode, provideZoneChangeDetection} from '@angular/core'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; import {environment} from 'src/environments/environment'; @@ -8,4 +8,6 @@ if (environment.production) { enableProdMode(); } -platformBrowserDynamic().bootstrapModule(DoubtfireAngularModule); +platformBrowserDynamic().bootstrapModule(DoubtfireAngularModule, { + applicationProviders: [provideZoneChangeDetection()], +}); diff --git a/tsconfig.json b/tsconfig.json index 3a4f21d922..84230f0709 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,18 +16,12 @@ "strict": false, "strictPropertyInitialization": false, "target": "ES2022", - "typeRoots": [ - "node_modules/@types" - ], - "lib": [ - "es2020", - "dom", - "ES2021.String" - ], + "typeRoots": ["node_modules/@types"], "useDefineForClassFields": false, "skipLibCheck": true }, "angularCompilerOptions": { - "strictTemplates": false + "strictTemplates": false, + "typeCheckHostBindings": false } } From 5fd0f3d51fb87dfc6058ff2176c839d25dd52de2 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:03:24 +1000 Subject: [PATCH 0993/1280] chore: ugprade to material 21 --- package-lock.json | 43 ++++++++++++++++++++++--------------------- package.json | 6 +++--- 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/package-lock.json b/package-lock.json index 465a278d8b..eb369a8db1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,13 +10,13 @@ "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", - "@angular/cdk": "^20.2.14", + "@angular/cdk": "^21.2.9", "@angular/common": "^21.2.11", "@angular/compiler": "^21.2.11", "@angular/core": "^21.2.11", "@angular/forms": "^21.2.11", - "@angular/material": "^20.2.14", - "@angular/material-date-fns-adapter": "^20.2.14", + "@angular/material": "^21.2.9", + "@angular/material-date-fns-adapter": "^21.2.9", "@angular/platform-browser": "^21.2.11", "@angular/platform-browser-dynamic": "^21.2.11", "@angular/router": "^21.2.11", @@ -835,17 +835,18 @@ } }, "node_modules/@angular/cdk": { - "version": "20.2.14", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-20.2.14.tgz", - "integrity": "sha512-7bZxc01URbiPiIBWThQ69XwOxVduqEKN4PhpbF2AAyfMc/W8Hcr4VoIJOwL0O1Nkq5beS8pCAqoOeIgFyXd/kg==", + "version": "21.2.9", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.9.tgz", + "integrity": "sha512-0JXsr8f7xjV2815esTSq4+zGqWMa0CyNT/DV1F7lYS6qkYXcFdYUzGcd/WjNL05VKkajkSkWmTi6uyVsOpYdGA==", "license": "MIT", "dependencies": { "parse5": "^8.0.0", "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/common": "^20.0.0 || ^21.0.0", - "@angular/core": "^20.0.0 || ^21.0.0", + "@angular/common": "^21.0.0 || ^22.0.0", + "@angular/core": "^21.0.0 || ^22.0.0", + "@angular/platform-browser": "^21.0.0 || ^22.0.0", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -1607,33 +1608,33 @@ } }, "node_modules/@angular/material": { - "version": "20.2.14", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-20.2.14.tgz", - "integrity": "sha512-IbAgV6XLsvmHiJzxycVhcNC1PA4M30qi+ERCOir6cT333Bxm8vDV32gsOjfL52uzG5YRARroPC+8s1XqR2oxeA==", + "version": "21.2.9", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-21.2.9.tgz", + "integrity": "sha512-uU5Sy0rSd4Y4WjqTcrqs3MpfY/Uy5tmDPSAAvwD0y5y4QVOLoV8uhTQDI/nNg2Lh9NoJKvykZE1ITRMvjfRALQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/cdk": "20.2.14", - "@angular/common": "^20.0.0 || ^21.0.0", - "@angular/core": "^20.0.0 || ^21.0.0", - "@angular/forms": "^20.0.0 || ^21.0.0", - "@angular/platform-browser": "^20.0.0 || ^21.0.0", + "@angular/cdk": "21.2.9", + "@angular/common": "^21.0.0 || ^22.0.0", + "@angular/core": "^21.0.0 || ^22.0.0", + "@angular/forms": "^21.0.0 || ^22.0.0", + "@angular/platform-browser": "^21.0.0 || ^22.0.0", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/material-date-fns-adapter": { - "version": "20.2.14", - "resolved": "https://registry.npmjs.org/@angular/material-date-fns-adapter/-/material-date-fns-adapter-20.2.14.tgz", - "integrity": "sha512-/LRtKSP1WOSgbahbeQlagCZoMOQc9VYZqSDSzmhV0xfiNtT6oQD9a5KMbr5LkozJZQnZUoY7QYveTXe4BD8r2Q==", + "version": "21.2.9", + "resolved": "https://registry.npmjs.org/@angular/material-date-fns-adapter/-/material-date-fns-adapter-21.2.9.tgz", + "integrity": "sha512-tZ48ToUMzGkrwRPsUxPElNsw4AHRtDo8wGjyihwPUAlDQRXU8Mx0oszHcceJFWlTeXSy5uK722jS4rOd+c1t0w==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/core": "^20.0.0 || ^21.0.0", - "@angular/material": "20.2.14", + "@angular/core": "^21.0.0 || ^22.0.0", + "@angular/material": "21.2.9", "date-fns": ">2.20.0 <5.0" } }, diff --git a/package.json b/package.json index 8257012b92..4af41c7999 100644 --- a/package.json +++ b/package.json @@ -27,13 +27,13 @@ "author": "", "dependencies": { "@angular/animations": "^21.2.11", - "@angular/cdk": "^20.2.14", + "@angular/cdk": "^21.2.9", "@angular/common": "^21.2.11", "@angular/compiler": "^21.2.11", "@angular/core": "^21.2.11", "@angular/forms": "^21.2.11", - "@angular/material": "^20.2.14", - "@angular/material-date-fns-adapter": "^20.2.14", + "@angular/material": "^21.2.9", + "@angular/material-date-fns-adapter": "^21.2.9", "@angular/platform-browser": "^21.2.11", "@angular/platform-browser-dynamic": "^21.2.11", "@angular/router": "^21.2.11", From 5114f184ed0cd48adaac29465bbc1c4b6ce08777 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 30 Apr 2026 14:42:55 +1000 Subject: [PATCH 0994/1280] chore: remove client side code to check for feedback --- src/app/api/models/task.ts | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index c66b757b6d..2f65d2bcce 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -989,20 +989,6 @@ export class Task extends Entity { return; } - if (status === 'complete' || status === 'fix_and_resubmit' || status === 'redo') { - if (!this.commentsSinceLatestReadyForFeedback().some((comment) => comment.isManualFeedback)) { - alerts.error( - status === 'complete' - ? 'Feedback must be given before moving this task to Complete' - : status === 'fix_and_resubmit' - ? 'Feedback must be given before moving this task to Fix and Resubmit' - : 'Feedback must be given before moving this task to Redo', - 6000, - ); - return; - } - } - const updateFunc = () => { const taskService: TaskService = AppInjector.get(TaskService); const options: RequestOptions = { From 1ff046bba12d6c59abf619f1cd97316d11e7283b Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 5 May 2026 11:17:17 +1000 Subject: [PATCH 0995/1280] chore(release): 10.0.1-36 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abe6841cd3..ce3017c2a9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [10.0.1-36](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-35...v10.0.1-36) (2026-05-05) + ### [10.0.1-35](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-34...v10.0.1-35) (2026-04-28) diff --git a/package-lock.json b/package-lock.json index 2d04bf6335..756a0fb315 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.1-35", + "version": "10.0.1-36", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.1-35", + "version": "10.0.1-36", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 03f33ec244..80e455b7b2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.1-35", + "version": "10.0.1-36", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From e4080d03a629654518bc362f48e8e0fbb790dd96 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Mon, 11 May 2026 12:35:21 +1000 Subject: [PATCH 0996/1280] fix: unlock task status selection for staff (#1222) fix: unlock task status selection for staff --- .../task-status-card/task-status-card.component.html | 6 ++++-- .../task-status-card/task-status-card.component.ts | 10 ++++++++++ 2 files changed, 14 insertions(+), 2 deletions(-) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.html index 7b49a65daa..fd2497ea4a 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.html @@ -4,7 +4,7 @@ @@ -47,7 +47,9 @@
    {{ task?.statusLabel() }}
    mat-stroked-button (click)="uploadSubmission()" [disabled]=" - isReadyForFeedback() || task?.blockedByPrerequisiteTasks() || isSubmittedForPortfolio() + isReadyForFeedback() || + (task?.blockedByPrerequisiteTasks() && !isTutor) || + isSubmittedForPortfolio() " > Upload Submission diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts index 8738a0bffd..b4233712db 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts @@ -12,6 +12,7 @@ import {SubmissionTypeModalService} from 'src/app/tasks/modals/submission-type-m import {Project} from 'src/app/api/models/project'; import {UserService} from 'src/app/api/services/user.service'; import {FeedbackAppealModalService} from 'src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.service'; +import {UnitRole} from 'src/app/api/models/unit-role'; @Component({ selector: 'f-task-status-card', templateUrl: './task-status-card.component.html', @@ -129,4 +130,13 @@ export class TaskStatusCardComponent implements OnChanges, AfterViewInit { openFeedbackAppealModal(): void { this.feedbackAppealService.show(this.task); } + + public get currentUnitRole(): UnitRole | undefined { + const currentUser = this.userService.currentUser; + return this.project.unit.staff.find((ur) => ur.user.id === currentUser.id); + } + + public get isTutor(): boolean { + return this.currentUnitRole.role === 'Convenor' || this.currentUnitRole.role === 'Tutor'; + } } From 8e18d30fc52ce62ee9d3c8ee94c7335bda652d9f Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 12 May 2026 11:39:15 +1000 Subject: [PATCH 0997/1280] chore(release): 10.0.1-37 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ce3017c2a9..6c02ea7571 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [10.0.1-37](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-36...v10.0.1-37) (2026-05-12) + + +### Bug Fixes + +* unlock task status selection for staff ([#1222](https://github.com/b0ink/doubtfire-deploy/issues/1222)) ([e4080d0](https://github.com/b0ink/doubtfire-deploy/commit/e4080d03a629654518bc362f48e8e0fbb790dd96)) + ### [10.0.1-36](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-35...v10.0.1-36) (2026-05-05) ### [10.0.1-35](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-34...v10.0.1-35) (2026-04-28) diff --git a/package-lock.json b/package-lock.json index 756a0fb315..9326ac911f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.1-36", + "version": "10.0.1-37", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.1-36", + "version": "10.0.1-37", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 80e455b7b2..0802cc8121 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.1-36", + "version": "10.0.1-37", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From f1528d1aedc7d6485b094ed3c4923b44c786d45b Mon Sep 17 00:00:00 2001 From: Cilly Leang Date: Tue, 12 May 2026 23:15:46 +1000 Subject: [PATCH 0998/1280] fix: prevent multiple global fetches --- src/app/projects/states/index/global-state.service.ts | 4 +--- src/app/sessions/states/sign-in/sign-in.component.ts | 2 -- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/app/projects/states/index/global-state.service.ts b/src/app/projects/states/index/global-state.service.ts index 6d3cdb12d2..63570b09e0 100644 --- a/src/app/projects/states/index/global-state.service.ts +++ b/src/app/projects/states/index/global-state.service.ts @@ -122,9 +122,7 @@ export class GlobalStateService implements OnDestroy { setTimeout(() => { // Try to login using the refresh token this.authenticationService.attemptLoginUsingRefreshToken((result: boolean) => { - if (result) { - this.loadGlobals(); - } else { + if (!result) { // Loading is finshed... this.isLoadingSubject.next(false); diff --git a/src/app/sessions/states/sign-in/sign-in.component.ts b/src/app/sessions/states/sign-in/sign-in.component.ts index 2196ee83c9..3417cefecc 100644 --- a/src/app/sessions/states/sign-in/sign-in.component.ts +++ b/src/app/sessions/states/sign-in/sign-in.component.ts @@ -211,7 +211,6 @@ export class SignInComponent implements OnInit { * Perform the actions needed when the user successfully signs in. */ private actionSignInSuccess(): void { - this.globalState.loadGlobals(); this.state.go('welcome'); } @@ -251,7 +250,6 @@ export class SignInComponent implements OnInit { this.authService.signIn(signInCredentials).subscribe({ next: () => { if (this.isLtiLogin) { - this.globalState.loadGlobals(); const params = getUrlParams(document.location.href); this.state.go('lti', { ltik: params.ltik, From d81ac52cf1b90e139a34bf13ed08142919b6cc53 Mon Sep 17 00:00:00 2001 From: Cilly Leang Date: Tue, 12 May 2026 23:16:29 +1000 Subject: [PATCH 0999/1280] fix: improve global loading logic for staff Ensure that specifically the CampusService and TeachingPeriodService are loaded before starting to load projects --- .../projects/states/index/global-state.service.ts | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/app/projects/states/index/global-state.service.ts b/src/app/projects/states/index/global-state.service.ts index 63570b09e0..e22ea3dc94 100644 --- a/src/app/projects/states/index/global-state.service.ts +++ b/src/app/projects/states/index/global-state.service.ts @@ -2,7 +2,7 @@ import {Inject, Injectable, OnDestroy} from '@angular/core'; import {MediaObserver} from 'ng-flex-layout'; import {UIRouter} from '@uirouter/angular'; import {EntityCache} from 'ngx-entity-service'; -import {BehaviorSubject, Observable, Subject, skip, take} from 'rxjs'; +import {BehaviorSubject, Observable, Subject, find} from 'rxjs'; import { CampusService, LearningOutcomeService, @@ -220,6 +220,7 @@ export class GlobalStateService implements OnDestroy { } public loadGlobals(): void { + let loaded = 0; // Indicate we are loading data... this.isLoadingSubject.next(true); @@ -228,7 +229,7 @@ export class GlobalStateService implements OnDestroy { // Loading campuses this.campusService.query().subscribe({ next: (_response) => { - subscriber.next(true); + subscriber.next(++loaded); }, error: (_response) => { this.alerts.error('Unable to access service. Failed loading campuses.', 6000); @@ -240,7 +241,7 @@ export class GlobalStateService implements OnDestroy { .query({}, {endpointFormat: LearningOutcomeService.globalEndpoint}) .subscribe({ next: (_response) => { - subscriber.next(true); + subscriber.next(null); }, error: (_response) => { this.alerts.error('Unable to access service. Failed loading GLOs.', 6000); @@ -251,7 +252,7 @@ export class GlobalStateService implements OnDestroy { .query({}, {endpointFormat: FeedbackTemplateService.globalEndpoint}) .subscribe({ next: (_response) => { - subscriber.next(true); + subscriber.next(null); }, error: (_response) => { this.alerts.error( @@ -265,7 +266,7 @@ export class GlobalStateService implements OnDestroy { // Loading teaching periods this.teachingPeriodService.query().subscribe({ next: (_response) => { - subscriber.next(true); + subscriber.next(++loaded); }, error: (_response) => { this.alerts.error('Unable to access service. Failed loading teaching periods.', 6000); @@ -274,7 +275,7 @@ export class GlobalStateService implements OnDestroy { }); // Watch for load of campuses and teaching periods, then trigger loading of unit roles and projects - loadingObserver.pipe(skip(1), take(1)).subscribe({ + loadingObserver.pipe(find(loaded => loaded === 2)).subscribe({ next: () => { // trigger loading of units and projects - this will end the loading when complete this.loadUnitsAndProjects(); From a415d45cdf51c04421a1cb39a480feecedc7a870 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 30 Apr 2026 16:25:31 +1000 Subject: [PATCH 1000/1280] chore: upgrade ngx-entity-service --- package-lock.json | 502 +++++++++++++++++- package.json | 8 +- .../api/models/activity-type/activity-type.ts | 9 +- src/app/api/models/campus/campus.ts | 14 +- src/app/api/models/groups/group-membership.ts | 7 +- src/app/api/models/groups/group-set.ts | 12 +- src/app/api/models/overseer/overseer-image.ts | 9 +- src/app/api/models/task-definition.ts | 10 +- src/app/api/models/task-outcome-alignment.ts | 10 +- src/app/api/models/teaching-period.ts | 31 +- src/app/api/models/tii-action.ts | 7 +- src/app/api/models/tutorial-enrolment.ts | 5 +- .../models/tutorial-stream/tutorial-stream.ts | 4 +- src/app/api/models/tutorial/tutorial.ts | 14 +- src/app/api/models/webcal/webcal.ts | 7 +- src/app/api/services/project.service.ts | 10 +- src/app/api/services/sidekiq-job.service.ts | 2 +- src/app/api/services/staff-note.service.ts | 2 +- src/app/api/services/task-comment.service.ts | 2 +- .../api/services/task-definition.service.ts | 4 +- src/app/api/services/task.service.ts | 5 +- src/app/api/services/tutorial.service.ts | 2 +- src/app/api/services/unit.service.ts | 4 +- .../entity-form/entity-form.component.ts | 27 +- .../unit-tutorials-list.component.ts | 70 ++- 25 files changed, 648 insertions(+), 129 deletions(-) diff --git a/package-lock.json b/package-lock.json index eb369a8db1..e9b7526355 100644 --- a/package-lock.json +++ b/package-lock.json @@ -51,15 +51,15 @@ "lottie-web": "^5.13.0", "marked": "^12", "moment": "^2.30", - "monaco-editor": "^0.52.2", + "monaco-editor": "^0.55.1", "ng-csv": "0.2.3", "ng-file-upload": "~5.0.9", "ng-flex-layout": "^17.3.7-beta.1", "ng2-pdf-viewer": "10.2.2", "ngx-bootstrap": "^6.1.0", - "ngx-entity-service": "^0.0.41", + "ngx-entity-service": "^0.0.42", "ngx-lottie": "^11.0.2", - "ngx-monaco-editor-v2": "^19", + "ngx-monaco-editor-v2": "^21", "npm": "^10.4.0", "nvd3": "1.8.6", "qrcode": "^1.5.4", @@ -3591,6 +3591,208 @@ "win32" ] }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "optional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "optional": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", + "optional": true + }, "node_modules/@mattlewis92/dom-autoscroller": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@mattlewis92/dom-autoscroller/-/dom-autoscroller-2.4.2.tgz", @@ -6064,6 +6266,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "license": "MIT", + "optional": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz", @@ -6380,7 +6589,7 @@ }, "node_modules/abbrev": { "version": "1.1.1", - "dev": true, + "devOptional": true, "license": "ISC" }, "node_modules/accepts": { @@ -7043,6 +7252,28 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/aproba": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "license": "ISC", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/arg": { "version": "5.0.2", "dev": true, @@ -8039,6 +8270,22 @@ "dev": true, "license": "MIT" }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/canvas-confetti": { "version": "1.9.4", "license": "ISC", @@ -8452,6 +8699,16 @@ "version": "1.1.4", "license": "MIT" }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -8662,6 +8919,13 @@ "date-now": "^0.1.4" } }, + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", + "optional": true + }, "node_modules/constantinople": { "version": "3.1.2", "dev": true, @@ -9280,6 +9544,19 @@ "node": ">=0.10" } }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "license": "MIT", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/deep-is": { "version": "0.1.4", "license": "MIT", @@ -9385,6 +9662,13 @@ "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", + "optional": true + }, "node_modules/depd": { "version": "2.0.0", "dev": true, @@ -9420,7 +9704,6 @@ }, "node_modules/detect-libc": { "version": "2.1.2", - "dev": true, "license": "Apache-2.0", "optional": true, "engines": { @@ -9547,6 +9830,15 @@ "url": "https://github.com/fb55/domhandler?sponsor=1" } }, + "node_modules/dompurify": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.2.7.tgz", + "integrity": "sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==", + "license": "(MPL-2.0 OR Apache-2.0)", + "optionalDependencies": { + "@types/trusted-types": "^2.0.7" + } + }, "node_modules/domutils": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", @@ -11029,6 +11321,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/gaze": { "version": "1.1.3", "dev": true, @@ -12596,6 +12910,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", + "optional": true + }, "node_modules/has-value": { "version": "1.0.0", "dev": true, @@ -15004,6 +15325,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "9.0.5", "dev": true, @@ -15219,10 +15553,26 @@ } }, "node_modules/monaco-editor": { - "version": "0.52.2", - "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.52.2.tgz", - "integrity": "sha512-GEQWEZmfkOGLdd3XK8ryrfWz3AIP8YymVXiPHEdewrUq7mh0qrKrfHLNCXcbB6sTnMLnOZ3ztSiKcciFUkIJwQ==", - "license": "MIT" + "version": "0.55.1", + "resolved": "https://registry.npmjs.org/monaco-editor/-/monaco-editor-0.55.1.tgz", + "integrity": "sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==", + "license": "MIT", + "dependencies": { + "dompurify": "3.2.7", + "marked": "14.0.0" + } + }, + "node_modules/monaco-editor/node_modules/marked": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/marked/-/marked-14.0.0.tgz", + "integrity": "sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==", + "license": "MIT", + "bin": { + "marked": "bin/marked.js" + }, + "engines": { + "node": ">= 18" + } }, "node_modules/morgan": { "version": "1.10.1", @@ -15359,7 +15709,6 @@ "version": "2.26.2", "resolved": "https://registry.npmjs.org/nan/-/nan-2.26.2.tgz", "integrity": "sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==", - "dev": true, "license": "MIT", "optional": true }, @@ -15538,6 +15887,8 @@ }, "node_modules/ng2-pdf-viewer": { "version": "10.2.2", + "resolved": "https://registry.npmjs.org/ng2-pdf-viewer/-/ng2-pdf-viewer-10.2.2.tgz", + "integrity": "sha512-GaKAvF0nXAiR9U4LFWuT54MM9nzp0ie8GGscp34W+lFsSOXdlwS0iFx5UPuVlODRm3YEUKx6xcK5oaJeBq0SAw==", "license": "MIT", "dependencies": { "pdfjs-dist": "^3.11.174", @@ -15553,13 +15904,15 @@ } }, "node_modules/ngx-entity-service": { - "version": "0.0.41", + "version": "0.0.42", + "resolved": "https://registry.npmjs.org/ngx-entity-service/-/ngx-entity-service-0.0.42.tgz", + "integrity": "sha512-RmehGi3FmftKz2W/i9o35MwR548mz+I/pRXPgU9CWtMhi4VFqqrq5+XFrzSzx3iMpRuLHER19tmdFnX5PYihtQ==", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/common": "^13.0 || ^14.0 || ^15.0 || ^16.0 || ^17 || ^18", - "@angular/core": "^13.0 || ^14.0 || ^15.0 || ^16.0 || ^17 || ^18" + "@angular/common": "^13.0 || ^14.0 || ^15.0 || ^16.0 || ^17 || ^18 || ^19 || ^20 || ^21", + "@angular/core": "^13.0 || ^14.0 || ^15.0 || ^16.0 || ^17 || ^18 || ^19 || ^20 || ^21" } }, "node_modules/ngx-lottie": { @@ -15575,17 +15928,17 @@ } }, "node_modules/ngx-monaco-editor-v2": { - "version": "19.0.2", - "resolved": "https://registry.npmjs.org/ngx-monaco-editor-v2/-/ngx-monaco-editor-v2-19.0.2.tgz", - "integrity": "sha512-hkPiCnLU0vdIF2DW7Ko/EHoGCtLxuN85eygKuk3fXL2GRbEIl5VcbUXmRX9ItfLOI1F5QcH80HhavY5r0gNfEw==", + "version": "21.1.4", + "resolved": "https://registry.npmjs.org/ngx-monaco-editor-v2/-/ngx-monaco-editor-v2-21.1.4.tgz", + "integrity": "sha512-dZu3dY3D1YXPTIDRn9zOERdtDtGy1SOztpWG6gJlaj6NMSV59kNR/hfzaP+L3BukP6Ve07f3bIyvsx6Pz7uOaA==", "license": "MIT", "dependencies": { - "tslib": "^2.1.0" + "tslib": "^2.8.1" }, "peerDependencies": { - "@angular/common": "^19.0.4", - "@angular/core": "^19.0.4", - "monaco-editor": "^0.52.2" + "@angular/common": "^21.1.4", + "@angular/core": "^21.1.4", + "monaco-editor": "^0.55.1" } }, "node_modules/no-case": { @@ -15604,6 +15957,27 @@ "license": "MIT", "optional": true }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "optional": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-gyp": { "version": "12.3.0", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.3.0.tgz", @@ -18262,6 +18636,20 @@ "node": ">=18" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -18605,7 +18993,7 @@ }, "node_modules/object-assign": { "version": "4.1.1", - "dev": true, + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -19179,6 +19567,8 @@ }, "node_modules/path2d-polyfill": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", + "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", "license": "MIT", "optional": true, "engines": { @@ -19187,6 +19577,8 @@ }, "node_modules/pdfjs-dist": { "version": "3.11.174", + "resolved": "https://registry.npmjs.org/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", + "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", "license": "Apache-2.0", "engines": { "node": ">=18" @@ -21628,11 +22020,44 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, "node_modules/simple-fmt": { "version": "0.1.0", "dev": true, "license": "MIT" }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/simple-is": { "version": "0.2.0", "dev": true, @@ -22606,6 +23031,13 @@ "node": ">=6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT", + "optional": true + }, "node_modules/tree-kill": { "version": "1.2.2", "dev": true, @@ -23607,6 +24039,13 @@ "node": ">=0.8.0" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause", + "optional": true + }, "node_modules/websocket-driver": { "version": "0.7.4", "dev": true, @@ -23628,6 +24067,17 @@ "node": ">=0.8.0" } }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "license": "ISC", @@ -23645,6 +24095,16 @@ "version": "2.0.1", "license": "ISC" }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, "node_modules/window-size": { "version": "0.1.0", "dev": true, diff --git a/package.json b/package.json index 4af41c7999..a3fe329138 100644 --- a/package.json +++ b/package.json @@ -68,15 +68,15 @@ "lottie-web": "^5.13.0", "marked": "^12", "moment": "^2.30", - "monaco-editor": "^0.52.2", + "monaco-editor": "^0.55.1", "ng-csv": "0.2.3", "ng-file-upload": "~5.0.9", "ng-flex-layout": "^17.3.7-beta.1", "ng2-pdf-viewer": "10.2.2", "ngx-bootstrap": "^6.1.0", - "ngx-entity-service": "^0.0.41", + "ngx-entity-service": "^0.0.42", "ngx-lottie": "^11.0.2", - "ngx-monaco-editor-v2": "^19", + "ngx-monaco-editor-v2": "^21", "npm": "^10.4.0", "nvd3": "1.8.6", "qrcode": "^1.5.4", @@ -161,4 +161,4 @@ "@rollup/rollup-linux-arm64-gnu": "*", "@rollup/rollup-linux-x64-gnu": "*" } -} \ No newline at end of file +} diff --git a/src/app/api/models/activity-type/activity-type.ts b/src/app/api/models/activity-type/activity-type.ts index e75d09677d..d084a1901e 100644 --- a/src/app/api/models/activity-type/activity-type.ts +++ b/src/app/api/models/activity-type/activity-type.ts @@ -1,13 +1,16 @@ -import { Entity, EntityMapping } from 'ngx-entity-service'; +import {Entity, EntityMapping} from 'ngx-entity-service'; export class ActivityType extends Entity { id: number; name: string; abbreviation: string; - public override toJson(mappingData: EntityMapping, ignoreKeys?: string[]): object { + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { return { - activity_type: super.toJson(mappingData, ignoreKeys) + activity_type: super.toJson(mappingData, ignoreKeys), }; } } diff --git a/src/app/api/models/campus/campus.ts b/src/app/api/models/campus/campus.ts index 9491e29e53..9df9ef23e6 100644 --- a/src/app/api/models/campus/campus.ts +++ b/src/app/api/models/campus/campus.ts @@ -1,4 +1,4 @@ -import { Entity, EntityMapping } from "ngx-entity-service"; +import {Entity, EntityMapping} from 'ngx-entity-service'; type campusModes = 'timetable' | 'automatic' | 'manual'; @@ -9,9 +9,12 @@ export class Campus extends Entity { abbreviation: string; timezone: string; - public override toJson(mappingData: EntityMapping, ignoreKeys?: string[]): object { + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { return { - campus: super.toJson(mappingData, ignoreKeys) + campus: super.toJson(mappingData, ignoreKeys), }; } @@ -21,6 +24,9 @@ export class Campus extends Entity { * @param matchText the text to match */ public matches(matchText: string): boolean { - return this.name.toLowerCase().indexOf(matchText) >= 0 || this.abbreviation.toLowerCase().indexOf(matchText) >= 0; + return ( + this.name.toLowerCase().indexOf(matchText) >= 0 || + this.abbreviation.toLowerCase().indexOf(matchText) >= 0 + ); } } diff --git a/src/app/api/models/groups/group-membership.ts b/src/app/api/models/groups/group-membership.ts index b7952d8b5e..0a0dca1539 100644 --- a/src/app/api/models/groups/group-membership.ts +++ b/src/app/api/models/groups/group-membership.ts @@ -1,9 +1,8 @@ -import { Entity } from 'ngx-entity-service'; +import {Entity} from 'ngx-entity-service'; export class GroupMembership extends Entity { - public get student_name(): string { - console.log("implement student_name"); - return "TODO NAME"; + console.log('implement student_name'); + return 'TODO NAME'; } } diff --git a/src/app/api/models/groups/group-set.ts b/src/app/api/models/groups/group-set.ts index 42882017d4..cb99f99e44 100644 --- a/src/app/api/models/groups/group-set.ts +++ b/src/app/api/models/groups/group-set.ts @@ -1,11 +1,9 @@ -import { Entity, EntityCache, EntityMapping } from 'ngx-entity-service'; -import { AppInjector } from 'src/app/app-injector'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; -import { Group, Unit, User } from '../doubtfire-model'; - +import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; +import {AppInjector} from 'src/app/app-injector'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Group, Unit, User} from '../doubtfire-model'; export class GroupSet extends Entity { - public id: number; public name: string; public allowStudentsToCreateGroups: boolean = true; @@ -34,7 +32,7 @@ export class GroupSet extends Entity { } public findGroupById(id: number): Group { - return this.groups.find(grp => grp.id === id); + return this.groups.find((grp) => grp.id === id); } public groupCSVUploadUrl(): string { diff --git a/src/app/api/models/overseer/overseer-image.ts b/src/app/api/models/overseer/overseer-image.ts index 277c3df426..2f6627d3be 100644 --- a/src/app/api/models/overseer/overseer-image.ts +++ b/src/app/api/models/overseer/overseer-image.ts @@ -1,5 +1,5 @@ -import { StringNullableChain } from 'lodash'; -import { Entity, EntityMapping } from 'ngx-entity-service'; +import {StringNullableChain} from 'lodash'; +import {Entity, EntityMapping} from 'ngx-entity-service'; export class OverseerImage extends Entity { id: number; @@ -9,7 +9,10 @@ export class OverseerImage extends Entity { pulledImageStatus: string; lastPulledDate: string; - public override toJson(mappingData: EntityMapping, ignoreKeys?: string[]): object { + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { return { overseer_image: super.toJson(mappingData, ignoreKeys), }; diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index c8f88d1e9e..cd5ede1e4b 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -11,15 +11,19 @@ import {TaskPrerequisite} from './task-prerequisite'; import {DiscussionPrompt} from './discussion-prompt'; import {OverseerStep} from './overseer/overseer-step'; -export type UploadRequirement = { +export interface UploadRequirement { key: string; name: string; type: string; tiiCheck?: boolean; tiiPct?: number; -}; +} -export type SimilarityCheck = {key: string; type: string; pattern: string}; +export interface SimilarityCheck { + key: string; + type: string; + pattern: string; +} export class TaskDefinition extends Entity { id: number; diff --git a/src/app/api/models/task-outcome-alignment.ts b/src/app/api/models/task-outcome-alignment.ts index 62414b5245..8569ae5549 100644 --- a/src/app/api/models/task-outcome-alignment.ts +++ b/src/app/api/models/task-outcome-alignment.ts @@ -1,6 +1,6 @@ -import { Entity } from 'ngx-entity-service'; -import { Project, Unit, TaskDefinition, Task } from './doubtfire-model'; -import { LearningOutcome } from './learning-outcome'; +import {Entity} from 'ngx-entity-service'; +import {Project, Unit, TaskDefinition, Task} from './doubtfire-model'; +import {LearningOutcome} from './learning-outcome'; export class TaskOutcomeAlignment extends Entity { public within: Unit | Project; @@ -18,7 +18,7 @@ export class TaskOutcomeAlignment extends Entity { } public get unit(): Unit { - if ( this.within instanceof Unit) { + if (this.within instanceof Unit) { return this.within; } else { return this.within.unit; @@ -26,7 +26,7 @@ export class TaskOutcomeAlignment extends Entity { } public get project(): Project { - if ( this.within instanceof Project) { + if (this.within instanceof Project) { return this.within; } diff --git a/src/app/api/models/teaching-period.ts b/src/app/api/models/teaching-period.ts index 2aca186b7c..f8e11f5f8e 100644 --- a/src/app/api/models/teaching-period.ts +++ b/src/app/api/models/teaching-period.ts @@ -1,7 +1,7 @@ -import { Entity, EntityCache, EntityMapping } from 'ngx-entity-service'; -import { Observable } from 'rxjs'; -import { AppInjector } from 'src/app/app-injector'; -import { TeachingPeriodBreakService, TeachingPeriodService, Unit } from './doubtfire-model'; +import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; +import {AppInjector} from 'src/app/app-injector'; +import {TeachingPeriodBreakService, TeachingPeriodService, Unit} from './doubtfire-model'; export class TeachingPeriodBreak extends Entity { id: number; @@ -27,7 +27,10 @@ export class TeachingPeriod extends Entity { * @param ignoreKeys * @returns */ - public override toJson(mappingData: EntityMapping, ignoreKeys?: string[]): object { + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { return { teaching_period: super.toJson(mappingData, ignoreKeys), }; @@ -69,7 +72,10 @@ export class TeachingPeriod extends Entity { breakEntity.numberOfWeeks = weeks; const breakService: TeachingPeriodBreakService = AppInjector.get(TeachingPeriodBreakService); - return breakService.create({ teaching_period_id: this.id }, { cache: this.breaksCache, entity: breakEntity }); + return breakService.create( + {teaching_period_id: this.id}, + {cache: this.breaksCache, entity: breakEntity}, + ); } /** @@ -79,10 +85,17 @@ export class TeachingPeriod extends Entity { */ public removeBreak(teachingBreakID: number): Observable { const breakService: TeachingPeriodBreakService = AppInjector.get(TeachingPeriodBreakService); - return breakService.delete({ teaching_period_id: this.id, id: teachingBreakID }, { cache: this.breaksCache }); + return breakService.delete( + {teaching_period_id: this.id, id: teachingBreakID}, + {cache: this.breaksCache}, + ); } - public rollover(newPeriod: TeachingPeriod, rolloverInactive: boolean, searchForward: boolean): Observable { + public rollover( + newPeriod: TeachingPeriod, + rolloverInactive: boolean, + searchForward: boolean, + ): Observable { const teachingPeriodService: TeachingPeriodService = AppInjector.get(TeachingPeriodService); return teachingPeriodService.post( @@ -94,7 +107,7 @@ export class TeachingPeriod extends Entity { }, { endpointFormat: TeachingPeriodService.rolloverEndpointFormat, - } + }, ); } } diff --git a/src/app/api/models/tii-action.ts b/src/app/api/models/tii-action.ts index 0f0ed3d599..661ba9324f 100644 --- a/src/app/api/models/tii-action.ts +++ b/src/app/api/models/tii-action.ts @@ -1,6 +1,6 @@ -import { Entity, EntityCache, EntityMapping } from 'ngx-entity-service'; -import { Observable } from 'rxjs'; -import { Unit } from './doubtfire-model'; +import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; +import {Unit} from './doubtfire-model'; export class TiiAction extends Entity { id: number; @@ -14,5 +14,4 @@ export class TiiAction extends Entity { log: string; description: string; - } diff --git a/src/app/api/models/tutorial-enrolment.ts b/src/app/api/models/tutorial-enrolment.ts index 7463175365..2b6f822405 100644 --- a/src/app/api/models/tutorial-enrolment.ts +++ b/src/app/api/models/tutorial-enrolment.ts @@ -1,6 +1,5 @@ -import { Entity } from 'ngx-entity-service'; -import { Tutorial, User } from './doubtfire-model'; - +import {Entity} from 'ngx-entity-service'; +import {Tutorial, User} from './doubtfire-model'; export class TutorialEnrolment extends Entity { public tutorial: Tutorial; diff --git a/src/app/api/models/tutorial-stream/tutorial-stream.ts b/src/app/api/models/tutorial-stream/tutorial-stream.ts index 2ccb96759d..b1ef5ad77d 100644 --- a/src/app/api/models/tutorial-stream/tutorial-stream.ts +++ b/src/app/api/models/tutorial-stream/tutorial-stream.ts @@ -1,5 +1,5 @@ -import { Entity } from 'ngx-entity-service'; -import { Unit, Tutorial } from '../doubtfire-model'; +import {Entity} from 'ngx-entity-service'; +import {Unit, Tutorial} from '../doubtfire-model'; export class TutorialStream extends Entity { name: string; diff --git a/src/app/api/models/tutorial/tutorial.ts b/src/app/api/models/tutorial/tutorial.ts index 181b1ec0d0..0ef41a464d 100644 --- a/src/app/api/models/tutorial/tutorial.ts +++ b/src/app/api/models/tutorial/tutorial.ts @@ -1,7 +1,13 @@ -import { Entity, EntityMapping } from 'ngx-entity-service'; -import { AppInjector } from '../../../app-injector'; -import { User, Campus, UserService, CampusService, TutorialStream } from 'src/app/api/models/doubtfire-model'; -import { Unit } from '../unit'; +import {Entity, EntityMapping} from 'ngx-entity-service'; +import {AppInjector} from '../../../app-injector'; +import { + User, + Campus, + UserService, + CampusService, + TutorialStream, +} from 'src/app/api/models/doubtfire-model'; +import {Unit} from '../unit'; export class Tutorial extends Entity { unit: Unit; // TODO: Convert to a unit object once this exists diff --git a/src/app/api/models/webcal/webcal.ts b/src/app/api/models/webcal/webcal.ts index 26dab8e18f..a77f247b14 100644 --- a/src/app/api/models/webcal/webcal.ts +++ b/src/app/api/models/webcal/webcal.ts @@ -1,4 +1,4 @@ -import { Entity, EntityMapping } from 'ngx-entity-service'; +import {Entity, EntityMapping} from 'ngx-entity-service'; export class Webcal extends Entity { enabled: boolean; @@ -15,7 +15,10 @@ export class Webcal extends Entity { // Used only when updating the webcal. Never returned from the API. shouldChangeGuid?: boolean; - public override toJson(mappingData: EntityMapping, ignoreKeys?: string[]): object { + public override toJson( + mappingData: EntityMapping, + ignoreKeys?: string[], + ): object { return { webcal: super.toJson(mappingData, ignoreKeys), }; diff --git a/src/app/api/services/project.service.ts b/src/app/api/services/project.service.ts index 0149e89793..3a99563192 100644 --- a/src/app/api/services/project.service.ts +++ b/src/app/api/services/project.service.ts @@ -1,4 +1,4 @@ -import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; +import {CachedEntityService, MappingProcess, RequestOptions} from 'ngx-entity-service'; import { CampusService, Project, @@ -15,12 +15,6 @@ import {TaskService} from './task.service'; import {TaskOutcomeAlignmentService} from './task-outcome-alignment.service'; import {GroupService} from './group.service'; -interface MappingProcessLike { - data: object; - entity: T; - continue(): void; -} - @Injectable() export class ProjectService extends CachedEntityService { protected readonly endpointFormat = 'projects/:id:'; @@ -142,7 +136,7 @@ export class ProjectService extends CachedEntityService { }, { keys: 'unitId', - toEntityOpAsync: (process: MappingProcessLike) => { + toEntityOpAsync: (process: MappingProcess) => { const unitService: UnitService = AppInjector.get(UnitService); const unitId = process.data['unit_id']; // Load what we have... or a a stub for now... diff --git a/src/app/api/services/sidekiq-job.service.ts b/src/app/api/services/sidekiq-job.service.ts index dd5332a258..8a61e01b55 100644 --- a/src/app/api/services/sidekiq-job.service.ts +++ b/src/app/api/services/sidekiq-job.service.ts @@ -15,7 +15,7 @@ export interface SidekiqJobEntry { export class SidekiqJobService extends CachedEntityService { protected readonly endpointFormat = 'sidekiq/:id:'; - public jobEntries: Map = new Map(); + public jobEntries = new Map(); // Allow components to track changes to jobEntries public sidekiqJobsSubject = new BehaviorSubject([]); diff --git a/src/app/api/services/staff-note.service.ts b/src/app/api/services/staff-note.service.ts index 0a707fea8c..6e989e17f3 100644 --- a/src/app/api/services/staff-note.service.ts +++ b/src/app/api/services/staff-note.service.ts @@ -8,7 +8,7 @@ import {Observable, tap} from 'rxjs'; @Injectable() export class StaffNoteService extends CachedEntityService { - public readonly staffNoteAdded$: EventEmitter = new EventEmitter(); + public readonly staffNoteAdded$ = new EventEmitter(); protected readonly endpointFormat = 'projects/:projectId:/staff_notes/:id:'; diff --git a/src/app/api/services/task-comment.service.ts b/src/app/api/services/task-comment.service.ts index 658cd85d80..8e49f12cc8 100644 --- a/src/app/api/services/task-comment.service.ts +++ b/src/app/api/services/task-comment.service.ts @@ -20,7 +20,7 @@ import {ScormExtensionComment} from '../models/task-comment/scorm-extension-comm @Injectable() export class TaskCommentService extends CachedEntityService { - public readonly commentAdded$: EventEmitter = new EventEmitter(); + public readonly commentAdded$ = new EventEmitter(); private readonly commentEndpointFormat = 'projects/:projectId:/task_def_id/:taskDefinitionId:/comments/:id:'; diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index 364d0f89c3..7591ae3f66 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -72,13 +72,13 @@ export class TaskDefinitionService extends CachedEntityService { }, toEntityFn: (data: object, key: string, taskDef: TaskDefinition, params?: any) => { return ( - data[key] as Array<{ + data[key] as { key: string; name: string; type: string; tii_check: boolean; tii_pct: number; - }> + }[] )?.map((upreq) => { return { key: upreq.key, diff --git a/src/app/api/services/task.service.ts b/src/app/api/services/task.service.ts index fdc69de09d..95cbceb5e1 100644 --- a/src/app/api/services/task.service.ts +++ b/src/app/api/services/task.service.ts @@ -16,7 +16,7 @@ import {Observable, map, tap} from 'rxjs'; @Injectable() export class TaskService extends CachedEntityService { - public readonly taskStatusUpdated$: EventEmitter = new EventEmitter(); + public readonly taskStatusUpdated$ = new EventEmitter(); protected readonly endpointFormat = '/projects/:projectId:/task_def_id/:taskDefId:'; @@ -231,7 +231,8 @@ export class TaskService extends CachedEntityService { public readonly statusSeq = TaskStatus.STATUS_SEQ; public readonly helpDescriptions = TaskStatus.HELP_DESCRIPTIONS; public readonly statusIcons: Map = TaskStatus.STATUS_ICONS; - public readonly statusMaterialIcons: Map = TaskStatus.STATUS_MATERIAL_ICONS; + public readonly statusMaterialIcons: Map = + TaskStatus.STATUS_MATERIAL_ICONS; public readonly rejectFutureStates = TaskStatus.REJECT_FUTURE_STATES; public statusClass(status: TaskStatusEnum): string { diff --git a/src/app/api/services/tutorial.service.ts b/src/app/api/services/tutorial.service.ts index 4d802b67fd..7f444157ce 100644 --- a/src/app/api/services/tutorial.service.ts +++ b/src/app/api/services/tutorial.service.ts @@ -102,7 +102,7 @@ export class TutorialService extends CachedEntityService { body: {}, }; - var observer: Observable; + let observer: Observable; if (isEnrol) { observer = this.post(pathIds, options); } else { diff --git a/src/app/api/services/unit.service.ts b/src/app/api/services/unit.service.ts index 08a27f3e58..114e050df1 100644 --- a/src/app/api/services/unit.service.ts +++ b/src/app/api/services/unit.service.ts @@ -78,7 +78,7 @@ export class UnitService extends CachedEntityService { { keys: ['mainConvenor', 'main_convenor_id'], toEntityFn: (data, key, entity) => { - let result = entity.staffCache.get(data[key]); + const result = entity.staffCache.get(data[key]); entity.mainConvenorUser = result?.user; return result; }, @@ -219,7 +219,7 @@ export class UnitService extends CachedEntityService { { keys: 'taskDefinitions', toEntityOp: (data, key, unit) => { - var seq: number = 0; + let seq: number = 0; data['task_definitions'].forEach((taskDefinitionJson: object) => { const td = unit.taskDefinitionCache.getOrCreate( taskDefinitionJson['id'], diff --git a/src/app/common/entity-form/entity-form.component.ts b/src/app/common/entity-form/entity-form.component.ts index 5ebe626f8a..abf2a498c5 100644 --- a/src/app/common/entity-form/entity-form.component.ts +++ b/src/app/common/entity-form/entity-form.component.ts @@ -1,10 +1,10 @@ -import { AfterViewInit, Directive } from '@angular/core'; -import { UntypedFormGroup, AbstractControl } from '@angular/forms'; -import { Entity, RequestOptions } from 'ngx-entity-service'; -import { EntityService } from 'ngx-entity-service'; -import { Observable, tap } from 'rxjs'; -import { Sort } from '@angular/material/sort'; -import { MatTableDataSource } from '@angular/material/table'; +import {AfterViewInit, Directive} from '@angular/core'; +import {UntypedFormGroup, AbstractControl} from '@angular/forms'; +import {Entity, RequestOptions} from 'ngx-entity-service'; +import {EntityService} from 'ngx-entity-service'; +import {Observable, tap} from 'rxjs'; +import {Sort} from '@angular/material/sort'; +import {MatTableDataSource} from '@angular/material/table'; export type OnSuccessMethod = (object: T, isNew: boolean) => void; @@ -47,7 +47,10 @@ export abstract class EntityFormComponent implements AfterView * * @param controls the FormControls that will make up the form. */ - constructor(controls: { [key: string]: AbstractControl }, protected entityName: string) { + constructor( + controls: Record, + protected entityName: string, + ) { this.formData = new UntypedFormGroup(controls); // Iterate over the FormControls passed in and assign the default values // For each based on the values that they are constructed with @@ -138,14 +141,14 @@ export abstract class EntityFormComponent implements AfterView response = service.create(data, this.optionsOnRequest('create')); } else { // Nothing has changed if the selected value, so we want to inform the user - alertService.error( `${this.entityName} was not changed`, 6000); + alertService.error(`${this.entityName} was not changed`, 6000); return; } // Handle the response response.subscribe({ next: (result: T) => { - alertService.success( `${this.entityName} saved`, 2000); + alertService.success(`${this.entityName} saved`, 2000); // Success is implemented on all inheriting instances and is used // to handle the response appropriately for the context of the form success(result, this.selected ? false : true); @@ -163,7 +166,7 @@ export abstract class EntityFormComponent implements AfterView if (this.selected) { this.restoreFromBackup(); } - alertService.error( `${this.entityName} save failed: ${error}`, 6000); + alertService.error(`${this.entityName} save failed: ${error}`, 6000); }, }); } else { @@ -179,7 +182,7 @@ export abstract class EntityFormComponent implements AfterView this.cancelEdit(); entities.splice(entities.indexOf(entity), 1); this.dataSource.data = entities; - }) + }), ); } diff --git a/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.ts b/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.ts index f482c9bb7e..6f87b1f1bf 100644 --- a/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.ts +++ b/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.ts @@ -1,6 +1,6 @@ -import { Component, Input, ViewChild, AfterViewInit } from '@angular/core'; -import { MatSort, Sort } from '@angular/material/sort'; -import { MatTableDataSource, MatTable } from '@angular/material/table'; +import {Component, Input, ViewChild, AfterViewInit} from '@angular/core'; +import {MatSort, Sort} from '@angular/material/sort'; +import {MatTableDataSource, MatTable} from '@angular/material/table'; import { Tutorial, TutorialService, @@ -11,28 +11,49 @@ import { TutorialStreamService, Unit, } from 'src/app/api/models/doubtfire-model'; -import { EntityFormComponent } from 'src/app/common/entity-form/entity-form.component'; -import { UntypedFormControl, Validators } from '@angular/forms'; -import { RequestOptions } from 'ngx-entity-service'; -import { AlertService } from 'src/app/common/services/alert.service'; -import { ConfirmationModalService } from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {EntityFormComponent} from 'src/app/common/entity-form/entity-form.component'; +import {UntypedFormControl, Validators} from '@angular/forms'; +import {RequestOptions} from 'ngx-entity-service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; @Component({ - selector: 'df-unit-tutorials-list', - templateUrl: 'unit-tutorials-list.component.html', - styleUrls: ['unit-tutorials-list.component.scss'], - standalone: false + selector: 'df-unit-tutorials-list', + templateUrl: 'unit-tutorials-list.component.html', + styleUrls: ['unit-tutorials-list.component.scss'], + standalone: false, }) -export class UnitTutorialsListComponent extends EntityFormComponent implements AfterViewInit { - @ViewChild(MatTable, { static: true }) table: MatTable; - @ViewChild(MatSort, { static: true }) sort: MatSort; +export class UnitTutorialsListComponent + extends EntityFormComponent + implements AfterViewInit +{ + @ViewChild(MatTable, {static: true}) table: MatTable; + @ViewChild(MatSort, {static: true}) sort: MatSort; @Input() stream: TutorialStream; @Input() unit: Unit; - days: string[] = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday', 'Asynchronous']; + days: string[] = [ + 'Monday', + 'Tuesday', + 'Wednesday', + 'Thursday', + 'Friday', + 'Saturday', + 'Sunday', + 'Asynchronous', + ]; campuses: Campus[] = new Array(); - columns: string[] = ['abbreviation', 'campus', 'location', 'day', 'time', 'tutor', 'capacity', 'options']; + columns: string[] = [ + 'abbreviation', + 'campus', + 'location', + 'day', + 'time', + 'tutor', + 'capacity', + 'options', + ]; tutorials: Tutorial[] = []; dataSource = new MatTableDataSource(); @@ -82,14 +103,15 @@ export class UnitTutorialsListComponent extends EntityFormComponent im private filterTutorials(): void { this.tutorials = this.unit.tutorials.filter( - (tutorial) => tutorial.tutorialStream === this.stream || (!tutorial.tutorialStream && !this.stream), + (tutorial) => + tutorial.tutorialStream === this.stream || (!tutorial.tutorialStream && !this.stream), ); this.dataSource.data = this.tutorials; } public saveStream(): void { this.tutorialStreamService - .update({ abbreviation: this.origStreamAbbr, unit_id: this.unit.id }, { entity: this.stream }) + .update({abbreviation: this.origStreamAbbr, unit_id: this.unit.id}, {entity: this.stream}) .subscribe({ next: (stream: TutorialStream) => { this.stream = stream; @@ -198,7 +220,9 @@ export class UnitTutorialsListComponent extends EntityFormComponent im /** * Ensure that the unit is passed to the Tutorial entity when create it called. */ - protected override optionsOnRequest(kind: 'create' | 'update' | 'delete'): RequestOptions { + protected override optionsOnRequest( + kind: 'create' | 'update' | 'delete', + ): RequestOptions { return { constructorParams: this.unit, cache: this.unit.tutorialsCache, @@ -223,7 +247,11 @@ export class UnitTutorialsListComponent extends EntityFormComponent im const isAsc = sort.direction === 'asc'; switch (sort.active) { case 'campus': - return this.sortCompare(a.campus ? a.campus.abbreviation : '', b.campus ? b.campus.abbreviation : '', isAsc); + return this.sortCompare( + a.campus ? a.campus.abbreviation : '', + b.campus ? b.campus.abbreviation : '', + isAsc, + ); case 'tutor': return this.sortCompare(a.tutor.name, b.tutor.name, isAsc); default: From 8a7c6b55090130612cf9d0d63a6309442013227d Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 13 May 2026 11:28:51 +1000 Subject: [PATCH 1001/1280] refactor: only show working on it status button if task is aip --- src/app/common/footer/footer.component.html | 110 ++++++++++---------- 1 file changed, 55 insertions(+), 55 deletions(-) diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index 50233659f3..22b9873c35 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -13,19 +13,32 @@ -
    + @if (selectedTask?.definition?.assessInPortfolioOnly) { - -
    - - - @if (selectedTask && selectedTask.suggestedTaskStatus) { +
    - } - + @if (selectedTask && selectedTask.suggestedTaskStatus) { + + } - @if (selectedTask?.definition?.assessInPortfolioOnly) { - } @else { +
    Date: Wed, 13 May 2026 13:39:40 +1000 Subject: [PATCH 1003/1280] chore(release): 11.0.0-1 --- CHANGELOG.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 56 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index abe6841cd3..85f1206dfe 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,59 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-1](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-21...v11.0.0-1) (2026-05-13) + + +### Features + +* (wip) add name to new student experience skeleton ([7b9ace4](https://github.com/b0ink/doubtfire-deploy/commit/7b9ace47132f0237bc621d3d0e45c3031e7fac05)) +* add burndown replacement ([837658a](https://github.com/b0ink/doubtfire-deploy/commit/837658afff090e52d53cefa7c2eed20a46c1ac01)) +* add new progress component ([8beef70](https://github.com/b0ink/doubtfire-deploy/commit/8beef701e6b7fc0dbea42f8849dc02e79a665fb7)) +* add new student experience ([9bb77ab](https://github.com/b0ink/doubtfire-deploy/commit/9bb77ab108e50b637329bd739925d1d9566d9203)) +* allow paste attachment comment ([#1165](https://github.com/b0ink/doubtfire-deploy/issues/1165)) ([0f24980](https://github.com/b0ink/doubtfire-deploy/commit/0f24980e6edcc5d0f81e015990adaf14afea400e)) +* batch upload feedback csv ([#1175](https://github.com/b0ink/doubtfire-deploy/issues/1175)) ([9f95987](https://github.com/b0ink/doubtfire-deploy/commit/9f959877b6f47d878d87b468f4aab73f536d598b)) +* bulk import staff via emails ([#1195](https://github.com/b0ink/doubtfire-deploy/issues/1195)) ([c91ab47](https://github.com/b0ink/doubtfire-deploy/commit/c91ab478ae1d1cd459040290f6f7a44c7dce3efe)) +* confirm recursive fix in mobile tutor view ([b64601a](https://github.com/b0ink/doubtfire-deploy/commit/b64601a425c7a64bccfaf47c1e4fccb0343b1589)) +* confirmation modal to reassign tutorials when removing staff ([5f90e90](https://github.com/b0ink/doubtfire-deploy/commit/5f90e9085d69913eced55ad54ce9ac09431d3822)) +* discussed in class refactor ([#1145](https://github.com/b0ink/doubtfire-deploy/issues/1145)) ([4d8bb5b](https://github.com/b0ink/doubtfire-deploy/commit/4d8bb5b82d89caa02ed4936819be601b3f6977fc)) +* display icon for tasks escalated by student ([dfcfd47](https://github.com/b0ink/doubtfire-deploy/commit/dfcfd472305ef2971fa72734c18e77253b98fa11)) +* display portfolio submission time ([d717b27](https://github.com/b0ink/doubtfire-deploy/commit/d717b270eb80c0b0245e6b39f0b3f0567c379512)) +* display sso redirecting state ([248c992](https://github.com/b0ink/doubtfire-deploy/commit/248c992f46488f61916e00a87ca32ed987721f31)) +* edit comments ([#1194](https://github.com/b0ink/doubtfire-deploy/issues/1194)) ([976b6ac](https://github.com/b0ink/doubtfire-deploy/commit/976b6ac4fa3bd2d5e954eebcae3fcb40dd8d1f0e)) +* enable task pinning in explorer ([1647e2b](https://github.com/b0ink/doubtfire-deploy/commit/1647e2bcc86ac6fb08c82be9795a06939c57bb6e)) +* improve look of task status count ([475c316](https://github.com/b0ink/doubtfire-deploy/commit/475c3165db099e1412e30fb6cf18bbaddd516e75)) +* pause feedback threshold during teaching period breaks ([#1138](https://github.com/b0ink/doubtfire-deploy/issues/1138)) ([12fbf81](https://github.com/b0ink/doubtfire-deploy/commit/12fbf8147107dc185a9a9cbea940efac93a0f316)) +* require discussion before marking complete ([#1103](https://github.com/b0ink/doubtfire-deploy/issues/1103)) ([86ae886](https://github.com/b0ink/doubtfire-deploy/commit/86ae8865268ee19e4b3430ff679358cc075e1346)) +* staff note and similarity indicators ([4a65a9b](https://github.com/b0ink/doubtfire-deploy/commit/4a65a9b21d615ecf78bf09743c9cf8c3026ff621)) +* visualisations ([f1cc39e](https://github.com/b0ink/doubtfire-deploy/commit/f1cc39e59dd224c55ee0e8b5f1d50855263d147e)) + + +### Bug Fixes + +* avoid rendering the staff list twice ([9e5be59](https://github.com/b0ink/doubtfire-deploy/commit/9e5be591b9a0cf72d01efa5e28e5b2b9e7eba043)) +* burndown chart visualisation ([#942](https://github.com/b0ink/doubtfire-deploy/issues/942)) ([8487b8d](https://github.com/b0ink/doubtfire-deploy/commit/8487b8d20e838fa1b2a2238bb856f73edc86442c)) +* check for valid unit ([d9560c3](https://github.com/b0ink/doubtfire-deploy/commit/d9560c3b68df0a09f577cdab990d252b5cd24c58)) +* complete student enrolment modal ([efa89c3](https://github.com/b0ink/doubtfire-deploy/commit/efa89c344069d386f2411a417e570d4158af91b9)) +* debounce duplicate task submission requests ([80f92e2](https://github.com/b0ink/doubtfire-deploy/commit/80f92e2277c48978e1738340063a7223c04fddb8)) +* display groups only when a group set is selected ([dde1e76](https://github.com/b0ink/doubtfire-deploy/commit/dde1e7697f8a9a93577bb0e18e3e81a3ebd1ace2)) +* duplicate files ([da51e8e](https://github.com/b0ink/doubtfire-deploy/commit/da51e8e0cc9518a2a76447a48079b42f144064fc)) +* ensure authorisation active in angular ([deaa1e9](https://github.com/b0ink/doubtfire-deploy/commit/deaa1e940f8295ff962c111f1dbac75ed5ff51fa)) +* ensure loading screen removed in sign in component ([6954ac6](https://github.com/b0ink/doubtfire-deploy/commit/6954ac62627e058b6a73c0e83dc8dc8a1740698d)) +* ensure pdf viewer is visible [#1186](https://github.com/b0ink/doubtfire-deploy/issues/1186) ([6bc0752](https://github.com/b0ink/doubtfire-deploy/commit/6bc075228fe2a48dcf91aa5350b5f15f602e2dc8)) +* ensure selected group is valid ([95cb9ac](https://github.com/b0ink/doubtfire-deploy/commit/95cb9ace6615b45dd75161fd02d6dd130420817b)) +* fix pdf viewer for portfolios ([456cf46](https://github.com/b0ink/doubtfire-deploy/commit/456cf466bf49b86467b269ec3d6fb4e63f6a059f)) +* get new visualisations to build ([f828fd4](https://github.com/b0ink/doubtfire-deploy/commit/f828fd42fafaf09d7f807cea8f6a1e14ec56ecc5)) +* link task list to definitions for project dashboard ([90853e9](https://github.com/b0ink/doubtfire-deploy/commit/90853e93c109430669e3f80e4324649cd2d0dba6)) +* new burndown and task status count ([bfecd08](https://github.com/b0ink/doubtfire-deploy/commit/bfecd086eeeae33e9bbba430c79bcc4f21506a07)) +* only render if submission date is valid ([04986a0](https://github.com/b0ink/doubtfire-deploy/commit/04986a0e501f0185dbd199b8d2554133217f7e75)) +* open report in turnitin ([091aaf8](https://github.com/b0ink/doubtfire-deploy/commit/091aaf8ba744bbf677f9b8f51a58bc16b7d631ab)) +* remove hardcoded chart view size ([1b31930](https://github.com/b0ink/doubtfire-deploy/commit/1b319303ac969ef63617b2362297233bc79bb916)) +* remove markdown filter from learning outcomes ([1de217c](https://github.com/b0ink/doubtfire-deploy/commit/1de217c0bc19b8dbedb21cf2e89e195772ae2a02)) +* set task data for project dashboard state ([ef75340](https://github.com/b0ink/doubtfire-deploy/commit/ef7534064ef92c06e459953076bc30b6eff4647d)) +* support building on windows ([b2aa7ae](https://github.com/b0ink/doubtfire-deploy/commit/b2aa7ae6ea7a456953ed4f2a8c63f784ac3870b5)) +* switch staff to unit roles in unit service ([0e5d9de](https://github.com/b0ink/doubtfire-deploy/commit/0e5d9de9df2eaf16e473f4f8fde920ffb59ce765)) +* task route transition race when switching from inbox ([63c52dc](https://github.com/b0ink/doubtfire-deploy/commit/63c52dc4cdb2f2fbc701f69c64b7273f5778c868)) + ### [10.0.1-35](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-34...v10.0.1-35) (2026-04-28) diff --git a/package-lock.json b/package-lock.json index e9b7526355..69cfec245b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.1-35", + "version": "11.0.0-1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.1-35", + "version": "11.0.0-1", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index edff34e09e..6b2eea5828 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.1-35", + "version": "11.0.0-1", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 014c778fa238273ed6b7535ec2ddbb78c5eb3072 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 13 May 2026 13:49:21 +1000 Subject: [PATCH 1004/1280] chore: disable ngsw and set beta href --- angular.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/angular.json b/angular.json index aad04ef924..f71b44e605 100644 --- a/angular.json +++ b/angular.json @@ -85,7 +85,8 @@ "outputHashing": "bundles", "sourceMap": false, "extractLicenses": true, - "serviceWorker": "ngsw-config.json" + "baseHref": "/beta/", + "deployUrl": "/beta/" }, "development": { "optimization": false, From eab4bc4a80dfc081e1b087379dc3840aeebb3311 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 13 May 2026 13:49:30 +1000 Subject: [PATCH 1005/1280] chore(release): 11.0.0-2 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 85f1206dfe..cfb5ee2c02 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-2](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-1...v11.0.0-2) (2026-05-13) + ## [11.0.0-1](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-21...v11.0.0-1) (2026-05-13) diff --git a/package-lock.json b/package-lock.json index 69cfec245b..e02d692e47 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-1", + "version": "11.0.0-2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-1", + "version": "11.0.0-2", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index 6b2eea5828..a2f1b0884a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-1", + "version": "11.0.0-2", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 41a2ec0d071043860e1b9b98f564fece3e4fb16b Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 13 May 2026 13:58:50 +1000 Subject: [PATCH 1006/1280] chore: enable beta access --- ngsw-config.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/ngsw-config.json b/ngsw-config.json index 5c8069284f..7e559abeb8 100644 --- a/ngsw-config.json +++ b/ngsw-config.json @@ -55,6 +55,8 @@ "!/JPlag/**", "!/JPlag", "!/sidekiq/**", - "!/sidekiq" + "!/sidekiq", + "!/beta/**", + "!/beta" ] } From 5cdae6313030850c75918627269b55fc888c00ef Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 13 May 2026 14:00:33 +1000 Subject: [PATCH 1007/1280] chore(release): 10.0.1-38 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6c02ea7571..8dcf8745cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [10.0.1-38](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-37...v10.0.1-38) (2026-05-13) + ### [10.0.1-37](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-36...v10.0.1-37) (2026-05-12) diff --git a/package-lock.json b/package-lock.json index 9326ac911f..0d00669e9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.1-37", + "version": "10.0.1-38", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.1-37", + "version": "10.0.1-38", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 0802cc8121..11df0fa2f2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.1-37", + "version": "10.0.1-38", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 5702082e7934ebcb8d4ae259b5904fd12cf04866 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 11:29:22 +1000 Subject: [PATCH 1008/1280] chore: null check unit role --- .../directives/task-status-card/task-status-card.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts index b4233712db..3bf4faf9a8 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts @@ -137,6 +137,6 @@ export class TaskStatusCardComponent implements OnChanges, AfterViewInit { } public get isTutor(): boolean { - return this.currentUnitRole.role === 'Convenor' || this.currentUnitRole.role === 'Tutor'; + return this.currentUnitRole?.role === 'Convenor' || this.currentUnitRole?.role === 'Tutor'; } } From 714303e21daf48cbd5e2dd417d04da2aafa63ae3 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 11:29:43 +1000 Subject: [PATCH 1009/1280] chore(release): 10.0.1-39 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dcf8745cc..bb308e9538 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +### [10.0.1-39](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-38...v10.0.1-39) (2026-05-14) + ### [10.0.1-38](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-37...v10.0.1-38) (2026-05-13) ### [10.0.1-37](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-36...v10.0.1-37) (2026-05-12) diff --git a/package-lock.json b/package-lock.json index 0d00669e9c..404cdd3efc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "10.0.1-38", + "version": "10.0.1-39", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "10.0.1-38", + "version": "10.0.1-39", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^17.3.6", diff --git a/package.json b/package.json index 11df0fa2f2..82a21b89d2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "10.0.1-38", + "version": "10.0.1-39", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 6837414ec0cfc03c302e572fe86582eb0901c009 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 13:03:28 +1000 Subject: [PATCH 1010/1280] refactor: add missing badges in task list --- src/app/api/models/task.ts | 4 +- ...te-portfolio-task-list-item.component.html | 2 +- .../unit-task-list.component.html | 124 ++++++++++++++++-- .../unit-task-list.component.ts | 4 + 4 files changed, 122 insertions(+), 12 deletions(-) diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index 20c5a66eaf..c8787c0795 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -525,9 +525,9 @@ export class Task extends Entity { public timeToDue(): string { const days = this.daysUntilDueDate(); if (days < 0) { - return '!'; + return 'Past Due Date'; } else if (days < 11) { - return `${days}d`; + return `Due in ${days} day${days > 1 ? 's' : ''}`; } else { return `${Math.floor(days / 7)}w`; } diff --git a/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.html b/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.html index bf3f0c0baf..c5a07269cc 100644 --- a/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.html +++ b/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.html @@ -1,5 +1,5 @@
    diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html index e620e5b0a6..e7efd21ac8 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html @@ -24,38 +24,144 @@ @for (taskDef of filteredTaskDefinitions; track taskDef) { @if (taskDef) { -
    +
    {{ taskDef.name }}
    -
    +
    @if (taskDef.isGroupTask()) { - groups + groups } @else { - person + person } -
    +
    {{ taskDef.abbreviation }} - {{ gradeNames[taskDef.targetGrade] }} Task
    + @if (taskListItem(taskDef); as task) { + + @if (!task.isBeforeStartDate() && !task.inSubmittedState()) { + + hourglass_bottom + {{ task.timeToDue() }} + + } + }
    - @if (hasTasks && taskForTaskDef(taskDef)) { - + @if (taskListItem(taskDef); as task) { +
    + + +
    + @if (task.numNewComments > 0) { + + {{ task.numNewComments }} + + } + @if (task.similaritiesDetected) { + + visibility + + } +
    + +
    + @if (task.hasGrade()) { + + {{ task.gradeDesc() }} + + } + @if (task.hasQualityPoints()) { + + {{ task.qualityPts }} + + {{ + task.definition.maxQualityPts + }} + + } + @if (task.isDueSoon() && !task.inFinalState()) { + + schedule + + } + @if ( + task.betweenDueDateAndDeadlineDate() && + !task.isPastDeadline() && + !task.inFinalState() + ) { + + schedule + + } + @if (task.isPastDeadline() && !task.inFinalState()) { + + schedule + ! + + } +
    +
    }
    } diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts index 89a2131f06..cbe680d79a 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts @@ -65,6 +65,10 @@ export class FUnitTaskListComponent implements OnChanges, OnInit { return this.tasks.find((task) => task.definition.id === taskDef?.id); } + public taskListItem(taskDef: TaskDefinition): Task { + return this.taskForTaskDef(taskDef); + } + /* TODO: There's still an issue where loading the route for the first time will cause child components (like task-dashboard) to load trigger OnInit and OnChanges twice... Causing duplicate queries to submission_details and task comments. From 94f4216e588d6dfb6abc4d10804971cb0e8f8678 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 13:05:49 +1000 Subject: [PATCH 1011/1280] fix: add padding --- src/app/common/footer/footer.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index be4c9bf647..4a451a79d7 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -1,4 +1,4 @@ - + @if (selectedTask?.similaritiesDetected) {

    Date: Thu, 14 May 2026 13:31:09 +1000 Subject: [PATCH 1012/1280] refactor: fix inbox layout --- src/app/common/footer/footer.component.html | 2 +- src/app/common/footer/footer.component.scss | 1 + .../projects/states/index/global-state.service.ts | 15 ++++++++++----- .../units/states/tasks/inbox/inbox.component.html | 2 +- .../inbox/unit-task-inbox-state.component.ts | 6 +++++- 5 files changed, 18 insertions(+), 8 deletions(-) diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index 4a451a79d7..be4c9bf647 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -1,4 +1,4 @@ - + @if (selectedTask?.similaritiesDetected) {

    ; private _showFooter = false; + private _isInboxState = false; private _showFooterWarning = false; /** @@ -148,7 +149,9 @@ export class GlobalStateService implements OnDestroy { setTimeout(() => { const vh = window.innerHeight * 0.01; - if (!this.mediaObserver.isActive('gt-sm') || !this._showFooter) { + if (this._isInboxState) { + document.body.style.setProperty('--vh', `${vh}px`); + } else if (!this.mediaObserver.isActive('gt-sm') || !this._showFooter) { document.body.style.setProperty('--vh', `${vh - 0.2}px`); } else { if (this._showFooter && !this._showFooterWarning) { @@ -161,13 +164,14 @@ export class GlobalStateService implements OnDestroy { } public get isInboxState(): boolean { - return this._showFooter; + return this._isInboxState; } public setInboxState() { - this._showFooter = true; - // set background color to white + this._isInboxState = true; + // set background color to inbox grey document.body.style.setProperty('background-color', '#f5f5f5'); + this.resetHeight(); } public goHome() { @@ -176,9 +180,10 @@ export class GlobalStateService implements OnDestroy { } public setNotInboxState() { - this._showFooter = false; + this._isInboxState = false; // set background color to white document.body.style.setProperty('background-color', '#fff'); + this.resetHeight(); } public showFooter(): void { diff --git a/src/app/units/states/tasks/inbox/inbox.component.html b/src/app/units/states/tasks/inbox/inbox.component.html index 0ff4e12217..93178c5467 100644 --- a/src/app/units/states/tasks/inbox/inbox.component.html +++ b/src/app/units/states/tasks/inbox/inbox.component.html @@ -1,5 +1,5 @@ @if (!isMobileView) { -

    +
    @if (taskData) { diff --git a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts index c362f24749..3cf5547882 100644 --- a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts +++ b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts @@ -82,6 +82,8 @@ export class UnitTaskInboxStateComponent implements OnInit, OnDestroy { ) {} ngOnInit(): void { + this.globalStateService.setInboxState(); + this.routeMode = this.route.snapshot.data.routeMode ?? this.routeMode; this.configureRouteMode(); this.setTaskKeyFromRoute(); @@ -121,7 +123,9 @@ export class UnitTaskInboxStateComponent implements OnInit, OnDestroy { }); } - ngOnDestroy(): void {} + ngOnDestroy(): void { + this.globalStateService.setNotInboxState(); + } private getTaskSource(): TaskSource { switch (this.routeMode) { From f4e4ff6d5541b3bcdef251f396d1590ad139a88c Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 13:31:45 +1000 Subject: [PATCH 1013/1280] chore(release): 11.0.0-3 --- CHANGELOG.md | 8 ++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 11 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cfb5ee2c02..999c07b59c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,14 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-3](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-2...v11.0.0-3) (2026-05-14) + + +### Bug Fixes + +* add padding ([94f4216](https://github.com/b0ink/doubtfire-deploy/commit/94f4216e588d6dfb6abc4d10804971cb0e8f8678)) +* unlock task status selection for staff ([#1222](https://github.com/b0ink/doubtfire-deploy/issues/1222)) ([e4080d0](https://github.com/b0ink/doubtfire-deploy/commit/e4080d03a629654518bc362f48e8e0fbb790dd96)) + ## [11.0.0-2](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-1...v11.0.0-2) (2026-05-13) ## [11.0.0-1](https://github.com/b0ink/doubtfire-deploy/compare/v10.0.1-21...v11.0.0-1) (2026-05-13) diff --git a/package-lock.json b/package-lock.json index e02d692e47..56e0dd6f6e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-2", + "version": "11.0.0-3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-2", + "version": "11.0.0-3", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index a2f1b0884a..c54fc09535 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-2", + "version": "11.0.0-3", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From e956ea8c2560bd19b7ccacec29fc7a00c183cae8 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 14:27:30 +1000 Subject: [PATCH 1014/1280] refactor: improve unauthorised component styling --- .../unauthorised/unauthorised.component.html | 12 ++++++------ .../unauthorised/unauthorised.component.scss | 14 -------------- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/src/app/errors/states/unauthorised/unauthorised.component.html b/src/app/errors/states/unauthorised/unauthorised.component.html index 6954101277..262a097696 100644 --- a/src/app/errors/states/unauthorised/unauthorised.component.html +++ b/src/app/errors/states/unauthorised/unauthorised.component.html @@ -1,7 +1,7 @@ - -
    - warning -
    +
    + warning

    Unauthorised

    -

    You do not have sufficient permissions to access this resource, or your session has expired.

    - +

    + You do not have sufficient permissions to access this resource, or your session has expired. +

    +
    diff --git a/src/app/errors/states/unauthorised/unauthorised.component.scss b/src/app/errors/states/unauthorised/unauthorised.component.scss index 52cb7522ff..e69de29bb2 100644 --- a/src/app/errors/states/unauthorised/unauthorised.component.scss +++ b/src/app/errors/states/unauthorised/unauthorised.component.scss @@ -1,14 +0,0 @@ -.icon-display { - font-size: 15rem; - padding-top: 10px; - padding-bottom: 10px; - -} - -.icon-container{ - padding-right: 12rem; -} - -.text-centre{ - text-align: center; -} \ No newline at end of file From f8b11af1abb5ff66200f790ec164a2105761fe77 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 14:31:44 +1000 Subject: [PATCH 1015/1280] refactor: add go back button --- .../unauthorised/unauthorised.component.html | 1 + .../unauthorised/unauthorised.component.ts | 17 +++++++++++------ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/src/app/errors/states/unauthorised/unauthorised.component.html b/src/app/errors/states/unauthorised/unauthorised.component.html index 262a097696..5bca2da675 100644 --- a/src/app/errors/states/unauthorised/unauthorised.component.html +++ b/src/app/errors/states/unauthorised/unauthorised.component.html @@ -4,4 +4,5 @@

    Unauthorised

    You do not have sufficient permissions to access this resource, or your session has expired.

    +
    diff --git a/src/app/errors/states/unauthorised/unauthorised.component.ts b/src/app/errors/states/unauthorised/unauthorised.component.ts index 7ec73045c5..289a4ad067 100644 --- a/src/app/errors/states/unauthorised/unauthorised.component.ts +++ b/src/app/errors/states/unauthorised/unauthorised.component.ts @@ -1,11 +1,16 @@ -import { Component } from '@angular/core'; +import {Location} from '@angular/common'; +import {Component} from '@angular/core'; @Component({ - selector: 'unauthorised', - templateUrl: 'unauthorised.component.html', - styleUrls: ['unauthorised.component.scss'], - standalone: false + selector: 'unauthorised', + templateUrl: 'unauthorised.component.html', + styleUrls: ['unauthorised.component.scss'], + standalone: false, }) export class UnauthorisedComponent { - constructor(){} + constructor(private location: Location) {} + + goBack() { + this.location.back(); + } } From b7585a4f969b62382ee933cca88d88b7d011a633 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 14:44:56 +1000 Subject: [PATCH 1016/1280] chore: format time until due --- src/app/api/models/task.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index c8787c0795..b0ed8902e4 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -527,7 +527,7 @@ export class Task extends Entity { if (days < 0) { return 'Past Due Date'; } else if (days < 11) { - return `Due in ${days} day${days > 1 ? 's' : ''}`; + return `Due in ${this.timeUntilDueDateDescription()}`; } else { return `${Math.floor(days / 7)}w`; } From fb2e78113b13782dbbafe38c21f27c5d63be69c6 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 14:54:09 +1000 Subject: [PATCH 1017/1280] feat: add route auth guards --- src/app/app.routes.ts | 47 +++++++++++++--- src/app/common/guards/role-whitelist.guard.ts | 56 +++++++++++++++++++ 2 files changed, 95 insertions(+), 8 deletions(-) create mode 100644 src/app/common/guards/role-whitelist.guard.ts diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 418c94d789..9b9bbc6da4 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -32,6 +32,7 @@ import {TaskViewerStateComponent} from './units/task-viewer/task-viewer-state.co import {resolveUnit} from './units/unit.resolver'; import {UnitRootStateComponent} from './units/unit-root-state.component'; import {WelcomeComponent} from './welcome/welcome.component'; +import {roleWhitelistGuard} from './common/guards/role-whitelist.guard'; export const routes: Routes = [ {path: '', pathMatch: 'full', redirectTo: 'home'}, @@ -63,11 +64,35 @@ export const routes: Routes = [ }, {path: 'view-all-units', component: FUnitsComponent, data: {mode: 'tutor'}}, {path: 'view-all-projects', component: FUnitsComponent, data: {mode: 'student'}}, - {path: 'admin/units', component: FUnitsComponent, data: {mode: 'admin'}}, - {path: 'admin/users', component: FUsersComponent}, - {path: 'admin/institution-settings', component: InstitutionSettingsComponent}, - {path: 'tutor-discussion', component: TutorDiscussionComponent, data: {task: 'Discussion'}}, - {path: 'tutor-attendance', component: TutorDiscussionComponent, data: {attendance: true, task: 'Check-in'}}, + { + path: 'admin/units', + component: FUnitsComponent, + canActivate: [roleWhitelistGuard], + data: {mode: 'admin', roleWhitelist: ['Admin', 'Auditor', 'Convenor']}, + }, + { + path: 'admin/users', + component: FUsersComponent, + canActivate: [roleWhitelistGuard], + data: {roleWhitelist: ['Admin', 'Auditor']}, + }, + { + path: 'admin/institution-settings', + component: InstitutionSettingsComponent, + canActivate: [roleWhitelistGuard], + data: {roleWhitelist: ['Admin', 'Auditor']}, + }, + { + path: 'tutor-discussion', + component: TutorDiscussionComponent, + canActivate: [roleWhitelistGuard], + data: {task: 'Discussion', roleWhitelist: ['Admin', 'Auditor', 'Tutor']}, + }, + { + path: 'tutor-attendance', + component: TutorDiscussionComponent, + data: {attendance: true, task: 'Check-in'}, + }, {path: 'projects2/:projectId', pathMatch: 'full', redirectTo: 'projects/:projectId/dashboard'}, { path: 'projects2/:projectId/dashboard2', @@ -149,12 +174,14 @@ export const routes: Routes = [ { path: 'admin', component: UnitAdminStateComponent, - data: {task: 'Unit Administration'}, + canActivate: [roleWhitelistGuard], + data: {task: 'Unit Administration', roleWhitelist: ['Convenor', 'Admin', 'Auditor']}, }, { path: 'admin/:tab', component: UnitAdminStateComponent, - data: {task: 'Unit Administration'}, + canActivate: [roleWhitelistGuard], + data: {task: 'Unit Administration', roleWhitelist: ['Convenor', 'Admin', 'Auditor']}, }, {path: 'rollover', component: RolloverComponent, data: {task: 'Unit Rollover'}}, {path: 'discussion', component: TutorDiscussionComponent, data: {task: 'Discussion'}}, @@ -167,10 +194,14 @@ export const routes: Routes = [ path: 'tasks', pathMatch: 'full', component: TaskViewerStateComponent, - data: {task: 'Task Lists'}, + data: {task: 'Task Lists', roleWhitelist: ['Convenor', 'Admin', 'Auditor']}, + canActivate: [roleWhitelistGuard], }, { path: 'tasks', + canActivate: [roleWhitelistGuard], + data: {roleWhitelist: ['Convenor', 'Admin', 'Auditor']}, + children: [ {path: '', pathMatch: 'full', redirectTo: 'inbox'}, { diff --git a/src/app/common/guards/role-whitelist.guard.ts b/src/app/common/guards/role-whitelist.guard.ts new file mode 100644 index 0000000000..2cbd19edf7 --- /dev/null +++ b/src/app/common/guards/role-whitelist.guard.ts @@ -0,0 +1,56 @@ +import {inject} from '@angular/core'; +import {ActivatedRouteSnapshot, CanActivateFn, Router, UrlTree} from '@angular/router'; +import {filter, map, Observable, of, take} from 'rxjs'; +import {AuthenticationService, UserService} from 'src/app/api/models/doubtfire-model'; +import {GlobalStateService} from 'src/app/projects/states/index/global-state.service'; + +export const roleWhitelistGuard: CanActivateFn = ( + route: ActivatedRouteSnapshot, +): Observable => { + const authenticationService = inject(AuthenticationService); + const globalState = inject(GlobalStateService); + const router = inject(Router); + const userService = inject(UserService); + const roleWhitelist = route.data['roleWhitelist'] as string[] | undefined; + + if (!roleWhitelist?.length) { + return of(true); + } + + return globalState.isLoadingSubject.pipe( + filter((isLoading) => !isLoading), + take(1), + map(() => { + const role = roleForRoute(route, userService, globalState); + return authenticationService.isAuthorised(roleWhitelist, role) + ? true + : router.createUrlTree(['/unauthorised']); + }), + ); +}; + +function roleForRoute( + route: ActivatedRouteSnapshot, + userService: UserService, + globalState: GlobalStateService, +): string | undefined { + const unitId = Number(route.paramMap.get('unitId') ?? route.parent?.paramMap.get('unitId')); + + if (!Number.isNaN(unitId) && unitId > 0) { + const unitRole = globalState.loadedUnitRoles.currentValues.find( + (role) => role.unit?.id === unitId, + ); + + if (unitRole) { + return unitRole.role; + } + + if (userService.currentUser.role === 'Admin' || userService.currentUser.role === 'Auditor') { + return userService.currentUser.role; + } + + return undefined; + } + + return userService.currentUser.role; +} From 05d3eda76bdcfb491649f5d83e69213db3de0885 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 15:19:06 +1000 Subject: [PATCH 1018/1280] fix: enable inbox access for tutors --- src/app/app.routes.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 9b9bbc6da4..c8b73f53d4 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -200,7 +200,7 @@ export const routes: Routes = [ { path: 'tasks', canActivate: [roleWhitelistGuard], - data: {roleWhitelist: ['Convenor', 'Admin', 'Auditor']}, + data: {roleWhitelist: ['Convenor', 'Admin', 'Auditor', 'Tutor']}, children: [ {path: '', pathMatch: 'full', redirectTo: 'inbox'}, From 164fbc3fc6fb59df35ee8323685c7ec9eb4682a3 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 15:25:04 +1000 Subject: [PATCH 1019/1280] chore: upgrade ngx-entity-service --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56e0dd6f6e..1d780776dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -57,7 +57,7 @@ "ng-flex-layout": "^17.3.7-beta.1", "ng2-pdf-viewer": "10.2.2", "ngx-bootstrap": "^6.1.0", - "ngx-entity-service": "^0.0.42", + "ngx-entity-service": "^0.0.43", "ngx-lottie": "^11.0.2", "ngx-monaco-editor-v2": "^21", "npm": "^10.4.0", @@ -15904,9 +15904,9 @@ } }, "node_modules/ngx-entity-service": { - "version": "0.0.42", - "resolved": "https://registry.npmjs.org/ngx-entity-service/-/ngx-entity-service-0.0.42.tgz", - "integrity": "sha512-RmehGi3FmftKz2W/i9o35MwR548mz+I/pRXPgU9CWtMhi4VFqqrq5+XFrzSzx3iMpRuLHER19tmdFnX5PYihtQ==", + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/ngx-entity-service/-/ngx-entity-service-0.0.43.tgz", + "integrity": "sha512-O77ZIu3822bKsiL8nBpj+4DW5q6V53URO5iiAojYVwITdd2zFmsiOZjgrYUEjEAIT7B+o5sDKvpzROZ1CS33OQ==", "dependencies": { "tslib": "^2.3.0" }, diff --git a/package.json b/package.json index c54fc09535..9aec3a9fb0 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ "ng-flex-layout": "^17.3.7-beta.1", "ng2-pdf-viewer": "10.2.2", "ngx-bootstrap": "^6.1.0", - "ngx-entity-service": "^0.0.42", + "ngx-entity-service": "^0.0.43", "ngx-lottie": "^11.0.2", "ngx-monaco-editor-v2": "^21", "npm": "^10.4.0", From f1a5020688d06d438f185fe7afd0d75e94f40b6d Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 15:26:22 +1000 Subject: [PATCH 1020/1280] chore(release): 11.0.0-4 --- CHANGELOG.md | 12 ++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 15 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 999c07b59c..d77d7c63ea 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,18 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-4](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-3...v11.0.0-4) (2026-05-14) + + +### Features + +* add route auth guards ([fb2e781](https://github.com/b0ink/doubtfire-deploy/commit/fb2e78113b13782dbbafe38c21f27c5d63be69c6)) + + +### Bug Fixes + +* enable inbox access for tutors ([05d3eda](https://github.com/b0ink/doubtfire-deploy/commit/05d3eda76bdcfb491649f5d83e69213db3de0885)) + ## [11.0.0-3](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-2...v11.0.0-3) (2026-05-14) diff --git a/package-lock.json b/package-lock.json index 1d780776dc..5db5a2fe97 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-3", + "version": "11.0.0-4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-3", + "version": "11.0.0-4", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index 9aec3a9fb0..eaad1f49b4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-3", + "version": "11.0.0-4", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 4875e2534349137411cff29cf334afce3a834a70 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 16:01:47 +1000 Subject: [PATCH 1021/1280] chore: display empty similarities --- .../task-similarity-view/task-similarity-view.component.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html index 9dcb038923..97e885640b 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html @@ -87,6 +87,10 @@

    } } + } @empty { +
    + There are no similarities for this submission +
    } } From 7d29aecd07199f508598eeea0874531112fe9eb2 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 16:08:45 +1000 Subject: [PATCH 1022/1280] chore: remove similarities flag from footer --- src/app/common/footer/footer.component.html | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index be4c9bf647..cb2e0216a7 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -1,5 +1,5 @@ - @if (selectedTask?.similaritiesDetected) { + @@ -180,7 +180,7 @@
    - @if (selectedTask?.similaritiesDetected) { + @if (selectedTask?.project) { @if (selectedTask?.definition.discussionPromptsCount) {
    } @case (InboxDashboardTab.similarities) { diff --git a/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.ts b/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.ts index e0f3f25c31..9c91ae71ee 100644 --- a/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.ts +++ b/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.ts @@ -1,6 +1,8 @@ import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core'; import {MatTabChangeEvent} from '@angular/material/tabs'; +import {UnitRole} from 'src/app/api/models/doubtfire-model'; import {Task} from 'src/app/api/models/task'; +import {UserService} from 'src/app/api/services/user.service'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; enum InboxDashboardTab { @@ -13,10 +15,10 @@ enum InboxDashboardTab { } @Component({ - selector: 'f-inbox-dashboard', - templateUrl: './inbox-dashboard.component.html', - host: { 'class': 'block h-full' }, - standalone: false + selector: 'f-inbox-dashboard', + templateUrl: './inbox-dashboard.component.html', + host: {'class': 'block h-full'}, + standalone: false, }) export class InboxDashboardComponent implements OnChanges { @Input() task: Task; @@ -26,7 +28,10 @@ export class InboxDashboardComponent implements OnChanges { public currentTab: InboxDashboardTab = InboxDashboardTab.submission; public currentIndex = InboxDashboardTab.submission; - constructor(private fileDownloader: FileDownloaderService) {} + constructor( + private fileDownloader: FileDownloaderService, + private userService: UserService, + ) {} ngOnChanges(changes: SimpleChanges): void { if (changes.task) { @@ -88,4 +93,30 @@ export class InboxDashboardComponent implements OnChanges { return null; } } + + public get currentUnitRole(): UnitRole | undefined { + const currentUser = this.userService.currentUser; + return this.task.unit.staff.find((ur) => ur.user.id === currentUser.id); + } + + public get canAccessTutorNotes(): boolean { + const tutor = this.task.tutor; + if (!tutor) { + return false; + } + + if (!this.currentUnitRole) { + return false; + } + + // Ensure the unit is mapped correctly to access the mentor + tutor.unit = this.task.unit; + + const canAccess = + this.currentUnitRole.role === 'Convenor' || + this.currentUnitRole.role === 'Admin' || + (tutor.mentor && tutor.mentor.id === this.currentUnitRole.id); + + return canAccess; + } } From deaae7fb819ea8dfc01d6ad67415f50c2e4258a2 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 14 May 2026 16:13:38 +1000 Subject: [PATCH 1024/1280] fix: ensure valid selected task --- src/app/common/footer/footer.component.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index cb2e0216a7..ae0ce25e83 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -147,7 +147,7 @@ } @@ -43,17 +48,26 @@ - - - + - \ No newline at end of file + diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.ts index 66cfc03d59..a763a1437b 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.ts @@ -1,26 +1,36 @@ -import { Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; -import { Task } from 'src/app/api/models/task'; -import { TaskService } from 'src/app/api/services/task.service'; -import { FileDownloaderService } from 'src/app/common/file-downloader/file-downloader.service'; -import { AlertService } from 'src/app/common/services/alert.service'; +import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import {Task} from 'src/app/api/models/task'; +import {TaskService} from 'src/app/api/services/task.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {AlertService} from 'src/app/common/services/alert.service'; @Component({ - selector: 'f-task-submission-card', - templateUrl: './task-submission-card.component.html', - styleUrls: ['./task-submission-card.component.scss'], - standalone: false + selector: 'f-task-submission-card', + templateUrl: './task-submission-card.component.html', + styleUrls: ['./task-submission-card.component.scss'], + standalone: false, }) export class TaskSubmissionCardComponent implements OnChanges, OnInit { @Input() task: Task; - canReuploadEvidence: boolean; - canRegeneratePdf: boolean; - submission: { isProcessing: boolean; isUploaded: boolean } = { isProcessing: false, isUploaded: false }; - urls: { pdf: string; files: string }; + + public get canRegeneratePdf(): boolean { + return ( + this.taskService.pdfRegeneratableStatuses.includes(this.task?.status) && this.task?.hasPdf + ); + } + + public get taskPdfUrl(): string { + return this.task?.submissionUrl(true); + } + + public get taskFilesUrl(): string { + return this.task?.submittedFilesUrl(); + } constructor( private taskService: TaskService, private alerts: AlertService, - private fileDownloader: FileDownloaderService + private fileDownloader: FileDownloaderService, ) {} ngOnInit(): void { @@ -36,18 +46,7 @@ export class TaskSubmissionCardComponent implements OnChanges, OnInit { } reapplySubmissionData(): void { - this.task.getSubmissionDetails().subscribe(() => { - this.canReuploadEvidence = this.task.inSubmittedState(); - this.canRegeneratePdf = this.taskService.pdfRegeneratableStatuses.includes(this.task.status) && this.task.hasPdf; - this.submission = { - isProcessing: this.task.processingPdf, - isUploaded: this.task.hasPdf, - }; - this.urls = { - pdf: this.task.submissionUrl(true), - files: this.task.submittedFilesUrl(), - }; - }); + this.task.getSubmissionDetails().subscribe(); } uploadAlternateFiles(): void { @@ -63,7 +62,7 @@ export class TaskSubmissionCardComponent implements OnChanges, OnInit { this.task.processingPdf = true; this.alerts.success( 'The PDF is being regenerated. Please refresh the page in a few minutes.', - 6000 + 6000, ); } }, @@ -74,10 +73,10 @@ export class TaskSubmissionCardComponent implements OnChanges, OnInit { } downloadSubmission(): void { - this.fileDownloader.downloadFile(this.urls.pdf, `${this.task.definition.abbreviation}.pdf`); + this.fileDownloader.downloadFile(this.taskPdfUrl, `${this.task.definition.abbreviation}.pdf`); } downloadSubmissionFiles(): void { - this.fileDownloader.downloadFile(this.urls.files, `${this.task.definition.abbreviation}.zip`); + this.fileDownloader.downloadFile(this.taskFilesUrl, `${this.task.definition.abbreviation}.zip`); } -} \ No newline at end of file +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html index 3ff78659d5..a7d0f9b1eb 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html @@ -8,7 +8,16 @@ > - + + + + Your Submission + @if (task.processingPdf) { + + } + + + -

    {{ taskData?.selectedTask?.project.student.nickname }}

    -
    - - +
    +
    + @if (loading) { + + } @else if (taskData) { + + }
    +
    +
    + +

    {{ taskData?.selectedTask?.project.student.nickname }}

    +
    + + +
    -
    - +
    + @if (loading) { + + } @else { + + } +
    -
    } diff --git a/src/app/units/states/tasks/inbox/inbox.component.ts b/src/app/units/states/tasks/inbox/inbox.component.ts index b9cadd8e8f..1d0bd529d7 100644 --- a/src/app/units/states/tasks/inbox/inbox.component.ts +++ b/src/app/units/states/tasks/inbox/inbox.component.ts @@ -25,6 +25,7 @@ export class InboxComponent implements OnInit, OnDestroy { @Input() unit: Unit; @Input() unitRole: UnitRole; @Input() taskData: {selectedTask: Task; any}; + @Input() loading = false; @Input() filters: Partial<{ taskDefinition: TaskDefinition; tutorials: Tutorial[]; diff --git a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.html b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.html index 7d5fc01f5d..fc283c02a6 100644 --- a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.html +++ b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.html @@ -1,13 +1,10 @@ -@if (unit && unitRole && studentsLoaded) { -} diff --git a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts index 23cce689bf..d8d6bfe81e 100644 --- a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts +++ b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts @@ -39,9 +39,9 @@ type TaskSource = ( ) => Observable; @Component({ - selector: 'f-unit-task-inbox-state', - templateUrl: './unit-task-inbox-state.component.html', - standalone: false + selector: 'f-unit-task-inbox-state', + templateUrl: './unit-task-inbox-state.component.html', + standalone: false, }) export class UnitTaskInboxStateComponent implements OnInit, OnDestroy { @Input() public unit$: Observable; @@ -55,6 +55,10 @@ export class UnitTaskInboxStateComponent implements OnInit, OnDestroy { public studentsLoaded = false; public filters: Partial = {}; + public get inboxLoading(): boolean { + return !(this.unit && this.unitRole && this.studentsLoaded); + } + public taskData: { taskKey: TaskKey | null; source: TaskSource; @@ -173,7 +177,7 @@ export class UnitTaskInboxStateComponent implements OnInit, OnDestroy { case 'inbox': default: this.viewType = 'inbox'; - this.showSearchOptions = true; + this.showSearchOptions = false; this.taskData.taskDefMode = false; break; } @@ -217,7 +221,8 @@ export class UnitTaskInboxStateComponent implements OnInit, OnDestroy { if ( !unitRole && - (this.userService.currentUser.role === 'Admin' || this.userService.currentUser.role === 'Auditor') + (this.userService.currentUser.role === 'Admin' || + this.userService.currentUser.role === 'Auditor') ) { unitRole = this.userService.adminOrAuditorRoleFor( this.userService.currentUser.role, diff --git a/src/app/units/unit.resolver.ts b/src/app/units/unit.resolver.ts index db682a9065..0ddeb34a9d 100644 --- a/src/app/units/unit.resolver.ts +++ b/src/app/units/unit.resolver.ts @@ -5,7 +5,7 @@ import {Unit, UnitRole, UnitService, UserService} from 'src/app/api/models/doubt import {AlertService} from 'src/app/common/services/alert.service'; import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global-state.service'; -export const resolveUnit: ResolveFn = (route) => { +export const resolveUnit: ResolveFn = (route, state) => { const unitService = inject(UnitService); const globalState = inject(GlobalStateService); const userService = inject(UserService); @@ -29,17 +29,30 @@ export const resolveUnit: ResolveFn = (route) => { ); } + const resolveProgressively = state.url.split('?')[0].includes('/tasks'); + if (resolveProgressively) { + const unit = + unitRole?.unit ?? unitService.cache.getOrCreate(unitId, unitService, {id: unitId}); + globalState.setView(ViewType.UNIT, routeEntity(unit, unitRole)); + observer.next(unit); + observer.complete(); + } + unitService.get(unitId).subscribe({ next: (unit) => { globalState.setView(ViewType.UNIT, routeEntity(unit, unitRole)); - observer.next(unit); - observer.complete(); + if (!resolveProgressively) { + observer.next(unit); + observer.complete(); + } }, error: (err) => { if (unitRole?.unit) { globalState.setView(ViewType.UNIT, unitRole); - observer.next(unitRole.unit); - observer.complete(); + if (!resolveProgressively) { + observer.next(unitRole.unit); + observer.complete(); + } return; } From 3de43060e165f4194dd1c6b482bd7c6248bc9615 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 19 May 2026 01:36:43 +1000 Subject: [PATCH 1035/1280] chore(release): 11.0.0-8 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 53c58b79ab..04f703353a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-8](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-7...v11.0.0-8) (2026-05-18) + ## [11.0.0-7](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-6...v11.0.0-7) (2026-05-17) ## [11.0.0-6](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-5...v11.0.0-6) (2026-05-14) diff --git a/package-lock.json b/package-lock.json index 9a7c90b0de..0b8c1966de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-7", + "version": "11.0.0-8", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-7", + "version": "11.0.0-8", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index 5e74d844f5..5928b811ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-7", + "version": "11.0.0-8", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 6d7c9fb8ff7fe714844ebc8f0e04f2ef9a40d4d0 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 19 May 2026 02:01:25 +1000 Subject: [PATCH 1036/1280] fix: ensure unit is loaded first before querying inbox --- .../inbox/unit-task-inbox-state.component.ts | 52 ++++++++++++------- src/app/units/unit.resolver.ts | 1 + 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts index d8d6bfe81e..f09ba87889 100644 --- a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts +++ b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts @@ -7,6 +7,7 @@ import { Tutorial, Unit, UnitRole, + UnitService, UserService, } from 'src/app/api/models/doubtfire-model'; import {Task} from 'src/app/api/models/task'; @@ -81,6 +82,7 @@ export class UnitTaskInboxStateComponent implements OnInit, OnDestroy { private taskService: TaskService, private globalStateService: GlobalStateService, private userService: UserService, + private unitService: UnitService, private projectService: ProjectService, private route: ActivatedRoute, private router: Router, @@ -100,25 +102,11 @@ export class UnitTaskInboxStateComponent implements OnInit, OnDestroy { this.unit$ = of(routeUnit); } - this.unit$.pipe(first()).subscribe((unit) => { - this.unit = unit; - this.unitRole = this.findUnitRole(unit.id); - this.filters = { - ...this.filters, - ...this.getFilterOverrides(unit), - }; - - this.projectService - .loadStudents(unit) + this.unit$.pipe(first()).subscribe((routeUnit) => { + this.unitService + .fetch(routeUnit.id) .pipe(first()) - .subscribe({ - next: () => { - this.studentsLoaded = true; - }, - error: () => { - this.studentsLoaded = true; - }, - }); + .subscribe((unit) => this.loadInboxData(unit)); }); this.route.paramMap.subscribe(() => { @@ -183,6 +171,34 @@ export class UnitTaskInboxStateComponent implements OnInit, OnDestroy { } } + private loadInboxData(unit: Unit): void { + this.unit = unit; + this.unitRole = this.findUnitRole(unit.id); + if (this.unitRole) { + this.unitRole.unit = unit; + this.globalStateService.setView(ViewType.UNIT, this.unitRole); + } else { + this.globalStateService.setView(ViewType.UNIT, unit); + } + + this.filters = { + ...this.filters, + ...this.getFilterOverrides(unit), + }; + + this.projectService + .loadStudents(unit) + .pipe(first()) + .subscribe({ + next: () => { + this.studentsLoaded = true; + }, + error: () => { + this.studentsLoaded = true; + }, + }); + } + private getFilterOverrides(unit: Unit): Partial { const selectedStudents = this.route.snapshot.queryParamMap.get('students'); diff --git a/src/app/units/unit.resolver.ts b/src/app/units/unit.resolver.ts index 0ddeb34a9d..7b5771d654 100644 --- a/src/app/units/unit.resolver.ts +++ b/src/app/units/unit.resolver.ts @@ -36,6 +36,7 @@ export const resolveUnit: ResolveFn = (route, state) => { globalState.setView(ViewType.UNIT, routeEntity(unit, unitRole)); observer.next(unit); observer.complete(); + return; } unitService.get(unitId).subscribe({ From f5c881dbe9181046819c6fd22f3e6e9361f738a1 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 19 May 2026 02:01:36 +1000 Subject: [PATCH 1037/1280] chore(release): 11.0.0-9 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04f703353a..297623589e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-9](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-8...v11.0.0-9) (2026-05-18) + + +### Bug Fixes + +* ensure unit is loaded first before querying inbox ([6d7c9fb](https://github.com/b0ink/doubtfire-deploy/commit/6d7c9fb8ff7fe714844ebc8f0e04f2ef9a40d4d0)) + ## [11.0.0-8](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-7...v11.0.0-8) (2026-05-18) ## [11.0.0-7](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-6...v11.0.0-7) (2026-05-17) diff --git a/package-lock.json b/package-lock.json index 0b8c1966de..b8346917ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-8", + "version": "11.0.0-9", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-8", + "version": "11.0.0-9", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index 5928b811ea..b71629cb0d 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-8", + "version": "11.0.0-9", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 71e8f2bec9579c664ca317b6027b64164e457bfa Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 19 May 2026 02:08:14 +1000 Subject: [PATCH 1038/1280] chore: fix invalid permissions-policy header --- nginx.conf | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/nginx.conf b/nginx.conf index 679f2082fc..a7721192b1 100644 --- a/nginx.conf +++ b/nginx.conf @@ -12,8 +12,7 @@ http { listen 80; add_header Content-Security-Policy "default-src https: 'unsafe-inline' 'unsafe-eval' blob: data: ws:" always; - # add_header Feature-Policy "microphone=(self),speaker=(self),fullscreen=(self),payment=(none);" always; - add_header Permissions-Policy "microphone=(self),speaker=(self),fullscreen=(self),payment=(none)" always; + add_header Permissions-Policy "microphone=(self),fullscreen=(self),payment=()" always; location / { try_files $uri $uri/ $uri/index.html /index.html; From 28ba58b62cdd926da382cbe02d7b12ee945baa80 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 19 May 2026 02:08:43 +1000 Subject: [PATCH 1039/1280] chore(release): 11.0.0-10 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 297623589e..1b8887b4ae 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-10](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-9...v11.0.0-10) (2026-05-18) + ## [11.0.0-9](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-8...v11.0.0-9) (2026-05-18) diff --git a/package-lock.json b/package-lock.json index b8346917ef..132ddbfeae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-9", + "version": "11.0.0-10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-9", + "version": "11.0.0-10", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index b71629cb0d..c965f4199c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-9", + "version": "11.0.0-10", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 04f3fd24670bddb046fada1aafb795e103668559 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 19 May 2026 11:40:16 +1000 Subject: [PATCH 1040/1280] chore: add overseer report to tutor inbox view --- .../directives/inbox-dashboard/inbox-dashboard.component.html | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.html b/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.html index 958e87da71..33533bbfb9 100644 --- a/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.html +++ b/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.html @@ -108,7 +108,9 @@
    } @case (InboxDashboardTab.overseer) { -
    +
    + +
    } }
    From 2fc28b8483674a726eb6f42b1aaaf6856412e10c Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 19 May 2026 11:51:04 +1000 Subject: [PATCH 1041/1280] chore(release): 11.0.0-11 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b8887b4ae..ffa5097323 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-11](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-10...v11.0.0-11) (2026-05-19) + ## [11.0.0-10](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-9...v11.0.0-10) (2026-05-18) ## [11.0.0-9](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-8...v11.0.0-9) (2026-05-18) diff --git a/package-lock.json b/package-lock.json index 132ddbfeae..db3fb1fdbc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-10", + "version": "11.0.0-11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-10", + "version": "11.0.0-11", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index c965f4199c..8d226020c6 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-10", + "version": "11.0.0-11", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From e3667b46779f0c459dde65e9496b4482a6763e37 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 2 Jun 2026 11:28:12 +1000 Subject: [PATCH 1042/1280] refactor: sticky tab group in task dashboard --- .../task-dashboard.component.html | 170 +++++++++--------- .../inbox-dashboard.component.html | 2 +- 2 files changed, 87 insertions(+), 85 deletions(-) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html index 17091f8089..d73b3cd91f 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html @@ -1,5 +1,5 @@ -
    -
    +
    +
    - @switch (currentView) { - @case (DashboardViews.details) { -
    - - - - - - - - -
    - } - - @case (DashboardViews.task) { - @if (task && task.blockedByPrerequisiteTasks()) { -
    - - Warning: This task has - {{ task.definition.taskPrerequisitesCache.currentValues.length }} prerequisite{{ - task.definition.taskPrerequisitesCache.currentValues.length > 1 ? 's' : '' - }} - that you still need to complete. You won’t be able to submit this task until all - prerequisites are met. -
    + @case (DashboardViews.task) { + @if (task && task.blockedByPrerequisiteTasks()) { +
    + + Warning: This task has + {{ task.definition.taskPrerequisitesCache.currentValues.length }} prerequisite{{ + task.definition.taskPrerequisitesCache.currentValues.length > 1 ? 's' : '' + }} + that you still need to complete. You won’t be able to submit this task until all + prerequisites are met. +
    + } + @if (task.definition.hasTaskSheet) { + + } @else { +
    + subtitles_off +
    + } } - @if (task.definition.hasTaskSheet) { - - } @else { -
    - subtitles_off -
    + @case (DashboardViews.submission) { + @if (task.hasPdf) { + + } @else { +
    + subtitles_off +
    + } } - } - @case (DashboardViews.submission) { - @if (task.hasPdf) { - - } @else { -
    - subtitles_off -
    + @case (DashboardViews.similarity) { + @if (canAccessStaffViews) { +
    + +
    + } } - } - @case (DashboardViews.similarity) { - @if (canAccessStaffViews) { -
    - -
    + @case (DashboardViews.overseer) { + @if (canAccessStaffViews) { +
    + +
    + } } - } - @case (DashboardViews.overseer) { - @if (canAccessStaffViews) { -
    - -
    + @case (DashboardViews.staff_notes) { + @if (canAccessStaffViews) { +
    + +
    + } } - } - @case (DashboardViews.staff_notes) { - @if (canAccessStaffViews) { -
    - + @case (DashboardViews.tutor_notes) { +
    + @if (canAccessTutorNotes) { + + }
    } - } - @case (DashboardViews.tutor_notes) { -
    - @if (canAccessTutorNotes) { - + @case (DashboardViews.discussion_prompts) { + @if (canAccessStaffViews) { + } -
    - } - @case (DashboardViews.discussion_prompts) { - @if (canAccessStaffViews) { - } } - } +
    -
    +
    -
    -
    + Teaching Period Name @@ -68,7 +68,7 @@ -

    Teaching Breaks for {{ newOrSelectedTeachingPeriod.name }}

    +

    Teaching Breaks for {{ newOrSelectedTeachingPeriod.name }}

    @for (break of newOrSelectedTeachingPeriod.breaksCache.values | async; track break) { @@ -86,8 +86,8 @@

    Teaching Breaks for {{ newOrSelectedTeachingPeriod.name }}

    }
    - - + + Break Start Date -
    +

    Teaching periods

    - + Bulk users operations diff --git a/src/app/admin/tii-action-log/tii-action-log.component.html b/src/app/admin/tii-action-log/tii-action-log.component.html index e61877520d..c12c822525 100644 --- a/src/app/admin/tii-action-log/tii-action-log.component.html +++ b/src/app/admin/tii-action-log/tii-action-log.component.html @@ -1,5 +1,5 @@
    -
    +

    Turnitin Actions

    diff --git a/src/app/common/archive-viewer/archive-viewer.component.html b/src/app/common/archive-viewer/archive-viewer.component.html index da1de5293f..e48d00a0dc 100644 --- a/src/app/common/archive-viewer/archive-viewer.component.html +++ b/src/app/common/archive-viewer/archive-viewer.component.html @@ -1,39 +1,39 @@
    @if (isLoading) {
    Loading archive...
    } @else if (errorMessage) { -
    - error_outline +
    + error_outline {{ errorMessage }}
    } @else if (!archiveFile) {
    - folder_zip + folder_zip Select an archive to preview.
    } @else if (!hasFiles) {
    - folder_off + folder_off No files to display.
    } @else { @if (!readOnly && saveEndpoint) { -
    +
    } -
    +
    @if (showUploader && uploadingInfo === null && shownUploadZones.length) {
    @for (upload of shownUploadZones; track upload) { @@ -41,7 +41,7 @@
    Select {{ upload.display.name }}
    Click to select {{ upload.display.type }} file } } @else { - + block Invalid file provided Select {{ upload.display.name }}
    @if (!singleDropZone && upload.model?.length > 0) { -
    +
    {{ upload.display.icon }} {{ upload.model[0].name }} diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index ae0ce25e83..7e0d7f62bc 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -1,6 +1,6 @@ - + @if (selectedTask?.definition?.assessInPortfolioOnly) {
    -

    Manage your learning, with feedback you'll want to receive.

    +

    Manage your learning, with feedback you'll want to receive.

    diff --git a/src/app/common/learning-outcome-editor/learning-outcome-editor.component.html b/src/app/common/learning-outcome-editor/learning-outcome-editor.component.html index 9031ccde39..c93603fa33 100644 --- a/src/app/common/learning-outcome-editor/learning-outcome-editor.component.html +++ b/src/app/common/learning-outcome-editor/learning-outcome-editor.component.html @@ -1,4 +1,4 @@ -
    +
    -
    +
    @@ -117,11 +117,11 @@ @if (selectedOutcome) { -
    +
    -

    Edit Outcome

    +

    Edit Outcome

    -
    +
    Abbreviation

    Download the {{ data.type }} CSV

    -
    +

    This action will download all {{ data.type.toLowerCase() }} associated with this unit.

    Include task {{ data.type.toLowerCase() }}Download the {{ data.type }} CSV
    -
    +
    diff --git a/src/app/common/modals/comments-modal/comments-modal.component.html b/src/app/common/modals/comments-modal/comments-modal.component.html index 707bcff36c..4236c93c2d 100644 --- a/src/app/common/modals/comments-modal/comments-modal.component.html +++ b/src/app/common/modals/comments-modal/comments-modal.component.html @@ -1,4 +1,4 @@ -
    +
    @if (taskComment.commentType === 'image') { } @else if (taskComment.commentType === 'pdf') { diff --git a/src/app/common/modals/confirmation-modal/confirmation-modal.component.html b/src/app/common/modals/confirmation-modal/confirmation-modal.component.html index 547f9fe8cd..4232cf08ee 100644 --- a/src/app/common/modals/confirmation-modal/confirmation-modal.component.html +++ b/src/app/common/modals/confirmation-modal/confirmation-modal.component.html @@ -1,7 +1,7 @@

    - help + help
    {{ title }}
    Please confirm that you want to perform this action. diff --git a/src/app/common/modals/csv-result-modal/csv-result-modal.component.html b/src/app/common/modals/csv-result-modal/csv-result-modal.component.html index bea497db15..1de2d91f66 100644 --- a/src/app/common/modals/csv-result-modal/csv-result-modal.component.html +++ b/src/app/common/modals/csv-result-modal/csv-result-modal.component.html @@ -4,7 +4,7 @@

    {{ data.title }}

    @for (selection of csvResponseSelections; track selection.key) { {{ data.title }}

    } - + @if (dataSource.data.length > 0) { +
    @if (showTaskAbbr && editMode) { } -
    +
    @if (showTaskAbbr) { } @else { @@ -70,13 +70,13 @@
    @if (editMode) { @if (afterDeadline()) { -
    diff --git a/src/app/groups/group-selector/group-selector.component.html b/src/app/groups/group-selector/group-selector.component.html index 641cb00bde..ba6a56d696 100644 --- a/src/app/groups/group-selector/group-selector.component.html +++ b/src/app/groups/group-selector/group-selector.component.html @@ -2,7 +2,7 @@
    -
    +
    Groups for @if (!showGroupSetSelector && selectedGroup) { @@ -21,7 +21,7 @@ }
    @if (unitRole || selectedGroupSet?.allowStudentsToCreateGroups) { -
    +
    @if (selectedGroupSet && selectedGroupSet.groups.length === 0) { -
    +
    group_off -

    There are no groups in this set

    +

    There are no groups in this set

    } @else {
    @@ -61,7 +61,7 @@ @for (ilo of learningOutcomes; track ilo) { - - - + + -
    Name @if (editing(group)) { - + } @else { @@ -74,7 +74,7 @@ Tutorial @if (editing(group)) { - + @for (tutorial of unit.tutorials; track tutorial) { {{ tutorial.abbreviation }} @@ -96,7 +96,7 @@ @if (unitRole) { @if (editing(group)) { - + } @if (unitRole) { -
    +
    @if (editing(group)) { -
    +
    diff --git a/src/app/groups/group-set-manager/group-set-manager.component.html b/src/app/groups/group-set-manager/group-set-manager.component.html index 6c013fcbe3..0f89d4712f 100644 --- a/src/app/groups/group-set-manager/group-set-manager.component.html +++ b/src/app/groups/group-set-manager/group-set-manager.component.html @@ -1,4 +1,4 @@ -
    +
    + } } @else { @if (unitRole || selectedGroup.groupSet?.allowStudentsToManageGroups) { - + - - } @@ -51,7 +51,7 @@ @if (unitRole) { - + +

    You are not enrolled in {{ externalName.value }}.

    Contact your unit convenor or tutor to enrol you in a subject.

    @@ -77,7 +77,7 @@

    Units you teach

    -
    +

    Enrolled units

    diff --git a/src/app/home/states/lti-dashboard/lti-dashboard.component.html b/src/app/home/states/lti-dashboard/lti-dashboard.component.html index ba12db70e8..0a31177529 100644 --- a/src/app/home/states/lti-dashboard/lti-dashboard.component.html +++ b/src/app/home/states/lti-dashboard/lti-dashboard.component.html @@ -1,5 +1,5 @@ -
    -
    +
    +
    -

    OnTrack

    +

    OnTrack

    @if (isLoading) { @if (unauthorised) { -
    +
    An error occurred. Please refresh the page.
    } @else { @@ -20,7 +20,7 @@

    OnTrack

    Loading...

    } } @else { -
    +
    @if (currentUser?.systemRole === 'Convenor' || currentUser?.systemRole === 'Admin') { -
    +
    @if (linkedUnit) { {{ linkedUnit.code }} — {{ linkedUnit.name }} @if (currentUser?.systemRole === 'Convenor' || currentUser?.systemRole === 'Admin') { diff --git a/src/app/home/states/lti-unit-link/lti-unit-link.component.html b/src/app/home/states/lti-unit-link/lti-unit-link.component.html index 2ab7465ca9..1020993ed1 100644 --- a/src/app/home/states/lti-unit-link/lti-unit-link.component.html +++ b/src/app/home/states/lti-unit-link/lti-unit-link.component.html @@ -1,5 +1,5 @@ -
    -
    +
    +
    -

    OnTrack

    +

    OnTrack

    @if (loadingUnits) { diff --git a/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html index 685e34f3af..b450dfad58 100644 --- a/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html +++ b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html @@ -1,22 +1,22 @@ @if (project$ | async; as project) { -
    +
    - + - -

    + +

    {{ project.student.nickname || project.student.firstName }}'s {{ project.unit.name }}

    -

    {{ project.unit.description }}

    +

    {{ project.unit.description }}

    - + - -

    Targetting

    + +

    Targetting

    info diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html index d3fdd7b90d..66174425af 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html @@ -1,13 +1,13 @@
    -
    -

    +
    +

    Progress Dashboard @if (tutor) { for {{ project.student.name }} }

    -
    +
    @@ -18,7 +18,7 @@

    Target Grade - +

    Your target grade changes which tasks you need to complete.

    @@ -39,7 +39,7 @@

    } -

    [grade]="project.targetGrade" >

    -
    +
    Aim to keep your Complete line close to or ahead of the @@ -85,15 +85,15 @@

    Progress Burndown

    -
    -
    -

    Task Statuses

    -

    +

    +
    +

    Task Statuses

    +

    Breakdown summary of each of your task statuses.

    -
    +
    Plan Your Tasks - +

    The Task Planner shows a timeline of your tasks, their due dates, and prerequisite relationships. Use it to plan when to start and submit tasks, ensuring prerequisites are diff --git a/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.html b/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.html index c5a07269cc..39825c6d7b 100644 --- a/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.html +++ b/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.html @@ -1,13 +1,13 @@ -

    -
    +
    +
    Create Portfolio
    -
    +
    person
    Create and submit your portfolio
    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html index 8cc634a7fd..5636823212 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html @@ -1,6 +1,6 @@ -
    +
    - comment + comment

    Discussion Prompts for {{ project?.student?.name }}

    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html index 8b57557240..f92fd644e5 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html @@ -1,6 +1,6 @@ -
    +
    - comment + comment

    Staff Notes for {{ project?.student?.name }}

    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html index 858f5ddd29..b7548c3c90 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html @@ -1,7 +1,7 @@ -
    - +
    + {{ taskDef?.name }}
    @@ -42,7 +42,7 @@ @if (flexibleDatesEnabled) { -

    +

    You should have submitted this task by {{ task?.localDueDateString() }} to keep your progress on track. Try to finish it as soon as possible to avoid delays. You can revise your project plan dates, but ensure you submit before the deadline to receive feedback.

    } @else { -

    +

    You should have completed this task by {{ task?.localDueDateString() }}. Try and finish it as soon as possible to avoid falling behind. You will need to @@ -116,16 +116,16 @@ @if (task?.isPastDeadline()) { - error - Passed Due Date By {{ task?.timePastDueDateDescription() }} -

    +

    @if (task?.definition?.unit.markLateSubmissionsAsAssessInPortfolio) { You should have completed this task by {{ task?.localDueDateString() }}{{ getIloContextLabel() }} Learning Outcomes - These outcomes describe the key skills and knowledge you are aiming to achieve by completing this {{ getIloContextLabel().toLowerCase() }}. @@ -11,11 +11,11 @@

    {{ ilo.abbreviation }}{{ ilo.fullOutcomeDescription }} + {{ ilo.abbreviation }}{{ ilo.fullOutcomeDescription }} @for (outcome of getLinkedOutcomes(ilo); track outcome.abbreviation) { - {{ + {{ outcome.abbreviation }} } diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html index 5d1d69f412..ae35bec796 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html @@ -1,4 +1,4 @@ -
    +

    @if (compareMode) { @@ -16,21 +16,21 @@

    -
    +
    @if (isLoading) {
    } @else if (errorMessage) {
    {{ errorMessage }}
    } @else if (compareMode) { @if (archiveBlob && comparedArchiveBlob) { -
    -
    +
    +
    @if (!bothSelectionsReady) {
    Select a file in both submissions to compare.
    } @else if (canShowDiffEditor) {
    -
    +
    {{ primarySelectedFile?.path ?? primarySelectedFile?.name }}
    @@ -105,7 +105,7 @@

    >

    } @else { -
    +
    } @else {
    Unable to load one or both submission archives.
    @@ -150,7 +150,7 @@

    } @else {
    Unable to load submission files.
    @@ -163,7 +163,7 @@

    let-isMostRecent="isMostRecent" let-timestamp="timestamp" > -
    +
    Submission{{ number !== undefined ? ' ' + number : '' }}{{ isMostRecent ? ' (Most recent)' : '' }}: {{ timestamp | date: 'dd/MM/yyyy HH:mm' }} @@ -173,7 +173,7 @@

    @@ -198,7 +198,7 @@

    } @else if (isArchivePdfFile(file)) { } @else if (isArchiveImageFile(file)) { -
    +
    />
    } @else { -
    +
    Preview not available for this file type.
    } diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html index 2773aed285..233333462b 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html @@ -1,4 +1,4 @@ -
    +
    @@ -10,7 +10,7 @@ [expanded]="oa.id === loadOverseerAssessmentId && oa.reportReady" > - + Submission {{ overseerAssessments.length - idx }}: {{ oa.timestamp | humanizedDate }} @if (idx === 0) { @@ -21,7 +21,7 @@ } @if (oa.reportReady) { -
    +
    {{ oa.passedSteps }} / {{ oa.totalSteps }} @if (oa.passedSteps === oa.totalSteps) { done @@ -67,7 +67,7 @@ }
    } @else { -
    +
    Tests In Progress
    @@ -92,7 +92,7 @@ @if (!result.pass) { -

    +

    {{ result.feedbackMessage }}

    } @@ -102,7 +102,7 @@ result.expectedOutput !== result.stdout && (result.overseerStep?.stepType === 'output_diff' || !result.overseerStep) ) { -
    +

    -
    {{ trigger.label }}
    +
    {{ trigger.label }}
    } @@ -42,7 +42,7 @@
    {{ task?.statusLabel() }}
    -
    +
    diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html index 575a9f5faf..ce69d3dcb3 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html @@ -8,22 +8,22 @@

    Select Grade

    -

    +

    In preparing your portfolio, you need to undertake a self-assessment. Use the unit's assessment criteria to determine the grade your portfolio should be awarded.

    - + - + warning Read the assessment criteria -

    +

    Make sure that you have reviewed the Assessment Criteria for the grade you are applying for. Each grade will have a list of criteria that you can use to determine if you meet the requirements to achieve that grade. @@ -40,15 +40,15 @@

    Select Grade

    @if (agreedToAssessmentCriteria) { - + - + Grade Application -

    +

    Select the grade you are applying for {{ unit.code }} {{ unit.name }} below.

    @@ -62,7 +62,7 @@

    Select Grade

    @for (grade of gradeValues; track grade) { @@ -70,7 +70,7 @@

    Select Grade

    } -

    +

    Make sure your Learning Summary Report justifies how your portfolio demonstrates you have met all unit learning outcomes to a {{ targetGrade }} level diff --git a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.html index 3ef553e787..74cb105802 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.html +++ b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.html @@ -3,7 +3,7 @@ Learning Summary Report -

    +

    Upload the Learning Summary Report, the primary porfolio document which justifies your desired grade.

    @@ -12,7 +12,7 @@ summary of what you have learnt in this unit. It consists of two sections:

    -
      +
      1. a self-assessment, and
      2. your reflections on the unit.
      @@ -30,13 +30,13 @@ @if ( projectHasDraftLearningSummaryReport && !forceLSRSubmit && !acceptUploadNewLearningSummary ) { -
      -

    @if (project) { -
    +
    @if (this.allTasks?.length > 0) { @if (this.filteredTasks?.length < this.allTasks?.length) {
    @if (project && filteredTasks.length) { -
    -
    +
    +
    @if (attendance) {

    @if (footerTabView === TutorDiscussionTabView.SHOW_COMMENTS) {
    - + } --> -
    +
    @if (!loadingTutorNotes) { @for (note of filteredNotes; track note) { @if (note.replyToId) {
    - reply + reply
    @if (note.replyTo) { Replying to {{ note.replyTo.user.preferredName }} {{ note.replyTo.user.lastName }} ({{ note.replyTo.user.nickname }}) - {{ note.replyTo.note }} + {{ note.replyTo.note }} } @else { - Replying to: Deleted note + Replying to: Deleted note }
    @@ -33,11 +33,11 @@ } -
    +
    @if (note.authorIsMe) { edit @@ -52,7 +52,7 @@ } } @else { -
    Read by tutor
    +
    Read by tutor
    }
    @@ -71,7 +71,7 @@
    -
    +
    @if (note.taskDefinition) { {{ note.taskDefinition?.abbreviation }} {{ note.taskDefinition.name }} - + @if (editingNote && editingNote.id === note.id) { Update Note @@ -98,9 +98,9 @@ #tutorNoteEditor matInput [(ngModel)]="editingNoteText" - class="resize-none w-full px-2 py-1 placeholder:px-2 placeholder:py-1 overflow-hidden" + class="resize-none w-full px-1 py-0.5 placeholder:px-1 placeholder:py-0.5 overflow-hidden" > -
    +
    -
    - +
    +
    - reply + reply
    Replying to {{ replyingToNote.user.firstName }} {{ replyingToNote.user.lastName }} ({{ replyingToNote.user.nickname }}) - {{ replyingToNote.note }} + {{ replyingToNote.note }}
    close @@ -165,7 +165,7 @@
    diff --git a/src/app/projects/states/tutorials/tutorials.component.html b/src/app/projects/states/tutorials/tutorials.component.html index a29c236808..726ed0745c 100644 --- a/src/app/projects/states/tutorials/tutorials.component.html +++ b/src/app/projects/states/tutorials/tutorials.component.html @@ -1,5 +1,5 @@ @if (project && unit) { -
    +

    Tutorials

    diff --git a/src/app/sessions/states/sign-in/sign-in.component.html b/src/app/sessions/states/sign-in/sign-in.component.html index 373d82d8b8..31917944ce 100644 --- a/src/app/sessions/states/sign-in/sign-in.component.html +++ b/src/app/sessions/states/sign-in/sign-in.component.html @@ -57,7 +57,7 @@

    type="form" [disabled]="form.invalid" > -
    +
    @if (redirectingSSO) { Signing In... diff --git a/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.html b/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.html index 131bc86541..ad6470153b 100644 --- a/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.html +++ b/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.html @@ -17,7 +17,7 @@

    Request Feedback Review

    request will not be counted against your remaining total.

    - + Reason for review request - + Priority diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html index 66290bd179..cca24f04c2 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html @@ -1,15 +1,15 @@ -
    +

    Details for {{ taskDefinition.abbreviation }} - {{ taskDefinition.name }}

    -
    -

    @if (staffView) { - + diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html index fb02d119a2..1db7e15ffc 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html @@ -1,4 +1,4 @@ -
    +
    Enable test for task @@ -11,7 +11,7 @@ [desiredFileName]="'SCORM zip'" /> @if (taskDefinition.hasScormData) { -
    +
    @@ -24,7 +24,7 @@
    } -
    +
    Allow students to review completed test attempt @@ -45,7 +45,7 @@
    -
    +
    @if (taskDefinition.needsJplag) { -
    +
    Language used for JPLAG checks diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html index f36a92f380..4f363e2b22 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html @@ -10,7 +10,7 @@ } -
    +
    Tutorial Stream - Which tutor provides feedback? 3) { -
  • +
  • +{{ taskDefinition.tutorialStream.tutorialsIn(unit).length - 3 }} more tutorials
  • } @if (taskDefinition.tutorialStream?.tutorialsIn(unit).length > 3) { -
    +
    @if (!showAllTutorials) { } @@ -39,13 +39,13 @@

    Task List

    @if (unit.allowFlexibleDates) { @if (manageDueDates) {
    - +

    Manage Target Dates

    Modify or add target dates for each target grade

    -
    +
    @@ -62,7 +62,7 @@

    Manage Target Dates

    - +
    Task -
    +
    Manage Target Dates } } -
    +
    -
    +
    -
    +
    @@ -246,7 +246,7 @@

    Tutorials without a stream

    -
    diff --git a/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html b/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html index 9f98162d6d..752fb350e6 100644 --- a/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html +++ b/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html @@ -7,13 +7,13 @@
    groups

    No Tutorials

    -

    +

    There are no tutorials yet. Create a tutorial stream to begin adding tutorials.

    } -
    +
    } -
    +
    @@ -177,10 +177,10 @@

    Mark portfolios

    matTooltipDelay="100" > @if (bar.key === 'not_started') { - {{ bar.value }}% + {{ bar.value }}% } @if (bar.key === 'complete') { - {{ bar.value }}% + {{ bar.value }}% }
    } @@ -212,7 +212,7 @@

    Mark portfolios

    >
    No students foundNo students found
    diff --git a/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.html b/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.html index c88222fa7c..c885e73b1f 100644 --- a/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.html +++ b/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.html @@ -1,4 +1,4 @@ -
    +

    Review portfolio of {{ project.student.name }}

    View or download portfolio for assessment.

    @@ -6,9 +6,9 @@

    Review portfolio of {{ project.student.name }}

    } @else { -
    +
    menu_book -

    No Portfolio Submitted

    +

    No Portfolio Submitted

    }
    diff --git a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html index fc9ea5374c..da4eacf5a9 100644 --- a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html +++ b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html @@ -1,20 +1,20 @@ -
    +

    Review progress of {{ project.student.name }}

    Review the students progress through the unit's tasks.

    -
    -
    +
    +
    Target Grade - -
    -
    + +
    +
    @for (grade of gradeValues; track grade) { @@ -30,9 +30,9 @@

    Review progress of {{ project.student.name }}

    Submitted Grade - -
    -
    + +
    +
    Review progress of {{ project.student.name }} @for (grade of gradeValues; track grade) { @@ -57,7 +57,7 @@

    Review progress of {{ project.student.name }}

    Task List - + Review progress of {{ project.student.name }} > -
    +
    Task Summary Chart - + Review progress of {{ project.student.name }} Burndown Chart - -
    + +
    {{ project.student.name }} has completed {{ taskStats.numberOfTasksCompleted }} tasks and have {{ taskStats.numberOfTasksRemaining }} left to complete to achieve their target of a diff --git a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html index 2ef82a722d..2d454fd43c 100644 --- a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html +++ b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html @@ -1,3 +1,3 @@ - diff --git a/src/app/units/states/portfolios/upload-grades/upload-grades.component.html b/src/app/units/states/portfolios/upload-grades/upload-grades.component.html index a2b05b8f79..a95e240410 100644 --- a/src/app/units/states/portfolios/upload-grades/upload-grades.component.html +++ b/src/app/units/states/portfolios/upload-grades/upload-grades.component.html @@ -1,3 +1,3 @@ - diff --git a/src/app/units/states/rollover/rollover.component.html b/src/app/units/states/rollover/rollover.component.html index f9ac373ed0..d2eee891a4 100644 --- a/src/app/units/states/rollover/rollover.component.html +++ b/src/app/units/states/rollover/rollover.component.html @@ -4,13 +4,13 @@ Copy {{ unit?.code }} {{ unit?.nameAndPeriod }} - +

    Duplicate this unit by copying it to the indicated teaching period, or a custom start and end date.

    -
    +
    Teaching Period @@ -21,7 +21,7 @@ -
    +
    @if (!teachingPeriod) { Start Date diff --git a/src/app/units/states/students-list/students-list.component.html b/src/app/units/states/students-list/students-list.component.html index 860e707883..ee55246c20 100644 --- a/src/app/units/states/students-list/students-list.component.html +++ b/src/app/units/states/students-list/students-list.component.html @@ -1,5 +1,5 @@
    -
    +

    Students

    Browse progress, filter tutorial groups, and manage enrolments.

    @@ -146,15 +146,15 @@

    Students

    >
    + No students were found using the filters specified.
    -
    -
    +
    +
    diff --git a/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.html b/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.html index e7477fa34f..f208622ae8 100644 --- a/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.html +++ b/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.html @@ -14,9 +14,9 @@ [disabled]=" !selectedTask || selectedTask.loadingSubmissionDetails || selectedTask.claimedByUnitRoleId " - class="ml-5" + class="ml-3" > -
    +
    @if (selectedTask.claimedByUnitRoleId) { @if (selectedTask.claimedByUnitRoleId === currentUnitRole.id) { check_circle diff --git a/src/app/units/states/tasks/inbox/inbox.component.html b/src/app/units/states/tasks/inbox/inbox.component.html index b7cded7591..1b29d83c9e 100644 --- a/src/app/units/states/tasks/inbox/inbox.component.html +++ b/src/app/units/states/tasks/inbox/inbox.component.html @@ -38,7 +38,7 @@ @if (!isMobileView) { -
    +
    @if (loading) { diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html index e7efd21ac8..d57c3d6d3c 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html @@ -24,7 +24,7 @@ @for (taskDef of filteredTaskDefinitions; track taskDef) { @if (taskDef) { -
    -
    -
    +
    +
    +
    {{ taskDef.name }}
    -
    +
    @if (taskDef.isGroupTask()) { groups } @else { @@ -54,7 +54,7 @@ @if (taskListItem(taskDef); as task) { @if (!task.isBeforeStartDate() && !task.inSubmittedState()) { +
    @if (task.numNewComments > 0) {
    @if (task.hasGrade()) { @@ -172,7 +172,7 @@ @if (mode === 'project' && project) { diff --git a/src/app/units/unit-root-state.component.html b/src/app/units/unit-root-state.component.html index a7f38ec243..44c6a074e3 100644 --- a/src/app/units/unit-root-state.component.html +++ b/src/app/units/unit-root-state.component.html @@ -2,7 +2,7 @@ } @else {

    Loading unit details...

    diff --git a/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html index 08cbcd19e9..25726a1383 100644 --- a/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html +++ b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html @@ -1,4 +1,4 @@ -
    +
    +
    Date: Wed, 3 Jun 2026 14:43:45 +1000 Subject: [PATCH 1053/1280] chore(release): 11.0.0-13 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8127ffc6f4..9e25745206 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-13](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-12...v11.0.0-13) (2026-06-03) + ## [11.0.0-12](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-11...v11.0.0-12) (2026-06-02) diff --git a/package-lock.json b/package-lock.json index ebb426d6ab..2b666898ff 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-12", + "version": "11.0.0-13", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-12", + "version": "11.0.0-13", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index cad96e247b..4a49f30c79 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-12", + "version": "11.0.0-13", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 84fb6b899e12983a4c44ed21b8a57901b10a5611 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 14:54:36 +1000 Subject: [PATCH 1054/1280] chore: switch to outlined version of icon --- src/app/api/models/task-status.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/models/task-status.ts b/src/app/api/models/task-status.ts index 86614c08f4..9e51c5386e 100644 --- a/src/app/api/models/task-status.ts +++ b/src/app/api/models/task-status.ts @@ -256,7 +256,7 @@ export class TaskStatus { // Material icons used by newer UI elements. public static readonly STATUS_MATERIAL_ICONS = new Map([ - ['ready_for_feedback', 'thumb_up_alt'], + ['ready_for_feedback', 'thumb_up_off_alt'], ['not_started', 'pause'], ['working_on_it', 'bolt'], ['need_help', 'help'], From 7547d4c6819b134c1796acf0cca7fc87ac334eed Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 14:56:41 +1000 Subject: [PATCH 1055/1280] refactor: reduce icon size to match original --- src/app/common/status-icon/status-icon.component.html | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/app/common/status-icon/status-icon.component.html b/src/app/common/status-icon/status-icon.component.html index 0db2f44416..816db2306a 100644 --- a/src/app/common/status-icon/status-icon.component.html +++ b/src/app/common/status-icon/status-icon.component.html @@ -3,8 +3,12 @@ matTooltip="{{ statusLabel(status) }}" matTooltipPosition="above" [matTooltipDisabled]="!showTooltip" - class="status-chip rounded-full cursor-pointer pl-3.5 pr-3.5 min-h-[30px] h-7 ml-0.5 mr-0.5 flex justify-center items-center" + class="status-chip rounded-full cursor-pointer px-3 min-h-[30px] h-7 mx-0.5 flex justify-center items-center" style="font-size: 14px; min-width: 50px" > - {{ statusIcon(status) }} + {{ statusIcon(status) }}
    From 68c51d290159e446ed23220894fcc810bac15fd1 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:01:49 +1000 Subject: [PATCH 1056/1280] chore: clarify tutorial change option --- .../unit-details-editor/unit-details-editor.component.html | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html index cc1672fdc2..2d41f55d16 100644 --- a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html +++ b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html @@ -166,7 +166,10 @@

    Unit Details

    Allow students to change tutorial -

    When false only staff can change student tutorials.

    +

    + When false only staff can change student tutorials. When true, students may switch between + tutors who provide feedback on their work. +

    From e13e69e4ab657ef7f9a6d80065483069dc0a873b Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:02:06 +1000 Subject: [PATCH 1057/1280] chore(release): 11.0.0-14 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e25745206..e4b1ac6757 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-14](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-13...v11.0.0-14) (2026-06-03) + ## [11.0.0-13](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-12...v11.0.0-13) (2026-06-03) ## [11.0.0-12](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-11...v11.0.0-12) (2026-06-02) diff --git a/package-lock.json b/package-lock.json index 2b666898ff..c6f60e3ac7 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-13", + "version": "11.0.0-14", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-13", + "version": "11.0.0-14", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index 4a49f30c79..71ba28446e 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-13", + "version": "11.0.0-14", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 9654d930fbe7072ee4dfc71c454c55c545fe354d Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:12:59 +1000 Subject: [PATCH 1058/1280] chore: temporarily disable discussion prompts from inbox view --- src/app/common/footer/footer.component.html | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index 7e0d7f62bc..e7a031ddc7 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -200,7 +200,8 @@
    } --> @if (selectedTask?.project) { - @if (selectedTask?.definition.discussionPromptsCount) { + +
    -
    +
    Homepage Logo diff --git a/src/styles/common/hero-sidebar-layout.scss b/src/styles/common/hero-sidebar-layout.scss index ab2213bcab..aa5f6ac4fc 100644 --- a/src/styles/common/hero-sidebar-layout.scss +++ b/src/styles/common/hero-sidebar-layout.scss @@ -8,7 +8,7 @@ font-size: 24px; } -.subcontainer { +.content-panel { overflow-y: hidden; height: auto; padding-top: 42px; @@ -48,8 +48,8 @@ h1 { } } -f-sign-in .container, -f-welcome .container { +f-sign-in .content-container, +f-welcome .content-container { max-width: 416px; width: 100%; margin: auto; From cd47f5c0e4c351e2421afd94647a1297b3b5ec75 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 15:49:28 +1000 Subject: [PATCH 1060/1280] fix: display past due date on same day --- src/app/api/models/task.ts | 3 +-- .../directives/unit-task-list/unit-task-list.component.html | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index f812ce1920..b022d3159a 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -525,8 +525,7 @@ export class Task extends Entity { public timeToDue(): string { const days = this.daysUntilDueDate(); - // TODO: check with <= - if (days < 0) { + if (days <= 0) { return 'Past Due Date'; } else if (days < 11) { return `Due in ${this.timeUntilDueDateDescription()}`; diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html index d57c3d6d3c..bd2daea1f6 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html @@ -66,7 +66,7 @@ Date: Wed, 3 Jun 2026 16:05:44 +1000 Subject: [PATCH 1063/1280] chore: update icon for assess in portfolio --- src/app/api/models/task-status.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/api/models/task-status.ts b/src/app/api/models/task-status.ts index 9e51c5386e..816d016ba5 100644 --- a/src/app/api/models/task-status.ts +++ b/src/app/api/models/task-status.ts @@ -268,7 +268,7 @@ export class TaskStatus { ['complete', 'done'], ['fail', 'close'], ['time_exceeded', 'schedule'], - ['assess_in_portfolio', 'folder_open'], + ['assess_in_portfolio', 'rate_review'], ['attention_required', 'sms_failed'], ]); From bc5348702280e1b515cfc0873dbf77fd86d3c065 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 16:17:54 +1000 Subject: [PATCH 1064/1280] chore: replace container with tailwind --- src/app/projects/states/plan/project-plan.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/projects/states/plan/project-plan.component.html b/src/app/projects/states/plan/project-plan.component.html index f48483b8bd..a29342d512 100644 --- a/src/app/projects/states/plan/project-plan.component.html +++ b/src/app/projects/states/plan/project-plan.component.html @@ -1,5 +1,5 @@ @if (project) { -
    +

    Task Planner

    @if (unit.allowFlexibleDates) { @@ -16,7 +16,7 @@

    Task Planner

    -
    +
    Target Grade From 7fdee2f43c3c041517a9cba1fb7412950bb159af Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 16:21:43 +1000 Subject: [PATCH 1065/1280] chore(release): 11.0.0-16 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 403239aa0a..cb7a8ea40f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-16](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-15...v11.0.0-16) (2026-06-03) + ## [11.0.0-15](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-14...v11.0.0-15) (2026-06-03) diff --git a/package-lock.json b/package-lock.json index 5eb4d88cd5..b28b8e1394 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-15", + "version": "11.0.0-16", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-15", + "version": "11.0.0-16", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index 4bccceda69..885d587841 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-15", + "version": "11.0.0-16", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 9e1ef8bcb8e677bd3390e89611d069d669561ab8 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 16:43:47 +1000 Subject: [PATCH 1066/1280] chore: increase stats bar size --- .../directives/portfolios-list/portfolios-list.component.html | 2 +- src/app/units/states/students-list/students-list.component.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html index 1bd6709bcc..fa83b9e354 100644 --- a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html +++ b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html @@ -164,7 +164,7 @@

    Mark portfolios

    Stats -
    +
    @for (bar of project.taskStats; track bar) {
    Students Stats -
    +
    @for (bar of project.taskStats; track bar.key) {
    Date: Wed, 3 Jun 2026 17:00:43 +1000 Subject: [PATCH 1067/1280] feat: support zip file submissions (#1240) --- src/app/app.routes.ts | 5 ++ .../file-uploader/file-uploader.component.ts | 10 ++-- .../submission-files-download.component.html | 26 +++++++++ .../submission-files-download.component.ts | 56 +++++++++++++++++++ src/app/doubtfire-angular.module.ts | 2 + ...tfolio-add-extra-files-step.component.html | 1 + ...ortfolio-add-extra-files-step.component.ts | 2 +- .../task-definition-upload.component.html | 1 + 8 files changed, 97 insertions(+), 6 deletions(-) create mode 100644 src/app/common/submission-files-download/submission-files-download.component.html create mode 100644 src/app/common/submission-files-download/submission-files-download.component.ts diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 25a3244008..5c3f4b8bf1 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -33,6 +33,7 @@ import {resolveUnit} from './units/unit.resolver'; import {UnitRootStateComponent} from './units/unit-root-state.component'; import {WelcomeComponent} from './welcome/welcome.component'; import {roleWhitelistGuard} from './common/guards/role-whitelist.guard'; +import {SubmissionFilesDownloadComponent} from './common/submission-files-download/submission-files-download.component'; export const routes: Routes = [ {path: '', pathMatch: 'full', redirectTo: 'home'}, @@ -62,6 +63,10 @@ export const routes: Routes = [ component: ScormPlayerComponent, data: {mode: 'preview'}, }, + { + path: 'projects/:projectId/task_def_id/:taskDefId/submission_files/download', + component: SubmissionFilesDownloadComponent, + }, {path: 'view-all-units', component: FUnitsComponent, data: {mode: 'tutor'}}, {path: 'view-all-projects', component: FUnitsComponent, data: {mode: 'student'}}, { diff --git a/src/app/common/file-uploader/file-uploader.component.ts b/src/app/common/file-uploader/file-uploader.component.ts index 5f27871ee2..b256d67f54 100644 --- a/src/app/common/file-uploader/file-uploader.component.ts +++ b/src/app/common/file-uploader/file-uploader.component.ts @@ -69,10 +69,9 @@ export const ACCEPTED_TYPES = { name: 'image', }, zip: { - extensions: ['zip', 'tar.gz', 'tar'], - // icon: 'folder_zip', - icon: 'zip_outlined', - name: 'archive', + extensions: ['zip', 'tar.gz', 'tgz', 'tar'], + icon: 'folder_zip', + name: 'zip', }, } as const; @@ -332,7 +331,8 @@ export class FileUploaderComponent implements OnInit, OnChanges { createUploadZones(files: FileData[]) { const zones = Object.entries(files).map(([uploadName, uploadData]) => { - const typeData = ACCEPTED_TYPES[uploadData.type]; + const uploadType = uploadData.type === 'archive' ? 'zip' : uploadData.type; + const typeData = ACCEPTED_TYPES[uploadType]; if (!typeData) throw new Error(`Invalid type provided to File Uploader ${uploadData.type}`); return { diff --git a/src/app/common/submission-files-download/submission-files-download.component.html b/src/app/common/submission-files-download/submission-files-download.component.html new file mode 100644 index 0000000000..67373cd3e5 --- /dev/null +++ b/src/app/common/submission-files-download/submission-files-download.component.html @@ -0,0 +1,26 @@ +
    + @switch (downloadState) { + @case ('downloading') { + +

    Downloading submitted files...

    + } + + @case ('downloaded') { + check_circle +

    Submitted files downloaded.

    + + } + + @case ('failed') { + error +

    Could not download submitted files.

    + + } + } +
    diff --git a/src/app/common/submission-files-download/submission-files-download.component.ts b/src/app/common/submission-files-download/submission-files-download.component.ts new file mode 100644 index 0000000000..386000446b --- /dev/null +++ b/src/app/common/submission-files-download/submission-files-download.component.ts @@ -0,0 +1,56 @@ +import {HttpResponse} from '@angular/common/http'; +import {Component, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {FileDownloaderService} from '../file-downloader/file-downloader.service'; + +type DownloadState = 'downloading' | 'downloaded' | 'failed'; + +@Component({ + selector: 'f-submission-files-download', + templateUrl: './submission-files-download.component.html', + standalone: false, +}) +export class SubmissionFilesDownloadComponent implements OnInit { + protected downloadState: DownloadState = 'downloading'; + private downloadUrl = ''; + + constructor( + private readonly route: ActivatedRoute, + private readonly constants: DoubtfireConstants, + private readonly fileDownloader: FileDownloaderService, + ) {} + + public ngOnInit(): void { + const projectId = this.route.snapshot.paramMap.get('projectId'); + const taskDefId = this.route.snapshot.paramMap.get('taskDefId'); + + this.downloadUrl = `${this.constants.API_URL}/projects/${projectId}/task_def_id/${taskDefId}/submission_files?as_attachment=true`; + this.download(); + } + + protected download(): void { + this.downloadState = 'downloading'; + + this.fileDownloader.downloadBlob( + this.downloadUrl, + (resourceUrl: string, response: HttpResponse) => { + this.fileDownloader.downloadBlobToFile( + resourceUrl, + this.filenameFromResponse(response) ?? 'submitted-files.zip', + ); + this.downloadState = 'downloaded'; + }, + () => { + this.downloadState = 'failed'; + }, + ); + } + + private filenameFromResponse(response: HttpResponse): string | null { + const filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/; + const matches = filenameRegex.exec(response.headers.get('Content-Disposition')); + + return matches?.[1]?.replace(/['"]/g, '') ?? null; + } +} diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 1b43b1af94..406b585682 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -81,6 +81,7 @@ import {ConfirmationModalComponent} from './common/modals/confirmation-modal/con import {DiscussedInClassReasonModalComponent} from './common/modals/discussed-in-class-reason-modal/discussed-in-class-reason-modal.component'; import {ExtensionModalComponent} from './common/modals/extension-modal/extension-modal.component'; import {HttpAuthenticationInterceptor} from './common/services/http-authentication.interceptor'; +import {SubmissionFilesDownloadComponent} from './common/submission-files-download/submission-files-download.component'; import {ProjectTasksListComponent} from './tasks/project-tasks-list/project-tasks-list.component'; import {DiscussionPromptComposerComponent} from './tasks/task-comment-composer/discussion-prompt-composer/discussion-prompt-composer.component'; import {ExtensionCommentComponent} from './tasks/task-comments-viewer/extension-comment/extension-comment.component'; @@ -484,6 +485,7 @@ const GANTT_CHART_CONFIG = { UnitDropdownComponent, TaskDropdownComponent, SplashScreenComponent, + SubmissionFilesDownloadComponent, ProjectDashboardComponent, GradeIconComponent, GradeTaskModalComponent, diff --git a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html index 237e5ce512..073401c523 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html +++ b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html @@ -31,6 +31,7 @@ Document File Code File Image File + Zip File
    diff --git a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts index 8b527c3edb..caaaff49ee 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts +++ b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts @@ -13,7 +13,7 @@ export class PortfolioAddExtraFilesStepComponent implements OnInit { @Input() project: Project; @Input() onAdvanceActiveTab?: (index: 1 | -1) => void; - public uploadType: 'document' | 'code' | 'image' = 'document'; + public uploadType: 'document' | 'code' | 'image' | 'zip' = 'document'; public isUploading: boolean; diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html index 6f6f505b28..802213c691 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html @@ -17,6 +17,7 @@ Code Document Image + Zip From 1827efa8f6b1121462e4971770cbc18e6163b656 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:06:46 +1000 Subject: [PATCH 1068/1280] chore(release): 11.0.0-17 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cb7a8ea40f..7cbbe891ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-17](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-16...v11.0.0-17) (2026-06-03) + + +### Features + +* support zip file submissions ([#1240](https://github.com/b0ink/doubtfire-deploy/issues/1240)) ([99d546f](https://github.com/b0ink/doubtfire-deploy/commit/99d546f1544feeab31fc6b2434e330b22544b56f)) + ## [11.0.0-16](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-15...v11.0.0-16) (2026-06-03) ## [11.0.0-15](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-14...v11.0.0-15) (2026-06-03) diff --git a/package-lock.json b/package-lock.json index b28b8e1394..ef98296e3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-16", + "version": "11.0.0-17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-16", + "version": "11.0.0-17", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index 885d587841..2258c84bdf 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-16", + "version": "11.0.0-17", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From f77115691730be298aa808d9a838b516d0a54b44 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:12:36 +1000 Subject: [PATCH 1069/1280] chore: capitalise zip --- .../task-definition-upload.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html index 802213c691..88a76bac70 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html @@ -17,7 +17,7 @@ Code Document Image - Zip + ZIP From 528fd749f730b4cd9cdc49945c2be1fbaca2c1a3 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:13:03 +1000 Subject: [PATCH 1070/1280] chore: capitalise zip --- .../portfolio-add-extra-files-step.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html index 073401c523..84bd32601d 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html +++ b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html @@ -31,7 +31,7 @@ Document File Code File Image File - Zip File + ZIP File
    From 13b476ac8e8460fe52384e7056b3e16988ad9c1d Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:13:11 +1000 Subject: [PATCH 1071/1280] chore(release): 11.0.0-18 --- CHANGELOG.md | 2 ++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7cbbe891ff..7109991baa 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-18](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-17...v11.0.0-18) (2026-06-03) + ## [11.0.0-17](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-16...v11.0.0-17) (2026-06-03) diff --git a/package-lock.json b/package-lock.json index ef98296e3c..efc4c770fa 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-17", + "version": "11.0.0-18", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-17", + "version": "11.0.0-18", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index 2258c84bdf..5bd7ecddde 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-17", + "version": "11.0.0-18", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 54b1cf03ed662447e7027a61d084f62f2548c996 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:23:59 +1000 Subject: [PATCH 1072/1280] fix: ensure unit is fetched in unit task editor --- src/app/units/unit.resolver.ts | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/app/units/unit.resolver.ts b/src/app/units/unit.resolver.ts index 7b5771d654..181cafe4fa 100644 --- a/src/app/units/unit.resolver.ts +++ b/src/app/units/unit.resolver.ts @@ -29,7 +29,7 @@ export const resolveUnit: ResolveFn = (route, state) => { ); } - const resolveProgressively = state.url.split('?')[0].includes('/tasks'); + const resolveProgressively = shouldResolveUnitProgressively(state.url, unitId); if (resolveProgressively) { const unit = unitRole?.unit ?? unitService.cache.getOrCreate(unitId, unitService, {id: unitId}); @@ -65,6 +65,14 @@ export const resolveUnit: ResolveFn = (route, state) => { }).pipe(first()); }; +// Only `/units/:unitId/tasks...` can safely start with a placeholder unit because those screens +// immediately fetch their own inbox/explorer data. Admin routes like `/units/:unitId/admin/tasks` +// still need the full unit payload here so staff, tutorials, and task definitions are populated. +function shouldResolveUnitProgressively(url: string, unitId: number): boolean { + const pathname = url.split('?')[0]; + return new RegExp(`^/units/${unitId}/tasks(?:/|$)`).test(pathname); +} + function routeEntity(unit: Unit, unitRole?: UnitRole): Unit | UnitRole { if (!unitRole) { return unit; From 82848dd8564313f5162b3bcf17c06df7cb2c70cc Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 3 Jun 2026 17:24:10 +1000 Subject: [PATCH 1073/1280] chore(release): 11.0.0-19 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7109991baa..bc93760c7a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-19](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-18...v11.0.0-19) (2026-06-03) + + +### Bug Fixes + +* ensure unit is fetched in unit task editor ([54b1cf0](https://github.com/b0ink/doubtfire-deploy/commit/54b1cf03ed662447e7027a61d084f62f2548c996)) + ## [11.0.0-18](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-17...v11.0.0-18) (2026-06-03) ## [11.0.0-17](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-16...v11.0.0-17) (2026-06-03) diff --git a/package-lock.json b/package-lock.json index efc4c770fa..98764a4477 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-18", + "version": "11.0.0-19", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-18", + "version": "11.0.0-19", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index 5bd7ecddde..a382363bcd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-18", + "version": "11.0.0-19", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 2febef9ef68ab455b47f46b4fbec77bd76746faa Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 4 Jun 2026 09:46:43 +1000 Subject: [PATCH 1074/1280] chore: rebuild package-lock.json --- package-lock.json | 2642 ++++++++++----------------------------------- 1 file changed, 586 insertions(+), 2056 deletions(-) diff --git a/package-lock.json b/package-lock.json index 98764a4477..b118832f0b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2365,660 +2365,460 @@ "tslib": "^2.4.0" } }, - "node_modules/@esbuild/aix-ppc64": { + "node_modules/@esbuild/linux-arm64": { "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", - "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", "cpu": [ - "ppc64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "aix" + "linux" ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/android-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", - "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", - "cpu": [ - "arm" - ], - "dev": true, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, "engines": { - "node": ">=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@esbuild/android-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", - "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": ">=18" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@esbuild/android-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", - "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "peer": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, "engines": { - "node": ">=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@esbuild/darwin-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", - "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.12.6", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@esbuild/darwin-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", - "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">=18" - } + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "license": "Python-2.0", + "peer": true }, - "node_modules/@esbuild/freebsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", - "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.12", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@esbuild/freebsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", - "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.1", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">=18" + "peer": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/@esbuild/linux-arm": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", - "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", - "cpu": [ - "arm" - ], - "dev": true, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "peer": true + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=18" + "node": "*" } }, - "node_modules/@esbuild/linux-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@eslint/js": { + "version": "8.57.1", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "peer": true, "engines": { - "node": ">=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" } }, - "node_modules/@esbuild/linux-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", - "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", - "cpu": [ - "ia32" - ], + "node_modules/@gar/promise-retry": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@gar/promise-retry/-/promise-retry-1.0.3.tgz", + "integrity": "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@esbuild/linux-loong64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", - "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", - "cpu": [ - "loong64" - ], + "node_modules/@harperfast/extended-iterable": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@harperfast/extended-iterable/-/extended-iterable-1.0.3.tgz", + "integrity": "sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=18" - } + "license": "Apache-2.0", + "optional": true }, - "node_modules/@esbuild/linux-mips64el": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", - "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", - "cpu": [ - "mips64el" - ], + "node_modules/@hono/node-server": { + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">=18" + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" } }, - "node_modules/@esbuild/linux-ppc64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", - "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", - "cpu": [ - "ppc64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, "engines": { - "node": ">=18" + "node": ">=10.10.0" } }, - "node_modules/@esbuild/linux-riscv64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", - "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", - "cpu": [ - "riscv64" - ], - "dev": true, + "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { + "version": "1.1.12", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "peer": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "license": "ISC", + "peer": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, "engines": { - "node": ">=18" + "node": "*" } }, - "node_modules/@esbuild/linux-s390x": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", - "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", - "cpu": [ - "s390x" - ], + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "license": "Apache-2.0", + "peer": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/linux-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", - "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/checkbox": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@esbuild/netbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", - "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@esbuild/netbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", - "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "netbsd" - ], + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" + }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@esbuild/openbsd-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", - "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/core/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "license": "ISC", "engines": { - "node": ">=18" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@esbuild/openbsd-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", - "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openbsd" - ], + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" + }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@esbuild/openharmony-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", - "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/expand": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@esbuild/sunos-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", - "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "sunos" - ], + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" + }, "engines": { "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@esbuild/win32-arm64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", - "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, "engines": { - "node": ">=18" + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@esbuild/win32-ia32": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", - "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", - "cpu": [ - "ia32" - ], + "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], "engines": { "node": ">=18" } }, - "node_modules/@esbuild/win32-x64": { - "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", - "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/input": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=18" - } - }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", - "license": "MIT", "dependencies": { - "eslint-visitor-keys": "^3.4.3" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" }, "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" - } - }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", - "license": "MIT", - "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "2.1.4", - "license": "MIT", - "peer": true, - "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^9.6.0", - "globals": "^13.19.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", - "license": "MIT", - "peer": true, - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/argparse": { - "version": "2.0.1", - "license": "Python-2.0", - "peer": true - }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@eslint/eslintrc/node_modules/js-yaml": { - "version": "4.1.1", - "license": "MIT", - "peer": true, - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "license": "MIT", - "peer": true - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" + "@types/node": ">=18" }, - "engines": { - "node": "*" - } - }, - "node_modules/@eslint/js": { - "version": "8.57.1", - "license": "MIT", - "peer": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - } - }, - "node_modules/@gar/promise-retry": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@gar/promise-retry/-/promise-retry-1.0.3.tgz", - "integrity": "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.17.0 || >=22.9.0" + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@harperfast/extended-iterable": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@harperfast/extended-iterable/-/extended-iterable-1.0.3.tgz", - "integrity": "sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw==", - "dev": true, - "license": "Apache-2.0", - "optional": true - }, - "node_modules/@hono/node-server": { - "version": "1.19.14", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", - "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "node_modules/@inquirer/number": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", "dev": true, "license": "MIT", - "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" - } - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "license": "Apache-2.0", - "peer": true, "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": ">=10.10.0" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.12", - "license": "MIT", - "peer": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", - "license": "ISC", - "peer": true, - "dependencies": { - "brace-expansion": "^1.1.7" + "node": ">=18" }, - "engines": { - "node": "*" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "license": "Apache-2.0", - "peer": true, - "engines": { - "node": ">=12.22" + "peerDependencies": { + "@types/node": ">=18" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "license": "BSD-3-Clause", - "peer": true - }, - "node_modules/@inquirer/ansi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", - "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@inquirer/checkbox": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", - "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", + "node_modules/@inquirer/password": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", "dev": true, "license": "MIT", "dependencies": { "@inquirer/ansi": "^1.0.2", "@inquirer/core": "^10.3.2", - "@inquirer/figures": "^1.0.15", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" + "@inquirer/type": "^3.0.10" }, "engines": { "node": ">=18" @@ -3032,248 +2832,23 @@ } } }, - "node_modules/@inquirer/confirm": { - "version": "5.1.21", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", - "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "node_modules/@inquirer/prompts": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/core": { - "version": "10.3.2", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", - "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/figures": "^1.0.15", - "@inquirer/type": "^3.0.10", - "cli-width": "^4.1.0", - "mute-stream": "^2.0.0", - "signal-exit": "^4.1.0", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/core/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/@inquirer/editor": { - "version": "4.2.23", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", - "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/external-editor": "^1.0.3", - "@inquirer/type": "^3.0.10" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/expand": { - "version": "4.0.23", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", - "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/external-editor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", - "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", - "dev": true, - "license": "MIT", - "dependencies": { - "chardet": "^2.1.1", - "iconv-lite": "^0.7.0" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/external-editor/node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@inquirer/figures": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", - "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/@inquirer/input": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", - "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/number": { - "version": "3.0.23", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", - "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/password": { - "version": "4.0.23", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", - "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } - } - }, - "node_modules/@inquirer/prompts": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", - "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/checkbox": "^4.3.2", - "@inquirer/confirm": "^5.1.21", - "@inquirer/editor": "^4.2.23", - "@inquirer/expand": "^4.0.23", - "@inquirer/input": "^4.3.1", - "@inquirer/number": "^3.0.23", - "@inquirer/password": "^4.0.23", - "@inquirer/rawlist": "^4.1.11", - "@inquirer/search": "^3.2.2", - "@inquirer/select": "^4.4.2" + "@inquirer/checkbox": "^4.3.2", + "@inquirer/confirm": "^5.1.21", + "@inquirer/editor": "^4.2.23", + "@inquirer/expand": "^4.0.23", + "@inquirer/input": "^4.3.1", + "@inquirer/number": "^3.0.23", + "@inquirer/password": "^4.0.23", + "@inquirer/rawlist": "^4.1.11", + "@inquirer/search": "^3.2.2", + "@inquirer/select": "^4.4.2" }, "engines": { "node": ">=18" @@ -3378,822 +2953,197 @@ } }, "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", - "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "license": "MIT" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, - "node_modules/@listr2/prompt-adapter-inquirer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.5.tgz", - "integrity": "sha512-WELs+hj6xcilkloBXYf9XXK8tYEnKsgLj01Xl5ONUJpKjmT5hGVUzNUS5tooUxs7pGMrw+jFD/41WpqW4V3LDA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@inquirer/type": "^3.0.8" - }, - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@inquirer/prompts": ">= 3 < 8", - "listr2": "9.0.5" - } - }, - "node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.5.1.tgz", - "integrity": "sha512-tpfN4kKrrMpQ+If1l8bhmoNkECJi0iOu6AEdrTJvWVC+32sLxTARX5Rsu579mPImRP9YFWfWgeRQ5oav7zApQQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.5.1.tgz", - "integrity": "sha512-+a2tTfc3rmWhLAolFUWRgJtpSuu+Fw/yjn4rF406NMxhfjbMuiOUTDRvRlMFV+DzyjkwnokisskHbCWkS3Ly5w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@lmdb/lmdb-linux-arm": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.5.1.tgz", - "integrity": "sha512-0EgcE6reYr8InjD7V37EgXcYrloqpxVPINy3ig1MwDSbl6LF/vXTYRH9OE1Ti1D8YZnB35ZH9aTcdfSb5lql2A==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.1.tgz", - "integrity": "sha512-aoERa5B6ywXdyFeYGQ1gbQpkMkDbEo45qVoXE5QpIRavqjnyPwjOulMkmkypkmsbJ5z4Wi0TBztON8agCTG0Vg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lmdb/lmdb-linux-x64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.5.1.tgz", - "integrity": "sha512-SqNDY1+vpji7bh0sFH5wlWyFTOzjbDOl0/kB5RLLYDAFyd/uw3n7wyrmas3rYPpAW7z18lMOi1yKlTPv967E3g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lmdb/lmdb-win32-arm64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.5.1.tgz", - "integrity": "sha512-50v0O1Lt37cwrmR9vWZK5hRW0Aw+KEmxJJ75fge/zIYdvNKB/0bSMSVR5Uc2OV9JhosIUyklOmrEvavwNJ8D6w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@lmdb/lmdb-win32-x64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.5.1.tgz", - "integrity": "sha512-qwosvPyl+zpUlp3gRb7UcJ3H8S28XHCzkv0Y0EgQToXjQP91ZD67EHSCDmaLjtKhe+GVIW5om1KUpzVLA0l6pg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", - "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", - "license": "BSD-3-Clause", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" - }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "license": "MIT", - "optional": true, - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "license": "ISC", - "optional": true, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "license": "ISC", - "optional": true, - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "license": "MIT", - "optional": true, - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "license": "MIT", - "optional": true, - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "license": "ISC", - "optional": true, - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "license": "ISC", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "license": "MIT", - "optional": true, - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "license": "ISC", - "optional": true, - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "license": "MIT", - "optional": true, - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "license": "ISC", - "optional": true, - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "license": "ISC", - "optional": true, - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "license": "ISC", - "optional": true - }, - "node_modules/@mattlewis92/dom-autoscroller": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@mattlewis92/dom-autoscroller/-/dom-autoscroller-2.4.2.tgz", - "integrity": "sha512-YbrUWREPGEjE/FU6foXcAT1YbVwqD/jkYnY1dFb0o4AxtP3s4xKBthlELjndZih8uwsDWgQZx1eNskRNe2BgZQ==", - "license": "MIT" - }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", - "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@hono/node-server": "^1.19.9", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" - }, - "peerDependenciesMeta": { - "@cfworker/json-schema": { - "optional": true - }, - "zod": { - "optional": false - } - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/@modelcontextprotocol/sdk/node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.3.tgz", - "integrity": "sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.3.tgz", - "integrity": "sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.3.tgz", - "integrity": "sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", - "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.3.tgz", - "integrity": "sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.3.tgz", - "integrity": "sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@napi-rs/nice": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", - "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">= 10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "optionalDependencies": { - "@napi-rs/nice-android-arm-eabi": "1.1.1", - "@napi-rs/nice-android-arm64": "1.1.1", - "@napi-rs/nice-darwin-arm64": "1.1.1", - "@napi-rs/nice-darwin-x64": "1.1.1", - "@napi-rs/nice-freebsd-x64": "1.1.1", - "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", - "@napi-rs/nice-linux-arm64-gnu": "1.1.1", - "@napi-rs/nice-linux-arm64-musl": "1.1.1", - "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", - "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", - "@napi-rs/nice-linux-s390x-gnu": "1.1.1", - "@napi-rs/nice-linux-x64-gnu": "1.1.1", - "@napi-rs/nice-linux-x64-musl": "1.1.1", - "@napi-rs/nice-openharmony-arm64": "1.1.1", - "@napi-rs/nice-win32-arm64-msvc": "1.1.1", - "@napi-rs/nice-win32-ia32-msvc": "1.1.1", - "@napi-rs/nice-win32-x64-msvc": "1.1.1" - } - }, - "node_modules/@napi-rs/nice-android-arm-eabi": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", - "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/nice-android-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", - "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==", - "cpu": [ - "arm64" - ], + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, "engines": { - "node": ">= 10" + "node": ">=18.0.0" } }, - "node_modules/@napi-rs/nice-darwin-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", - "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==", - "cpu": [ - "arm64" - ], + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], "engines": { - "node": ">= 10" + "node": ">=8" } }, - "node_modules/@napi-rs/nice-darwin-x64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", - "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==", - "cpu": [ - "x64" - ], + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, "engines": { - "node": ">= 10" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/@napi-rs/nice-freebsd-x64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", - "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==", - "cpu": [ - "x64" - ], + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", - "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==", - "cpu": [ - "arm" - ], + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" } }, - "node_modules/@napi-rs/nice-linux-arm64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", - "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", - "cpu": [ - "arm64" - ], + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": ">= 10" + "node": ">=6.0.0" } }, - "node_modules/@napi-rs/nice-linux-arm64-musl": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", - "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", - "cpu": [ - "arm64" - ], + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" } }, - "node_modules/@napi-rs/nice-linux-ppc64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", - "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==", - "cpu": [ - "ppc64" - ], + "node_modules/@listr2/prompt-adapter-inquirer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.5.tgz", + "integrity": "sha512-WELs+hj6xcilkloBXYf9XXK8tYEnKsgLj01Xl5ONUJpKjmT5hGVUzNUS5tooUxs7pGMrw+jFD/41WpqW4V3LDA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@inquirer/type": "^3.0.8" + }, "engines": { - "node": ">= 10" + "node": ">=20.0.0" + }, + "peerDependencies": { + "@inquirer/prompts": ">= 3 < 8", + "listr2": "9.0.5" } }, - "node_modules/@napi-rs/nice-linux-riscv64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", - "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==", + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.1.tgz", + "integrity": "sha512-aoERa5B6ywXdyFeYGQ1gbQpkMkDbEo45qVoXE5QpIRavqjnyPwjOulMkmkypkmsbJ5z4Wi0TBztON8agCTG0Vg==", "cpu": [ - "riscv64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ "linux" - ], - "engines": { - "node": ">= 10" - } + ] }, - "node_modules/@napi-rs/nice-linux-s390x-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", - "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==", - "cpu": [ - "s390x" - ], + "node_modules/@mattlewis92/dom-autoscroller": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@mattlewis92/dom-autoscroller/-/dom-autoscroller-2.4.2.tgz", + "integrity": "sha512-YbrUWREPGEjE/FU6foXcAT1YbVwqD/jkYnY1dFb0o4AxtP3s4xKBthlELjndZih8uwsDWgQZx1eNskRNe2BgZQ==", + "license": "MIT" + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", + "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, "engines": { - "node": ">= 10" + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } } }, - "node_modules/@napi-rs/nice-linux-x64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", - "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==", - "cpu": [ - "x64" - ], + "node_modules/@modelcontextprotocol/sdk/node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, "engines": { - "node": ">= 10" + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/@napi-rs/nice-linux-x64-musl": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", - "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==", - "cpu": [ - "x64" - ], + "node_modules/@modelcontextprotocol/sdk/node_modules/raw-body": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.7.0", + "unpipe": "~1.0.0" + }, "engines": { - "node": ">= 10" + "node": ">= 0.10" } }, - "node_modules/@napi-rs/nice-openharmony-arm64": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", - "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==", + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", + "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", "cpu": [ "arm64" ], @@ -4201,58 +3151,72 @@ "license": "MIT", "optional": true, "os": [ - "openharmony" - ], - "engines": { - "node": ">= 10" - } + "linux" + ] }, - "node_modules/@napi-rs/nice-win32-arm64-msvc": { + "node_modules/@napi-rs/nice": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", - "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==", - "cpu": [ - "arm64" - ], + "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", + "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", "dev": true, "license": "MIT", "optional": true, - "os": [ - "win32" - ], "engines": { "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/nice-android-arm-eabi": "1.1.1", + "@napi-rs/nice-android-arm64": "1.1.1", + "@napi-rs/nice-darwin-arm64": "1.1.1", + "@napi-rs/nice-darwin-x64": "1.1.1", + "@napi-rs/nice-freebsd-x64": "1.1.1", + "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", + "@napi-rs/nice-linux-arm64-gnu": "1.1.1", + "@napi-rs/nice-linux-arm64-musl": "1.1.1", + "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", + "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", + "@napi-rs/nice-linux-s390x-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-musl": "1.1.1", + "@napi-rs/nice-openharmony-arm64": "1.1.1", + "@napi-rs/nice-win32-arm64-msvc": "1.1.1", + "@napi-rs/nice-win32-ia32-msvc": "1.1.1", + "@napi-rs/nice-win32-x64-msvc": "1.1.1" } }, - "node_modules/@napi-rs/nice-win32-ia32-msvc": { + "node_modules/@napi-rs/nice-linux-arm64-gnu": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", - "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", + "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", "cpu": [ - "ia32" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { "node": ">= 10" } }, - "node_modules/@napi-rs/nice-win32-x64-msvc": { + "node_modules/@napi-rs/nice-linux-arm64-musl": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", - "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", + "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { "node": ">= 10" @@ -4835,323 +3799,106 @@ }, "node_modules/@nx/nx-win32-x64-msvc": { "version": "18.3.5", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-18.3.5.tgz", - "integrity": "sha512-xFwKVTIXSgjdfxkpriqHv5NpmmFILTrWLEkUGSoimuRaAm1u15YWx/VmaUQ+UWuJnmgqvB/so4SMHSfNkq3ijA==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.113.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.113.0.tgz", - "integrity": "sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@parcel/watcher": { - "version": "2.5.6", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.3", - "is-glob": "^4.0.3", - "node-addon-api": "^7.0.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.6", - "@parcel/watcher-darwin-arm64": "2.5.6", - "@parcel/watcher-darwin-x64": "2.5.6", - "@parcel/watcher-freebsd-x64": "2.5.6", - "@parcel/watcher-linux-arm-glibc": "2.5.6", - "@parcel/watcher-linux-arm-musl": "2.5.6", - "@parcel/watcher-linux-arm64-glibc": "2.5.6", - "@parcel/watcher-linux-arm64-musl": "2.5.6", - "@parcel/watcher-linux-x64-glibc": "2.5.6", - "@parcel/watcher-linux-x64-musl": "2.5.6", - "@parcel/watcher-win32-arm64": "2.5.6", - "@parcel/watcher-win32-ia32": "2.5.6", - "@parcel/watcher-win32-x64": "2.5.6" - } - }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.6", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher/node_modules/node-addon-api": { - "version": "7.1.1", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/@parcel/watcher/node_modules/picomatch": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.4.tgz", - "integrity": "sha512-vRq9f4NzvbdZavhQbjkJBx7rRebDKYR9zHfO/Wg486+I7bSecdUapzCm5cyXoK+LHokTxgSq7A5baAXUZkIz0w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.4.tgz", - "integrity": "sha512-kFgEvkWLqt3YCgKB5re9RlIrx9bRsvyVUnaTakEpOPuLGzLpLapYxE9BufJNvPg8GjT6mB1alN4yN1NjzoeM8Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.4.tgz", - "integrity": "sha512-JXmaOJGsL/+rsmMfutcDjxWM2fTaVgCHGoXS7nE8Z3c9NAYjGqHvXrAhMUZvMpHS/k7Mg+X7n/MVKb7NYWKKww==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.4.tgz", - "integrity": "sha512-ep3Catd6sPnHTM0P4hNEvIv5arnDvk01PfyJIJ+J3wVCG1eEaPo09tvFqdtcaTrkwQy0VWR24uz+cb4IsK53Qw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.4.tgz", - "integrity": "sha512-LwA5ayKIpnsgXJEwWc3h8wPiS33NMIHd9BhsV92T8VetVAbGe2qXlJwNVDGHN5cOQ22R9uYvbrQir2AB+ntT2w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.4.tgz", - "integrity": "sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.4.tgz", - "integrity": "sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.4.tgz", - "integrity": "sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.4.tgz", - "integrity": "sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-18.3.5.tgz", + "integrity": "sha512-xFwKVTIXSgjdfxkpriqHv5NpmmFILTrWLEkUGSoimuRaAm1u15YWx/VmaUQ+UWuJnmgqvB/so4SMHSfNkq3ijA==", "cpu": [ "x64" ], - "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 10" } }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.4.tgz", - "integrity": "sha512-6lcI79+X8klGiGd8yHuTgQRjuuJYNggmEml+RsyN596P23l/zf9FVmJ7K0KVKkFAeYEdg0iMUKyIxiV5vebDNQ==", - "cpu": [ - "arm64" - ], + "node_modules/@oxc-project/types": { + "version": "0.113.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.113.0.tgz", + "integrity": "sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.4.tgz", - "integrity": "sha512-wz7ohsKCAIWy91blZ/1FlpPdqrsm1xpcEOQVveWoL6+aSPKL4VUcoYmmzuLTssyZxRpEwzuIxL/GDsvpjaBtOw==", - "cpu": [ - "wasm32" - ], + "node_modules/@parcel/watcher": { + "version": "2.5.6", "dev": true, + "hasInstallScript": true, "license": "MIT", "optional": true, "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.1" + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" }, "engines": { - "node": ">=14.0.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" } }, - "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.1" + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@rolldown/binding-wasm32-wasi/node_modules/@tybys/wasm-util": { - "version": "0.10.1", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz", - "integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==", + "node_modules/@parcel/watcher/node_modules/node-addon-api": { + "version": "7.1.1", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/@parcel/watcher/node_modules/picomatch": { + "version": "4.0.3", "dev": true, "license": "MIT", "optional": true, - "dependencies": { - "tslib": "^2.4.0" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { + "node_modules/@rolldown/binding-linux-arm64-gnu": { "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.4.tgz", - "integrity": "sha512-cfiMrfuWCIgsFmcVG0IPuO6qTRHvF7NuG3wngX1RZzc6dU8FuBFb+J3MIR5WrdTNozlumfgL4cvz+R4ozBCvsQ==", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.4.tgz", + "integrity": "sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==", "cpu": [ "arm64" ], @@ -5159,24 +3906,24 @@ "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rolldown/binding-win32-x64-msvc": { + "node_modules/@rolldown/binding-linux-arm64-musl": { "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.4.tgz", - "integrity": "sha512-p6UeR9y7ht82AH57qwGuFYn69S6CZ7LLKdCKy/8T3zS9VTrJei2/CGsTUV45Da4Z9Rbhc7G4gyWQ/Ioamqn09g==", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.4.tgz", + "integrity": "sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==", "cpu": [ - "x64" + "arm64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { "node": "^20.19.0 || >=22.12.0" @@ -5427,9 +4174,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", - "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", + "version": "4.61.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.0.tgz", + "integrity": "sha512-0uMOcf3eZ5K+K4cYHkdxShFMPlPXCOdfDFEFn9dNYAEEd2cVvmOfH7zFgRVoDgmtQ1m9k5q7qfrHzyMAubKYUA==", "cpu": [ "x64" ], @@ -6545,11 +5292,6 @@ "dev": true, "license": "Python-2.0" }, - "node_modules/abbrev": { - "version": "1.1.1", - "license": "ISC", - "optional": true - }, "node_modules/accepts": { "version": "1.3.8", "dev": true, @@ -7155,28 +5897,6 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/aproba": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", - "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", - "license": "ISC", - "optional": true - }, - "node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "optional": true, - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/arg": { "version": "5.0.2", "dev": true, @@ -7887,22 +6607,6 @@ "dev": true, "license": "MIT" }, - "node_modules/canvas": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", - "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@mapbox/node-pre-gyp": "^1.0.0", - "nan": "^2.17.0", - "simple-get": "^3.0.3" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/canvas-confetti": { "version": "1.9.4", "license": "ISC", @@ -8113,16 +6817,6 @@ "version": "1.1.4", "license": "MIT" }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "license": "ISC", - "optional": true, - "bin": { - "color-support": "bin.js" - } - }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -8302,13 +6996,6 @@ "dev": true, "license": "MIT" }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", - "license": "ISC", - "optional": true - }, "node_modules/content-disposition": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", @@ -8883,19 +7570,6 @@ "node": ">=0.10.0" } }, - "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "license": "MIT", - "optional": true, - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/deep-is": { "version": "0.1.4", "license": "MIT", @@ -8990,13 +7664,6 @@ "node": ">=0.4.0" } }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "license": "MIT", - "optional": true - }, "node_modules/depd": { "version": "2.0.0", "dev": true, @@ -9024,6 +7691,7 @@ }, "node_modules/detect-libc": { "version": "2.1.2", + "dev": true, "license": "Apache-2.0", "optional": true, "engines": { @@ -10424,28 +9092,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "optional": true, - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -10760,13 +9406,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", - "license": "ISC", - "optional": true - }, "node_modules/hasown": { "version": "2.0.2", "dev": true, @@ -12623,19 +11262,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "license": "MIT", - "optional": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/minimatch": { "version": "9.0.5", "dev": true, @@ -12917,13 +11543,6 @@ "thenify-all": "^1.0.0" } }, - "node_modules/nan": { - "version": "2.26.2", - "resolved": "https://registry.npmjs.org/nan/-/nan-2.26.2.tgz", - "integrity": "sha512-0tTvBTYkt3tdGw22nrAy50x7gpbGCCFH3AFcyS5WiUu7Eu4vWlri1woE6qHBSfy11vksDqkiwjOnlR7WV8G1Hw==", - "license": "MIT", - "optional": true - }, "node_modules/nanoid": { "version": "3.3.11", "dev": true, @@ -13052,27 +11671,6 @@ "license": "MIT", "optional": true }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "license": "MIT", - "optional": true, - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, "node_modules/node-gyp": { "version": "12.3.0", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.3.0.tgz", @@ -15720,20 +14318,6 @@ "node": ">=18" } }, - "node_modules/npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "deprecated": "This package is no longer supported.", - "license": "ISC", - "optional": true, - "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -16077,7 +14661,7 @@ }, "node_modules/object-assign": { "version": "4.1.1", - "devOptional": true, + "dev": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -17766,6 +16350,20 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", + "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -18294,39 +16892,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", - "optional": true - }, - "node_modules/simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", - "license": "MIT", - "optional": true, - "dependencies": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, "node_modules/slash": { "version": "3.0.0", "dev": true, @@ -18998,13 +17563,6 @@ "node": ">=6" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT", - "optional": true - }, "node_modules/tree-kill": { "version": "1.2.2", "dev": true, @@ -19855,24 +18413,6 @@ "node": ">=0.8.0" } }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause", - "optional": true - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "optional": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, "node_modules/which": { "version": "2.0.2", "license": "ISC", @@ -19890,16 +18430,6 @@ "version": "2.0.1", "license": "ISC" }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "license": "ISC", - "optional": true, - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, "node_modules/word-wrap": { "version": "1.2.5", "license": "MIT", From 0eb003ae99454d158d06f48067f4477e18157756 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 4 Jun 2026 15:07:05 +1000 Subject: [PATCH 1075/1280] chore: remove npm package --- package-lock.json | 3147 +++++++++------------------------------------ package.json | 1 - 2 files changed, 589 insertions(+), 2559 deletions(-) diff --git a/package-lock.json b/package-lock.json index b118832f0b..70f9a49c31 100644 --- a/package-lock.json +++ b/package-lock.json @@ -58,7 +58,6 @@ "ngx-lottie": "^11.0.2", "ngx-monaco-editor-v2": "^21", "ngx-skeleton-loader": "^12.0.0", - "npm": "^10.4.0", "nvd3": "1.8.6", "qrcode": "^1.5.4", "rxjs": "~7.8.2", @@ -2428,7 +2427,9 @@ } }, "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.12.6", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "license": "MIT", "peer": true, "dependencies": { @@ -2448,7 +2449,9 @@ "peer": true }, "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.12", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "license": "MIT", "peer": true, "dependencies": { @@ -2473,7 +2476,9 @@ "peer": true }, "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.2", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "peer": true, "dependencies": { @@ -2536,7 +2541,9 @@ } }, "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { - "version": "1.1.12", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "license": "MIT", "peer": true, "dependencies": { @@ -2545,7 +2552,9 @@ } }, "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { - "version": "3.1.2", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "peer": true, "dependencies": { @@ -3446,9 +3455,9 @@ } }, "node_modules/@npmcli/package-json/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { @@ -3858,6 +3867,132 @@ "@parcel/watcher-win32-x64": "2.5.6" } }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@parcel/watcher-linux-arm64-glibc": { "version": "2.5.6", "cpu": [ @@ -3877,6 +4012,132 @@ "url": "https://opencollective.com/parcel" } }, + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, "node_modules/@parcel/watcher/node_modules/node-addon-api": { "version": "7.1.1", "dev": true, @@ -3884,7 +4145,9 @@ "optional": true }, "node_modules/@parcel/watcher/node_modules/picomatch": { - "version": "4.0.3", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "dev": true, "license": "MIT", "optional": true, @@ -4852,9 +5115,9 @@ } }, "node_modules/@tufjs/models/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { @@ -4978,6 +5241,16 @@ "license": "MIT", "optional": true }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "7.11.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.11.0.tgz", @@ -5419,7 +5692,10 @@ } }, "node_modules/angular": { - "version": "1.5.11", + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/angular/-/angular-1.8.3.tgz", + "integrity": "sha512-5qjkWIQQVsHj4Sb5TcEs4WZWpFeVFHXwxEBHUhrny41D8UrBAd6T/6nPPAsLngJCReIOqi95W3mxdveveutpZw==", + "deprecated": "For the actively supported Angular, see https://www.npmjs.com/package/@angular/core. AngularJS support has officially ended. For extended AngularJS support options, see https://goo.gle/angularjs-path-forward.", "license": "MIT" }, "node_modules/angular-calendar": { @@ -5715,9 +5991,9 @@ } }, "node_modules/angular-eslint/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -5887,7 +6163,9 @@ } }, "node_modules/anymatch/node_modules/picomatch": { - "version": "2.3.1", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "devOptional": true, "license": "MIT", "engines": { @@ -6100,15 +6378,29 @@ "license": "MIT" }, "node_modules/axios": { - "version": "1.13.6", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.13.6.tgz", - "integrity": "sha512-ChTCHMouEe2kn713WHbQGcuYrr6fXTBiu460OTwWrWob16g1bXn4vtz07Ope7ewMozJAnEquLk5lWQWtBig9DQ==", + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.17.0.tgz", + "integrity": "sha512-J8SwNxprqqpbfenehxWYXE7CW+wM1BB4w3+N+g+/Wx40xM4rsLrfPmHHxSWIxJLYDgSY/HqlFPIYb2/S3rxafw==", "dev": true, "license": "MIT", "dependencies": { - "follow-redirects": "^1.15.11", + "follow-redirects": "^1.16.0", "form-data": "^4.0.5", - "proxy-from-env": "^1.1.0" + "https-proxy-agent": "^5.0.1", + "proxy-from-env": "^2.1.0" + } + }, + "node_modules/axios/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" } }, "node_modules/axios/node_modules/form-data": { @@ -6128,6 +6420,20 @@ "node": ">= 6" } }, + "node_modules/axios/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/axobject-query": { "version": "4.0.0", "dev": true, @@ -6245,7 +6551,9 @@ } }, "node_modules/body-parser": { - "version": "1.20.4", + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", "dev": true, "license": "MIT", "dependencies": { @@ -6257,7 +6565,7 @@ "http-errors": "~2.0.1", "iconv-lite": "~0.4.24", "on-finished": "~2.4.1", - "qs": "~6.14.0", + "qs": "~6.15.1", "raw-body": "~2.5.3", "type-is": "~1.6.18", "unpipe": "~1.0.0" @@ -6310,7 +6618,9 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "2.0.2", + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.1.tgz", + "integrity": "sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==", "dev": true, "license": "MIT", "dependencies": { @@ -6469,9 +6779,9 @@ } }, "node_modules/cacache/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { @@ -7948,19 +8258,22 @@ } }, "node_modules/engine.io": { - "version": "6.6.5", + "version": "6.6.8", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.8.tgz", + "integrity": "sha512-2agL3ueZhqxoVrfmntO8yuVj+uNSlIOnhykYHk3Cq0ShYPdUjjUiSJrQvXjq01I9jAuI0Zl2YO8Evv5Mqytm5g==", "dev": true, "license": "MIT", "dependencies": { "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", + "@types/ws": "^8.5.12", "accepts": "~1.3.4", "base64id": "2.0.0", "cookie": "~0.7.2", "cors": "~2.8.5", "debug": "~4.4.1", "engine.io-parser": "~5.2.1", - "ws": "~8.18.3" + "ws": "~8.20.1" }, "engines": { "node": ">=10.2.0" @@ -8256,7 +8569,9 @@ } }, "node_modules/eslint/node_modules/ajv": { - "version": "6.12.6", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "license": "MIT", "peer": true, "dependencies": { @@ -8276,7 +8591,9 @@ "peer": true }, "node_modules/eslint/node_modules/brace-expansion": { - "version": "1.1.12", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "license": "MIT", "peer": true, "dependencies": { @@ -8327,7 +8644,9 @@ "peer": true }, "node_modules/eslint/node_modules/minimatch": { - "version": "3.1.2", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "peer": true, "dependencies": { @@ -8496,13 +8815,13 @@ } }, "node_modules/express-rate-limit": { - "version": "8.4.1", - "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.4.1.tgz", - "integrity": "sha512-NGVYwQSAyEQgzxX1iCM978PP9AdO/hW93gMcF6ZwQCm+rFvLsBH6w4xcXWTcliS8La5EPRN3p9wzItqBwJrfNw==", + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/express-rate-limit/-/express-rate-limit-8.5.2.tgz", + "integrity": "sha512-5Kb34ipNX694DH48vN9irak1Qx30nb0PLYHXfJgw4YEjiC3ZEmZJhwOp+VfiCYwFzvFTdB9QkArYS5kXa2cx2A==", "dev": true, "license": "MIT", "dependencies": { - "ip-address": "10.1.0" + "ip-address": "^10.2.0" }, "engines": { "node": ">= 16" @@ -8794,9 +9113,9 @@ "peer": true }, "node_modules/fast-uri": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.0.tgz", - "integrity": "sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==", + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", + "integrity": "sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ==", "funding": [ { "type": "github", @@ -8975,11 +9294,15 @@ } }, "node_modules/flatted": { - "version": "3.3.3", + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.4.2.tgz", + "integrity": "sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==", "license": "ISC" }, "node_modules/follow-redirects": { - "version": "1.15.11", + "version": "1.16.0", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.16.0.tgz", + "integrity": "sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==", "dev": true, "funding": [ { @@ -9219,7 +9542,9 @@ "license": "BSD-2-Clause" }, "node_modules/glob/node_modules/brace-expansion": { - "version": "1.1.12", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -9227,7 +9552,9 @@ } }, "node_modules/glob/node_modules/minimatch": { - "version": "3.1.2", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -9336,7 +9663,9 @@ } }, "node_modules/har-validator/node_modules/ajv": { - "version": "6.12.6", + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "dev": true, "license": "MIT", "dependencies": { @@ -9418,9 +9747,9 @@ } }, "node_modules/hono": { - "version": "4.12.15", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.15.tgz", - "integrity": "sha512-qM0jDhFEaCBb4TxoW7f53Qrpv9RBiayUHo0S52JudprkhvpjIrGoU1mnnr29Fvd1U335ZFPZQY1wlkqgfGXyLg==", + "version": "4.12.23", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.23.tgz", + "integrity": "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==", "dev": true, "license": "MIT", "engines": { @@ -9655,9 +9984,9 @@ } }, "node_modules/ignore-walk/node_modules/brace-expansion": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz", - "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "dev": true, "license": "MIT", "dependencies": { @@ -9688,7 +10017,9 @@ "license": "MIT" }, "node_modules/immutable": { - "version": "5.1.4", + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-5.1.6.tgz", + "integrity": "sha512-q1swsS8K7L8usSHuOqF2TAoCCkonYz0SG38wLAggaa4Wml70zixIvt2ql4coQ2C2B3hTjltJry4r6bULwgAXLQ==", "dev": true, "license": "MIT" }, @@ -9769,9 +10100,9 @@ "license": "MIT" }, "node_modules/ip-address": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", - "integrity": "sha512-XXADHxXmvT9+CRxhXg56LJovE+bmWnEWB78LB83VZTprKTmaC5QfruXocxzTZ2Kl0DNwKuBdlIhjL8LeY8Sf8Q==", + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.2.0.tgz", + "integrity": "sha512-/+S6j4E9AHvW9SWMSEY9Xfy66O5PWvVEJ08O0y5JGyEKQpojb0K0GKpz/v5HJ/G0vi3D2sjGK78119oXZeE0qA==", "dev": true, "license": "MIT", "engines": { @@ -10434,7 +10765,9 @@ } }, "node_modules/karma-coverage-istanbul-reporter/node_modules/brace-expansion": { - "version": "1.1.12", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -10443,7 +10776,9 @@ } }, "node_modules/karma-coverage-istanbul-reporter/node_modules/minimatch": { - "version": "3.1.2", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -10483,7 +10818,9 @@ "license": "MIT" }, "node_modules/karma/node_modules/brace-expansion": { - "version": "1.1.12", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", "dependencies": { @@ -10502,7 +10839,9 @@ } }, "node_modules/karma/node_modules/minimatch": { - "version": "3.1.2", + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", "dependencies": { @@ -11202,7 +11541,9 @@ } }, "node_modules/micromatch/node_modules/picomatch": { - "version": "2.3.1", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", "engines": { @@ -11263,11 +11604,13 @@ } }, "node_modules/minimatch": { - "version": "9.0.5", + "version": "9.0.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", + "integrity": "sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==", "dev": true, "license": "ISC", "dependencies": { - "brace-expansion": "^2.0.1" + "brace-expansion": "^2.0.2" }, "engines": { "node": ">=16 || 14 >=14.17" @@ -11796,2526 +12139,201 @@ }, "node_modules/normalize-range": { "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm": { - "version": "10.9.6", - "resolved": "https://registry.npmjs.org/npm/-/npm-10.9.6.tgz", - "integrity": "sha512-EHxr81fXY1K9yyLklI2gc9WuhMSh2e4PXuVG/VXJoHSrH4Lbrv01V/Nhkqu+mvm+58UMh59YBtvHU2wb4ikCUw==", - "bundleDependencies": [ - "@isaacs/string-locale-compare", - "@npmcli/arborist", - "@npmcli/config", - "@npmcli/fs", - "@npmcli/map-workspaces", - "@npmcli/package-json", - "@npmcli/promise-spawn", - "@npmcli/redact", - "@npmcli/run-script", - "@sigstore/tuf", - "abbrev", - "archy", - "cacache", - "chalk", - "ci-info", - "cli-columns", - "fastest-levenshtein", - "fs-minipass", - "glob", - "graceful-fs", - "hosted-git-info", - "ini", - "init-package-json", - "is-cidr", - "json-parse-even-better-errors", - "libnpmaccess", - "libnpmdiff", - "libnpmexec", - "libnpmfund", - "libnpmhook", - "libnpmorg", - "libnpmpack", - "libnpmpublish", - "libnpmsearch", - "libnpmteam", - "libnpmversion", - "make-fetch-happen", - "minimatch", - "minipass", - "minipass-pipeline", - "ms", - "node-gyp", - "nopt", - "normalize-package-data", - "npm-audit-report", - "npm-install-checks", - "npm-package-arg", - "npm-pick-manifest", - "npm-profile", - "npm-registry-fetch", - "npm-user-validate", - "p-map", - "pacote", - "parse-conflict-json", - "proc-log", - "qrcode-terminal", - "read", - "semver", - "spdx-expression-parse", - "ssri", - "supports-color", - "tar", - "text-table", - "tiny-relative-date", - "treeverse", - "validate-npm-package-name", - "which", - "write-file-atomic" - ], - "license": "Artistic-2.0", - "workspaces": [ - "docs", - "smoke-tests", - "mock-globals", - "mock-registry", - "workspaces/*" - ], - "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/arborist": "^8.0.3", - "@npmcli/config": "^9.0.0", - "@npmcli/fs": "^4.0.0", - "@npmcli/map-workspaces": "^4.0.2", - "@npmcli/package-json": "^6.2.0", - "@npmcli/promise-spawn": "^8.0.3", - "@npmcli/redact": "^3.2.2", - "@npmcli/run-script": "^9.1.0", - "@sigstore/tuf": "^3.1.1", - "abbrev": "^3.0.1", - "archy": "~1.0.0", - "cacache": "^19.0.1", - "chalk": "^5.6.2", - "ci-info": "^4.4.0", - "cli-columns": "^4.0.0", - "fastest-levenshtein": "^1.0.16", - "fs-minipass": "^3.0.3", - "glob": "^10.5.0", - "graceful-fs": "^4.2.11", - "hosted-git-info": "^8.1.0", - "ini": "^5.0.0", - "init-package-json": "^7.0.2", - "is-cidr": "^5.1.1", - "json-parse-even-better-errors": "^4.0.0", - "libnpmaccess": "^9.0.0", - "libnpmdiff": "^7.0.3", - "libnpmexec": "^9.0.3", - "libnpmfund": "^6.0.3", - "libnpmhook": "^11.0.0", - "libnpmorg": "^7.0.0", - "libnpmpack": "^8.0.3", - "libnpmpublish": "^10.0.2", - "libnpmsearch": "^8.0.0", - "libnpmteam": "^7.0.0", - "libnpmversion": "^7.0.0", - "make-fetch-happen": "^14.0.3", - "minimatch": "^9.0.9", - "minipass": "^7.1.3", - "minipass-pipeline": "^1.2.4", - "ms": "^2.1.2", - "node-gyp": "^11.5.0", - "nopt": "^8.1.0", - "normalize-package-data": "^7.0.1", - "npm-audit-report": "^6.0.0", - "npm-install-checks": "^7.1.2", - "npm-package-arg": "^12.0.2", - "npm-pick-manifest": "^10.0.0", - "npm-profile": "^11.0.1", - "npm-registry-fetch": "^18.0.2", - "npm-user-validate": "^3.0.0", - "p-map": "^7.0.4", - "pacote": "^19.0.1", - "parse-conflict-json": "^4.0.0", - "proc-log": "^5.0.0", - "qrcode-terminal": "^0.12.0", - "read": "^4.1.0", - "semver": "^7.7.4", - "spdx-expression-parse": "^4.0.0", - "ssri": "^12.0.0", - "supports-color": "^9.4.0", - "tar": "^7.5.11", - "text-table": "~0.2.0", - "tiny-relative-date": "^1.3.0", - "treeverse": "^3.0.0", - "validate-npm-package-name": "^6.0.2", - "which": "^5.0.0", - "write-file-atomic": "^6.0.0" - }, - "bin": { - "npm": "bin/npm-cli.js", - "npx": "bin/npx-cli.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm-bundled": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-5.0.0.tgz", - "integrity": "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-normalize-package-bin": "^5.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm-bundled/node_modules/npm-normalize-package-bin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", - "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm-install-checks": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-8.0.0.tgz", - "integrity": "sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==", - "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm-normalize-package-bin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", - "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm-package-arg": { - "version": "13.0.2", - "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.2.tgz", - "integrity": "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==", - "dev": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^9.0.0", - "proc-log": "^6.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^7.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm-packlist": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.4.tgz", - "integrity": "sha512-uMW73iajD8hiH4ZBxEV3HC+eTnppIqwakjOYuvgddnalIw2lJguKviK1pcUJDlIWm1wSJkchpDZDSVVsZEYRng==", - "dev": true, - "license": "ISC", - "dependencies": { - "ignore-walk": "^8.0.0", - "proc-log": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm-pick-manifest": { - "version": "11.0.3", - "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-11.0.3.tgz", - "integrity": "sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "npm-install-checks": "^8.0.0", - "npm-normalize-package-bin": "^5.0.0", - "npm-package-arg": "^13.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm-pick-manifest/node_modules/npm-normalize-package-bin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", - "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm-registry-fetch": { - "version": "19.1.1", - "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-19.1.1.tgz", - "integrity": "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==", - "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/redact": "^4.0.0", - "jsonparse": "^1.3.1", - "make-fetch-happen": "^15.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^5.0.0", - "minizlib": "^3.0.1", - "npm-package-arg": "^13.0.0", - "proc-log": "^6.0.0" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/npm-run-all2": { - "version": "7.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "cross-spawn": "^7.0.6", - "memorystream": "^0.3.1", - "minimatch": "^9.0.0", - "pidtree": "^0.6.0", - "read-package-json-fast": "^4.0.0", - "shell-quote": "^1.7.3", - "which": "^5.0.0" - }, - "bin": { - "npm-run-all": "bin/npm-run-all/index.js", - "npm-run-all2": "bin/npm-run-all/index.js", - "run-p": "bin/run-p/index.js", - "run-s": "bin/run-s/index.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0", - "npm": ">= 9" - } - }, - "node_modules/npm-run-all2/node_modules/ansi-styles": { - "version": "6.2.3", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/npm-run-all2/node_modules/isexe": { - "version": "3.1.5", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/npm-run-all2/node_modules/which": { - "version": "5.0.0", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui": { - "version": "8.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.2.2", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.2.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/npm/node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/npm/node_modules/@isaacs/string-locale-compare": { - "version": "1.1.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/@npmcli/agent": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^10.0.1", - "socks-proxy-agent": "^8.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/arborist": { - "version": "8.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@isaacs/string-locale-compare": "^1.1.0", - "@npmcli/fs": "^4.0.0", - "@npmcli/installed-package-contents": "^3.0.0", - "@npmcli/map-workspaces": "^4.0.1", - "@npmcli/metavuln-calculator": "^8.0.0", - "@npmcli/name-from-folder": "^3.0.0", - "@npmcli/node-gyp": "^4.0.0", - "@npmcli/package-json": "^6.0.1", - "@npmcli/query": "^4.0.0", - "@npmcli/redact": "^3.0.0", - "@npmcli/run-script": "^9.0.1", - "bin-links": "^5.0.0", - "cacache": "^19.0.1", - "common-ancestor-path": "^1.0.1", - "hosted-git-info": "^8.0.0", - "json-parse-even-better-errors": "^4.0.0", - "json-stringify-nice": "^1.1.4", - "lru-cache": "^10.2.2", - "minimatch": "^9.0.4", - "nopt": "^8.0.0", - "npm-install-checks": "^7.1.0", - "npm-package-arg": "^12.0.0", - "npm-pick-manifest": "^10.0.0", - "npm-registry-fetch": "^18.0.1", - "pacote": "^19.0.0", - "parse-conflict-json": "^4.0.0", - "proc-log": "^5.0.0", - "proggy": "^3.0.0", - "promise-all-reject-late": "^1.0.0", - "promise-call-limit": "^3.0.1", - "promise-retry": "^2.0.1", - "read-package-json-fast": "^4.0.0", - "semver": "^7.3.7", - "ssri": "^12.0.0", - "treeverse": "^3.0.0", - "walk-up-path": "^3.0.1" - }, - "bin": { - "arborist": "bin/index.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/config": { - "version": "9.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/map-workspaces": "^4.0.1", - "@npmcli/package-json": "^6.0.1", - "ci-info": "^4.0.0", - "ini": "^5.0.0", - "nopt": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "walk-up-path": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/fs": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "semver": "^7.3.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/git": { - "version": "6.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/promise-spawn": "^8.0.0", - "ini": "^5.0.0", - "lru-cache": "^10.0.1", - "npm-pick-manifest": "^10.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "semver": "^7.3.5", - "which": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/installed-package-contents": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-bundled": "^4.0.0", - "npm-normalize-package-bin": "^4.0.0" - }, - "bin": { - "installed-package-contents": "bin/index.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/map-workspaces": { - "version": "4.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/name-from-folder": "^3.0.0", - "@npmcli/package-json": "^6.0.0", - "glob": "^10.2.2", - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/metavuln-calculator": { - "version": "8.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "cacache": "^19.0.0", - "json-parse-even-better-errors": "^4.0.0", - "pacote": "^20.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/metavuln-calculator/node_modules/pacote": { - "version": "20.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^6.0.0", - "@npmcli/installed-package-contents": "^3.0.0", - "@npmcli/package-json": "^6.0.0", - "@npmcli/promise-spawn": "^8.0.0", - "@npmcli/run-script": "^9.0.0", - "cacache": "^19.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^7.0.2", - "npm-package-arg": "^12.0.0", - "npm-packlist": "^9.0.0", - "npm-pick-manifest": "^10.0.0", - "npm-registry-fetch": "^18.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "sigstore": "^3.0.0", - "ssri": "^12.0.0", - "tar": "^7.5.10" - }, - "bin": { - "pacote": "bin/index.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/name-from-folder": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/node-gyp": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/package-json": { - "version": "6.2.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^6.0.0", - "glob": "^10.2.2", - "hosted-git-info": "^8.0.0", - "json-parse-even-better-errors": "^4.0.0", - "proc-log": "^5.0.0", - "semver": "^7.5.3", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/promise-spawn": { - "version": "8.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "which": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/query": { - "version": "4.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "postcss-selector-parser": "^7.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/redact": { - "version": "3.2.2", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@npmcli/run-script": { - "version": "9.1.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/node-gyp": "^4.0.0", - "@npmcli/package-json": "^6.0.0", - "@npmcli/promise-spawn": "^8.0.0", - "node-gyp": "^11.0.0", - "proc-log": "^5.0.0", - "which": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "inBundle": true, - "license": "MIT", - "optional": true, - "engines": { - "node": ">=14" - } - }, - "node_modules/npm/node_modules/@sigstore/protobuf-specs": { - "version": "0.4.3", - "inBundle": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@sigstore/tuf": { - "version": "3.1.1", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.4.1", - "tuf-js": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/@tufjs/canonical-json": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "^16.14.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/abbrev": { - "version": "3.0.1", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/agent-base": { - "version": "7.1.4", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/ansi-regex": { - "version": "5.0.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/ansi-styles": { - "version": "6.2.3", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/npm/node_modules/aproba": { - "version": "2.1.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/archy": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/balanced-match": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/bin-links": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "cmd-shim": "^7.0.0", - "npm-normalize-package-bin": "^4.0.0", - "proc-log": "^5.0.0", - "read-cmd-shim": "^5.0.0", - "write-file-atomic": "^6.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/binary-extensions": { - "version": "2.3.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/brace-expansion": { - "version": "2.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/npm/node_modules/cacache": { - "version": "19.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/fs": "^4.0.0", - "fs-minipass": "^3.0.0", - "glob": "^10.2.2", - "lru-cache": "^10.0.1", - "minipass": "^7.0.3", - "minipass-collect": "^2.0.1", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "p-map": "^7.0.2", - "ssri": "^12.0.0", - "tar": "^7.4.3", - "unique-filename": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/chalk": { - "version": "5.6.2", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/npm/node_modules/chownr": { - "version": "3.0.0", - "inBundle": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/ci-info": { - "version": "4.4.0", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/sibiraj-s" - } - ], - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/cidr-regex": { - "version": "4.1.3", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "ip-regex": "^5.0.0" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/npm/node_modules/cli-columns": { - "version": "4.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">= 10" - } - }, - "node_modules/npm/node_modules/cmd-shim": { - "version": "7.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/color-convert": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/npm/node_modules/color-name": { - "version": "1.1.4", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/common-ancestor-path": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/cross-spawn": { - "version": "7.0.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/cross-spawn/node_modules/which": { - "version": "2.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/cssesc": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/debug": { - "version": "4.4.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/npm/node_modules/diff": { - "version": "5.2.2", - "inBundle": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "node_modules/npm/node_modules/eastasianwidth": { - "version": "0.2.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/emoji-regex": { - "version": "8.0.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/encoding": { - "version": "0.1.13", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "iconv-lite": "^0.6.2" - } - }, - "node_modules/npm/node_modules/env-paths": { - "version": "2.2.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/npm/node_modules/err-code": { - "version": "2.0.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/exponential-backoff": { - "version": "3.1.3", - "inBundle": true, - "license": "Apache-2.0" - }, - "node_modules/npm/node_modules/fastest-levenshtein": { - "version": "1.0.16", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 4.9.1" - } - }, - "node_modules/npm/node_modules/fdir": { - "version": "6.5.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/npm/node_modules/foreground-child": { - "version": "3.3.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/fs-minipass": { - "version": "3.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/glob": { - "version": "10.5.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^3.1.2", - "minimatch": "^9.0.4", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^1.11.1" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/graceful-fs": { - "version": "4.2.11", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/hosted-git-info": { - "version": "8.1.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "lru-cache": "^10.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/http-cache-semantics": { - "version": "4.2.0", - "inBundle": true, - "license": "BSD-2-Clause" - }, - "node_modules/npm/node_modules/http-proxy-agent": { - "version": "7.0.2", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.0", - "debug": "^4.3.4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/https-proxy-agent": { - "version": "7.0.6", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/iconv-lite": { - "version": "0.6.3", - "inBundle": true, - "license": "MIT", - "optional": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/npm/node_modules/ignore-walk": { - "version": "7.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minimatch": "^9.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/imurmurhash": { - "version": "0.1.4", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=0.8.19" - } - }, - "node_modules/npm/node_modules/ini": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/init-package-json": { - "version": "7.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/package-json": "^6.0.0", - "npm-package-arg": "^12.0.0", - "promzard": "^2.0.0", - "read": "^4.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4", - "validate-npm-package-name": "^6.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/ip-address": { - "version": "10.1.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, - "node_modules/npm/node_modules/ip-regex": { - "version": "5.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/is-cidr": { - "version": "5.1.1", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "cidr-regex": "^4.1.1" - }, - "engines": { - "node": ">=14" - } - }, - "node_modules/npm/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/isexe": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/jackspeak": { - "version": "3.4.3", - "inBundle": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, - "node_modules/npm/node_modules/json-parse-even-better-errors": { - "version": "4.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/json-stringify-nice": { - "version": "1.1.4", - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/jsonparse": { - "version": "1.3.1", - "engines": [ - "node >= 0.2.0" - ], - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/just-diff": { - "version": "6.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/just-diff-apply": { - "version": "5.5.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/libnpmaccess": { - "version": "9.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-package-arg": "^12.0.0", - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmdiff": { - "version": "7.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^8.0.3", - "@npmcli/installed-package-contents": "^3.0.0", - "binary-extensions": "^2.3.0", - "diff": "^5.1.0", - "minimatch": "^9.0.4", - "npm-package-arg": "^12.0.0", - "pacote": "^19.0.0", - "tar": "^7.5.11" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmexec": { - "version": "9.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^8.0.3", - "@npmcli/run-script": "^9.0.1", - "ci-info": "^4.0.0", - "npm-package-arg": "^12.0.0", - "pacote": "^19.0.0", - "proc-log": "^5.0.0", - "read": "^4.0.0", - "read-package-json-fast": "^4.0.0", - "semver": "^7.3.7", - "walk-up-path": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmfund": { - "version": "6.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^8.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmhook": { - "version": "11.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmorg": { - "version": "7.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmpack": { - "version": "8.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/arborist": "^8.0.3", - "@npmcli/run-script": "^9.0.1", - "npm-package-arg": "^12.0.0", - "pacote": "^19.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmpublish": { - "version": "10.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "ci-info": "^4.0.0", - "normalize-package-data": "^7.0.0", - "npm-package-arg": "^12.0.0", - "npm-registry-fetch": "^18.0.1", - "proc-log": "^5.0.0", - "semver": "^7.3.7", - "sigstore": "^3.0.0", - "ssri": "^12.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmsearch": { - "version": "8.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmteam": { - "version": "7.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "aproba": "^2.0.0", - "npm-registry-fetch": "^18.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/libnpmversion": { - "version": "7.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^6.0.1", - "@npmcli/run-script": "^9.0.1", - "json-parse-even-better-errors": "^4.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.7" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/lru-cache": { - "version": "10.4.3", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/make-fetch-happen": { - "version": "14.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/agent": "^3.0.0", - "cacache": "^19.0.1", - "http-cache-semantics": "^4.1.1", - "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", - "minipass-flush": "^1.0.5", - "minipass-pipeline": "^1.2.4", - "negotiator": "^1.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "ssri": "^12.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/minimatch": { - "version": "9.0.9", - "inBundle": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.2" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/minipass": { - "version": "7.1.3", - "inBundle": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/npm/node_modules/minipass-collect": { - "version": "2.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/npm/node_modules/minipass-fetch": { - "version": "4.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.0.3", - "minipass-sized": "^1.0.3", - "minizlib": "^3.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - }, - "optionalDependencies": { - "encoding": "^0.1.13" - } - }, - "node_modules/npm/node_modules/minipass-flush": { - "version": "1.0.5", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/npm/node_modules/minipass-flush/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-flush/node_modules/yallist": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/minipass-pipeline": { - "version": "1.2.4", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-pipeline/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-pipeline/node_modules/yallist": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/minipass-sized": { - "version": "1.0.3", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-sized/node_modules/minipass": { - "version": "3.3.6", - "inBundle": true, - "license": "ISC", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/minipass-sized/node_modules/yallist": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/minizlib": { - "version": "3.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "minipass": "^7.1.2" - }, - "engines": { - "node": ">= 18" - } - }, - "node_modules/npm/node_modules/ms": { - "version": "2.1.3", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/mute-stream": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/negotiator": { - "version": "1.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/npm/node_modules/node-gyp": { - "version": "11.5.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "env-paths": "^2.2.0", - "exponential-backoff": "^3.1.1", - "graceful-fs": "^4.2.6", - "make-fetch-happen": "^14.0.3", - "nopt": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "tar": "^7.4.3", - "tinyglobby": "^0.2.12", - "which": "^5.0.0" - }, - "bin": { - "node-gyp": "bin/node-gyp.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/nopt": { - "version": "8.1.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "abbrev": "^3.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/normalize-package-data": { - "version": "7.0.1", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^8.0.0", - "semver": "^7.3.5", - "validate-npm-package-license": "^3.0.4" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-audit-report": { - "version": "6.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-bundled": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-normalize-package-bin": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-install-checks": { - "version": "7.1.2", - "inBundle": true, - "license": "BSD-2-Clause", - "dependencies": { - "semver": "^7.1.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-normalize-package-bin": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-package-arg": { - "version": "12.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "hosted-git-info": "^8.0.0", - "proc-log": "^5.0.0", - "semver": "^7.3.5", - "validate-npm-package-name": "^6.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-packlist": { - "version": "9.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "ignore-walk": "^7.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-pick-manifest": { - "version": "10.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-install-checks": "^7.1.0", - "npm-normalize-package-bin": "^4.0.0", - "npm-package-arg": "^12.0.0", - "semver": "^7.3.5" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-profile": { - "version": "11.0.1", - "inBundle": true, - "license": "ISC", - "dependencies": { - "npm-registry-fetch": "^18.0.0", - "proc-log": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-registry-fetch": { - "version": "18.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/redact": "^3.0.0", - "jsonparse": "^1.3.1", - "make-fetch-happen": "^14.0.0", - "minipass": "^7.0.2", - "minipass-fetch": "^4.0.0", - "minizlib": "^3.0.1", - "npm-package-arg": "^12.0.0", - "proc-log": "^5.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/npm-user-validate": { - "version": "3.0.0", - "inBundle": true, - "license": "BSD-2-Clause", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/p-map": { - "version": "7.0.4", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/npm/node_modules/package-json-from-dist": { - "version": "1.0.1", - "inBundle": true, - "license": "BlueOak-1.0.0" - }, - "node_modules/npm/node_modules/pacote": { - "version": "19.0.2", - "inBundle": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^6.0.0", - "@npmcli/installed-package-contents": "^3.0.0", - "@npmcli/package-json": "^6.0.0", - "@npmcli/promise-spawn": "^8.0.0", - "@npmcli/run-script": "^9.0.0", - "cacache": "^19.0.0", - "fs-minipass": "^3.0.0", - "minipass": "^7.0.2", - "npm-package-arg": "^12.0.0", - "npm-packlist": "^9.0.0", - "npm-pick-manifest": "^10.0.0", - "npm-registry-fetch": "^18.0.0", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1", - "sigstore": "^3.0.0", - "ssri": "^12.0.0", - "tar": "^7.5.10" - }, - "bin": { - "pacote": "bin/index.js" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/parse-conflict-json": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^4.0.0", - "just-diff": "^6.0.0", - "just-diff-apply": "^5.2.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/path-key": { - "version": "3.1.1", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/path-scurry": { - "version": "1.11.1", - "inBundle": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^10.2.0", - "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" - }, - "engines": { - "node": ">=16 || 14 >=14.18" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/picomatch": { - "version": "4.0.3", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/npm/node_modules/postcss-selector-parser": { - "version": "7.1.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/npm/node_modules/proc-log": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/proggy": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/promise-all-reject-late": { - "version": "1.0.1", - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/promise-call-limit": { - "version": "3.0.2", - "inBundle": true, - "license": "ISC", - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/promise-retry": { - "version": "2.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/promzard": { - "version": "2.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "read": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/qrcode-terminal": { - "version": "0.12.0", - "inBundle": true, - "bin": { - "qrcode-terminal": "bin/qrcode-terminal.js" - } - }, - "node_modules/npm/node_modules/read": { - "version": "4.1.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "mute-stream": "^2.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/read-cmd-shim": { - "version": "5.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/read-package-json-fast": { - "version": "4.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "json-parse-even-better-errors": "^4.0.0", - "npm-normalize-package-bin": "^4.0.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/retry": { - "version": "0.12.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/npm/node_modules/safer-buffer": { - "version": "2.1.2", - "inBundle": true, - "license": "MIT", - "optional": true - }, - "node_modules/npm/node_modules/semver": { - "version": "7.7.4", - "inBundle": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/npm/node_modules/shebang-command": { - "version": "2.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/shebang-regex": { - "version": "3.0.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/signal-exit": { - "version": "4.1.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/npm/node_modules/sigstore": { - "version": "3.1.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^3.1.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.4.0", - "@sigstore/sign": "^3.1.0", - "@sigstore/tuf": "^3.1.0", - "@sigstore/verify": "^2.1.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/sigstore/node_modules/@sigstore/bundle": { - "version": "3.1.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/protobuf-specs": "^0.4.0" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/sigstore/node_modules/@sigstore/core": { - "version": "2.0.0", - "inBundle": true, - "license": "Apache-2.0", - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/sigstore/node_modules/@sigstore/sign": { - "version": "3.1.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^3.1.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.4.0", - "make-fetch-happen": "^14.0.2", - "proc-log": "^5.0.0", - "promise-retry": "^2.0.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/sigstore/node_modules/@sigstore/verify": { - "version": "2.1.1", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "@sigstore/bundle": "^3.1.0", - "@sigstore/core": "^2.0.0", - "@sigstore/protobuf-specs": "^0.4.1" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/smart-buffer": { - "version": "4.2.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">= 6.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/npm/node_modules/socks": { - "version": "2.8.7", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ip-address": "^10.0.1", - "smart-buffer": "^4.2.0" - }, - "engines": { - "node": ">= 10.0.0", - "npm": ">= 3.0.0" - } - }, - "node_modules/npm/node_modules/socks-proxy-agent": { - "version": "8.0.5", - "inBundle": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "^4.3.4", - "socks": "^2.8.3" - }, - "engines": { - "node": ">= 14" - } - }, - "node_modules/npm/node_modules/spdx-correct": { - "version": "3.2.0", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-correct/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-exceptions": { - "version": "2.5.0", - "inBundle": true, - "license": "CC-BY-3.0" - }, - "node_modules/npm/node_modules/spdx-expression-parse": { - "version": "4.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/npm/node_modules/spdx-license-ids": { - "version": "3.0.23", - "inBundle": true, - "license": "CC0-1.0" - }, - "node_modules/npm/node_modules/ssri": { - "version": "12.0.0", - "inBundle": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/string-width": { - "version": "4.2.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "inBundle": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/strip-ansi": { - "version": "6.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm/node_modules/supports-color": { - "version": "9.4.0", - "inBundle": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" - } - }, - "node_modules/npm/node_modules/tar": { - "version": "7.5.11", - "inBundle": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/npm/node_modules/text-table": { - "version": "0.2.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/tiny-relative-date": { - "version": "1.3.0", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/tinyglobby": { - "version": "0.2.15", - "inBundle": true, - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">=12.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/npm/node_modules/treeverse": { - "version": "3.0.0", - "inBundle": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, - "node_modules/npm/node_modules/tuf-js": { - "version": "3.1.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "@tufjs/models": "3.0.1", - "debug": "^4.4.1", - "make-fetch-happen": "^14.0.3" - }, - "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/tuf-js/node_modules/@tufjs/models": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", - "dependencies": { - "@tufjs/canonical-json": "2.0.0", - "minimatch": "^9.0.5" - }, + "dev": true, + "license": "MIT", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": ">=0.10.0" } }, - "node_modules/npm/node_modules/unique-filename": { - "version": "4.0.0", - "inBundle": true, + "node_modules/npm-bundled": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-5.0.0.tgz", + "integrity": "sha512-JLSpbzh6UUXIEoqPsYBvVNVmyrjVZ1fzEFbqxKkTJQkWBO3xFzFT+KDnSKQWwOQNbuWRwt5LSD6HOTLGIWzfrw==", + "dev": true, "license": "ISC", "dependencies": { - "unique-slug": "^5.0.0" + "npm-normalize-package-bin": "^5.0.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/unique-slug": { + "node_modules/npm-bundled/node_modules/npm-normalize-package-bin": { "version": "5.0.0", - "inBundle": true, + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", + "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", + "dev": true, "license": "ISC", - "dependencies": { - "imurmurhash": "^0.1.4" - }, "engines": { - "node": "^18.17.0 || >=20.5.0" - } - }, - "node_modules/npm/node_modules/util-deprecate": { - "version": "1.0.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/validate-npm-package-license": { - "version": "3.0.4", - "inBundle": true, - "license": "Apache-2.0", - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { - "version": "3.0.1", - "inBundle": true, - "license": "MIT", + "node_modules/npm-install-checks": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-8.0.0.tgz", + "integrity": "sha512-ScAUdMpyzkbpxoNekQ3tNRdFI8SJ86wgKZSQZdUxT+bj0wVFpsEMWnkXP0twVe1gJyNF5apBWDJhhIbgrIViRA==", + "dev": true, + "license": "BSD-2-Clause", "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "semver": "^7.1.1" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/validate-npm-package-name": { - "version": "6.0.2", - "inBundle": true, + "node_modules/npm-normalize-package-bin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", + "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", + "dev": true, "license": "ISC", "engines": { "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/npm/node_modules/walk-up-path": { - "version": "3.0.1", - "inBundle": true, - "license": "ISC" - }, - "node_modules/npm/node_modules/which": { - "version": "5.0.0", - "inBundle": true, + "node_modules/npm-package-arg": { + "version": "13.0.2", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-13.0.2.tgz", + "integrity": "sha512-IciCE3SY3uE84Ld8WZU23gAPPV9rIYod4F+rc+vJ7h7cwAJt9Vk6TVsK60ry7Uj3SRS3bqRRIGuTp9YVlk6WNA==", + "dev": true, "license": "ISC", "dependencies": { - "isexe": "^3.1.1" - }, - "bin": { - "node-which": "bin/which.js" + "hosted-git-info": "^9.0.0", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^7.0.0" }, "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/which/node_modules/isexe": { - "version": "3.1.5", - "inBundle": true, - "license": "BlueOak-1.0.0", + "node_modules/npm-packlist": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-10.0.4.tgz", + "integrity": "sha512-uMW73iajD8hiH4ZBxEV3HC+eTnppIqwakjOYuvgddnalIw2lJguKviK1pcUJDlIWm1wSJkchpDZDSVVsZEYRng==", + "dev": true, + "license": "ISC", + "dependencies": { + "ignore-walk": "^8.0.0", + "proc-log": "^6.0.0" + }, "engines": { - "node": ">=18" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/wrap-ansi": { - "version": "8.1.0", - "inBundle": true, - "license": "MIT", + "node_modules/npm-pick-manifest": { + "version": "11.0.3", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-11.0.3.tgz", + "integrity": "sha512-buzyCfeoGY/PxKqmBqn1IUJrZnUi1VVJTdSSRPGI60tJdUhUoSQFhs0zycJokDdOznQentgrpf8LayEHyyYlqQ==", + "dev": true, + "license": "ISC", "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" + "npm-install-checks": "^8.0.0", + "npm-normalize-package-bin": "^5.0.0", + "npm-package-arg": "^13.0.0", + "semver": "^7.3.5" }, "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, + "node_modules/npm-pick-manifest/node_modules/npm-normalize-package-bin": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", + "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", + "dev": true, + "license": "ISC", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { - "version": "4.3.0", - "inBundle": true, - "license": "MIT", + "node_modules/npm-registry-fetch": { + "version": "19.1.1", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-19.1.1.tgz", + "integrity": "sha512-TakBap6OM1w0H73VZVDf44iFXsOS3h+L4wVMXmbWOQroZgFhMch0juN6XSzBNlD965yIKvWg2dfu7NSiaYLxtw==", + "dev": true, + "license": "ISC", "dependencies": { - "color-convert": "^2.0.1" + "@npmcli/redact": "^4.0.0", + "jsonparse": "^1.3.1", + "make-fetch-happen": "^15.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^5.0.0", + "minizlib": "^3.0.1", + "npm-package-arg": "^13.0.0", + "proc-log": "^6.0.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/ansi-regex": { - "version": "6.2.2", - "inBundle": true, + "node_modules/npm-run-all2": { + "version": "7.0.2", + "dev": true, "license": "MIT", - "engines": { - "node": ">=12" + "dependencies": { + "ansi-styles": "^6.2.1", + "cross-spawn": "^7.0.6", + "memorystream": "^0.3.1", + "minimatch": "^9.0.0", + "pidtree": "^0.6.0", + "read-package-json-fast": "^4.0.0", + "shell-quote": "^1.7.3", + "which": "^5.0.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "bin": { + "npm-run-all": "bin/npm-run-all/index.js", + "npm-run-all2": "bin/npm-run-all/index.js", + "run-p": "bin/run-p/index.js", + "run-s": "bin/run-s/index.js" + }, + "engines": { + "node": "^18.17.0 || >=20.5.0", + "npm": ">= 9" } }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/emoji-regex": { - "version": "9.2.2", - "inBundle": true, - "license": "MIT" - }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/string-width": { - "version": "5.1.2", - "inBundle": true, + "node_modules/npm-run-all2/node_modules/ansi-styles": { + "version": "6.2.3", + "dev": true, "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/npm/node_modules/wrap-ansi/node_modules/strip-ansi": { - "version": "7.2.0", - "inBundle": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, + "node_modules/npm-run-all2/node_modules/isexe": { + "version": "3.1.5", + "dev": true, + "license": "BlueOak-1.0.0", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "node": ">=18" } }, - "node_modules/npm/node_modules/write-file-atomic": { - "version": "6.0.0", - "inBundle": true, + "node_modules/npm-run-all2/node_modules/which": { + "version": "5.0.0", + "dev": true, "license": "ISC", "dependencies": { - "imurmurhash": "^0.1.4", - "signal-exit": "^4.0.1" + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" }, "engines": { "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/npm/node_modules/yallist": { - "version": "5.0.0", - "inBundle": true, - "license": "BlueOak-1.0.0", + "node_modules/npm-run-path": { + "version": "4.0.1", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, "engines": { - "node": ">=18" + "node": ">=8" } }, "node_modules/nth-check": { @@ -15280,20 +13298,6 @@ "url": "https://github.com/sponsors/antonk52" } }, - "node_modules/postcss-load-config/node_modules/yaml": { - "version": "2.8.2", - "dev": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/postcss-media-query-parser": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", @@ -15798,11 +13802,14 @@ } }, "node_modules/proxy-from-env": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", - "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-2.1.0.tgz", + "integrity": "sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==", "dev": true, - "license": "MIT" + "license": "MIT", + "engines": { + "node": ">=10" + } }, "node_modules/psl": { "version": "1.15.0", @@ -15949,7 +13956,9 @@ } }, "node_modules/qs": { - "version": "6.14.2", + "version": "6.15.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.2.tgz", + "integrity": "sha512-Rzq0KEyX/w/tEybncDgdkZrJgVUsUMk3xjh3t5bv3S1HTAtg+uOYt72+ZfwiQwKdysThkTBdL/rTi6HDmX9Ddw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -16120,7 +14129,9 @@ } }, "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.1", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "devOptional": true, "license": "MIT", "engines": { @@ -16168,7 +14179,9 @@ } }, "node_modules/request/node_modules/qs": { - "version": "6.5.3", + "version": "6.5.5", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.5.tgz", + "integrity": "sha512-mzR4sElr1bfCaPJe7m8ilJ6ZXdDaGoObcYR0ZHSsktM/Lt21MVHj5De30GQH2eiZ1qGRTO7LCAzQsUeXTNexWQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -16975,16 +14988,20 @@ } }, "node_modules/socket.io-adapter": { - "version": "2.5.6", + "version": "2.5.7", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.7.tgz", + "integrity": "sha512-e0LyK91f3cUxTmv95/KzoLg47+zF+s/sbxRGDNsyG4dmIP8ZSX8ax6byOxfJXeNNtS/8AZlfD+uP7gBeR7DLlg==", "dev": true, "license": "MIT", "dependencies": { "debug": "~4.4.1", - "ws": "~8.18.3" + "ws": "~8.20.1" } }, "node_modules/socket.io-parser": { - "version": "4.2.5", + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.6.tgz", + "integrity": "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==", "dev": true, "license": "MIT", "dependencies": { @@ -17025,16 +15042,6 @@ "node": ">= 14" } }, - "node_modules/socks/node_modules/ip-address": { - "version": "10.1.1", - "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.1.tgz", - "integrity": "sha512-1FMu8/N15Ck1BL551Jf42NYIoin2unWjLQ2Fze/DXryJRl5twqtwNHlO39qERGbIOcKYWHdgRryhOC+NG4eaLw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12" - } - }, "node_modules/source-map": { "version": "0.7.4", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", @@ -17507,7 +15514,9 @@ } }, "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.3", + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", "engines": { "node": ">=12" @@ -17517,7 +15526,9 @@ } }, "node_modules/tmp": { - "version": "0.2.3", + "version": "0.2.7", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", + "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", "dev": true, "license": "MIT", "engines": { @@ -17937,9 +15948,9 @@ } }, "node_modules/typescript-eslint/node_modules/brace-expansion": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.4.tgz", - "integrity": "sha512-h+DEnpVvxmfVefa4jFbCf5HdH5YMDXRsmKflpf1pILZWRFlTbJpxeU55nJl4Smt5HQaGzg1o6RHFPJaOqnmBDg==", + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -18022,7 +16033,9 @@ } }, "node_modules/underscore": { - "version": "1.13.7", + "version": "1.13.8", + "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.13.8.tgz", + "integrity": "sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ==", "dev": true, "license": "MIT" }, @@ -18455,7 +16468,9 @@ "license": "ISC" }, "node_modules/ws": { - "version": "8.18.3", + "version": "8.20.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz", + "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", "dev": true, "license": "MIT", "engines": { @@ -18509,6 +16524,22 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "dev": true, + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yargs": { "version": "17.7.2", "dev": true, diff --git a/package.json b/package.json index a382363bcd..5abce61683 100644 --- a/package.json +++ b/package.json @@ -73,7 +73,6 @@ "ngx-lottie": "^11.0.2", "ngx-monaco-editor-v2": "^21", "ngx-skeleton-loader": "^12.0.0", - "npm": "^10.4.0", "nvd3": "1.8.6", "qrcode": "^1.5.4", "rxjs": "~7.8.2", From b46d6070744d98b04c71c43203ec6cee6c0ae228 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 5 Jun 2026 08:52:00 +1000 Subject: [PATCH 1076/1280] refactor: migrate about modal to tailwind --- .../about-doubtfire-modal-content.tpl.html | 62 ++++++--- .../about-doubtfire-modal.scss | 119 ------------------ 2 files changed, 42 insertions(+), 139 deletions(-) diff --git a/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal-content.tpl.html b/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal-content.tpl.html index 08c5fd09bf..8b6732c0ea 100644 --- a/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal-content.tpl.html +++ b/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal-content.tpl.html @@ -1,32 +1,51 @@ -
    - +
    + - + - + - + - + - + - + - + - +
    Name @if (!editing(activityType)) { -
    - {{ activityType.name }} -
    +
    + {{ activityType.name }} +
    } @else { @@ -32,9 +38,9 @@

    Activities

    Abbreviation @if (!editing(activityType)) { -
    - {{ activityType.abbreviation }} -
    +
    + {{ activityType.abbreviation }} +
    } @else { @@ -53,21 +59,34 @@

    Activities

    @if (!editing(activityType)) { -
    - -
    +
    + +
    } @else {
    - - diff --git a/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.ts b/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.ts index 57b765b93c..773f811760 100644 --- a/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.ts +++ b/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.ts @@ -1,19 +1,22 @@ -import {Component, ViewChild} from '@angular/core'; -import {MatTableDataSource, MatTable} from '@angular/material/table'; import {ActivityType, ActivityTypeService} from 'src/app/api/models/doubtfire-model'; import {EntityFormComponent} from 'src/app/common/entity-form/entity-form.component'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {AfterViewInit, Component, ViewChild} from '@angular/core'; import {UntypedFormControl, Validators} from '@angular/forms'; import {MatSort, Sort} from '@angular/material/sort'; -import {AlertService} from 'src/app/common/services/alert.service'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; @Component({ - selector: 'activity-type-list', - templateUrl: 'activity-type-list.component.html', - styleUrls: ['activity-type-list.component.scss'], - standalone: false + selector: 'activity-type-list', + templateUrl: 'activity-type-list.component.html', + styleUrls: ['activity-type-list.component.scss'], + standalone: false, }) -export class ActivityTypeListComponent extends EntityFormComponent { - @ViewChild(MatTable, {static: true}) table: MatTable; +export class ActivityTypeListComponent + extends EntityFormComponent + implements AfterViewInit +{ + @ViewChild(MatTable, {static: true}) table: MatTable; @ViewChild(MatSort, {static: true}) sort: MatSort; // Set up the table @@ -55,7 +58,11 @@ export class ActivityTypeListComponent extends EntityFormComponent // to the datasource private pushToTable(value: ActivityType | ActivityType[]) { if (!value) return; - value instanceof Array ? this.activityTypes.push(...value) : this.activityTypes.push(value); + if (value instanceof Array) { + this.activityTypes.push(...value); + } else { + this.activityTypes.push(value); + } this.dataSource.sort = this.sort; this.table.renderRows(); } diff --git a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html index 1307b8f8f1..5045f1adcf 100644 --- a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html +++ b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html @@ -5,7 +5,14 @@

    Campuses

    Add new campuses or modify existing ones

    - +
    @@ -61,9 +68,9 @@

    Campuses

    Default Sync Mode @for (mode of syncModes; track mode) { - - {{ mode | titlecase }} - + + {{ mode | titlecase }} + } @@ -74,9 +81,9 @@

    Campuses

    Default Sync Mode @for (mode of syncModes; track mode) { - - {{ mode | titlecase }} - + + {{ mode | titlecase }} + } @@ -129,26 +136,36 @@

    Campuses

    @@ -80,9 +84,11 @@

    @@ -91,39 +97,41 @@

    @@ -132,22 +140,23 @@

    diff --git a/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts b/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts index aecdea2434..4cafb185e5 100644 --- a/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts +++ b/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts @@ -1,10 +1,16 @@ -import { Component, Inject, Injectable, OnInit, ViewChild } from '@angular/core'; -import { MAT_DIALOG_DATA, MatDialogRef, MatDialog } from '@angular/material/dialog'; -import { FormControl } from '@angular/forms'; -import { Unit, TeachingPeriod, User, UserService, UnitService } from 'src/app/api/models/doubtfire-model'; -import { MatTable, MatTableDataSource } from '@angular/material/table'; -import { GlobalStateService } from 'src/app/projects/states/index/global-state.service'; -import { Observable, map, startWith } from 'rxjs'; +import {Observable, map, startWith} from 'rxjs'; +import { + TeachingPeriod, + Unit, + UnitService, + User, + UserService, +} from 'src/app/api/models/doubtfire-model'; +import {GlobalStateService} from 'src/app/projects/states/index/global-state.service'; +import {Component, Inject, Injectable, OnInit, ViewChild} from '@angular/core'; +import {FormControl} from '@angular/forms'; +import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; export interface TeachingPeriodUnitImportData { teachingPeriod: TeachingPeriod; @@ -15,7 +21,7 @@ interface UnitImportData { unitName?: string; sourceUnit: Unit; convenor: User; - relatedUnits?: { value: Unit; text: string }[]; + relatedUnits?: {value: Unit; text: string}[]; done?: boolean; convenorFormControl: FormControl; filteredStaff: Observable; @@ -27,7 +33,7 @@ export class TeachingPeriodUnitImportService { openImportUnitsDialog(teachingPeriod: TeachingPeriod): void { const dialogRef = this.dialog.open(TeachingPeriodUnitImportDialogComponent, { - data: { teachingPeriod: teachingPeriod }, + data: {teachingPeriod: teachingPeriod}, }); dialogRef.afterClosed().subscribe(() => { @@ -41,13 +47,13 @@ export class TeachingPeriodUnitImportService { * This dialog allows the user to enter a number of units to be rolled over into the a teaching period. */ @Component({ - selector: 'f-teaching-period-unit-import', - templateUrl: 'teaching-period-unit-import.dialog.html', - styleUrls: ['teaching-period-unit-import.dialog.scss'], - standalone: false + selector: 'f-teaching-period-unit-import', + templateUrl: 'teaching-period-unit-import.dialog.html', + styleUrls: ['teaching-period-unit-import.dialog.scss'], + standalone: false, }) export class TeachingPeriodUnitImportDialogComponent implements OnInit { - @ViewChild(MatTable, { static: true }) table: MatTable; + @ViewChild(MatTable, {static: true}) table: MatTable; /** * The list of unit related data for the import. @@ -66,7 +72,14 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit { */ public codesToAdd: string = ''; - public displayedColumns: string[] = ['unitCode', 'sourceUnit', 'unitName', 'convenor', 'status', 'actions']; + public displayedColumns: string[] = [ + 'unitCode', + 'sourceUnit', + 'unitName', + 'convenor', + 'status', + 'actions', + ]; constructor( public dialogRef: MatDialogRef, @@ -105,8 +118,8 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit { private loadAllUnits() { // Load all units - this.unitService.query(undefined, { params: { include_in_active: true } }).subscribe({ - next: (success) => { + this.unitService.query(undefined, {params: {include_in_active: true}}).subscribe({ + next: () => { return; }, error: (failure) => { @@ -134,12 +147,12 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit { value.sourceUnit = value.relatedUnits.length > 0 ? value.relatedUnits[0].value : null; } - public relatedUnits(code: string): { value: Unit; text: string }[] { + public relatedUnits(code: string): {value: Unit; text: string}[] { return this.allUnits .filter((u) => u.code.includes(code) || code.includes(u.code)) .sort((a, b) => b.startDate.valueOf() - a.startDate.valueOf()) .map((u) => { - return { value: u, text: u.codeAndPeriod }; + return {value: u, text: u.codeAndPeriod}; }); } @@ -151,7 +164,8 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit { if (value.done) return 'Done!'; if (value.done !== undefined && !value.done) return 'Error! - check log'; if (!value.sourceUnit) return 'Create new unit'; - if (this.teachigPeriod.hasUnitLike(value.sourceUnit)) return 'Skip - Already in teaching period'; + if (this.teachigPeriod.hasUnitLike(value.sourceUnit)) + return 'Skip - Already in teaching period'; if (this.unitsToImport.filter((u) => u.unitCode === value.sourceUnit.code).length > 1) { return 'Duplicate - Source unit appears twice'; } @@ -179,7 +193,9 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit { const relatedUnits = this.relatedUnits(code); const sourceUnit = relatedUnits.length > 0 ? relatedUnits[0].value : null; - const formControl = new FormControl(sourceUnit?.mainConvenor?.user || sourceUnit?.mainConvenorUser); + const formControl: FormControl = new FormControl( + sourceUnit?.mainConvenor?.user || sourceUnit?.mainConvenorUser, + ); this.unitsToImport.push({ unitCode: code, @@ -252,7 +268,7 @@ export class TeachingPeriodUnitImportDialogComponent implements OnInit { }, }) .subscribe({ - next: (newUnit: Unit) => { + next: () => { unitToImport.done = true; this.importUnit(idx + 1); }, diff --git a/src/app/admin/states/units/units.component.html b/src/app/admin/states/units/units.component.html index e718d73431..769db63c2d 100644 --- a/src/app/admin/states/units/units.component.html +++ b/src/app/admin/states/units/units.component.html @@ -1,11 +1,11 @@
    -
    +

    {{ title }}

    - + Search search @@ -13,7 +13,7 @@

    {{ title }}

    Name @if (!editing(campus)) { -
    - - - - -
    + + + + } @else {
    - - diff --git a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts index bbd2a18090..51e8a760d5 100644 --- a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts +++ b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts @@ -1,18 +1,18 @@ -import {Component, ViewChild} from '@angular/core'; -import {MatSort, Sort} from '@angular/material/sort'; -import {MatTableDataSource, MatTable} from '@angular/material/table'; -import {UntypedFormControl, Validators} from '@angular/forms'; import {Campus, CampusService} from 'src/app/api/models/doubtfire-model'; import {EntityFormComponent} from 'src/app/common/entity-form/entity-form.component'; import {AlertService} from 'src/app/common/services/alert.service'; +import {AfterViewInit, Component, ViewChild} from '@angular/core'; +import {UntypedFormControl, Validators} from '@angular/forms'; +import {MatSort, Sort} from '@angular/material/sort'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; @Component({ - selector: 'campus-list', - templateUrl: 'campus-list.component.html', - styleUrls: ['campus-list.component.scss'], - standalone: false + selector: 'campus-list', + templateUrl: 'campus-list.component.html', + styleUrls: ['campus-list.component.scss'], + standalone: false, }) -export class CampusListComponent extends EntityFormComponent { +export class CampusListComponent extends EntityFormComponent implements AfterViewInit { @ViewChild(MatTable, {static: true}) table: MatTable; @ViewChild(MatSort, {static: true}) sort: MatSort; @@ -61,7 +61,11 @@ export class CampusListComponent extends EntityFormComponent { private pushToTable(value: Campus | Campus[]) { if (!value) return; - value instanceof Array ? this.campuses.push(...value) : this.campuses.push(value); + if (value instanceof Array) { + this.campuses.push(...value); + } else { + this.campuses.push(value); + } this.dataSource.sort = this.sort; } diff --git a/src/app/admin/institution-settings/institution-settings.component.html b/src/app/admin/institution-settings/institution-settings.component.html index bb183c747a..3cb3491d22 100644 --- a/src/app/admin/institution-settings/institution-settings.component.html +++ b/src/app/admin/institution-settings/institution-settings.component.html @@ -21,13 +21,14 @@

    Learning Outcomes

    @if (overseerEnabled) { - - - - } @if (tiiEnabled) { - - - + + + + } + @if (tiiEnabled) { + + + } diff --git a/src/app/admin/institution-settings/institution-settings.component.ts b/src/app/admin/institution-settings/institution-settings.component.ts index 0d2ef01806..8de6ae566e 100644 --- a/src/app/admin/institution-settings/institution-settings.component.ts +++ b/src/app/admin/institution-settings/institution-settings.component.ts @@ -1,23 +1,20 @@ -import { Component } from '@angular/core'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Component} from '@angular/core'; @Component({ - selector: 'institution-settings', - templateUrl: 'institution-settings.component.html', - styleUrls: ['institution-settings.component.scss'], - standalone: false + selector: 'institution-settings', + templateUrl: 'institution-settings.component.html', + styleUrls: ['institution-settings.component.scss'], + standalone: false, }) export class InstitutionSettingsComponent { + constructor(private constants: DoubtfireConstants) {} - constructor( - private constants: DoubtfireConstants, - ) { } - - public get overseerEnabled() : boolean { + public get overseerEnabled(): boolean { return this.constants.IsOverseerEnabled.value; } - public get tiiEnabled() : boolean { + public get tiiEnabled(): boolean { return this.constants.IsTiiEnabled.value; } } diff --git a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html index a41c1dd67b..62667efd70 100644 --- a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html +++ b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html @@ -1,5 +1,5 @@ - +
    {{ data.text }}
    @@ -27,14 +27,15 @@

    Name -
    - {{ overseerImage.name }} -
    - + @if (!editing(overseerImage)) { +
    + {{ overseerImage.name }} +
    + } @else { -
    + }
    @@ -47,14 +48,15 @@

    Tag -
    - {{ overseerImage.tag }} -
    - + @if (!editing(overseerImage)) { +
    + {{ overseerImage.tag }} +
    + } @else { -
    + }
    @@ -67,11 +69,13 @@

    -
    - -
    + @if (!editing(overseerImage)) { +
    + +
    + }
    Last Pulled -
    - {{ overseerImage.lastPulledDate | humanizedDate }} -
    + @if (!editing(overseerImage)) { +
    + {{ overseerImage.lastPulledDate | humanizedDate }} +
    + }
    Status -
    - - - -
    + @if (overseerImage.pulledImageStatus === 'success') { + + } + @if (overseerImage.pulledImageStatus === 'loading') { + + } + @if (overseerImage.pulledImageStatus === 'failed') { + + } + + }
    -
    - - - - -
    - + + + + + } @else {
    -
    + }
    diff --git a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts index 2cb839338c..7320f0aac0 100644 --- a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts +++ b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts @@ -1,27 +1,27 @@ +import {OverseerImage, OverseerImageService} from 'src/app/api/models/doubtfire-model'; +import {EntityFormComponent} from 'src/app/common/entity-form/entity-form.component'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; import {HttpClient} from '@angular/common/http'; import {AfterViewInit, Component, TemplateRef, ViewChild} from '@angular/core'; import {UntypedFormControl, Validators} from '@angular/forms'; import {MatDialog} from '@angular/material/dialog'; import {MatSort, Sort} from '@angular/material/sort'; import {MatTable, MatTableDataSource} from '@angular/material/table'; -import {OverseerImage, OverseerImageService} from 'src/app/api/models/doubtfire-model'; -import {EntityFormComponent} from 'src/app/common/entity-form/entity-form.component'; -import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; -import {AlertService} from 'src/app/common/services/alert.service'; @Component({ - selector: 'overseer-image-list', - templateUrl: 'overseer-image-list.component.html', - styleUrls: ['overseer-image-list.component.scss'], - standalone: false + selector: 'overseer-image-list', + templateUrl: 'overseer-image-list.component.html', + styleUrls: ['overseer-image-list.component.scss'], + standalone: false, }) export class OverseerImageListComponent extends EntityFormComponent implements AfterViewInit { - @ViewChild('textDialog') textDialog!: TemplateRef; + @ViewChild('textDialog') textDialog!: TemplateRef; - @ViewChild(MatTable, {static: true}) table: MatTable; + @ViewChild(MatTable, {static: true}) table: MatTable; @ViewChild(MatSort, {static: true}) sort: MatSort; // Set up the table @@ -75,7 +75,11 @@ export class OverseerImageListComponent // to the datasource private pushToTable(value: OverseerImage | OverseerImage[]) { if (!value) return; - value instanceof Array ? this.overseerImages.push(...value) : this.overseerImages.push(value); + if (value instanceof Array) { + this.overseerImages.push(...value); + } else { + this.overseerImages.push(value); + } this.dataSource.sort = this.sort; } @@ -103,7 +107,7 @@ export class OverseerImageListComponent deleteOverseerImage(image: OverseerImage) { this.overseerImageService.delete(image).subscribe( - ((response) => { + ((_response) => { this.cancelEdit(); this.overseerImages.splice(this.overseerImages.indexOf(image), 1); this.dataSource.data = this.overseerImages; diff --git a/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal-content.component.ts b/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal-content.component.ts index 2592fa920c..d735b6f7ca 100644 --- a/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal-content.component.ts +++ b/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal-content.component.ts @@ -1,13 +1,14 @@ -import { Component, OnInit } from '@angular/core'; -import { MatDialogRef } from '@angular/material/dialog'; -import { TeachingPeriod } from 'src/app/api/models/teaching-period'; -import { TeachingPeriodService } from 'src/app/api/services/teaching-period.service'; -import { UnitService } from 'src/app/api/services/unit.service'; -import { AlertService } from 'src/app/common/services/alert.service'; +import {TeachingPeriod} from 'src/app/api/models/teaching-period'; +import {TeachingPeriodService} from 'src/app/api/services/teaching-period.service'; +import {UnitService} from 'src/app/api/services/unit.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {Component, OnInit} from '@angular/core'; +import {MatDialogRef} from '@angular/material/dialog'; + @Component({ - selector: 'create-new-unit-modal-content', - templateUrl: 'create-new-unit-modal-content.component.html', - standalone: false + selector: 'create-new-unit-modal-content', + templateUrl: 'create-new-unit-modal-content.component.html', + standalone: false, }) export class CreateNewUnitModalContentComponent implements OnInit { constructor( @@ -28,7 +29,11 @@ export class CreateNewUnitModalContentComponent implements OnInit { }); } - public createUnit(unit: { unitName: string; unitCode: string; selectedTeachingPeriod: number }): void { + public createUnit(unit: { + unitName: string; + unitCode: string; + selectedTeachingPeriod: number; + }): void { let newUnit; if (this.selectedTeachingPeriod === null) { diff --git a/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal.component.html b/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal.component.ts b/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal.component.ts index 2dd7597ce3..6096f86bcc 100644 --- a/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal.component.ts +++ b/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal.component.ts @@ -1,11 +1,11 @@ -import { Component } from '@angular/core'; -import { MatDialog } from '@angular/material/dialog'; -import { CreateNewUnitModalContentComponent } from './create-new-unit-modal-content.component'; +import {Component} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import {CreateNewUnitModalContentComponent} from './create-new-unit-modal-content.component'; @Component({ - selector: 'create-new-unit-modal', - template: '', - standalone: false + selector: 'create-new-unit-modal', + templateUrl: './create-new-unit-modal.component.html', + standalone: false, }) export class CreateNewUnitModal { constructor(public dialog: MatDialog) {} diff --git a/src/app/admin/states/teaching-periods/teaching-period-list/new-teaching-period-dialog.component.html b/src/app/admin/states/teaching-periods/teaching-period-list/new-teaching-period-dialog.component.html index 58049818e9..b8ae10c207 100644 --- a/src/app/admin/states/teaching-periods/teaching-period-list/new-teaching-period-dialog.component.html +++ b/src/app/admin/states/teaching-periods/teaching-period-list/new-teaching-period-dialog.component.html @@ -1,6 +1,8 @@ -
    +
    - + + @@ -9,7 +11,7 @@ --> -
    +
    - + Teaching Period Name - + Teaching Period Year - + @@ -71,22 +85,22 @@

    Teaching Breaks for {{ newOrSelectedTeachingPeriod.name }}

    @for (break of newOrSelectedTeachingPeriod.breaksCache.values | async; track break) { - - - - {{ break.startDate | date }} - {{ break.numberOfWeeks }} week(s) + + + + {{ break.startDate | date }} + {{ break.numberOfWeeks }} week(s) + + + - - - - + } - + Break Start Date @@ -105,7 +119,13 @@

    Teaching Breaks for {{ newOrSelectedTeachingPeriod.name }}

    Number of weeks - +
    Unit Code - +
    boolean; matchesGroup?: (filter: string) => boolean; matches: (filter: string) => boolean; -}; +} @Component({ - selector: 'f-units', - templateUrl: './units.component.html', - styleUrls: ['./units.component.scss'], - standalone: false + selector: 'f-units', + templateUrl: './units.component.html', + styleUrls: ['./units.component.scss'], + standalone: false, }) export class FUnitsComponent implements OnInit, AfterViewInit { @ViewChild(MatTable, {static: false}) table: MatTable; @@ -88,7 +88,7 @@ export class FUnitsComponent implements OnInit, AfterViewInit { this.globalStateService.onLoad(() => { this.unitService.query(undefined, {params: {include_in_active: true}}).subscribe({ - next: (units) => { + next: () => { this.globalStateService.loadedUnits.values.subscribe( (loadedUnits) => (this.dataSource.data = this.mapUnitOrProjectsToColumns(loadedUnits)), diff --git a/src/app/admin/states/users/users.component.ts b/src/app/admin/states/users/users.component.ts index ccc747653c..03aa2d7af4 100644 --- a/src/app/admin/states/users/users.component.ts +++ b/src/app/admin/states/users/users.component.ts @@ -1,27 +1,34 @@ -import { Component, AfterViewInit, ViewChild, OnDestroy, OnInit } from '@angular/core'; -import { MatTable, MatTableDataSource } from '@angular/material/table'; -import { MatSort, Sort } from '@angular/material/sort'; -import { User } from 'src/app/api/models/doubtfire-model'; -import { MatPaginator } from '@angular/material/paginator'; -import { UserService } from 'src/app/api/models/doubtfire-model'; -import { EditProfileDialogService } from 'src/app/common/modals/edit-profile-dialog/edit-profile-dialog.service'; -import { Subscription } from 'rxjs'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; -import { FileDownloaderService } from 'src/app/common/file-downloader/file-downloader.service'; -import { AlertService } from 'src/app/common/services/alert.service'; +import {Subscription} from 'rxjs'; +import {User} from 'src/app/api/models/doubtfire-model'; +import {UserService} from 'src/app/api/models/doubtfire-model'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {EditProfileDialogService} from 'src/app/common/modals/edit-profile-dialog/edit-profile-dialog.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {AfterViewInit, Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {MatPaginator} from '@angular/material/paginator'; +import {MatSort, Sort} from '@angular/material/sort'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; @Component({ - selector: 'f-users', - templateUrl: './users.component.html', - styleUrls: ['./users.component.scss'], - standalone: false + selector: 'f-users', + templateUrl: './users.component.html', + styleUrls: ['./users.component.scss'], + standalone: false, }) export class FUsersComponent implements OnInit, AfterViewInit, OnDestroy { - @ViewChild(MatTable, { static: false }) table: MatTable; - @ViewChild(MatSort, { static: false }) sort: MatSort; - @ViewChild(MatPaginator, { static: false }) paginator: MatPaginator; - - displayedColumns: string[] = ['avatar', 'firstName', 'lastName', 'username', 'email', 'systemRole']; + @ViewChild(MatTable, {static: false}) table: MatTable; + @ViewChild(MatSort, {static: false}) sort: MatSort; + @ViewChild(MatPaginator, {static: false}) paginator: MatPaginator; + + displayedColumns: string[] = [ + 'avatar', + 'firstName', + 'lastName', + 'username', + 'email', + 'systemRole', + ]; public dataSource: MatTableDataSource; public filter: string; dataload: boolean; @@ -88,7 +95,9 @@ export class FUsersComponent implements OnInit, AfterViewInit, OnDestroy { error_string += error.message + '\n'; }); - max_full_errors > num_errors ? (error_string += `... and ${max_full_errors - num_errors} more`) : null; + if (num_errors > max_full_errors) { + error_string += `... and ${num_errors - max_full_errors} more`; + } this.alerts.error(error_string); this.userService.query(); diff --git a/src/app/admin/tii-action-log/tii-action-log.component.html b/src/app/admin/tii-action-log/tii-action-log.component.html index c12c822525..9d1e9d85d3 100644 --- a/src/app/admin/tii-action-log/tii-action-log.component.html +++ b/src/app/admin/tii-action-log/tii-action-log.component.html @@ -1,16 +1,21 @@
    -
    +

    Turnitin Actions

    - +
    Turnitin Actions diff --git a/src/app/admin/tii-action-log/tii-action-log.component.spec.ts b/src/app/admin/tii-action-log/tii-action-log.component.spec.ts index a3caf79062..38e5d9ec65 100644 --- a/src/app/admin/tii-action-log/tii-action-log.component.spec.ts +++ b/src/app/admin/tii-action-log/tii-action-log.component.spec.ts @@ -1,6 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { TiiActionLogComponent } from './tii-action-log.component'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {TiiActionLogComponent} from './tii-action-log.component'; describe('TiiActionLogComponent', () => { let component: TiiActionLogComponent; @@ -8,7 +7,7 @@ describe('TiiActionLogComponent', () => { beforeEach(() => { TestBed.configureTestingModule({ - declarations: [TiiActionLogComponent] + declarations: [TiiActionLogComponent], }); fixture = TestBed.createComponent(TiiActionLogComponent); component = fixture.componentInstance; diff --git a/src/app/admin/tii-action-log/tii-action-log.component.ts b/src/app/admin/tii-action-log/tii-action-log.component.ts index 8d1771cce4..d53d488d47 100644 --- a/src/app/admin/tii-action-log/tii-action-log.component.ts +++ b/src/app/admin/tii-action-log/tii-action-log.component.ts @@ -1,29 +1,37 @@ -import { AfterViewInit, Component, ViewChild } from '@angular/core'; -import { MatPaginator } from '@angular/material/paginator'; -import { MatSort, Sort } from '@angular/material/sort'; -import { MatTable, MatTableDataSource } from '@angular/material/table'; -import { TiiAction } from 'src/app/api/models/doubtfire-model'; -import { TiiActionService } from 'src/app/api/services/tii-action.service'; -import { AlertService } from 'src/app/common/services/alert.service'; +import {TiiAction} from 'src/app/api/models/doubtfire-model'; +import {TiiActionService} from 'src/app/api/services/tii-action.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {AfterViewInit, Component, ViewChild} from '@angular/core'; +import {MatPaginator} from '@angular/material/paginator'; +import {MatSort, Sort} from '@angular/material/sort'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; @Component({ - selector: 'f-tii-action-log', - templateUrl: './tii-action-log.component.html', - styleUrls: ['./tii-action-log.component.scss'], - standalone: false + selector: 'f-tii-action-log', + templateUrl: './tii-action-log.component.html', + styleUrls: ['./tii-action-log.component.scss'], + standalone: false, }) export class TiiActionLogComponent implements AfterViewInit { - @ViewChild(MatTable, { static: false }) table: MatTable; - @ViewChild(MatSort, { static: false }) sort: MatSort; - @ViewChild(MatPaginator, { static: false }) paginator: MatPaginator; + @ViewChild(MatTable, {static: false}) table: MatTable; + @ViewChild(MatSort, {static: false}) sort: MatSort; + @ViewChild(MatPaginator, {static: false}) paginator: MatPaginator; public tiiActionsSource: MatTableDataSource; - public columns: string[] = ['type', 'lastRun', 'retries', 'retry', 'errorMessage', 'tiiActionTools']; //, 'complete', 'retries', 'lastRun', 'errorCode', 'log', 'tiiActionAction']; + public columns: string[] = [ + 'type', + 'lastRun', + 'retries', + 'retry', + 'errorMessage', + 'tiiActionTools', + ]; //, 'complete', 'retries', 'lastRun', 'errorCode', 'log', 'tiiActionAction']; public filter: string; - constructor(private tiiActionService: TiiActionService, private alertService: AlertService) { - - } + constructor( + private tiiActionService: TiiActionService, + private alertService: AlertService, + ) {} ngAfterViewInit(): void { this.tiiActionService.query().subscribe((actions) => { @@ -31,8 +39,10 @@ export class TiiActionLogComponent implements AfterViewInit { this.tiiActionsSource = new MatTableDataSource(actions); this.tiiActionsSource.paginator = this.paginator; this.tiiActionsSource.sort = this.sort; - this.tiiActionsSource.filterPredicate = (data: any, filter: string) => data.matches(filter); - + this.tiiActionsSource.filterPredicate = ( + data: TiiAction & {matches(filter: string): boolean}, + filter: string, + ) => data.matches(filter); }); } @@ -68,20 +78,20 @@ export class TiiActionLogComponent implements AfterViewInit { } public retryAction(action: TiiAction) { - this.tiiActionService.put(action, { - body: { - action: 'retry' - } - }).subscribe({ - next: (updatedAction) => { - action.retry = true; - this.alertService.success('Action has been queued for retry'); - }, - error: (error) => { - this.alertService.error('Failed to queue action for retry'); - } - }); + this.tiiActionService + .put(action, { + body: { + action: 'retry', + }, + }) + .subscribe({ + next: () => { + action.retry = true; + this.alertService.success('Action has been queued for retry'); + }, + error: (error) => { + this.alertService.error(`Failed to queue action for retry: ${error}`); + }, + }); } - - } diff --git a/src/app/api/models/d2l/d2l_assessment_mapping.service.ts b/src/app/api/models/d2l/d2l_assessment_mapping.service.ts index 3f2fe47087..afd5318aca 100644 --- a/src/app/api/models/d2l/d2l_assessment_mapping.service.ts +++ b/src/app/api/models/d2l/d2l_assessment_mapping.service.ts @@ -1,9 +1,9 @@ -import {Injectable} from '@angular/core'; import {EntityService} from 'ngx-entity-service'; import API_URL from 'src/app/config/constants/apiUrl'; import {HttpClient} from '@angular/common/http'; -import {D2lAssessmentMapping} from './d2l_assessment_mapping'; +import {Injectable} from '@angular/core'; import {Unit} from '../doubtfire-model'; +import {D2lAssessmentMapping} from './d2l_assessment_mapping'; @Injectable() export class D2lAssessmentMappingService extends EntityService { diff --git a/src/app/api/models/discussion-prompt.ts b/src/app/api/models/discussion-prompt.ts index e984847084..2f9d7605c5 100644 --- a/src/app/api/models/discussion-prompt.ts +++ b/src/app/api/models/discussion-prompt.ts @@ -51,8 +51,9 @@ export class DiscussionPrompt extends Entity { next: (_response: object) => { AppInjector.get(AlertService).success('Successfully deleted discussion note', 4000); }, - error: (error: any) => { - AppInjector.get(AlertService).error(error?.message || error || 'Unknown error', 2000); + error: (error: Error) => { + const message = error.message || 'Unknown error'; + AppInjector.get(AlertService).error(message, 2000); }, }); } diff --git a/src/app/api/models/feedback-template.ts b/src/app/api/models/feedback-template.ts index 1634cb70d6..0df083f96d 100644 --- a/src/app/api/models/feedback-template.ts +++ b/src/app/api/models/feedback-template.ts @@ -61,7 +61,7 @@ export class FeedbackTemplate extends Entity { return !this.id; } - public delete(): Observable { + public delete(): Observable { const svc = AppInjector.get(FeedbackTemplateService); return svc.delete( diff --git a/src/app/api/models/grade.ts b/src/app/api/models/grade.ts index e139dee8fb..7506f647cd 100644 --- a/src/app/api/models/grade.ts +++ b/src/app/api/models/grade.ts @@ -2,7 +2,10 @@ export class Grade { public static readonly PASS_RANGE: number[] = [0, 1, 2, 3]; public static readonly FULL_RANGE: number[] = [-1, 0, 1, 2, 3]; - public static readonly GRADE_ACRONYMS: Map = new Map([ + public static readonly GRADE_ACRONYMS: Map = new Map< + string | number, + string + >([ ['Fail', 'F'], ['Pass', 'P'], ['Credit', 'C'], diff --git a/src/app/api/models/groups/group-set.ts b/src/app/api/models/groups/group-set.ts index cb99f99e44..5e15231ee1 100644 --- a/src/app/api/models/groups/group-set.ts +++ b/src/app/api/models/groups/group-set.ts @@ -1,7 +1,7 @@ import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; import {AppInjector} from 'src/app/app-injector'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; -import {Group, Unit, User} from '../doubtfire-model'; +import {Group, Unit} from '../doubtfire-model'; export class GroupSet extends Entity { public id: number; diff --git a/src/app/api/models/groups/group.ts b/src/app/api/models/groups/group.ts index 6a55b2d716..e2202df690 100644 --- a/src/app/api/models/groups/group.ts +++ b/src/app/api/models/groups/group.ts @@ -1,10 +1,10 @@ -import {HttpClient} from '@angular/common/http'; import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; import {Observable, tap} from 'rxjs'; import {AppInjector} from 'src/app/app-injector'; -import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; -import {Unit, GroupSet, Project, Tutorial, ProjectService} from '../doubtfire-model'; import {AlertService} from 'src/app/common/services/alert.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {HttpClient} from '@angular/common/http'; +import {GroupSet, Project, ProjectService, Tutorial, Unit} from '../doubtfire-model'; export interface MemberContribution { project: Project; @@ -86,7 +86,7 @@ export class Group extends Entity { httpClient .post(`${AppInjector.get(DoubtfireConstants).API_URL}/${this.memberUri(member)}`, {}) .subscribe({ - next: (success) => { + next: () => { // Get old group.. const grp = member.groupForGroupSet(this.groupSet); if (grp) { @@ -119,7 +119,7 @@ export class Group extends Entity { httpClient .delete(`${AppInjector.get(DoubtfireConstants).API_URL}/${this.memberUri(member)}`, {}) .subscribe({ - next: (success) => { + next: () => { // Get old group.. this.projectsCache.delete(member); member.groupCache.delete(this); diff --git a/src/app/api/models/learning-outcome.ts b/src/app/api/models/learning-outcome.ts index dfdc55fa19..211c3931d1 100644 --- a/src/app/api/models/learning-outcome.ts +++ b/src/app/api/models/learning-outcome.ts @@ -1,8 +1,8 @@ import {Entity, EntityMapping} from 'ngx-entity-service'; import {Observable, tap} from 'rxjs'; import {AppInjector} from 'src/app/app-injector'; -import {LearningOutcomeService, TaskDefinition, Unit} from './doubtfire-model'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {LearningOutcomeService, TaskDefinition, Unit} from './doubtfire-model'; export class LearningOutcome extends Entity { id: number; @@ -121,7 +121,7 @@ export class LearningOutcome extends Entity { return !this.id; } - public delete(): Observable { + public delete(): Observable { const svc = AppInjector.get(LearningOutcomeService); if (this.context) { diff --git a/src/app/api/models/overseer/overseer-assessment.ts b/src/app/api/models/overseer/overseer-assessment.ts index a41bcbb5d2..f658c57986 100644 --- a/src/app/api/models/overseer/overseer-assessment.ts +++ b/src/app/api/models/overseer/overseer-assessment.ts @@ -9,7 +9,7 @@ export class OverseerAssessment extends Entity { // overseerStepId: number; timestamp: Date; timestampString: string; - content?: [{label: string; result: string}]; + content?: {label: string; result: string}[]; task?: Task; taskStatus?: string; submissionStatus?: 'queued' | 'executing' | 'passed' | 'failed' | 'error'; diff --git a/src/app/api/models/overseer/overseer-image.ts b/src/app/api/models/overseer/overseer-image.ts index 2f6627d3be..aef5b416bb 100644 --- a/src/app/api/models/overseer/overseer-image.ts +++ b/src/app/api/models/overseer/overseer-image.ts @@ -1,4 +1,3 @@ -import {StringNullableChain} from 'lodash'; import {Entity, EntityMapping} from 'ngx-entity-service'; export class OverseerImage extends Entity { diff --git a/src/app/api/models/overseer/overseer-step-result.ts b/src/app/api/models/overseer/overseer-step-result.ts index 2a44371825..ebba556c69 100644 --- a/src/app/api/models/overseer/overseer-step-result.ts +++ b/src/app/api/models/overseer/overseer-step-result.ts @@ -18,7 +18,7 @@ export class OverseerStepResult extends Entity { expectedOutputSha256: string; feedbackMessage: string; - constructor(oa?: OverseerAssessment, os?: OverseerStep) { + constructor(oa?: OverseerAssessment, _os?: OverseerStep) { super(); this.overseerAssessment = oa; // this.overseerStep = os; diff --git a/src/app/api/models/overseer/overseer-step.ts b/src/app/api/models/overseer/overseer-step.ts index 6fa14bf1bf..7ed380fee7 100644 --- a/src/app/api/models/overseer/overseer-step.ts +++ b/src/app/api/models/overseer/overseer-step.ts @@ -1,9 +1,9 @@ import {Entity, EntityMapping} from 'ngx-entity-service'; -import {TaskDefinition} from '../task-definition'; -import {TaskStatus, TaskStatusEnum} from '../task-status'; -import {OverseerStepService} from '../../services/overseer-step.service'; import {AppInjector} from 'src/app/app-injector'; import {AlertService} from 'src/app/common/services/alert.service'; +import {OverseerStepService} from '../../services/overseer-step.service'; +import {TaskDefinition} from '../task-definition'; +import {TaskStatusEnum} from '../task-status'; export class OverseerStep extends Entity { id: number; diff --git a/src/app/api/models/project.ts b/src/app/api/models/project.ts index f833fd3383..3cf3e7a3b0 100644 --- a/src/app/api/models/project.ts +++ b/src/app/api/models/project.ts @@ -1,9 +1,9 @@ -import {HttpClient} from '@angular/common/http'; import {Entity, EntityCache, RequestOptions} from 'ngx-entity-service'; import {Observable, tap} from 'rxjs'; import {AppInjector} from 'src/app/app-injector'; import {AlertService} from 'src/app/common/services/alert.service'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {HttpClient} from '@angular/common/http'; import {MappingFunctions} from '../services/mapping-fn'; import { Campus, @@ -284,7 +284,7 @@ export class Project extends Entity { return httpClient.delete(this.portfolioUrl(false)); } - public deleteFileFromPortfolio(file: {idx: any; kind: any; name: any}) { + public deleteFileFromPortfolio(file: {idx: number; kind: string; name: string}) { const httpClient = AppInjector.get(HttpClient); return httpClient .delete( @@ -331,7 +331,7 @@ export class Project extends Entity { cache: this.unit.studentCache, }; - projectService.get(this, options).subscribe((response) => { + projectService.get(this, options).subscribe(() => { // Legacy AngularJS visualisation refresh hook removed with upgraded providers. // (AppInjector.get(visualisations) as any).refreshAll(); }); @@ -423,7 +423,7 @@ export class Project extends Entity { // get total value of all tasks assigned to this project const total = targetTasks .map((td) => td.weighting) - .reduce((prev, current, idx, array) => prev + current, 0); + .reduce((prev, current, _idx, _array) => prev + current, 0); // exit if no tasks or no weights if (targetTasks.length === 0 || total === 0) { @@ -438,7 +438,7 @@ export class Project extends Entity { task.status, ), ); - let lastTargetDate: Date; + // let lastTargetDate: Date; const completedTasks = tasks.filter((task) => task.status === 'complete'); @@ -452,11 +452,11 @@ export class Project extends Entity { // last done task date) if (readyOrCompleteTasks.length === 0) { - lastTargetDate = this.unit.startDate; + // lastTargetDate = this.unit.startDate; } else { - lastTargetDate = readyOrCompleteTasks - .sort((a, b) => a.dueDate.getTime() - b.dueDate.getTime()) - .splice(-1)[0].dueDate; + // lastTargetDate = readyOrCompleteTasks + // .sort((a, b) => a.dueDate.getTime() - b.dueDate.getTime()) + // .splice(-1)[0].dueDate; } // today is used to determine when to stop adding done tasks @@ -470,7 +470,7 @@ export class Project extends Entity { if (weeksElapsed > 0) { const completedTasksWeight = readyOrCompleteTasks .map((t) => t.definition.weighting) - .reduce((prev, current, idx, arr) => prev + current, 0); + .reduce((prev, current, _idx, _arr) => prev + current, 0); completionRate = completedTasksWeight / weeksElapsed; } } diff --git a/src/app/api/models/scorm-datamodel.ts b/src/app/api/models/scorm-datamodel.ts index 0fdc2d3a06..b967e24c83 100644 --- a/src/app/api/models/scorm-datamodel.ts +++ b/src/app/api/models/scorm-datamodel.ts @@ -1,5 +1,5 @@ export class ScormDataModel { - dataModel: {[key: string]: any} = {}; + dataModel: Record = {}; readonly msgPrefix = 'SCORM DataModel: '; constructor() { @@ -8,19 +8,19 @@ export class ScormDataModel { public restore(dataModel: string) { // console.log(this.msgPrefix + 'restoring DataModel with provided data'); - this.dataModel = JSON.parse(dataModel); + this.dataModel = JSON.parse(dataModel) as Record; } public get(key: string): string { // console.log(`SCORM DataModel: get ${key} ${this.dataModel[key]}`); - return this.dataModel[key] ?? ''; + return String(this.dataModel[key] ?? ''); } - public dump(): {[key: string]: any} { + public dump(): Record { return this.dataModel; } - public set(key: string, value: any): string { + public set(key: string, value: string): string { // console.log(this.msgPrefix + 'set: ', key, value); this.dataModel[key] = value; if (key.match('cmi.interactions.\\d+.id')) { @@ -28,7 +28,8 @@ export class ScormDataModel { const interactionPath = key.match('cmi.interactions.\\d+'); const objectivesCounterForInteraction = interactionPath.toString() + '.objectives._count'; // console.log('Incrementing cmi.interactions._count'); - this.dataModel['cmi.interactions._count']++; + this.dataModel['cmi.interactions._count'] = + Number(this.dataModel['cmi.interactions._count'] ?? 0) + 1; // cmi.interactions.n.objectives._count must be initialized after an interaction is created // console.log(`Initializing ${objectivesCounterForInteraction}`); this.dataModel[objectivesCounterForInteraction] = 0; @@ -38,12 +39,14 @@ export class ScormDataModel { const objectivesCounterForInteraction = interactionPath.toString() + '._count'; // cmi.interactions.n.objectives._count must be incremented after objective creation // console.log(`Incrementing ${objectivesCounterForInteraction}`); - this.dataModel[objectivesCounterForInteraction.toString()]++; + this.dataModel[objectivesCounterForInteraction.toString()] = + Number(this.dataModel[objectivesCounterForInteraction.toString()] ?? 0) + 1; } if (key.match('cmi.objectives.\\d+.id')) { // cmi.objectives._count must be incremented after a new objective is created // console.log('Incrementing cmi.objectives._count'); - this.dataModel['cmi.objectives._count']++; + this.dataModel['cmi.objectives._count'] = + Number(this.dataModel['cmi.objectives._count'] ?? 0) + 1; } return 'true'; } diff --git a/src/app/api/models/staff-note.ts b/src/app/api/models/staff-note.ts index bcd1b00e34..ab3ab60a8a 100644 --- a/src/app/api/models/staff-note.ts +++ b/src/app/api/models/staff-note.ts @@ -1,8 +1,8 @@ import {Entity} from 'ngx-entity-service'; -import {Project, Unit, User, UserService} from './doubtfire-model'; import {AppInjector} from 'src/app/app-injector'; import {AlertService} from 'src/app/common/services/alert.service'; import {StaffNoteService} from '../services/staff-note.service'; +import {Project, User, UserService} from './doubtfire-model'; export class StaffNote extends Entity { id: number; @@ -41,13 +41,14 @@ export class StaffNote extends Entity { staffNoteService .delete({projectId: this.project.id, id: this.id}, {cache: this.project.staffNoteCache}) .subscribe({ - next: (response: object) => { + next: () => { AppInjector.get(AlertService).error('Successfully deleted staff note', 4000); this.project.staffNoteCount--; staffNoteService.updateStaffNoteReplies(this.project.staffNoteCache.currentValues); }, - error: (error: any) => { - AppInjector.get(AlertService).error(error?.message || error || 'Unknown error', 2000); + error: (error: Error) => { + const message = error.message || 'Unknown error'; + AppInjector.get(AlertService).error(message, 2000); }, }); } diff --git a/src/app/api/models/task-comment/discussion-comment.ts b/src/app/api/models/task-comment/discussion-comment.ts index 97bb24ee7e..c69968f2b7 100644 --- a/src/app/api/models/task-comment/discussion-comment.ts +++ b/src/app/api/models/task-comment/discussion-comment.ts @@ -1,6 +1,6 @@ -import { AppInjector } from 'src/app/app-injector'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; -import { Task, TaskComment } from '../doubtfire-model' +import {AppInjector} from 'src/app/app-injector'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Task, TaskComment} from '../doubtfire-model'; /** * Create a Discussion Comment, extending the base TaskComment class diff --git a/src/app/api/models/task-comment/extension-comment.ts b/src/app/api/models/task-comment/extension-comment.ts index 443bb34200..8c07459d31 100644 --- a/src/app/api/models/task-comment/extension-comment.ts +++ b/src/app/api/models/task-comment/extension-comment.ts @@ -1,8 +1,8 @@ -import { Observable } from 'rxjs'; -import { tap } from 'rxjs/operators'; -import { AppInjector } from 'src/app/app-injector'; -import { TaskCommentService } from '../../services/task-comment.service'; -import { TaskComment, TaskStatusEnum, Task } from '../doubtfire-model'; +import {Observable} from 'rxjs'; +import {AppInjector} from 'src/app/app-injector'; +import {tap} from 'rxjs/operators'; +import {TaskCommentService} from '../../services/task-comment.service'; +import {Task, TaskComment, TaskStatusEnum} from '../doubtfire-model'; /** * Create a Discussion Comment, extending the base TaskComment class @@ -46,7 +46,7 @@ export class ExtensionComment extends TaskComment { tc.project.updateBurndownChart(); tc.project.calcTopTasks(); // Sort the task list again - }) + }), ); } diff --git a/src/app/api/models/task-comment/scorm-extension-comment.ts b/src/app/api/models/task-comment/scorm-extension-comment.ts index b8aac7909b..d5c6f19168 100644 --- a/src/app/api/models/task-comment/scorm-extension-comment.ts +++ b/src/app/api/models/task-comment/scorm-extension-comment.ts @@ -1,8 +1,8 @@ import {Observable} from 'rxjs'; -import {tap} from 'rxjs/operators'; import {AppInjector} from 'src/app/app-injector'; +import {tap} from 'rxjs/operators'; import {TaskCommentService} from '../../services/task-comment.service'; -import {TaskComment, Task} from '../doubtfire-model'; +import {Task, TaskComment} from '../doubtfire-model'; export class ScormExtensionComment extends TaskComment { assessed: boolean; diff --git a/src/app/api/models/task-comment/task-comment.ts b/src/app/api/models/task-comment/task-comment.ts index fad8869f9a..d1c74abd86 100644 --- a/src/app/api/models/task-comment/task-comment.ts +++ b/src/app/api/models/task-comment/task-comment.ts @@ -1,10 +1,9 @@ -import {AppInjector} from 'src/app/app-injector'; import {Entity} from 'ngx-entity-service'; import {Project, Task, TaskCommentService, User} from 'src/app/api/models/doubtfire-model'; -import {UserService} from '../../services/user.service'; -import API_URL from 'src/app/config/constants/apiUrl'; -import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {AppInjector} from 'src/app/app-injector'; import {AlertService} from 'src/app/common/services/alert.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {UserService} from '../../services/user.service'; export class TaskComment extends Entity { private static readonly EDIT_WINDOW_MS = 10 * 60 * 1000; @@ -46,12 +45,12 @@ export class TaskComment extends Entity { } public get authorIsMe(): boolean { - const userService: any = AppInjector.get(UserService); + const userService: UserService = AppInjector.get(UserService); return this.author.id === userService.currentUser.id; } public get recipientIsMe(): boolean { - const userService: any = AppInjector.get(UserService); + const userService: UserService = AppInjector.get(UserService); return this.recipient.id === userService.currentUser.id; } @@ -102,12 +101,13 @@ export class TaskComment extends Entity { {cache: this.task.commentCache}, ) .subscribe({ - next: (response: object) => { + next: (_response: object) => { // this.task.comments = this.task.comments.filter((e: TaskComment) => e.id !== this.id); this.task.refreshCommentData(); }, - error: (error: any) => { - AppInjector.get(AlertService).error(error?.message || error || 'Unknown error', 2000); + error: (error: Error) => { + const message = error.message || 'Unknown error'; + AppInjector.get(AlertService).error(message, 2000); }, }); } diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index cd5ede1e4b..f9f575fc6d 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -1,15 +1,15 @@ -import {HttpClient} from '@angular/common/http'; import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; import {Observable, tap} from 'rxjs'; import {AppInjector} from 'src/app/app-injector'; import {AlertService} from 'src/app/common/services/alert.service'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {HttpClient} from '@angular/common/http'; import {TaskDefinitionService} from '../services/task-definition.service'; +import {DiscussionPrompt} from './discussion-prompt'; import {Grade, GroupSet, LearningOutcome, Project, TutorialStream, Unit} from './doubtfire-model'; import {Task} from './doubtfire-model'; -import {TaskPrerequisite} from './task-prerequisite'; -import {DiscussionPrompt} from './discussion-prompt'; import {OverseerStep} from './overseer/overseer-step'; +import {TaskPrerequisite} from './task-prerequisite'; export interface UploadRequirement { key: string; @@ -307,27 +307,31 @@ export class TaskDefinition extends Entity { return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.unit.id}/task_definitions/${this.id}/jplag_report`; } - public deleteTaskSheet(): Observable { + public deleteTaskSheet(): Observable { const httpClient = AppInjector.get(HttpClient); - return httpClient.delete(this.taskSheetUploadUrl).pipe(tap(() => (this.hasTaskSheet = false))); + return httpClient + .delete(this.taskSheetUploadUrl) + .pipe(tap(() => (this.hasTaskSheet = false))); } - public deleteTaskResources(): Observable { + public deleteTaskResources(): Observable { const httpClient = AppInjector.get(HttpClient); return httpClient - .delete(this.taskResourcesUploadUrl) + .delete(this.taskResourcesUploadUrl) .pipe(tap(() => (this.hasTaskResources = false))); } - public deleteScormData(): Observable { + public deleteScormData(): Observable { const httpClient = AppInjector.get(HttpClient); - return httpClient.delete(this.scormDataUploadUrl).pipe(tap(() => (this.hasScormData = false))); + return httpClient + .delete(this.scormDataUploadUrl) + .pipe(tap(() => (this.hasScormData = false))); } - public deleteOverseerResources(): Observable { + public deleteOverseerResources(): Observable { const httpClient = AppInjector.get(HttpClient); return httpClient - .delete(this.taskOverseerResourcesUploadUrl) + .delete(this.taskOverseerResourcesUploadUrl) .pipe(tap(() => (this.hasTaskAssessmentResources = false))); } diff --git a/src/app/api/models/task-outcome-alignment.ts b/src/app/api/models/task-outcome-alignment.ts index 8569ae5549..0fcf222056 100644 --- a/src/app/api/models/task-outcome-alignment.ts +++ b/src/app/api/models/task-outcome-alignment.ts @@ -1,5 +1,5 @@ import {Entity} from 'ngx-entity-service'; -import {Project, Unit, TaskDefinition, Task} from './doubtfire-model'; +import {Project, Task, TaskDefinition, Unit} from './doubtfire-model'; import {LearningOutcome} from './learning-outcome'; export class TaskOutcomeAlignment extends Entity { diff --git a/src/app/api/models/task-prerequisite.ts b/src/app/api/models/task-prerequisite.ts index 9645adfe5b..4e26df0917 100644 --- a/src/app/api/models/task-prerequisite.ts +++ b/src/app/api/models/task-prerequisite.ts @@ -5,6 +5,12 @@ import {AlertService} from 'src/app/common/services/alert.service'; import {TaskPrerequisiteService} from '../services/task-prerequisite.service'; import {Project, TaskDefinition, TaskStatus, TaskStatusEnum} from './doubtfire-model'; +export interface TaskPrerequisiteData { + taskDefinitionId: number; + prerequisiteId: number; + taskStatus: TaskStatusEnum; +} + export class TaskPrerequisite extends Entity { id: number; @@ -28,7 +34,7 @@ export class TaskPrerequisite extends Entity { complete: 3, }; - constructor(json: any) { + constructor(json: TaskPrerequisiteData) { super(); this.taskDefinitionId = json.taskDefinitionId; this.prerequisiteId = json.prerequisiteId; @@ -61,12 +67,12 @@ export class TaskPrerequisite extends Entity { return false; } - public delete(): Observable { + public delete(): Observable { const taskPrerequisiteService: TaskPrerequisiteService = AppInjector.get(TaskPrerequisiteService); return taskPrerequisiteService - .delete( + .delete( { unitId: this.taskDefinition.unit.id, taskDefId: this.taskDefinitionId, diff --git a/src/app/api/models/task-similarity.ts b/src/app/api/models/task-similarity.ts index cb9640966c..c18a012d36 100644 --- a/src/app/api/models/task-similarity.ts +++ b/src/app/api/models/task-similarity.ts @@ -1,8 +1,8 @@ import {Entity} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; import {AppInjector} from 'src/app/app-injector'; -import {Task, TaskSimilarityService, User} from './doubtfire-model'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; -import {Observable} from 'rxjs'; +import {Task, TaskSimilarityService, User} from './doubtfire-model'; export enum TaskSimilarityType { Jplag = 'JplagTaskSimilarity', diff --git a/src/app/api/models/task-status.ts b/src/app/api/models/task-status.ts index 816d016ba5..d2894a4478 100644 --- a/src/app/api/models/task-status.ts +++ b/src/app/api/models/task-status.ts @@ -204,7 +204,7 @@ export class TaskStatus { ['attention_required', ['ready_for_feedback', 'not_started', 'working_on_it', 'need_help']], ]); - public static readonly STATUS_LABELS = new Map([ + public static readonly STATUS_LABELS: Map = new Map([ ['ready_for_feedback', 'Awaiting Feedback'], ['not_started', 'Not Started'], ['working_on_it', 'Working On It'], @@ -221,7 +221,7 @@ export class TaskStatus { ['attention_required', 'Attention Required'], ]); - public static readonly STATUS_NAME_TO_KEY = new Map([ + public static readonly STATUS_NAME_TO_KEY: Map = new Map([ ['Ready for Feedback', 'ready_for_feedback'], ['Awaiting Feedback', 'ready_for_feedback'], ['Not Started', 'not_started'], @@ -237,7 +237,7 @@ export class TaskStatus { ['Time Exceeded', 'time_exceeded'], ]); - public static readonly STATUS_ICONS = new Map([ + public static readonly STATUS_ICONS: Map = new Map([ ['ready_for_feedback', 'thumb_up'], ['not_started', 'pause'], ['working_on_it', 'bolt'], @@ -255,7 +255,7 @@ export class TaskStatus { ]); // Material icons used by newer UI elements. - public static readonly STATUS_MATERIAL_ICONS = new Map([ + public static readonly STATUS_MATERIAL_ICONS: Map = new Map([ ['ready_for_feedback', 'thumb_up_off_alt'], ['not_started', 'pause'], ['working_on_it', 'bolt'], @@ -273,7 +273,7 @@ export class TaskStatus { ]); // Please make sure this matches task-status-colors.less - public static readonly STATUS_COLORS = new Map([ + public static readonly STATUS_COLORS: Map = new Map([ ['ready_for_feedback', '#0079D8'], ['not_started', '#CCCCCC'], ['working_on_it', '#EB8F06'], @@ -290,7 +290,7 @@ export class TaskStatus { ['attention_required', '#f1814d'], ]); - public static readonly STATUS_SEQ = new Map([ + public static readonly STATUS_SEQ: Map = new Map([ ['not_started', 1], ['fail', 2], ['feedback_exceeded', 3], @@ -325,10 +325,10 @@ export class TaskStatus { // detail = in a brief context to the student // reason = reason for this status // action = action student can take - public static readonly HELP_DESCRIPTIONS = new Map< + public static readonly HELP_DESCRIPTIONS: Map< TaskStatusEnum, {detail: string; reason: string; action: string} - >([ + > = new Map([ [ 'ready_for_feedback', { diff --git a/src/app/api/models/task.ts b/src/app/api/models/task.ts index b022d3159a..de1c41d59a 100644 --- a/src/app/api/models/task.ts +++ b/src/app/api/models/task.ts @@ -1,36 +1,36 @@ import {Entity, EntityCache, RequestOptions} from 'ngx-entity-service'; +import {Observable, firstValueFrom, map} from 'rxjs'; import {AppInjector} from 'src/app/app-injector'; -import {formatDate} from '@angular/common'; +import {AlertService} from 'src/app/common/services/alert.service'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {GradeTaskModalService} from 'src/app/tasks/modals/grade-task-modal/grade-task-modal.service'; +import {UploadSubmissionModalService} from 'src/app/tasks/modals/upload-submission-modal/upload-submission-modal.service'; +import {formatDate} from '@angular/common'; +import {HttpClient} from '@angular/common/http'; +import {LOCALE_ID} from '@angular/core'; +import {MappingFunctions} from '../services/mapping-fn'; +import {TutorNoteService} from '../services/tutor-note.service'; import { - TaskDefinition, + Group, Project, - Unit, + ScormComment, TaskComment, - TaskStatusEnum, - TaskStatus, - TaskStatusUiData, - TaskService, - Group, TaskCommentService, + TaskDefinition, + TaskService, TaskSimilarity, TaskSimilarityService, + TaskStatus, + TaskStatusEnum, + TaskStatusUiData, TestAttempt, TestAttemptService, - ScormComment, - UnitRoleService, + Unit, UnitRole, + UnitRoleService, UserService, } from './doubtfire-model'; -import {TutorNoteService} from '../services/tutor-note.service'; import {Grade} from './grade'; -import {LOCALE_ID} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; -import {Observable, firstValueFrom, map} from 'rxjs'; -import {AlertService} from 'src/app/common/services/alert.service'; -import {MappingFunctions} from '../services/mapping-fn'; -import {GradeTaskModalService} from 'src/app/tasks/modals/grade-task-modal/grade-task-modal.service'; -import {UploadSubmissionModalService} from 'src/app/tasks/modals/upload-submission-modal/upload-submission-modal.service'; import {TaskPrerequisite} from './task-prerequisite'; export const FeedbackModerationAction = { @@ -148,9 +148,9 @@ export class Task extends Entity { AppInjector.get(TaskCommentService) .addComment(this, textString, 'text') .subscribe({ - next: (tc) => {}, error: (error) => { - console.log(error); + const alerts: AlertService = AppInjector.get(AlertService); + alerts.error(`Failed to add comment: ${error}`); }, }); } @@ -631,7 +631,6 @@ export class Task extends Entity { } comments[comments.length - 1].shouldShowAvatar = true; - comments; } public taskKey(): {studentId: number; taskDefAbbr: string} { @@ -650,14 +649,14 @@ export class Task extends Entity { return this.similarityFlag; } - public getSimilarityData(match: number): Observable { + public getSimilarityData(match: number): Observable { const httpClient = AppInjector.get(HttpClient); return httpClient.get( `${AppInjector.get(DoubtfireConstants).API_URL}/tasks/${this.id}/similarity/${match}`, ); } - public updateSimilarity(match: number, other: any, dismissed: boolean): Observable { + public updateSimilarity(match: number, other: object, dismissed: boolean): Observable { const httpClient = AppInjector.get(HttpClient); return httpClient.put( `${AppInjector.get(DoubtfireConstants).API_URL}/tasks/${this.id}/similarity/${match}`, @@ -892,13 +891,15 @@ export class Task extends Entity { modal.result.then( // Grade was selected (modal closed with result) - (response) => {}, + (_response) => { + /* empty */ + }, // Grade was not selected (modal was dismissed) (_dismissed) => { if (!isTestSubmission) { this.status = oldStatus; } - const alerts: any = AppInjector.get(AlertService); + const alerts: AlertService = AppInjector.get(AlertService); alerts.message('Submission cancelled. Status was reverted.', 6000); }, ); @@ -1033,7 +1034,7 @@ export class Task extends Entity { options, ) .subscribe({ - next: (response) => { + next: (_response) => { if (!hasId && this.id > 0) { this.project.taskCache.delete(this.definition.abbreviation); this.project.taskCache.add(this); @@ -1112,7 +1113,7 @@ export class Task extends Entity { const http = AppInjector.get(HttpClient); http.post(`${AppInjector.get(DoubtfireConstants).API_URL}/tasks/${this.id}/pin`, {}).subscribe({ - next: (data) => { + next: (_data) => { this.pinned = true; onSuccess?.(); }, diff --git a/src/app/api/models/tii-action.ts b/src/app/api/models/tii-action.ts index 661ba9324f..75afd42516 100644 --- a/src/app/api/models/tii-action.ts +++ b/src/app/api/models/tii-action.ts @@ -1,6 +1,4 @@ -import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; -import {Observable} from 'rxjs'; -import {Unit} from './doubtfire-model'; +import {Entity} from 'ngx-entity-service'; export class TiiAction extends Entity { id: number; diff --git a/src/app/api/models/tutorial-enrolment.ts b/src/app/api/models/tutorial-enrolment.ts index 2b6f822405..9af8408c51 100644 --- a/src/app/api/models/tutorial-enrolment.ts +++ b/src/app/api/models/tutorial-enrolment.ts @@ -1,5 +1,5 @@ import {Entity} from 'ngx-entity-service'; -import {Tutorial, User} from './doubtfire-model'; +import {Tutorial} from './doubtfire-model'; export class TutorialEnrolment extends Entity { public tutorial: Tutorial; diff --git a/src/app/api/models/tutorial-stream/tutorial-stream.ts b/src/app/api/models/tutorial-stream/tutorial-stream.ts index b1ef5ad77d..2ba8c4db36 100644 --- a/src/app/api/models/tutorial-stream/tutorial-stream.ts +++ b/src/app/api/models/tutorial-stream/tutorial-stream.ts @@ -1,5 +1,5 @@ import {Entity} from 'ngx-entity-service'; -import {Unit, Tutorial} from '../doubtfire-model'; +import {Tutorial, Unit} from '../doubtfire-model'; export class TutorialStream extends Entity { name: string; diff --git a/src/app/api/models/tutorial/tutorial.ts b/src/app/api/models/tutorial/tutorial.ts index 0ef41a464d..b4cf26785d 100644 --- a/src/app/api/models/tutorial/tutorial.ts +++ b/src/app/api/models/tutorial/tutorial.ts @@ -1,12 +1,5 @@ import {Entity, EntityMapping} from 'ngx-entity-service'; -import {AppInjector} from '../../../app-injector'; -import { - User, - Campus, - UserService, - CampusService, - TutorialStream, -} from 'src/app/api/models/doubtfire-model'; +import {Campus, TutorialStream, User} from 'src/app/api/models/doubtfire-model'; import {Unit} from '../unit'; export class Tutorial extends Entity { diff --git a/src/app/api/models/unit-role.ts b/src/app/api/models/unit-role.ts index 967d542381..1436c96847 100644 --- a/src/app/api/models/unit-role.ts +++ b/src/app/api/models/unit-role.ts @@ -1,5 +1,5 @@ import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; -import {User, Unit} from './doubtfire-model'; +import {Unit, User} from './doubtfire-model'; import {TutorNote} from './tutor-note'; /** diff --git a/src/app/api/models/unit.ts b/src/app/api/models/unit.ts index 55dd4275ea..a976538d4f 100644 --- a/src/app/api/models/unit.ts +++ b/src/app/api/models/unit.ts @@ -1,10 +1,10 @@ -import {HttpClient, HttpParams} from '@angular/common/http'; import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; import {Observable, tap} from 'rxjs'; import {AppInjector} from 'src/app/app-injector'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {HttpClient, HttpParams} from '@angular/common/http'; import {GroupService} from '../services/group.service'; import {MarkingSessionService} from '../services/marking-session.service'; import {ProjectService} from '../services/project.service'; @@ -101,8 +101,6 @@ export class Unit extends Entity { readonly studentCache: EntityCache = new EntityCache(); - analytics: {} = {}; - public override toJson( mappingData: EntityMapping, ignoreKeys?: string[], @@ -220,7 +218,7 @@ export class Unit extends Entity { taskDefinitionService .delete({unitId: this.id, id: taskDef.id}, {cache: this.taskDefinitionCache, entity: taskDef}) .subscribe({ - next: (response) => { + next: () => { alerts.success('Task Deleted', 2000); }, error: (message) => alerts.error(message, 6000), @@ -447,7 +445,7 @@ export class Unit extends Entity { return `${AppInjector.get(DoubtfireConstants).API_URL}/units/${this.id}/grades/csv`; } - public taskStatusFactor(td: TaskDefinition): number { + public taskStatusFactor(_td: TaskDefinition): number { return 1; } diff --git a/src/app/api/models/user/user.ts b/src/app/api/models/user/user.ts index b11826505a..f157d80b03 100644 --- a/src/app/api/models/user/user.ts +++ b/src/app/api/models/user/user.ts @@ -1,9 +1,8 @@ -import {HttpClient} from '@angular/common/http'; import {Entity, EntityMapping} from 'ngx-entity-service'; import {Observable, map} from 'rxjs'; import {AppInjector} from 'src/app/app-injector'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; -import {AuthenticationService} from '../doubtfire-model'; +import {HttpClient} from '@angular/common/http'; export type Tutor = User; diff --git a/src/app/api/services/activity-type.service.ts b/src/app/api/services/activity-type.service.ts index 628acde622..3b39e4ac2c 100644 --- a/src/app/api/services/activity-type.service.ts +++ b/src/app/api/services/activity-type.service.ts @@ -1,8 +1,8 @@ -import {ActivityType} from 'src/app/api/models/doubtfire-model'; -import {Injectable} from '@angular/core'; import {CachedEntityService} from 'ngx-entity-service'; +import {ActivityType} from 'src/app/api/models/doubtfire-model'; import API_URL from 'src/app/config/constants/apiUrl'; import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; @Injectable() export class ActivityTypeService extends CachedEntityService { @@ -16,7 +16,7 @@ export class ActivityTypeService extends CachedEntityService { this.mapping.mapAllKeysToJsonExcept('id'); } - public createInstanceFrom(json: object, other?: any): ActivityType { + public createInstanceFrom(_json: object): ActivityType { return new ActivityType(); } } diff --git a/src/app/api/services/authentication.service.ts b/src/app/api/services/authentication.service.ts index ce19ab7178..0020c89ae3 100644 --- a/src/app/api/services/authentication.service.ts +++ b/src/app/api/services/authentication.service.ts @@ -1,12 +1,12 @@ -import {HttpClient} from '@angular/common/http'; -import {Injectable} from '@angular/core'; -import {Router} from '@angular/router'; -import {AsyncSubject, catchError, map, Observable, throwError} from 'rxjs'; +import {AsyncSubject, Observable, catchError, map, throwError} from 'rxjs'; import {User, UserService} from 'src/app/api/models/doubtfire-model'; import {AppInjector} from 'src/app/app-injector'; import {AlertService} from 'src/app/common/services/alert.service'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global-state.service'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {Router} from '@angular/router'; /** * The format for the data returned from the auth api. diff --git a/src/app/api/services/campus.service.ts b/src/app/api/services/campus.service.ts index d46d793cc3..5ec6e65c48 100644 --- a/src/app/api/services/campus.service.ts +++ b/src/app/api/services/campus.service.ts @@ -1,8 +1,8 @@ -import {Campus} from 'src/app/api/models/doubtfire-model'; -import {Injectable} from '@angular/core'; import {CachedEntityService} from 'ngx-entity-service'; -import {HttpClient} from '@angular/common/http'; +import {Campus} from 'src/app/api/models/doubtfire-model'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; @Injectable() export class CampusService extends CachedEntityService { @@ -16,7 +16,7 @@ export class CampusService extends CachedEntityService { this.mapping.mapAllKeysToJsonExcept('id'); } - public createInstanceFrom(json: object, other?: any): Campus { + public createInstanceFrom(_json: object): Campus { return new Campus(); } } diff --git a/src/app/api/services/discussion-prompt.service.ts b/src/app/api/services/discussion-prompt.service.ts index c102fbcbf1..482c80dfe8 100644 --- a/src/app/api/services/discussion-prompt.service.ts +++ b/src/app/api/services/discussion-prompt.service.ts @@ -1,5 +1,3 @@ -import {HttpClient} from '@angular/common/http'; -import {Injectable} from '@angular/core'; import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; import {Observable} from 'rxjs'; import { @@ -10,6 +8,8 @@ import { UserService, } from 'src/app/api/models/doubtfire-model'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; import {DiscussionPrompt} from '../models/discussion-prompt'; @Injectable() @@ -57,7 +57,7 @@ export class DiscussionPromptService extends CachedEntityService { + toJsonFn: (entity: DiscussionPrompt, _key: string) => { return entity.taskDefinition?.id; }, }, diff --git a/src/app/api/services/feedback-template.service.ts b/src/app/api/services/feedback-template.service.ts index 54d981d56b..7d9e110031 100644 --- a/src/app/api/services/feedback-template.service.ts +++ b/src/app/api/services/feedback-template.service.ts @@ -1,8 +1,8 @@ -import {Injectable} from '@angular/core'; import {CachedEntityService} from 'ngx-entity-service'; -import {FeedbackTemplate} from '../models/feedback-template'; -import {HttpClient} from '@angular/common/http'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {FeedbackTemplate} from '../models/feedback-template'; @Injectable() export class FeedbackTemplateService extends CachedEntityService { @@ -29,7 +29,7 @@ export class FeedbackTemplateService extends CachedEntityService { @@ -24,7 +24,7 @@ export class GroupSetService extends CachedEntityService { this.mapping.mapAllKeysToJsonExcept('id'); } - public createInstanceFrom(json: object, other?: any): GroupSet { - return new GroupSet(other as Unit); + public createInstanceFrom(_json: object, other?: Unit): GroupSet { + return new GroupSet(other); } } diff --git a/src/app/api/services/group.service.ts b/src/app/api/services/group.service.ts index c9a7435828..6bc73d95db 100644 --- a/src/app/api/services/group.service.ts +++ b/src/app/api/services/group.service.ts @@ -1,8 +1,8 @@ import {CachedEntityService} from 'ngx-entity-service'; import {Group, Unit} from 'src/app/api/models/doubtfire-model'; -import {Injectable} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; @Injectable() export class GroupService extends CachedEntityService { @@ -28,7 +28,7 @@ export class GroupService extends CachedEntityService { toEntityFn: (data: object, jsonKey: string, grp: Group) => { return grp.unit.tutorialsCache.get(data[jsonKey]); }, - toJsonFn: (group: Group, key: string) => { + toJsonFn: (group: Group, _key: string) => { return group.tutorial.id; }, }, @@ -37,7 +37,7 @@ export class GroupService extends CachedEntityService { this.mapping.mapAllKeysToJsonExcept('id', 'groupSet', 'studentCount'); } - public createInstanceFrom(json: object, other?: any): Group { - return new Group(other as Unit); + public createInstanceFrom(_json: object, other?: Unit): Group { + return new Group(other); } } diff --git a/src/app/api/services/learning-outcome.service.ts b/src/app/api/services/learning-outcome.service.ts index 2c4d6181c8..24377596c0 100644 --- a/src/app/api/services/learning-outcome.service.ts +++ b/src/app/api/services/learning-outcome.service.ts @@ -1,8 +1,8 @@ import {CachedEntityService} from 'ngx-entity-service'; import {LearningOutcome} from 'src/app/api/models/doubtfire-model'; -import {Injectable} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; @Injectable() export class LearningOutcomeService extends CachedEntityService { @@ -27,7 +27,7 @@ export class LearningOutcomeService extends CachedEntityService this.mapping.mapAllKeysToJsonExcept('id', 'context'); } - public createInstanceFrom(json: object, other?: any): LearningOutcome { + public createInstanceFrom(_json: object): LearningOutcome { return new LearningOutcome(); } } diff --git a/src/app/api/services/lti.service.ts b/src/app/api/services/lti.service.ts index f4d7004ec7..b0f62ef09a 100644 --- a/src/app/api/services/lti.service.ts +++ b/src/app/api/services/lti.service.ts @@ -1,16 +1,16 @@ -import {HttpClient} from '@angular/common/http'; -import {Injectable} from '@angular/core'; import {Observable} from 'rxjs'; +import {CsvResult} from 'src/app/common/modals/csv-result-modal/csv-result-modal.service'; import LTI_API_URL from 'src/app/config/constants/ltiApiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; import {Project} from '../models/project'; import {SidekiqJob} from '../models/sidekiq-job'; -import {CsvResult} from 'src/app/common/modals/csv-result-modal/csv-result-modal.service'; interface info { name?: string; email?: string; roles?: string[]; - custom?: any; + custom?: Record; context?: | { id?: string; @@ -35,6 +35,19 @@ export interface UnitLink { unitId: string; } +export interface LtiMembers { + members: LtiMember[]; +} + +export interface LtiMember { + email: string; + family_name: string; + given_name: string; + name: string; + user_id: string; + roles: string[]; +} + @Injectable() export class LtiService { constructor(private httpClient: HttpClient) {} @@ -59,8 +72,8 @@ export class LtiService { return this.httpClient.post(`${LTI_API_URL}/enrol`, unit); } - public getMembers(): Observable { - return this.httpClient.get(`${LTI_API_URL}/members`); + public getMembers(): Observable { + return this.httpClient.get(`${LTI_API_URL}/members`); } // Sync grades for all members in the context (course) diff --git a/src/app/api/services/marking-session.service.ts b/src/app/api/services/marking-session.service.ts index a621dfa5f0..5c67dd5f80 100644 --- a/src/app/api/services/marking-session.service.ts +++ b/src/app/api/services/marking-session.service.ts @@ -1,8 +1,8 @@ -import {HttpClient} from '@angular/common/http'; -import {Injectable} from '@angular/core'; import {CachedEntityService} from 'ngx-entity-service'; import {Unit} from 'src/app/api/models/doubtfire-model'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; import {MarkingSession} from '../models/marking-session'; @Injectable() diff --git a/src/app/api/services/overseer-assessment.service.ts b/src/app/api/services/overseer-assessment.service.ts index 82c41e3dbc..aa60a2ff50 100644 --- a/src/app/api/services/overseer-assessment.service.ts +++ b/src/app/api/services/overseer-assessment.service.ts @@ -1,10 +1,10 @@ -import {Injectable} from '@angular/core'; import {EntityService} from 'ngx-entity-service'; import {Observable} from 'rxjs'; -import {HttpClient} from '@angular/common/http'; import API_URL from 'src/app/config/constants/apiUrl'; -import {OverseerAssessment} from '../models/overseer/overseer-assessment'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; import {Task} from '../models/doubtfire-model'; +import {OverseerAssessment} from '../models/overseer/overseer-assessment'; import {OverseerStepResultService} from './overseer-step-result.service'; @Injectable() @@ -30,7 +30,7 @@ export class OverseerAssessmentService extends EntityService ['submissionStatus', 'status'], { keys: ['timestamp', 'submission_timestamp'], - toEntityFn: (data, key, entity, params?) => { + toEntityFn: (data, _key, _entity, _params?) => { return new Date(data['submission_timestamp'] * 1000); }, }, @@ -57,7 +57,7 @@ export class OverseerAssessmentService extends EntityService ); } - public createInstanceFrom(json: any, other?: any): OverseerAssessment { + public createInstanceFrom(_json: object, other?: Task): OverseerAssessment { return new OverseerAssessment(other); } diff --git a/src/app/api/services/overseer-image.service.ts b/src/app/api/services/overseer-image.service.ts index 7edc65932f..a282288160 100644 --- a/src/app/api/services/overseer-image.service.ts +++ b/src/app/api/services/overseer-image.service.ts @@ -1,9 +1,9 @@ import {CachedEntityService} from 'ngx-entity-service'; -import {Observable, switchMap} from 'rxjs'; +import {Observable} from 'rxjs'; import {OverseerImage} from 'src/app/api/models/doubtfire-model'; -import {Injectable} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; import {SidekiqJob} from '../models/sidekiq-job'; @Injectable() @@ -32,7 +32,7 @@ export class OverseerImageService extends CachedEntityService { }); } - public createInstanceFrom(json: object, other?: any): OverseerImage { + public createInstanceFrom(_json: object): OverseerImage { return new OverseerImage(); } } diff --git a/src/app/api/services/overseer-step-result.service.ts b/src/app/api/services/overseer-step-result.service.ts index f7e873281b..d3f3c99009 100644 --- a/src/app/api/services/overseer-step-result.service.ts +++ b/src/app/api/services/overseer-step-result.service.ts @@ -1,10 +1,10 @@ -import {HttpClient} from '@angular/common/http'; -import {Injectable} from '@angular/core'; import {CachedEntityService} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; import {OverseerAssessment} from '../models/doubtfire-model'; import {OverseerStepResult} from '../models/overseer/overseer-step-result'; -import {Observable} from 'rxjs'; @Injectable() export class OverseerStepResultService extends CachedEntityService { @@ -31,8 +31,8 @@ export class OverseerStepResultService extends CachedEntityService { diff --git a/src/app/api/services/overseer-step.service.ts b/src/app/api/services/overseer-step.service.ts index 3d8a8fca9a..90a1ad70d7 100644 --- a/src/app/api/services/overseer-step.service.ts +++ b/src/app/api/services/overseer-step.service.ts @@ -1,7 +1,7 @@ -import {HttpClient} from '@angular/common/http'; -import {Injectable} from '@angular/core'; import {CachedEntityService} from 'ngx-entity-service'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; import {OverseerStep} from '../models/overseer/overseer-step'; import {TaskDefinition} from '../models/task-definition'; @@ -23,7 +23,7 @@ export class OverseerStepService extends CachedEntityService { // 'runCommand', { keys: 'runCommand', - toEntityFn: (data: object, key: string, entity: OverseerStep, params?: any) => { + toEntityFn: (data: object, key: string, entity: OverseerStep) => { const raw = data['run_command']; if (raw?.startsWith('b64:')) { entity.decodedRunCommand = atob(raw.slice(4)); @@ -54,7 +54,7 @@ export class OverseerStepService extends CachedEntityService { this.mapping.mapAllKeysToJsonExcept('id'); } - public createInstanceFrom(json: object, other?: any): OverseerStep { - return new OverseerStep(other as TaskDefinition); + public createInstanceFrom(_json: object, other?: TaskDefinition): OverseerStep { + return new OverseerStep(other); } } diff --git a/src/app/api/services/project.service.ts b/src/app/api/services/project.service.ts index 3a99563192..aee67e8c87 100644 --- a/src/app/api/services/project.service.ts +++ b/src/app/api/services/project.service.ts @@ -1,4 +1,5 @@ import {CachedEntityService, MappingProcess, RequestOptions} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; import { CampusService, Project, @@ -6,14 +7,13 @@ import { UnitService, UserService, } from 'src/app/api/models/doubtfire-model'; -import {Injectable} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiUrl'; import {AppInjector} from 'src/app/app-injector'; -import {Observable} from 'rxjs'; -import {TaskService} from './task.service'; -import {TaskOutcomeAlignmentService} from './task-outcome-alignment.service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; import {GroupService} from './group.service'; +import {TaskOutcomeAlignmentService} from './task-outcome-alignment.service'; +import {TaskService} from './task.service'; @Injectable() export class ProjectService extends CachedEntityService { @@ -36,20 +36,20 @@ export class ProjectService extends CachedEntityService { 'id', { keys: ['campus', 'campus_id'], - toEntityOp: (data: object, key: string, entity: Project, params?: any) => { + toEntityOp: (data: object, key: string, entity: Project) => { if (data['campus_id']) { return this.campusService.get(data['campus_id']).subscribe((campus) => { entity.campus = campus; }); } }, - toJsonFn: (entity: Project, key: string) => { + toJsonFn: (entity: Project, _key: string) => { return entity.campus ? entity.campus.id : entity.originalJson['camput_id'] ? -1 : null; }, }, { keys: 'student', - toEntityFn: (data: object, key: string, entity: Project, params?: any) => { + toEntityFn: (data: object) => { const userData = data['student']; return this.userService.cache.getOrCreate(userData.id, this.userService, userData); @@ -57,7 +57,7 @@ export class ProjectService extends CachedEntityService { }, { keys: 'userId', - toEntityOp: (data: object, key: string, entity: Project, params?: any) => { + toEntityOp: (data: object, key: string, entity: Project) => { const userId = data['user_id']; this.userService.get(userId).subscribe({ @@ -77,7 +77,7 @@ export class ProjectService extends CachedEntityService { 'staffNoteCount', { keys: 'hasPortfolio', - toEntityFn: (data: object, key: string, entity: Project, params?: any) => { + toEntityFn: (data: object, key: string, entity: Project) => { const result = data[key] === true; if (result) entity.portfolioStatus = 1; @@ -91,7 +91,7 @@ export class ProjectService extends CachedEntityService { 'usesDraftLearningSummary', { keys: ['taskStats', 'stats'], - toEntityOp: (data: object, key: string, entity: Project, params?: any) => { + toEntityOp: (data: object, key: string, entity: Project) => { const values = data[key]; entity.taskStats = [ { @@ -123,14 +123,14 @@ export class ProjectService extends CachedEntityService { 'gradeRationale', { keys: 'unit', - toEntityFn: (data: object, key: string, entity: Project, params?: any) => { + toEntityFn: (data: object, key: string, entity: Project) => { const unitService: UnitService = AppInjector.get(UnitService); const unitData = data['unit']; const result = unitService.cache.getOrCreate(unitData.id, unitService, unitData); result.studentCache.add(entity); return result; }, - toJsonFn: (entity: Project, key: string) => { + toJsonFn: (entity: Project, _key: string) => { return entity.unit?.id; }, }, @@ -150,7 +150,7 @@ export class ProjectService extends CachedEntityService { }, { keys: 'tutorialEnrolments', - toEntityOp: (data: object, key: string, project: Project, params?: any) => { + toEntityOp: (data: object, key: string, project: Project) => { const unit: Unit = project.unit; data[key]?.forEach((tutorialEnrolment: {tutorial_id: number}) => { if (tutorialEnrolment.tutorial_id) { @@ -162,7 +162,7 @@ export class ProjectService extends CachedEntityService { }, { keys: 'groups', - toEntityOp: (data: object, key: string, project: Project, params?: any) => { + toEntityOp: (data: object, key: string, project: Project) => { data[key]?.forEach((group) => { const theGroup = project.unit.groupSetsCache .get(group.group_set_id) @@ -174,13 +174,13 @@ export class ProjectService extends CachedEntityService { theGroup.projectsCache.add(project); }); }, - toJsonFn: (entity: Project, key: string) => { + toJsonFn: (entity: Project, _key: string) => { return entity.unit?.id; }, }, { keys: 'tasks', - toEntityOp: (data: object, key: string, project: Project, params?: any) => { + toEntityOp: (data: object, key: string, project: Project) => { // create tasks from json data['tasks']?.forEach((taskData) => { project.taskCache.getOrCreate(taskData['id'], this.taskService, taskData, { @@ -193,7 +193,7 @@ export class ProjectService extends CachedEntityService { }, { keys: 'taskOutcomeAlignments', - toEntityOp: (data: object, key: string, project: Project, params?: any) => { + toEntityOp: (data: object, key: string, project: Project) => { data[key]?.forEach((alignment) => { project.taskOutcomeAlignmentsCache.getOrCreate( alignment['id'], @@ -221,8 +221,8 @@ export class ProjectService extends CachedEntityService { ); } - public createInstanceFrom(json: object, other?: any): Project { - return new Project(other as Unit); + public createInstanceFrom(_json: object, other?: Unit): Project { + return new Project(other); } public loadStudents( diff --git a/src/app/api/services/scorm-adapter.service.ts b/src/app/api/services/scorm-adapter.service.ts index bdeb14fc77..5cb1fd717d 100644 --- a/src/app/api/services/scorm-adapter.service.ts +++ b/src/app/api/services/scorm-adapter.service.ts @@ -1,7 +1,7 @@ +import {ScormDataModel, ScormPlayerContext} from 'src/app/api/models/doubtfire-model'; +import API_URL from 'src/app/config/constants/apiUrl'; import {Injectable} from '@angular/core'; import {UserService} from './user.service'; -import API_URL from 'src/app/config/constants/apiUrl'; -import {ScormDataModel, ScormPlayerContext} from 'src/app/api/models/doubtfire-model'; @Injectable({ providedIn: 'root', @@ -200,7 +200,7 @@ export class ScormAdapterService { return value; } - SetValue(element: string, value: any): string { + SetValue(element: string, value: string): string { // console.log(`API_1484_11: SetValue:`, element, value); // TODO: error reporting @@ -275,7 +275,7 @@ export class ScormAdapterService { return errorString; } - GetDiagnostic(errorCode: string): string { + GetDiagnostic(_errorCode: string): string { // TODO: implement this // console.log(`API_1484_11: GetDiagnostic:`, errorCode); return 'GetDiagnostic is currently not implemented'; diff --git a/src/app/api/services/sidekiq-job.service.ts b/src/app/api/services/sidekiq-job.service.ts index 8a61e01b55..e103ad4258 100644 --- a/src/app/api/services/sidekiq-job.service.ts +++ b/src/app/api/services/sidekiq-job.service.ts @@ -1,8 +1,8 @@ -import {HttpClient} from '@angular/common/http'; -import {Injectable} from '@angular/core'; import {CachedEntityService} from 'ngx-entity-service'; import {BehaviorSubject, Observable, Subject} from 'rxjs'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; import {SidekiqJob} from '../models/sidekiq-job'; export interface SidekiqJobEntry { @@ -15,10 +15,10 @@ export interface SidekiqJobEntry { export class SidekiqJobService extends CachedEntityService { protected readonly endpointFormat = 'sidekiq/:id:'; - public jobEntries = new Map(); + public jobEntries: Map = new Map(); // Allow components to track changes to jobEntries - public sidekiqJobsSubject = new BehaviorSubject([]); + public sidekiqJobsSubject: BehaviorSubject = new BehaviorSubject([]); public setJob(jobId: string, title: string, subject: Subject, job?: SidekiqJob) { this.jobEntries.set(jobId, { diff --git a/src/app/api/services/spec/campus.service.spec.ts b/src/app/api/services/spec/campus.service.spec.ts index a91b8c7685..9ac6fc32fe 100644 --- a/src/app/api/services/spec/campus.service.spec.ts +++ b/src/app/api/services/spec/campus.service.spec.ts @@ -1,8 +1,8 @@ -import { TestBed, tick, fakeAsync } from '@angular/core/testing'; -import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; -import { Campus } from 'src/app/api/models/doubtfire-model'; -import { CampusService } from '../campus.service'; -import { HttpRequest, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import {Campus} from 'src/app/api/models/doubtfire-model'; +import {HttpRequest, provideHttpClient, withInterceptorsFromDi} from '@angular/common/http'; +import {HttpTestingController, provideHttpClientTesting} from '@angular/common/http/testing'; +import {TestBed, fakeAsync, tick} from '@angular/core/testing'; +import {CampusService} from '../campus.service'; describe('CampusService', () => { let campusService: CampusService; @@ -10,9 +10,13 @@ describe('CampusService', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [], - providers: [CampusService, provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] -}); + imports: [], + providers: [ + CampusService, + provideHttpClient(withInterceptorsFromDi()), + provideHttpClientTesting(), + ], + }); campusService = TestBed.inject(CampusService); httpMock = TestBed.inject(HttpTestingController); @@ -31,9 +35,11 @@ describe('CampusService', () => { const expectedCampuses: Campus[] = [c]; - campusService.query().subscribe((campuses) => expect(campuses).toEqual(expectedCampuses, 'expected campuses')); + campusService + .query() + .subscribe((campuses) => expect(campuses).toEqual(expectedCampuses, 'expected campuses')); - const req = httpMock.expectOne((request: HttpRequest): boolean => { + const req = httpMock.expectOne((request: HttpRequest): boolean => { expect(request.url).toEqual('http://localhost:3000/api/campuses/'); expect(request.method).toBe('GET'); return true; diff --git a/src/app/api/services/spec/user.service.spec.ts b/src/app/api/services/spec/user.service.spec.ts index 2d5272b7a4..9d0fc0b774 100644 --- a/src/app/api/services/spec/user.service.spec.ts +++ b/src/app/api/services/spec/user.service.spec.ts @@ -1,7 +1,7 @@ -import { TestBed, tick, fakeAsync } from '@angular/core/testing'; -import { HttpTestingController, provideHttpClientTesting } from '@angular/common/http/testing'; -import { User, UserService } from 'src/app/api/models/doubtfire-model'; -import { HttpRequest, provideHttpClient, withInterceptorsFromDi } from '@angular/common/http'; +import {User, UserService} from 'src/app/api/models/doubtfire-model'; +import {HttpRequest, provideHttpClient, withInterceptorsFromDi} from '@angular/common/http'; +import {HttpTestingController, provideHttpClientTesting} from '@angular/common/http/testing'; +import {TestBed, fakeAsync, tick} from '@angular/core/testing'; describe('UserService', () => { let userService: UserService; @@ -9,9 +9,13 @@ describe('UserService', () => { beforeEach(() => { TestBed.configureTestingModule({ - imports: [], - providers: [UserService, provideHttpClient(withInterceptorsFromDi()), provideHttpClientTesting()] -}); + imports: [], + providers: [ + UserService, + provideHttpClient(withInterceptorsFromDi()), + provideHttpClientTesting(), + ], + }); userService = TestBed.inject(UserService); httpMock = TestBed.inject(HttpTestingController); @@ -38,9 +42,11 @@ describe('UserService', () => { const expectedUsers: User[] = [u]; - userService.query().subscribe((users) => expect(users).toEqual(expectedUsers, 'expected users')); + userService + .query() + .subscribe((users) => expect(users).toEqual(expectedUsers, 'expected users')); - const req = httpMock.expectOne((request: HttpRequest): boolean => { + const req = httpMock.expectOne((request: HttpRequest): boolean => { expect(request.url).toEqual('http://localhost:3000/api/users/'); expect(request.method).toBe('GET'); return true; @@ -71,7 +77,7 @@ describe('UserService', () => { const expectedUser = user; expectedUser.id = 1; - const req = httpMock.expectOne((request: HttpRequest): boolean => { + const req = httpMock.expectOne((request: HttpRequest): boolean => { expect(request.url).toEqual('http://localhost:3000/api/users/'); expect(request.method).toBe('POST'); @@ -120,7 +126,7 @@ describe('UserService', () => { expect(result.firstName).toBe(u.firstName); }, fail); - let req = httpMock.expectOne((request: HttpRequest): boolean => { + let req = httpMock.expectOne((request: HttpRequest): boolean => { expect(request.url).toEqual('http://localhost:3000/api/users/1'); expect(request.method).toBe('PUT'); return true; @@ -136,7 +142,7 @@ describe('UserService', () => { error: fail, }); - req = httpMock.expectOne((request: HttpRequest): boolean => { + req = httpMock.expectOne((request: HttpRequest): boolean => { expect(request.url).toEqual('http://localhost:3000/api/users/1'); expect(request.method).toBe('PUT'); return true; @@ -161,9 +167,9 @@ describe('UserService', () => { user.receiveFeedbackNotifications = false; user.receiveTaskNotifications = false; - userService.get(1).subscribe((data) => {}); + userService.get(1).subscribe(); - const req = httpMock.expectOne((request: HttpRequest): boolean => { + const req = httpMock.expectOne((request: HttpRequest): boolean => { expect(request.url).toEqual('http://localhost:3000/api/users/1'); expect(request.method).toBe('GET'); return true; @@ -173,9 +179,9 @@ describe('UserService', () => { req.flush(user2); tick(); - userService.get(1).subscribe((data) => {}); + userService.get(1).subscribe(); - httpMock.expectNone((request: HttpRequest): boolean => { + httpMock.expectNone((_request: HttpRequest): boolean => { return true; }); tick(); @@ -201,7 +207,7 @@ describe('UserService', () => { user = data; }); - let req = httpMock.expectOne((request: HttpRequest): boolean => { + let req = httpMock.expectOne((request: HttpRequest): boolean => { expect(request.url).toEqual('http://localhost:3000/api/users/1'); expect(request.method).toBe('GET'); return true; @@ -213,7 +219,7 @@ describe('UserService', () => { req.flush(user2); tick(); - let user3; + let _user3; // 1 request here userService.fetch(1).subscribe((data) => { @@ -221,7 +227,7 @@ describe('UserService', () => { user3 = data; }); - req = httpMock.expectOne((request: HttpRequest): boolean => { + req = httpMock.expectOne((request: HttpRequest): boolean => { expect(request.url).toEqual('http://localhost:3000/api/users/1'); expect(request.method).toBe('GET'); return true; @@ -232,7 +238,7 @@ describe('UserService', () => { user4.firstName = 'fred'; req.flush(user4); - httpMock.expectNone((request: HttpRequest): boolean => { + httpMock.expectNone((_request: HttpRequest): boolean => { return true; }); tick(); diff --git a/src/app/api/services/staff-note.service.ts b/src/app/api/services/staff-note.service.ts index 6e989e17f3..decb75316e 100644 --- a/src/app/api/services/staff-note.service.ts +++ b/src/app/api/services/staff-note.service.ts @@ -1,14 +1,14 @@ -import {HttpClient} from '@angular/common/http'; -import {EventEmitter, Injectable} from '@angular/core'; import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; +import {Observable, tap} from 'rxjs'; import {Project, ProjectService, UserService} from 'src/app/api/models/doubtfire-model'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {EventEmitter, Injectable} from '@angular/core'; import {StaffNote} from '../models/staff-note'; -import {Observable, tap} from 'rxjs'; @Injectable() export class StaffNoteService extends CachedEntityService { - public readonly staffNoteAdded$ = new EventEmitter(); + public readonly staffNoteAdded$: EventEmitter = new EventEmitter(); protected readonly endpointFormat = 'projects/:projectId:/staff_notes/:id:'; diff --git a/src/app/api/services/task-comment.service.ts b/src/app/api/services/task-comment.service.ts index 8e49f12cc8..ca29cacc91 100644 --- a/src/app/api/services/task-comment.service.ts +++ b/src/app/api/services/task-comment.service.ts @@ -1,3 +1,5 @@ +import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; import { ScormComment, Task, @@ -5,22 +7,20 @@ import { TestAttemptService, UserService, } from 'src/app/api/models/doubtfire-model'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {EmojiService} from 'src/app/common/services/emoji.service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; import {EventEmitter, Injectable} from '@angular/core'; -import {Observable} from 'rxjs'; import {tap} from 'rxjs/operators'; -import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; import {DiscussionComment} from '../models/task-comment/discussion-comment'; import {ExtensionComment} from '../models/task-comment/extension-comment'; -import {HttpClient} from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiUrl'; -import {EmojiService} from 'src/app/common/services/emoji.service'; -import {MappingFunctions} from './mapping-fn'; -import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; import {ScormExtensionComment} from '../models/task-comment/scorm-extension-comment'; +import {MappingFunctions} from './mapping-fn'; @Injectable() export class TaskCommentService extends CachedEntityService { - public readonly commentAdded$ = new EventEmitter(); + public readonly commentAdded$: EventEmitter = new EventEmitter(); private readonly commentEndpointFormat = 'projects/:projectId:/task_def_id/:taskDefinitionId:/comments/:id:'; @@ -62,7 +62,7 @@ export class TaskCommentService extends CachedEntityService { }, { keys: 'recipient', - toEntityFn: (data: object, key: string, comment: TaskComment) => { + toEntityFn: (data: object, key: string, _comment: TaskComment) => { return this.userService.cache.getOrCreate(data[key]?.id, userService, data[key]); }, }, @@ -71,7 +71,7 @@ export class TaskCommentService extends CachedEntityService { 'isNew', { keys: ['text', 'comment'], - toEntityFn: (data, key, entity) => { + toEntityFn: (data, _key, _entity) => { return this.emojiService.colonsToNative(data['comment']); }, }, @@ -132,7 +132,7 @@ export class TaskCommentService extends CachedEntityService { /** * Create a Task Comment - use the type to determine the exact object type to return. */ - public createInstanceFrom(json: any, other?: any): TaskComment { + public createInstanceFrom(json: {type?: string}, other?: Task): TaskComment { switch (json.type) { case 'discussion': return new DiscussionComment(other); @@ -160,9 +160,9 @@ export class TaskCommentService extends CachedEntityService { options?: RequestOptions, ): Observable { return super.query(pathIds, options).pipe( - tap((result) => { + tap((_result) => { // Access the task and set the number of new comments to 0 - they are now read on the server - const task = other as any; //TODO: change to Task object + const task = other as Task; task.numNewComments = 0; }), ); @@ -257,7 +257,7 @@ export class TaskCommentService extends CachedEntityService { public requestExtension( reason: string, weeksRequested: number, - task: any, + task: Task, ): Observable { const opts: RequestOptions = { endpointFormat: this.requestExtensionEndpointFormat, @@ -292,7 +292,7 @@ export class TaskCommentService extends CachedEntityService { ); } - public requestScormExtension(reason: string, task: any): Observable { + public requestScormExtension(reason: string, task: Task): Observable { const opts: RequestOptions = { endpointFormat: this.scormRequestExtensionEndpointFormat, body: { diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index 7591ae3f66..3badfc2a56 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -1,21 +1,21 @@ import {CachedEntityService} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; import { LearningOutcomeService, TaskDefinition, TaskStatusEnum, Unit, } from 'src/app/api/models/doubtfire-model'; -import {Injectable} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiUrl'; -import {MappingFunctions} from './mapping-fn'; import {AppInjector} from 'src/app/app-injector'; -import {Observable} from 'rxjs'; -import {TaskPrerequisiteService} from './task-prerequisite.service'; -import {TaskPrerequisite} from '../models/task-prerequisite'; +import API_URL from 'src/app/config/constants/apiUrl'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; import {SidekiqJob} from '../models/sidekiq-job'; +import {TaskPrerequisite} from '../models/task-prerequisite'; +import {MappingFunctions} from './mapping-fn'; import {OverseerStepService} from './overseer-step.service'; +import {TaskPrerequisiteService} from './task-prerequisite.service'; @Injectable() export class TaskDefinitionService extends CachedEntityService { @@ -57,7 +57,7 @@ export class TaskDefinitionService extends CachedEntityService { }, { keys: 'uploadRequirements', - toJsonFn: (taskDef: TaskDefinition, key: string) => { + toJsonFn: (taskDef: TaskDefinition, _key: string) => { return JSON.stringify( taskDef.uploadRequirements?.map((upreq) => { return { @@ -70,7 +70,7 @@ export class TaskDefinitionService extends CachedEntityService { }), ); }, - toEntityFn: (data: object, key: string, taskDef: TaskDefinition, params?: any) => { + toEntityFn: (data: object, key: string) => { return ( data[key] as { key: string; @@ -92,10 +92,10 @@ export class TaskDefinitionService extends CachedEntityService { }, { keys: ['tutorialStream', 'tutorial_stream_abbr'], - toEntityFn: (data: object, key: string, taskDef: TaskDefinition, params?: any) => { + toEntityFn: (data: object, key: string, taskDef: TaskDefinition) => { return taskDef.unit.tutorialStreamsCache.get(data[key]); }, - toJsonFn: (taskDef: TaskDefinition, key: string) => { + toJsonFn: (taskDef: TaskDefinition, _key: string) => { return taskDef.tutorialStream?.abbreviation; }, }, @@ -103,14 +103,14 @@ export class TaskDefinitionService extends CachedEntityService { 'restrictStatusUpdates', { keys: ['groupSet', 'group_set_id'], - toEntityFn: (data: object, key: string, taskDef: TaskDefinition, params?: any) => { + toEntityFn: (data: object, key: string, taskDef: TaskDefinition) => { if (data[key]) { return taskDef.unit.groupSetsCache.get(data[key]); } else { return data[key]; } }, - toJsonFn: (taskDef: TaskDefinition, key: string) => { + toJsonFn: (taskDef: TaskDefinition, _key: string) => { return taskDef.groupSet?.id; }, }, @@ -207,8 +207,8 @@ export class TaskDefinitionService extends CachedEntityService { ); } - public override createInstanceFrom(json: object, other?: any): TaskDefinition { - return new TaskDefinition(other as Unit); + public override createInstanceFrom(_json: object, other?: Unit): TaskDefinition { + return new TaskDefinition(other); } public uploadTaskSheet(taskDefinition: TaskDefinition, file: File): Observable { diff --git a/src/app/api/services/task-outcome-alignment.service.ts b/src/app/api/services/task-outcome-alignment.service.ts index 44fd1ea07f..e0a542869e 100644 --- a/src/app/api/services/task-outcome-alignment.service.ts +++ b/src/app/api/services/task-outcome-alignment.service.ts @@ -1,9 +1,8 @@ -import {HttpClient} from '@angular/common/http'; import {CachedEntityService} from 'ngx-entity-service'; import {Project, TaskOutcomeAlignment, Unit} from 'src/app/api/models/doubtfire-model'; -import {Injectable} from '@angular/core'; import API_URL from 'src/app/config/constants/apiUrl'; -import {UnitTutorialsListComponent} from 'src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; @Injectable() export class TaskOutcomeAlignmentService extends CachedEntityService { @@ -22,7 +21,7 @@ export class TaskOutcomeAlignmentService extends CachedEntityService { + toJsonFn: (entity: TaskOutcomeAlignment, _key: string) => { return entity.learningOutcome.id; }, }, @@ -32,7 +31,7 @@ export class TaskOutcomeAlignmentService extends CachedEntityService { + toJsonFn: (entity: TaskOutcomeAlignment, _key: string) => { return entity.taskDefinition.id; }, }, @@ -42,7 +41,7 @@ export class TaskOutcomeAlignmentService extends CachedEntityService { + toJsonFn: (entity: TaskOutcomeAlignment, _key: string) => { return entity.task?.id; }, }, @@ -51,7 +50,7 @@ export class TaskOutcomeAlignmentService extends CachedEntityService { @@ -20,7 +20,7 @@ export class TaskPrerequisiteService extends CachedEntityService { diff --git a/src/app/api/services/task.service.ts b/src/app/api/services/task.service.ts index f7b9bd6f61..06a59b6ce1 100644 --- a/src/app/api/services/task.service.ts +++ b/src/app/api/services/task.service.ts @@ -1,3 +1,5 @@ +import {CachedEntityService, EntityCache, RequestOptions} from 'ngx-entity-service'; +import {Observable, map, tap} from 'rxjs'; import { Project, Task, @@ -7,16 +9,14 @@ import { TaskStatusUiData, Unit, } from 'src/app/api/models/doubtfire-model'; -import {EventEmitter, Injectable} from '@angular/core'; -import {CachedEntityService, EntityCache, RequestOptions} from 'ngx-entity-service'; -import {HttpClient} from '@angular/common/http'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {EventEmitter, Injectable} from '@angular/core'; import {MappingFunctions} from './mapping-fn'; -import {Observable, map, tap} from 'rxjs'; @Injectable() export class TaskService extends CachedEntityService { - public readonly taskStatusUpdated$ = new EventEmitter(); + public readonly taskStatusUpdated$: EventEmitter = new EventEmitter(); protected readonly endpointFormat = '/projects/:projectId:/task_def_id/:taskDefId:'; @@ -33,14 +33,14 @@ export class TaskService extends CachedEntityService { 'id', { keys: 'projectId', - toEntityOp: (data: object, jsonKey: string, task: Task, _params?: any) => { + toEntityOp: (data: object, jsonKey: string, task: Task) => { // Is fetching task outside of project... task.project = task.unit.findStudent(data[jsonKey]); }, }, { keys: 'taskDefinitionId', - toEntityOp: (data: object, key: string, entity: Task, _params?: any) => { + toEntityOp: (data: object, key: string, entity: Task) => { entity.definition = entity.project.unit.taskDef(data['task_definition_id']); }, }, @@ -79,13 +79,13 @@ export class TaskService extends CachedEntityService { 'pinned', { keys: 'new_stat', - toEntityOp: (data: object, key: string, entity: Task, params?: any) => { + toEntityOp: (data: object, key: string, entity: Task) => { entity.project.taskStats = data['new_stat']; }, }, { keys: 'otherProjects', - toEntityOp: (data: object, key: string, entity: Task, params?: any) => { + toEntityOp: (data: object, key: string, entity: Task) => { data['other_projects'].forEach((details) => { const proj = entity.unit.findStudent(details.id); if (proj) { @@ -106,8 +106,8 @@ export class TaskService extends CachedEntityService { this.mapping.addJsonKey('qualityPts', 'grade', 'includeInPortfolio', 'trigger'); } - public createInstanceFrom(json: object, other?: any): Task { - return new Task(other as Project); + public createInstanceFrom(_json: object, other?: Project): Task { + return new Task(other); } public queryTasksForTaskInbox( @@ -209,7 +209,6 @@ export class TaskService extends CachedEntityService { }; this.get(pathIds, options).subscribe({ - next: (value: Task) => {}, error: (message) => { console.log(`Failed to refresh tasks ${message}`); }, diff --git a/src/app/api/services/teaching-period-break.service.ts b/src/app/api/services/teaching-period-break.service.ts index a7e3b296de..75dbae6fe1 100644 --- a/src/app/api/services/teaching-period-break.service.ts +++ b/src/app/api/services/teaching-period-break.service.ts @@ -1,8 +1,8 @@ -import {HttpClient} from '@angular/common/http'; import {CachedEntityService} from 'ngx-entity-service'; import {TeachingPeriodBreak} from 'src/app/api/models/doubtfire-model'; -import {Injectable} from '@angular/core'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; import {MappingFunctions} from './mapping-fn'; @Injectable() @@ -25,7 +25,7 @@ export class TeachingPeriodBreakService extends CachedEntityService { this.cacheBehaviourOnGet = 'cacheQuery'; } - public createInstanceFrom(json: any, other?: any): TeachingPeriod { + public createInstanceFrom(_json: object): TeachingPeriod { return new TeachingPeriod(); } } diff --git a/src/app/api/services/test-attempt.service.ts b/src/app/api/services/test-attempt.service.ts index 9b418045ec..b9e6e1e0a7 100644 --- a/src/app/api/services/test-attempt.service.ts +++ b/src/app/api/services/test-attempt.service.ts @@ -1,12 +1,12 @@ -import {Injectable} from '@angular/core'; import {CachedEntityService} from 'ngx-entity-service'; -import API_URL from 'src/app/config/constants/apiUrl'; -import {Task, TestAttempt} from 'src/app/api/models/doubtfire-model'; import {Observable} from 'rxjs'; +import {Task, TestAttempt} from 'src/app/api/models/doubtfire-model'; import {AppInjector} from 'src/app/app-injector'; -import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {AlertService} from 'src/app/common/services/alert.service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; @Injectable() export class TestAttemptService extends CachedEntityService { diff --git a/src/app/api/services/tii-action.service.ts b/src/app/api/services/tii-action.service.ts index 330a1bd147..21bfced4d9 100644 --- a/src/app/api/services/tii-action.service.ts +++ b/src/app/api/services/tii-action.service.ts @@ -1,9 +1,8 @@ +import {CachedEntityService} from 'ngx-entity-service'; +import {TiiAction} from 'src/app/api/models/doubtfire-model'; +import API_URL from 'src/app/config/constants/apiUrl'; import {HttpClient} from '@angular/common/http'; -import {CachedEntityService, Entity} from 'ngx-entity-service'; -import {TiiAction, Unit, UnitService, UserService} from 'src/app/api/models/doubtfire-model'; import {Injectable} from '@angular/core'; -import API_URL from 'src/app/config/constants/apiUrl'; -import {AppInjector} from 'src/app/app-injector'; import {MappingFunctions} from './mapping-fn'; @Injectable() @@ -36,7 +35,7 @@ export class TiiActionService extends CachedEntityService { // this.cacheBehaviourOnGet = 'cacheQuery'; } - public createInstanceFrom(json: any, other?: any): TiiAction { + public createInstanceFrom(_json: object): TiiAction { return new TiiAction(); } } diff --git a/src/app/api/services/tii.service.spec.ts b/src/app/api/services/tii.service.spec.ts index af14851920..5aefcb548c 100644 --- a/src/app/api/services/tii.service.spec.ts +++ b/src/app/api/services/tii.service.spec.ts @@ -1,6 +1,5 @@ -import { TestBed } from '@angular/core/testing'; - -import { TiiService } from './tii.service'; +import {TestBed} from '@angular/core/testing'; +import {TiiService} from './tii.service'; describe('TiiServiceService', () => { let service: TiiService; diff --git a/src/app/api/services/tii.service.ts b/src/app/api/services/tii.service.ts index 385e9eef5c..75b1d311a3 100644 --- a/src/app/api/services/tii.service.ts +++ b/src/app/api/services/tii.service.ts @@ -1,7 +1,7 @@ -import {HttpClient} from '@angular/common/http'; -import {Injectable} from '@angular/core'; import {Observable} from 'rxjs'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; @Injectable({ providedIn: 'root', diff --git a/src/app/api/services/tutor-note.service.ts b/src/app/api/services/tutor-note.service.ts index 3e08ce451d..481526b023 100644 --- a/src/app/api/services/tutor-note.service.ts +++ b/src/app/api/services/tutor-note.service.ts @@ -1,9 +1,9 @@ -import {HttpClient} from '@angular/common/http'; -import {Injectable} from '@angular/core'; import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; import {Observable, tap} from 'rxjs'; import {ProjectService, Task, UnitRole, UserService} from 'src/app/api/models/doubtfire-model'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; import {TutorNote} from '../models/tutor-note'; @Injectable() diff --git a/src/app/api/services/tutorial-stream.service.ts b/src/app/api/services/tutorial-stream.service.ts index 4a5c5a617d..0f17efcb7c 100644 --- a/src/app/api/services/tutorial-stream.service.ts +++ b/src/app/api/services/tutorial-stream.service.ts @@ -1,8 +1,8 @@ -import {HttpClient} from '@angular/common/http'; import {CachedEntityService} from 'ngx-entity-service'; import {TutorialStream} from 'src/app/api/models/doubtfire-model'; -import {Injectable} from '@angular/core'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; @Injectable() export class TutorialStreamService extends CachedEntityService { @@ -16,11 +16,11 @@ export class TutorialStreamService extends CachedEntityService { this.mapping.mapAllKeysToJson(); } - public createInstanceFrom(json: any, other?: any): TutorialStream { + public createInstanceFrom(_json: object): TutorialStream { return new TutorialStream(); } - public override keyForJson(json: any): string { + public override keyForJson(json: {abbreviation: string}): string { return json['abbreviation']; } diff --git a/src/app/api/services/tutorial.service.ts b/src/app/api/services/tutorial.service.ts index 7f444157ce..d2c14fbaa4 100644 --- a/src/app/api/services/tutorial.service.ts +++ b/src/app/api/services/tutorial.service.ts @@ -1,5 +1,5 @@ -import {Inject, Injectable} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; +import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; import { CampusService, Project, @@ -7,10 +7,10 @@ import { Unit, UserService, } from 'src/app/api/models/doubtfire-model'; -import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; -import API_URL from 'src/app/config/constants/apiUrl'; -import {Observable} from 'rxjs'; import {AlertService} from 'src/app/common/services/alert.service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; @Injectable() export class TutorialService extends CachedEntityService { @@ -34,22 +34,22 @@ export class TutorialService extends CachedEntityService { 'abbreviation', { keys: ['campus', 'campus_id'], - toEntityOp: (data: object, key: string, entity: Tutorial, params?: any) => { + toEntityOp: (data: object, key: string, entity: Tutorial) => { this.campusService.get(data['campus_id']).subscribe((campus) => { entity.campus = campus; }); }, - toJsonFn: (entity: Tutorial, key: string) => { + toJsonFn: (entity: Tutorial, _key: string) => { return entity.campus ? entity.campus.id : -1; }, }, 'capacity', { keys: ['tutor', 'tutor_id'], - toEntityFn: (data: object, key: string, entity: Tutorial, params?: any) => { + toEntityFn: (data: object, key: string) => { return this.userService.cache.get(data[key]); }, - toJsonFn: (entity: Tutorial, key: string) => { + toJsonFn: (entity: Tutorial, _key: string) => { return entity.tutor?.id; }, }, @@ -57,17 +57,17 @@ export class TutorialService extends CachedEntityService { 'numStudents', { keys: ['tutorialStream', 'tutorial_stream_abbr'], - toEntityFn: (data: object, key: string, entity: Tutorial, params?: any) => { + toEntityFn: (data: object, key: string, entity: Tutorial) => { return entity.unit.tutorialStreamForAbbr(data[key]); }, - toJsonFn: (entity: Tutorial, key: string) => { + toJsonFn: (entity: Tutorial, _key: string) => { return entity.tutorialStream ? entity.tutorialStream.abbreviation : null; }, }, { keys: ['unit', 'unit_id'], - toJsonFn: (entity: Tutorial, key: string) => { + toJsonFn: (entity: Tutorial, _key: string) => { return entity.unit?.id; }, }, @@ -76,11 +76,11 @@ export class TutorialService extends CachedEntityService { this.mapping.mapAllKeysToJsonExcept('numStudents'); } - public createInstanceFrom(json: any, other?: any): Tutorial { - return new Tutorial(other as Unit); + public createInstanceFrom(_json: object, other?: Unit): Tutorial { + return new Tutorial(other); } - public override keyForJson(json: any): string | number { + public override keyForJson(json: {tutorial_id?: number}): string | number { if (json.tutorial_id) { return json.tutorial_id; } else { @@ -102,7 +102,7 @@ export class TutorialService extends CachedEntityService { body: {}, }; - let observer: Observable; + let observer: Observable<{enrolments: {tutorial_id: number}[]}>; if (isEnrol) { observer = this.post(pathIds, options); } else { diff --git a/src/app/api/services/unit-role.service.ts b/src/app/api/services/unit-role.service.ts index 2aee5b609f..4d6f71b4e1 100644 --- a/src/app/api/services/unit-role.service.ts +++ b/src/app/api/services/unit-role.service.ts @@ -1,3 +1,4 @@ +import {CachedEntityService} from 'ngx-entity-service'; import { TeachingPeriodService, Unit, @@ -5,10 +6,9 @@ import { UnitService, UserService, } from 'src/app/api/models/doubtfire-model'; -import {CachedEntityService} from 'ngx-entity-service'; -import {Injectable} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; @Injectable() export class UnitRoleService extends CachedEntityService { @@ -26,7 +26,7 @@ export class UnitRoleService extends CachedEntityService { 'id', { keys: 'unit', - toEntityFn: (data, key, entity) => { + toEntityFn: (data, _key, _entity) => { const unitData = data['unit']; const result: Unit = this.unitService.cache.getOrCreate( unitData.id, @@ -36,13 +36,13 @@ export class UnitRoleService extends CachedEntityService { result.updateFromJson(unitData, this.unitService.mapping); return result; }, - toJsonFn: (entity: UnitRole, key: string) => { + toJsonFn: (entity: UnitRole, _key: string) => { return entity.unit?.id; }, }, { keys: 'user', - toEntityFn: (data: object, key: string, entity: UnitRole, params?: any) => { + toEntityFn: (data: object) => { return this.userService.cache.getOrCreate(data['user']['id'], userService, data['user']); }, }, @@ -50,13 +50,13 @@ export class UnitRoleService extends CachedEntityService { 'roleId', { keys: 'userId', - toJsonFn: (entity: UnitRole, key: string) => { + toJsonFn: (entity: UnitRole, _key: string) => { return entity.user?.id; }, }, { keys: 'unitId', - toJsonFn: (entity: UnitRole, key: string) => { + toJsonFn: (entity: UnitRole, _key: string) => { return entity.unit?.id; }, }, @@ -77,7 +77,7 @@ export class UnitRoleService extends CachedEntityService { ); } - public createInstanceFrom(json: any, other?: any): UnitRole { + public createInstanceFrom(_json: object): UnitRole { return new UnitRole(); } } diff --git a/src/app/api/services/unit.service.ts b/src/app/api/services/unit.service.ts index abb09084f7..150f99ba38 100644 --- a/src/app/api/services/unit.service.ts +++ b/src/app/api/services/unit.service.ts @@ -1,5 +1,5 @@ -import {Injectable} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; +import {CachedEntityService} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; import { GroupSetService, LearningOutcomeService, @@ -11,16 +11,16 @@ import { Unit, UserService, } from 'src/app/api/models/doubtfire-model'; -import {CachedEntityService, Entity, EntityMapping} from 'ngx-entity-service'; -import API_URL from 'src/app/config/constants/apiUrl'; -import {UnitRoleService} from './unit-role.service'; +import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; import {AppInjector} from 'src/app/app-injector'; -import {TaskDefinitionService} from './task-definition.service'; -import {GroupService} from './group.service'; -import {Observable} from 'rxjs'; +import API_URL from 'src/app/config/constants/apiUrl'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; -import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {GroupService} from './group.service'; import {MappingFunctions} from './mapping-fn'; +import {TaskDefinitionService} from './task-definition.service'; +import {UnitRoleService} from './unit-role.service'; export type IloStats = { median: number; @@ -30,6 +30,35 @@ export type IloStats = { max: number; }[]; +export interface TaskStatusStat { + tutorial_stream_id: number; + status: string; + num: number; +} + +export type TaskStatusStats = Record>; + +export interface TargetGradeStat { + tutorial_id: number; + tutorial_stream_id: number; + grade: number; + num: number; +} + +export interface TaskCompletionSummary { + median: number; + lower: number; + upper: number; + min: number; + max: number; +} + +export interface TaskCompletionStats { + unit: TaskCompletionSummary; + tutorial: Record; + grade: Record; +} + @Injectable() export class UnitService extends CachedEntityService { protected readonly endpointFormat = 'units/:id:'; @@ -59,7 +88,7 @@ export class UnitService extends CachedEntityService { 'myRole', { keys: 'unitRole', - toEntityFn: (data: object, jsonKey: string, entity: Unit) => { + toEntityFn: (data: object, jsonKey: string, _entity: Unit) => { const unitRoleService = AppInjector.get(UnitRoleService); unitRoleService.cache.get(data[jsonKey]); }, @@ -83,16 +112,16 @@ export class UnitService extends CachedEntityService { entity.mainConvenorUser = result?.user; return result; }, - toJsonFn: (unit: Unit, key: string) => { + toJsonFn: (unit: Unit, _key: string) => { return unit.mainConvenor?.id; }, }, { keys: ['mainConvenorUser', 'main_convenor_user_id'], - toEntityFn: (data, key, entity) => { + toEntityFn: (data, key, _entity) => { return AppInjector.get(UserService).cache.get(data[key]); }, - toJsonFn: (unit: Unit, key: string) => { + toJsonFn: (unit: Unit, _key: string) => { return unit.mainConvenor?.user.id; }, }, @@ -107,27 +136,27 @@ export class UnitService extends CachedEntityService { return undefined; } }, - toJsonFn: (entity: Unit, key: string) => { + toJsonFn: (entity: Unit, _key: string) => { return entity.teachingPeriod ? entity.teachingPeriod.id : undefined; }, }, { keys: 'startDate', - toEntityFn: (data, key, entity, params?) => { + toEntityFn: (data, key, _entity, _params?) => { return new Date(data[key]); }, toJsonFn: MappingFunctions.mapDayToJson, }, { keys: 'endDate', - toEntityFn: (data, key, entity, params?) => { + toEntityFn: (data, key, _entity, _params?) => { return new Date(data[key]); }, toJsonFn: MappingFunctions.mapDayToJson, }, { keys: 'portfolioAutoGenerationDate', - toEntityFn: (data, key, entity, params?) => { + toEntityFn: (data, key, _entity, _params?) => { return new Date(data[key]); }, toJsonFn: MappingFunctions.mapDayToJson, @@ -231,7 +260,7 @@ export class UnitService extends CachedEntityService { toEntityFn: (data: object, jsonKey: string, unit: Unit) => { return unit.taskDef(data[jsonKey]); }, - toJsonFn: (unit: Unit, key: string) => { + toJsonFn: (unit: Unit, _key: string) => { return unit.draftTaskDefinition?.id; }, }, @@ -289,7 +318,7 @@ export class UnitService extends CachedEntityService { ); } - public override createInstanceFrom(json: any, other?: any): Unit { + public override createInstanceFrom(_json: object): Unit { return new Unit(); } @@ -307,25 +336,25 @@ export class UnitService extends CachedEntityService { return httpClient.get(url); } - public taskStatusCountByTutorial(unit: Unit): Observable { + public taskStatusCountByTutorial(unit: Unit): Observable { const url = `${AppInjector.get(DoubtfireConstants).API_URL}/units/${unit.id}/stats/task_status_pct`; const httpClient = AppInjector.get(HttpClient); - return httpClient.get(url); + return httpClient.get(url); } - public targetGradeStats(unit: Unit): Observable { + public targetGradeStats(unit: Unit): Observable { const url = `${AppInjector.get(DoubtfireConstants).API_URL}/units/${unit.id}/stats/student_target_grade`; const httpClient = AppInjector.get(HttpClient); - return httpClient.get(url); + return httpClient.get(url); } - public taskCompletionStats(unit: Unit): Observable { + public taskCompletionStats(unit: Unit): Observable { const url = `${AppInjector.get(DoubtfireConstants).API_URL}/units/${unit.id}/stats/task_completion_stats`; const httpClient = AppInjector.get(HttpClient); - return httpClient.get(url); + return httpClient.get(url); } public zipPortfolios(unit: Unit): Observable { diff --git a/src/app/api/services/user.service.ts b/src/app/api/services/user.service.ts index d4396e8666..fe52b4e341 100644 --- a/src/app/api/services/user.service.ts +++ b/src/app/api/services/user.service.ts @@ -1,11 +1,10 @@ +import {CachedEntityService} from 'ngx-entity-service'; +import {Observable} from 'rxjs'; import {UnitRole, UnitService, User} from 'src/app/api/models/doubtfire-model'; -import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; -import {Injectable} from '@angular/core'; -import {HttpClient} from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiUrl'; import {AppInjector} from 'src/app/app-injector'; -import {AuthenticationService} from './authentication.service'; -import {Observable, tap} from 'rxjs'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; @Injectable() export class UserService extends CachedEntityService { diff --git a/src/app/api/services/webcal.service.ts b/src/app/api/services/webcal.service.ts index 9644b85d73..c0a213a5f5 100644 --- a/src/app/api/services/webcal.service.ts +++ b/src/app/api/services/webcal.service.ts @@ -1,8 +1,8 @@ +import {EntityService} from 'ngx-entity-service'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; import {Injectable} from '@angular/core'; import {Webcal} from '../models/webcal/webcal'; -import {Entity, EntityService} from 'ngx-entity-service'; -import {HttpClient} from '@angular/common/http'; -import API_URL from 'src/app/config/constants/apiUrl'; @Injectable() export class WebcalService extends EntityService { @@ -29,7 +29,7 @@ export class WebcalService extends EntityService { this.mapping.mapAllKeysToJsonExcept('id'); } - public createInstanceFrom(json: any, other?: any): Webcal { + public createInstanceFrom(_json: object): Webcal { return new Webcal(); } } diff --git a/src/app/app-injector.ts b/src/app/app-injector.ts index 0d113cf3fc..9a37215985 100644 --- a/src/app/app-injector.ts +++ b/src/app/app-injector.ts @@ -1,4 +1,4 @@ -import { Injector } from '@angular/core'; +import {Injector} from '@angular/core'; /** * Allows for retrieving singletons using `AppInjector.get(MyService)` (whereas diff --git a/src/app/app.component.ts b/src/app/app.component.ts index a42564e5b5..13e1f88e52 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,11 +1,11 @@ +import {Subscription, filter} from 'rxjs'; import {Component, OnDestroy, OnInit, Renderer2} from '@angular/core'; import {NavigationEnd, Router} from '@angular/router'; -import {Subscription, filter} from 'rxjs'; @Component({ - selector: 'app-root', - templateUrl: './app.component.html', - standalone: false + selector: 'app-root', + templateUrl: './app.component.html', + standalone: false, }) export class AppComponent implements OnInit, OnDestroy { private routerSub?: Subscription; diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 5c3f4b8bf1..6122dd6101 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -1,39 +1,39 @@ import {Routes} from '@angular/router'; import {EditProfileComponent} from './account/edit-profile/edit-profile.component'; -import {UnauthorisedComponent} from './errors/states/unauthorised/unauthorised.component'; +import {InstitutionSettingsComponent} from './admin/institution-settings/institution-settings.component'; +import {FUnitsComponent} from './admin/states/units/units.component'; +import {FUsersComponent} from './admin/states/users/users.component'; +import {roleWhitelistGuard} from './common/guards/role-whitelist.guard'; +import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component'; +import {SubmissionFilesDownloadComponent} from './common/submission-files-download/submission-files-download.component'; +import {SuccessCloseComponent} from './common/success-close/success-close.component'; import {TimeoutComponent} from './errors/states/timeout/timeout.component'; +import {UnauthorisedComponent} from './errors/states/unauthorised/unauthorised.component'; import {AcceptEulaComponent} from './eula/accept-eula/accept-eula.component'; import {HomeComponent} from './home/states/home/home.component'; import {LtiDashboardComponent} from './home/states/lti-dashboard/lti-dashboard.component'; import {LtiUnitLinkComponent} from './home/states/lti-unit-link/lti-unit-link.component'; -import {SignInComponent} from './sessions/states/sign-in/sign-in.component'; -import {SuccessCloseComponent} from './common/success-close/success-close.component'; -import {ScormPlayerComponent} from './common/scorm-player/scorm-player.component'; -import {FUnitsComponent} from './admin/states/units/units.component'; -import {FUsersComponent} from './admin/states/users/users.component'; -import {InstitutionSettingsComponent} from './admin/institution-settings/institution-settings.component'; -import {TutorDiscussionComponent} from './projects/states/tutor-discussion/tutor-discussion.component'; -import {JplagReportViewerComponent} from './projects/states/jplag/jplag-report-viewer.component'; +import {resolveProject} from './projects/project.resolver'; import {ProjectDashboardComponent} from './projects/states/dashboard/project-dashboard/project-dashboard.component'; import {ProjectGroupsStateComponent} from './projects/states/groups/project-groups-state.component'; +import {JplagReportViewerComponent} from './projects/states/jplag/jplag-report-viewer.component'; import {ProjectPlanComponent} from './projects/states/plan/project-plan.component'; -import {ProjectRootStateComponent} from './projects/states/project-root-state.component'; import {PortfolioStateComponent} from './projects/states/portfolio/portfolio-state.component'; +import {ProjectRootStateComponent} from './projects/states/project-root-state.component'; +import {TutorDiscussionComponent} from './projects/states/tutor-discussion/tutor-discussion.component'; import {TutorialsComponent} from './projects/states/tutorials/tutorials.component'; -import {resolveProject} from './projects/project.resolver'; +import {SignInComponent} from './sessions/states/sign-in/sign-in.component'; +import {UnitAnalyticsComponent} from './units/states/analytics/unit-analytics-route.component'; import {UnitAdminStateComponent} from './units/states/edit/unit-admin-state.component'; -import {RolloverComponent} from './units/states/rollover/rollover.component'; import {UnitGroupsComponent} from './units/states/groups/unit-groups/unit-groups.component'; -import {UnitAnalyticsComponent} from './units/states/analytics/unit-analytics-route.component'; -import {StudentsListComponent} from './units/states/students-list/students-list.component'; import {PortfoliosComponent} from './units/states/portfolios/portfolios.component'; +import {RolloverComponent} from './units/states/rollover/rollover.component'; +import {StudentsListComponent} from './units/states/students-list/students-list.component'; import {UnitTaskInboxStateComponent} from './units/states/tasks/inbox/unit-task-inbox-state.component'; import {TaskViewerStateComponent} from './units/task-viewer/task-viewer-state.component'; -import {resolveUnit} from './units/unit.resolver'; import {UnitRootStateComponent} from './units/unit-root-state.component'; +import {resolveUnit} from './units/unit.resolver'; import {WelcomeComponent} from './welcome/welcome.component'; -import {roleWhitelistGuard} from './common/guards/role-whitelist.guard'; -import {SubmissionFilesDownloadComponent} from './common/submission-files-download/submission-files-download.component'; export const routes: Routes = [ {path: '', pathMatch: 'full', redirectTo: 'home'}, diff --git a/src/app/common/archive-viewer/archive-viewer.component.html b/src/app/common/archive-viewer/archive-viewer.component.html index e48d00a0dc..5368148a38 100644 --- a/src/app/common/archive-viewer/archive-viewer.component.html +++ b/src/app/common/archive-viewer/archive-viewer.component.html @@ -1,33 +1,27 @@ -
    +
    @if (isLoading) { -
    +
    Loading archive...
    } @else if (errorMessage) { -
    - error_outline +
    + error_outline {{ errorMessage }}
    } @else if (!archiveFile) { -
    - folder_zip +
    + folder_zip Select an archive to preview.
    } @else if (!hasFiles) { -
    - folder_off +
    + folder_off No files to display.
    } @else { @if (!readOnly && saveEndpoint) { -
    +
    ) => { + ((blobUrl: string, _response: HttpResponse) => { this.isLoaded = true; this.setSrc(blobUrl); this.audio.src = blobUrl; @@ -97,9 +97,9 @@ export class AudioPlayerComponent implements OnDestroy { fn(); } }).bind(this), - ((error: any) => { + ((error: Error) => { this.alerts.error(`Error loading audio. ${error}`, 6000); - }).bind(this) + }).bind(this), ); } } @@ -115,7 +115,7 @@ export class AudioPlayerComponent implements OnDestroy { this.audio.pause(); this.isPlaying = false; } - }).bind(this) + }).bind(this), ); } } diff --git a/src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.html b/src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.html index 26d0f04358..1638aeb89d 100644 --- a/src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.html +++ b/src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.html @@ -3,7 +3,12 @@ Audio recording
    only supported in modern versions of Chrome, Firefox and Safari.

    - +
    - {{isRecording ? 'stop_circle' : 'radio_button_checked' }} + {{isRecording ? 'stop_circle' : 'radio_button_checked' }} + - +
    - +
    @@ -17,14 +25,22 @@

    Step 1. Record some audio!

    -
    +

    Step 2. Stop the recording, and playback the audio to make sure it's audible:

    - +
    -
    -

    Step 3. Check the "Ready to go" cehckbox below if you're all set!

    +
    +

    Step 3. Check the "Ready to go" cehckbox below if you're all set!

    diff --git a/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester-component.scss b/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester-component.scss index 4b6a37e52a..d201a8dadd 100644 --- a/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester-component.scss +++ b/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester-component.scss @@ -1,5 +1,4 @@ microphone-tester { - h1 { font-size: 12pt; } @@ -9,7 +8,9 @@ microphone-tester { border-radius: 72px; color: #fff; height: 72px; - transition: width 0.1s, height 0.1s; + transition: + width 0.1s, + height 0.1s; width: 72px; border: none; outline: none; @@ -18,7 +19,7 @@ microphone-tester { top: 50%; p { - font-family: "Helvetica Neue", "Segoe UI", "Helvetica", "Arial", "sans-serif"; + font-family: 'Helvetica Neue', 'Segoe UI', 'Helvetica', 'Arial', 'sans-serif'; text-rendering: optimizeLegibility; line-height: 1.3; font-size: 14px; diff --git a/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester.component.ts b/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester.component.ts index dbb42e7a4c..05736d3db9 100644 --- a/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester.component.ts +++ b/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester.component.ts @@ -1,13 +1,13 @@ -import { Input, Component, AfterViewInit } from '@angular/core'; -import { BaseAudioRecorderComponent } from '../base-audio-recorder'; -import { Task } from 'src/app/api/models/doubtfire-model'; -import { MediaRecorderService } from 'src/app/common/services/recorder-service'; +import {Task} from 'src/app/api/models/doubtfire-model'; +import {MediaRecorderService} from 'src/app/common/services/recorder-service'; +import {AfterViewInit, Component, Input} from '@angular/core'; +import {BaseAudioRecorderComponent} from '../base-audio-recorder'; @Component({ - selector: 'microphone-tester', - templateUrl: './microphone-tester-component.html', - providers: [MediaRecorderService], - standalone: false + selector: 'microphone-tester', + templateUrl: './microphone-tester-component.html', + providers: [MediaRecorderService], + standalone: false, }) export class MicrophoneTesterComponent extends BaseAudioRecorderComponent implements AfterViewInit { @Input() task: Task; @@ -25,9 +25,6 @@ export class MicrophoneTesterComponent extends BaseAudioRecorderComponent implem } } - // We need to override default behaviour of the parent class. - ngOnInit() {} - init(): void { super.init(); this.canvas = document.getElementById('micTesterVisualiser') as HTMLCanvasElement; @@ -35,5 +32,7 @@ export class MicrophoneTesterComponent extends BaseAudioRecorderComponent implem this.canvasCtx = this.canvas.getContext('2d'); } - sendRecording(): void {} + sendRecording(): void { + /* empty */ + } } diff --git a/src/app/common/chart-base/chart-base-component/chart-base-component.component.html b/src/app/common/chart-base/chart-base-component/chart-base-component.component.html new file mode 100644 index 0000000000..16e336d2ba --- /dev/null +++ b/src/app/common/chart-base/chart-base-component/chart-base-component.component.html @@ -0,0 +1 @@ +

    chart-base-component works!

    diff --git a/src/app/common/chart-base/chart-base-component/chart-base-component.component.ts b/src/app/common/chart-base/chart-base-component/chart-base-component.component.ts index 1bf6262fe9..0fa371406d 100644 --- a/src/app/common/chart-base/chart-base-component/chart-base-component.component.ts +++ b/src/app/common/chart-base/chart-base-component/chart-base-component.component.ts @@ -1,6 +1,6 @@ -import { Component, ViewContainerRef } from '@angular/core'; -import { TooltipService } from '@swimlane/ngx-charts'; -import { AppInjector } from "src/app/app-injector"; +import {TooltipService} from '@swimlane/ngx-charts'; +import {AppInjector} from 'src/app/app-injector'; +import {Component, ViewContainerRef} from '@angular/core'; /** * @title chart-base-component @@ -9,8 +9,8 @@ import { AppInjector } from "src/app/app-injector"; * Child classes need to extend this class and call super() in the constructor, passing in the ViewContainerRef. */ @Component({ - template: `

    chart-base-component works!

    `, - standalone: false + templateUrl: './chart-base-component.component.html', + standalone: false, }) export class ChartBaseComponent { constructor(public viewContainerRef: ViewContainerRef) { diff --git a/src/app/common/directives/drag-drop.directive.spec.ts b/src/app/common/directives/drag-drop.directive.spec.ts index 0d39e1f01c..101b686e5a 100644 --- a/src/app/common/directives/drag-drop.directive.spec.ts +++ b/src/app/common/directives/drag-drop.directive.spec.ts @@ -1,4 +1,4 @@ -import { DragDropDirective } from './drag-drop.directive'; +import {DragDropDirective} from './drag-drop.directive'; describe('DragDropDirective', () => { it('should create an instance', () => { diff --git a/src/app/common/directives/drag-drop.directive.ts b/src/app/common/directives/drag-drop.directive.ts index 0f2b352581..415e2475b4 100644 --- a/src/app/common/directives/drag-drop.directive.ts +++ b/src/app/common/directives/drag-drop.directive.ts @@ -1,4 +1,4 @@ -import { Directive, Output, EventEmitter, HostBinding, HostListener } from '@angular/core'; +import {Directive, EventEmitter, HostBinding, HostListener, Output} from '@angular/core'; /** * The "appDragDrop" directive can be added to angular components to allow them to act as @@ -7,11 +7,11 @@ import { Directive, Output, EventEmitter, HostBinding, HostListener } from '@ang * class will be applied to the element. */ @Directive({ - selector: '[appDragDrop]', - standalone: false + selector: '[appDragDrop]', + standalone: false, }) export class DragDropDirective { - @Output() fileDropped = new EventEmitter(); + @Output() fileDropped: EventEmitter = new EventEmitter(); // @HostBinding('style.background-color') private background = '#f5fcff'; // @HostBinding('style.opacity') private opacity = '1'; diff --git a/src/app/common/edit-profile-form/edit-profile-form.component.html b/src/app/common/edit-profile-form/edit-profile-form.component.html index 585012d1bd..f314ea254c 100644 --- a/src/app/common/edit-profile-form/edit-profile-form.component.html +++ b/src/app/common/edit-profile-form/edit-profile-form.component.html @@ -5,11 +5,11 @@ fxLayoutAlign="center start" [ngClass]="{'p-10': modal}" > -
    -
    +
    +
    -
    -
    +
    +
    @@ -35,7 +35,7 @@

    {{ user?.firstName }}

    --> Username - +
    @@ -84,10 +84,10 @@

    {{ user?.firstName }}

    @if (user.systemRole === 'Student') { - - Student ID - - + + Student ID + + } @@ -96,28 +96,43 @@

    {{ user?.firstName }}

    @if (canSeeSystemRole) { - - System Role - - Administrator - Convenor - Tutor - Student - Auditor - - + + System Role + + Administrator + Convenor + Tutor + Student + Auditor + + }
    - Receive notifications for new messages
    - Receive notifications when your portfolio is ready
    - Receive notifications when new tasks are available
    @@ -127,33 +142,52 @@

    {{ user?.firstName }}

    - @if(tiiEnabled){ -
    - Accepted TurnItIn EULA - -
    + @if (tiiEnabled) { +
    + Accepted TurnItIn EULA + +
    }
    - -
    - @if (mode === 'create') { - - } @if (mode === 'edit') { +
    + @if (mode === 'create') { + + } + @if (mode === 'edit') { + }
    diff --git a/src/app/common/edit-profile-form/edit-profile-form.component.spec.ts b/src/app/common/edit-profile-form/edit-profile-form.component.spec.ts index 969d9531ae..18f1c2815b 100644 --- a/src/app/common/edit-profile-form/edit-profile-form.component.spec.ts +++ b/src/app/common/edit-profile-form/edit-profile-form.component.spec.ts @@ -1,5 +1,4 @@ import {ComponentFixture, TestBed} from '@angular/core/testing'; - import {EditProfileFormComponent} from './edit-profile-form.component'; describe('EditProfileComponent', () => { diff --git a/src/app/common/edit-profile-form/edit-profile-form.component.ts b/src/app/common/edit-profile-form/edit-profile-form.component.ts index e8bf1204de..5ff0848938 100644 --- a/src/app/common/edit-profile-form/edit-profile-form.component.ts +++ b/src/app/common/edit-profile-form/edit-profile-form.component.ts @@ -1,17 +1,17 @@ -import {Component, Inject, Input, OnInit, Optional} from '@angular/core'; -import {MAT_DIALOG_DATA} from '@angular/material/dialog'; -import {MatSnackBar} from '@angular/material/snack-bar'; -import {Router} from '@angular/router'; import {User} from 'src/app/api/models/user/user'; import {AuthenticationService} from 'src/app/api/services/authentication.service'; import {UserService} from 'src/app/api/services/user.service'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Component, Inject, Input, OnInit, Optional} from '@angular/core'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {Router} from '@angular/router'; @Component({ - selector: 'f-edit-profile-form', - templateUrl: './edit-profile-form.component.html', - styleUrls: ['./edit-profile-form.component.scss'], - standalone: false + selector: 'f-edit-profile-form', + templateUrl: './edit-profile-form.component.html', + styleUrls: ['./edit-profile-form.component.scss'], + standalone: false, }) export class EditProfileFormComponent implements OnInit { constructor( diff --git a/src/app/common/entity-form/entity-form.component.ts b/src/app/common/entity-form/entity-form.component.ts index abf2a498c5..e46257a9df 100644 --- a/src/app/common/entity-form/entity-form.component.ts +++ b/src/app/common/entity-form/entity-form.component.ts @@ -1,8 +1,9 @@ -import {AfterViewInit, Directive} from '@angular/core'; -import {UntypedFormGroup, AbstractControl} from '@angular/forms'; import {Entity, RequestOptions} from 'ngx-entity-service'; import {EntityService} from 'ngx-entity-service'; import {Observable, tap} from 'rxjs'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {AfterViewInit, Directive} from '@angular/core'; +import {AbstractControl, UntypedFormGroup} from '@angular/forms'; import {Sort} from '@angular/material/sort'; import {MatTableDataSource} from '@angular/material/table'; @@ -59,7 +60,10 @@ export abstract class EntityFormComponent implements AfterView } } - ngAfterViewInit() {} + // eslint-disable-next-line @angular-eslint/no-empty-lifecycle-method + ngAfterViewInit() { + /* empty */ + } /** * Cancel edit of current selected value. @@ -116,7 +120,7 @@ export abstract class EntityFormComponent implements AfterView * @param alertService the alert service used to provide alerts. * @param success the function, provided by inheritor, that is executed on success of CRUD methods. */ - submit(service: EntityService, alertService: any, success: OnSuccessMethod) { + submit(service: EntityService, alertService: AlertService, success: OnSuccessMethod) { // response is what we get back from the server // when creating or updating let response: Observable; @@ -176,9 +180,9 @@ export abstract class EntityFormComponent implements AfterView } } - protected delete(entity: T, entities: T[], service: EntityService): Observable { - return service.delete(entity, this.optionsOnRequest('delete')).pipe( - tap((obj) => { + protected delete(entity: T, entities: T[], service: EntityService): Observable { + return service.delete(entity, this.optionsOnRequest('delete')).pipe( + tap((_obj) => { this.cancelEdit(); entities.splice(entities.indexOf(entity), 1); this.dataSource.data = entities; @@ -210,7 +214,7 @@ export abstract class EntityFormComponent implements AfterView * to the entity constructor when an object is created. This is then passed along * in the `create` call as the `other` value to the EntityService's create method. */ - protected optionsOnRequest(kind: 'create' | 'update' | 'delete'): RequestOptions { + protected optionsOnRequest(_kind: 'create' | 'update' | 'delete'): RequestOptions { return undefined; } diff --git a/src/app/common/f-chip/chip.component.html b/src/app/common/f-chip/chip.component.html index d247144b2a..9d414dc60e 100644 --- a/src/app/common/f-chip/chip.component.html +++ b/src/app/common/f-chip/chip.component.html @@ -1,5 +1,5 @@
    diff --git a/src/app/common/f-chip/chip.component.spec.ts b/src/app/common/f-chip/chip.component.spec.ts index a08f153a40..2360020249 100644 --- a/src/app/common/f-chip/chip.component.spec.ts +++ b/src/app/common/f-chip/chip.component.spec.ts @@ -1,6 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { FChipComponent } from './chip.component'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {FChipComponent} from './chip.component'; describe('FChipComponent', () => { let component: FChipComponent; @@ -8,9 +7,8 @@ describe('FChipComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ FChipComponent ] - }) - .compileComponents(); + declarations: [FChipComponent], + }).compileComponents(); fixture = TestBed.createComponent(FChipComponent); component = fixture.componentInstance; diff --git a/src/app/common/f-chip/chip.component.ts b/src/app/common/f-chip/chip.component.ts index edb9ea33a6..ff926f0556 100644 --- a/src/app/common/f-chip/chip.component.ts +++ b/src/app/common/f-chip/chip.component.ts @@ -1,9 +1,9 @@ -import { Component } from '@angular/core'; +import {Component} from '@angular/core'; @Component({ - selector: 'f-chip', - templateUrl: './chip.component.html', - styleUrls: ['./chip.component.scss'], - standalone: false + selector: 'f-chip', + templateUrl: './chip.component.html', + styleUrls: ['./chip.component.scss'], + standalone: false, }) export class FChipComponent {} diff --git a/src/app/common/feedback-template-editor/feedback-template-editor.component.html b/src/app/common/feedback-template-editor/feedback-template-editor.component.html index 516c4709cc..1def23d307 100644 --- a/src/app/common/feedback-template-editor/feedback-template-editor.component.html +++ b/src/app/common/feedback-template-editor/feedback-template-editor.component.html @@ -1,11 +1,11 @@ -
    +
    -

    Edit Feedback Templates for Outcome

    +

    Edit Feedback Templates for Outcome

    @if (!(action.complete || action.retry)) { - + }
    Edit Feedback Templates for Outcom @if (selectedTemplate) {
    -

    Edit Template

    +

    Edit Template

    @if (selectedTemplate.isNew) { diff --git a/src/app/common/feedback-template-editor/feedback-template-editor.component.ts b/src/app/common/feedback-template-editor/feedback-template-editor.component.ts index dc98c9b8a1..55ad47f8b7 100644 --- a/src/app/common/feedback-template-editor/feedback-template-editor.component.ts +++ b/src/app/common/feedback-template-editor/feedback-template-editor.component.ts @@ -1,8 +1,3 @@ -import {AfterViewInit, Component, Input, OnChanges, SimpleChanges, ViewChild} from '@angular/core'; -import {MatPaginator} from '@angular/material/paginator'; -import {MatSelectChange} from '@angular/material/select'; -import {MatSort, Sort} from '@angular/material/sort'; -import {MatTable, MatTableDataSource} from '@angular/material/table'; import { FeedbackTemplate, FeedbackTemplateService, @@ -12,6 +7,11 @@ import { Unit, } from 'src/app/api/models/doubtfire-model'; import {AlertService} from 'src/app/common/services/alert.service'; +import {AfterViewInit, Component, Input, OnChanges, SimpleChanges, ViewChild} from '@angular/core'; +import {MatPaginator} from '@angular/material/paginator'; +import {MatSelectChange} from '@angular/material/select'; +import {MatSort, Sort} from '@angular/material/sort'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; import {FileDownloaderService} from '../file-downloader/file-downloader.service'; import {ConfirmationModalService} from '../modals/confirmation-modal/confirmation-modal.service'; import { @@ -21,9 +21,9 @@ import { import {CsvUploadModalService} from '../modals/csv-upload-modal/csv-upload-modal.service'; @Component({ - selector: 'f-feedback-template-editor', - templateUrl: 'feedback-template-editor.component.html', - standalone: false + selector: 'f-feedback-template-editor', + templateUrl: 'feedback-template-editor.component.html', + standalone: false, }) export class FeedbackTemplateEditorComponent implements OnChanges, AfterViewInit { @Input() context?: TaskDefinition | Unit; @@ -61,7 +61,7 @@ export class FeedbackTemplateEditorComponent implements OnChanges, AfterViewInit this.getFeedbackChips(); } - ngOnChanges(changes: SimpleChanges): void { + ngOnChanges(_changes: SimpleChanges): void { this.selectedTemplate = null; this.getFeedbackChips(); } @@ -147,7 +147,7 @@ export class FeedbackTemplateEditorComponent implements OnChanges, AfterViewInit const sortedTemplates = [...this.templateSource.data].sort(compare); // Determine maximum depth of the hierarchy (only groups contribute to depth) - const depthMap = new Map(); + const depthMap: Map = new Map(); let maxDepth = 0; const feedbackGroups = sortedTemplates.filter((t) => t.type === 'group'); @@ -167,7 +167,7 @@ export class FeedbackTemplateEditorComponent implements OnChanges, AfterViewInit }); // Assign sequential order numbers - const orderMap = new Map(); + const orderMap: Map = new Map(); let orderIndex = 1; sortedTemplates.forEach((template) => { diff --git a/src/app/common/file-downloader/file-downloader.service.ts b/src/app/common/file-downloader/file-downloader.service.ts index 14dfaffb33..57b8fff783 100644 --- a/src/app/common/file-downloader/file-downloader.service.ts +++ b/src/app/common/file-downloader/file-downloader.service.ts @@ -1,4 +1,4 @@ -import { HttpClient, HttpResponse } from '@angular/common/http'; +import {HttpClient, HttpResponse} from '@angular/common/http'; import {Injectable} from '@angular/core'; import {AlertService} from '../services/alert.service'; diff --git a/src/app/common/file-drop/file-drop.component.html b/src/app/common/file-drop/file-drop.component.html index bbb7236982..4fdd27ad68 100644 --- a/src/app/common/file-drop/file-drop.component.html +++ b/src/app/common/file-drop/file-drop.component.html @@ -7,27 +7,28 @@ #fileUpload /> -
    +
    -
    -
    +
    +
    @if (file?.name) { - upload_file + upload_file } - {{ file?.name || message }} + {{ file?.name || message }} {{ uploadProgress }}
    @if (uploadProgress) { - - } @if (!uploadProgress) { - + + } + @if (!uploadProgress) { + }
    diff --git a/src/app/common/file-drop/file-drop.component.scss b/src/app/common/file-drop/file-drop.component.scss index 2c3f68d5d2..bb6482adfe 100644 --- a/src/app/common/file-drop/file-drop.component.scss +++ b/src/app/common/file-drop/file-drop.component.scss @@ -1,6 +1,6 @@ // import color .f-inner-border { - box-shadow: inset 0 0 1px rgba(0,0,0,0.8); + box-shadow: inset 0 0 1px rgba(0, 0, 0, 0.8); clip-path: inset(-1px -1px 0px 0px); } diff --git a/src/app/common/file-drop/file-drop.component.ts b/src/app/common/file-drop/file-drop.component.ts index 0f020a3f38..93f613812a 100644 --- a/src/app/common/file-drop/file-drop.component.ts +++ b/src/app/common/file-drop/file-drop.component.ts @@ -1,19 +1,19 @@ -import { HttpClient, HttpErrorResponse, HttpEventType, HttpResponse } from '@angular/common/http'; -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Subscription, throwError } from 'rxjs'; -import { AlertService } from '../services/alert.service'; +import {Subscription, throwError} from 'rxjs'; +import {HttpClient, HttpErrorResponse, HttpEventType, HttpResponse} from '@angular/common/http'; +import {Component, EventEmitter, Input, Output} from '@angular/core'; +import {AlertService} from '../services/alert.service'; /** * Allow files to be dropped for upload */ @Component({ - selector: 'f-file-drop', - templateUrl: 'file-drop.component.html', - styleUrls: ['file-drop.component.scss'], - standalone: false + selector: 'f-file-drop', + templateUrl: 'file-drop.component.html', + styleUrls: ['file-drop.component.scss'], + standalone: false, }) export class FileDropComponent { - @Input({ required: true }) mode: 'endpoint' | 'event'; + @Input({required: true}) mode: 'endpoint' | 'event'; /** The name of the file(s) you are asking the user to upload */ @Input() desiredFileName: string; @@ -27,8 +27,8 @@ export class FileDropComponent { /** The URL of the endpoint to POST the file to if mode is endpoint*/ @Input() endpoint: string; @Input() body: object; - @Output() fileChange = new EventEmitter(); - @Output() uploadSuccess = new EventEmitter>(); + @Output() fileChange: EventEmitter = new EventEmitter(); + @Output() uploadSuccess: EventEmitter> = new EventEmitter(); protected uploadProgress: number; protected uploadSub: Subscription; @@ -39,7 +39,7 @@ export class FileDropComponent { /** * Report all files dropped if mode is event */ - @Output() filesDropped = new EventEmitter(); + @Output() filesDropped: EventEmitter = new EventEmitter(); constructor( private http: HttpClient, @@ -80,21 +80,23 @@ export class FileDropComponent { const formData = new FormData(); formData.append('file', this.file); - this.http.post(this.endpoint, formData, { reportProgress: true, observe: 'events' }).subscribe( - (data) => { - if (data.type == HttpEventType.UploadProgress) { - this.uploadProgress = Math.round(100 * (data.loaded / data.total)); - } - if (data.type == HttpEventType.Response) { - if (data.ok) { - this.alert.success(`File uploaded successfully`); - this.uploadSuccess.emit(data as HttpResponse); + this.http + .post(this.endpoint, formData, {reportProgress: true, observe: 'events'}) + .subscribe( + (data) => { + if (data.type == HttpEventType.UploadProgress) { + this.uploadProgress = Math.round(100 * (data.loaded / data.total)); } - } - }, - (error) => this.handleError(error), - () => this.reset(), - ); + if (data.type == HttpEventType.Response) { + if (data.ok) { + this.alert.success(`File uploaded successfully`); + this.uploadSuccess.emit(data as HttpResponse); + } + } + }, + (error) => this.handleError(error), + () => this.reset(), + ); } } else { this.filesDropped.emit([this.file]); diff --git a/src/app/common/file-uploader/file-uploader.component.html b/src/app/common/file-uploader/file-uploader.component.html index 96f067af6f..2ff41c792b 100644 --- a/src/app/common/file-uploader/file-uploader.component.html +++ b/src/app/common/file-uploader/file-uploader.component.html @@ -34,14 +34,18 @@
    Select {{ upload.display.name }}
    @if (!upload.display.error) { {{ upload.display.icon }} @if (dropSupported) { - - Drop {{ upload.display.type }} file here
    or click to select + + Drop {{ upload.display.type }} file here
    or click to select
    } @else { Click to select {{ upload.display.type }} file } } @else { - + block Invalid file provided Select {{ upload.display.name }}
    Upload Summary
    @for (upload of uploadZones; track upload) { -
    +
    {{ upload.display.icon }} {{ upload.display.name }} @@ -115,13 +119,13 @@
    Upload Summary
    @if (showUploader && readyToUpload() && isUploading) { @if (!uploadingInfo?.complete) { -
    -
    +
    +
    @for (upload of uploadZones; track upload) { {{ upload.display.icon }} } arrow_right_alt - +
    @@ -130,8 +134,8 @@
    Upload Summary
    } @if (uploadingInfo?.complete) { -
    -
    +
    +
    {{ uploadingInfo.success ? 'check_circle' : 'cancel' }} @@ -142,7 +146,7 @@
    Upload Summary
    @if (!uploadingInfo.success) { -
    +

    Error Message: {{ uploadingInfo.error }}

    diff --git a/src/app/common/file-uploader/file-uploader.component.ts b/src/app/common/file-uploader/file-uploader.component.ts index b256d67f54..021d0e4e83 100644 --- a/src/app/common/file-uploader/file-uploader.component.ts +++ b/src/app/common/file-uploader/file-uploader.component.ts @@ -1,3 +1,5 @@ +import {UserService} from 'src/app/api/services/user.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import { Component, EventEmitter, @@ -7,8 +9,6 @@ import { Output, SimpleChanges, } from '@angular/core'; -import {UserService} from 'src/app/api/services/user.service'; -import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; interface FileData { name: string; @@ -107,8 +107,8 @@ export class FileUploaderComponent implements OnInit, OnChanges { // Once all parent components such as upload-submission-modal are migrated.. // .. these *wont* be necessary anymore // Parent components should declare the file-uploader using @ViewChild() and directly call initiateUpload() - @Output() isReadyChange = new EventEmitter(); - @Output() uploadReady = new EventEmitter<() => void>(); + @Output() isReadyChange: EventEmitter = new EventEmitter(); + @Output() uploadReady: EventEmitter<() => void> = new EventEmitter(); public readonly ACCEPTED_TYPES = ACCEPTED_TYPES; diff --git a/src/app/common/file-viewer/file-viewer.component.html b/src/app/common/file-viewer/file-viewer.component.html index 476c76b464..537049c15b 100644 --- a/src/app/common/file-viewer/file-viewer.component.html +++ b/src/app/common/file-viewer/file-viewer.component.html @@ -1,23 +1,27 @@
    - @if (blobUrl && fileType === 'pdf') { @if (!loaded) { - + @if (blobUrl && fileType === 'pdf') { + @if (!loaded) { + + } + } - - - } @if (fileType === 'html') { -
    - -
    + @if (fileType === 'html') { +
    + +
    }
    diff --git a/src/app/common/file-viewer/file-viewer.component.spec.ts b/src/app/common/file-viewer/file-viewer.component.spec.ts index bfec618b8c..d3e256c208 100644 --- a/src/app/common/file-viewer/file-viewer.component.spec.ts +++ b/src/app/common/file-viewer/file-viewer.component.spec.ts @@ -1,6 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { FileViewerComponent } from './file-viewer.component'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {FileViewerComponent} from './file-viewer.component'; describe('FileViewerComponent', () => { let component: FileViewerComponent; @@ -8,9 +7,8 @@ describe('FileViewerComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ FileViewerComponent ] - }) - .compileComponents(); + declarations: [FileViewerComponent], + }).compileComponents(); fixture = TestBed.createComponent(FileViewerComponent); component = fixture.componentInstance; diff --git a/src/app/common/file-viewer/file-viewer.component.ts b/src/app/common/file-viewer/file-viewer.component.ts index f3145a2e6d..ae6ae795d1 100644 --- a/src/app/common/file-viewer/file-viewer.component.ts +++ b/src/app/common/file-viewer/file-viewer.component.ts @@ -1,17 +1,17 @@ -import { Component, Input, OnChanges, OnDestroy, SimpleChanges } from '@angular/core'; -import { FileDownloaderService } from '../file-downloader/file-downloader.service'; -import { HttpResponse } from '@angular/common/http'; -import { PDFProgressData } from 'ng2-pdf-viewer'; -import { AlertService } from '../services/alert.service'; +import {PDFProgressData} from 'ng2-pdf-viewer'; +import {HttpResponse} from '@angular/common/http'; +import {Component, Input, OnChanges, OnDestroy, SimpleChanges} from '@angular/core'; +import {FileDownloaderService} from '../file-downloader/file-downloader.service'; +import {AlertService} from '../services/alert.service'; /** * The file viewer downloads a file from a URL and displays it's contents. */ @Component({ - selector: 'f-file-viewer', - templateUrl: './file-viewer.component.html', - styleUrls: ['./file-viewer.component.scss'], - standalone: false + selector: 'f-file-viewer', + templateUrl: './file-viewer.component.html', + styleUrls: ['./file-viewer.component.scss'], + standalone: false, }) export class FileViewerComponent implements OnDestroy, OnChanges { /** @@ -51,7 +51,10 @@ export class FileViewerComponent implements OnDestroy, OnChanges { * @param fileDownloader is used to download the resources from the api * @param alerts is used to render alerts */ - constructor(private fileDownloader: FileDownloaderService, private alertService: AlertService) {} + constructor( + private fileDownloader: FileDownloaderService, + private alertService: AlertService, + ) {} /** * When destroyed, the component must free its resources. @@ -99,12 +102,12 @@ export class FileViewerComponent implements OnDestroy, OnChanges { private downloadBlob(downloadUrl: string): void { this.fileDownloader.downloadBlob( downloadUrl, - (url: string, response: HttpResponse) => { + (url: string, _response: HttpResponse) => { this.blobUrl = url; }, - (error: any) => { + (error: Error) => { this.alertService.error(`Error downloading resource. ${error}`); - } + }, ); } diff --git a/src/app/common/filters/filters.pipe.ts b/src/app/common/filters/filters.pipe.ts index 51c71088f1..1a130df9f1 100644 --- a/src/app/common/filters/filters.pipe.ts +++ b/src/app/common/filters/filters.pipe.ts @@ -1,11 +1,11 @@ -import { Pipe, PipeTransform } from '@angular/core'; +import {Pipe, PipeTransform} from '@angular/core'; @Pipe({ - name: 'filters', - standalone: false + name: 'filters', + standalone: false, }) export class FiltersPipe implements PipeTransform { - transform(value: unknown, ...args: unknown[]): unknown { + transform(_value: unknown, ..._args: unknown[]): unknown { return null; } } diff --git a/src/app/common/filters/order-by.pipe.ts b/src/app/common/filters/order-by.pipe.ts index 445cab4c14..7f86a0139b 100644 --- a/src/app/common/filters/order-by.pipe.ts +++ b/src/app/common/filters/order-by.pipe.ts @@ -1,11 +1,15 @@ -import { Pipe, PipeTransform } from '@angular/core'; +import {Pipe, PipeTransform} from '@angular/core'; @Pipe({ - name: 'orderBy', - standalone: false + name: 'orderBy', + standalone: false, }) export class OrderByPipe implements PipeTransform { - transform(array: any[], field: string, reverse: boolean = false): any[] { + transform>( + array: T[], + field: keyof T, + reverse: boolean = false, + ): T[] { if (!array || !field) { return array; } diff --git a/src/app/common/filters/task-definition-name.pipe.ts b/src/app/common/filters/task-definition-name.pipe.ts index adbb4ed9ea..6ee6f136b8 100644 --- a/src/app/common/filters/task-definition-name.pipe.ts +++ b/src/app/common/filters/task-definition-name.pipe.ts @@ -1,14 +1,15 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { Task, TaskDefinition } from '../../api/models/doubtfire-model'; +import {Pipe, PipeTransform} from '@angular/core'; +import {TaskDefinition} from '../../api/models/doubtfire-model'; @Pipe({ - name: 'taskDefinitionName', - standalone: false + name: 'taskDefinitionName', + standalone: false, }) export class TaskDefinitionNamePipe implements PipeTransform { transform(taskDefinitions: TaskDefinition[], searchName: string): TaskDefinition[] { searchName = searchName.toLowerCase(); - return taskDefinitions.filter( // use lodash filter? + return taskDefinitions.filter( + // use lodash filter? (td) => { return ( td?.name.toLowerCase().includes(searchName) || diff --git a/src/app/common/filters/tasks-by-tutor.pipe.ts b/src/app/common/filters/tasks-by-tutor.pipe.ts index 92f49f13cf..0bc94b7635 100644 --- a/src/app/common/filters/tasks-by-tutor.pipe.ts +++ b/src/app/common/filters/tasks-by-tutor.pipe.ts @@ -2,8 +2,8 @@ import {Pipe, PipeTransform} from '@angular/core'; import {Task, UnitRole} from '../../api/models/doubtfire-model'; @Pipe({ - name: 'tasksByTutor', - standalone: false + name: 'tasksByTutor', + standalone: false, }) export class TasksByTutorPipe implements PipeTransform { transform(currentUnitRole: UnitRole, tasks: Task[], unitRoleId?: number | string): Task[] { diff --git a/src/app/common/filters/tasks-for-group-set.pipe.ts b/src/app/common/filters/tasks-for-group-set.pipe.ts index 10f611f29b..214647340f 100644 --- a/src/app/common/filters/tasks-for-group-set.pipe.ts +++ b/src/app/common/filters/tasks-for-group-set.pipe.ts @@ -1,16 +1,16 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { Task, GroupSet } from 'src/app/api/models/doubtfire-model'; +import {GroupSet, Task} from 'src/app/api/models/doubtfire-model'; +import {Pipe, PipeTransform} from '@angular/core'; @Pipe({ - name: 'tasksForGroupset', - standalone: false + name: 'tasksForGroupset', + standalone: false, }) export class TasksForGroupsetPipe implements PipeTransform { transform(tasks: Task[], groupSet: GroupSet): Task[] { if (!tasks) return tasks; - return tasks.filter(task => { - return (task.definition.groupSet === groupSet) || (!task.definition.groupSet && !groupSet); + return tasks.filter((task) => { + return task.definition.groupSet === groupSet || (!task.definition.groupSet && !groupSet); }); } } diff --git a/src/app/common/filters/tasks-for-inbox-search.pipe.ts b/src/app/common/filters/tasks-for-inbox-search.pipe.ts index d48da24b17..26a923f665 100644 --- a/src/app/common/filters/tasks-for-inbox-search.pipe.ts +++ b/src/app/common/filters/tasks-for-inbox-search.pipe.ts @@ -1,9 +1,9 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { Task } from 'src/app/api/models/task'; +import {Task} from 'src/app/api/models/task'; +import {Pipe, PipeTransform} from '@angular/core'; @Pipe({ - name: 'tasksWithStudentName', - standalone: false + name: 'tasksWithStudentName', + standalone: false, }) export class TasksForInboxSearchPipe implements PipeTransform { transform(tasks: Task[], searchText: string): Task[] { @@ -20,8 +20,8 @@ export class TasksForInboxSearchPipe implements PipeTransform { searchTerms .map((term: string) => task.matches(term)) .reduce((prev: boolean, current: boolean, currentIndex: number) => - operators[currentIndex - 1] === '&' ? prev && current : prev || current - ) + operators[currentIndex - 1] === '&' ? prev && current : prev || current, + ), ); } } diff --git a/src/app/common/filters/tasks-in-tutorials.pipe.ts b/src/app/common/filters/tasks-in-tutorials.pipe.ts index 93ab0b15ad..918a8da811 100644 --- a/src/app/common/filters/tasks-in-tutorials.pipe.ts +++ b/src/app/common/filters/tasks-in-tutorials.pipe.ts @@ -1,9 +1,9 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { Task } from '../../api/models/doubtfire-model'; +import {Pipe, PipeTransform} from '@angular/core'; +import {Task} from '../../api/models/doubtfire-model'; @Pipe({ - name: 'tasksInTutorials', - standalone: false + name: 'tasksInTutorials', + standalone: false, }) export class TasksInTutorialsPipe implements PipeTransform { transform(tasks: Task[], tutorialIds: number[], forceStream: boolean): Task[] { diff --git a/src/app/common/filters/tasks-of-task-definition.pipe.ts b/src/app/common/filters/tasks-of-task-definition.pipe.ts index ae1a4ceaaf..bd039c8a00 100644 --- a/src/app/common/filters/tasks-of-task-definition.pipe.ts +++ b/src/app/common/filters/tasks-of-task-definition.pipe.ts @@ -1,9 +1,9 @@ -import { Pipe, PipeTransform } from '@angular/core'; -import { Task, TaskDefinition } from 'src/app/api/models/doubtfire-model'; +import {Task, TaskDefinition} from 'src/app/api/models/doubtfire-model'; +import {Pipe, PipeTransform} from '@angular/core'; @Pipe({ - name: 'tasksOfTaskDefinition', - standalone: false + name: 'tasksOfTaskDefinition', + standalone: false, }) export class TasksOfTaskDefinitionPipe implements PipeTransform { transform(tasks: Task[], taskDefinition: TaskDefinition): Task[] { diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index e7a031ddc7..8e470d155d 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -1,4 +1,4 @@ - + more_time Overflow @@ -136,16 +112,10 @@ - - @@ -154,10 +124,7 @@ - @if ( diff --git a/src/app/common/header/task-dropdown/task-dropdown.component.spec.ts b/src/app/common/header/task-dropdown/task-dropdown.component.spec.ts index 7bea55283c..298ab4f769 100644 --- a/src/app/common/header/task-dropdown/task-dropdown.component.spec.ts +++ b/src/app/common/header/task-dropdown/task-dropdown.component.spec.ts @@ -1,7 +1,6 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; - -import { TaskDropdownComponent } from './task-dropdown.component'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {RouterTestingModule} from '@angular/router/testing'; +import {TaskDropdownComponent} from './task-dropdown.component'; describe('TaskDropdownComponent', () => { let component: TaskDropdownComponent; diff --git a/src/app/common/header/task-dropdown/task-dropdown.component.ts b/src/app/common/header/task-dropdown/task-dropdown.component.ts index 4bde5624ac..e964b3307d 100644 --- a/src/app/common/header/task-dropdown/task-dropdown.component.ts +++ b/src/app/common/header/task-dropdown/task-dropdown.component.ts @@ -1,26 +1,26 @@ -import {Component, Input} from '@angular/core'; -import {ActivatedRoute, NavigationEnd, Router} from '@angular/router'; +import {filter} from 'rxjs'; import {Project, Unit, UnitRole} from 'src/app/api/models/doubtfire-model'; import {ViewType} from 'src/app/projects/states/index/global-state.service'; +import {Component, Input} from '@angular/core'; +import {ActivatedRoute, NavigationEnd, Router} from '@angular/router'; import {TutorNotesModalService} from '../../modals/tutor-notes-modal/tutor-notes-modal.service'; -import {filter} from 'rxjs'; @Component({ - selector: 'task-dropdown', - templateUrl: './task-dropdown.component.html', - styleUrls: ['./task-dropdown.component.scss'], - standalone: false + selector: 'task-dropdown', + templateUrl: './task-dropdown.component.html', + styleUrls: ['./task-dropdown.component.scss'], + standalone: false, }) export class TaskDropdownComponent { currentActivity: string; menuText: string; - @Input() data: { isTutor: boolean }; + @Input() data: {isTutor: boolean}; @Input() currentUnit: Unit; @Input() currentProject: Project; @Input() currentView: ViewType; @Input() unitRole: UnitRole; - taskToShortName: { [key: string]: string } = { + taskToShortName: Record = { 'Portfolio Creation': 'Portfolio', 'Staff Tasks': 'Staff Tasks', 'Student Groups': 'Groups', @@ -36,7 +36,7 @@ export class TaskDropdownComponent { 'Unit Analytics': 'Analytics', }; - taskDropdownData: {title: string; target: string; visible: any}[]; + taskDropdownData: {title: string; target: string; visible: boolean}[]; constructor( private angularRouter: Router, private route: ActivatedRoute, diff --git a/src/app/common/header/unit-dropdown/unit-dropdown.component.html b/src/app/common/header/unit-dropdown/unit-dropdown.component.html index 5830470da8..7c0afe82e5 100644 --- a/src/app/common/header/unit-dropdown/unit-dropdown.component.html +++ b/src/app/common/header/unit-dropdown/unit-dropdown.component.html @@ -47,8 +47,8 @@

    Units y mat-menu-item class="w-full" > -
    -
    {{ unitRole.unit.name }}
    +
    +
    {{ unitRole.unit.name }}
    @@ -62,12 +62,12 @@

    Units yo @if (!project.unit.teachingPeriod || project.unit.teachingPeriod.active) { diff --git a/src/app/common/header/unit-dropdown/unit-dropdown.component.spec.ts b/src/app/common/header/unit-dropdown/unit-dropdown.component.spec.ts index 255c47f1bb..17d17ccaaa 100644 --- a/src/app/common/header/unit-dropdown/unit-dropdown.component.spec.ts +++ b/src/app/common/header/unit-dropdown/unit-dropdown.component.spec.ts @@ -1,26 +1,22 @@ -import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -import { MatMenuModule } from '@angular/material/menu'; -import { DateService } from 'src/app/common/services/date.service'; - -import { UnitDropdownComponent } from './unit-dropdown.component'; +import {DateService} from 'src/app/common/services/date.service'; +import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; +import {MatMenuModule} from '@angular/material/menu'; +import {UnitDropdownComponent} from './unit-dropdown.component'; describe('UnitDropdownComponent', () => { let component: UnitDropdownComponent; let fixture: ComponentFixture; - let dateServiceStub: jasmine.SpyObj; + let dateServiceStub: Pick; - beforeEach( - waitForAsync(() => { - dateServiceStub = jasmine.createSpy(); - dateServiceStub.showDate = true; + beforeEach(waitForAsync(() => { + dateServiceStub = {showDate: true}; - TestBed.configureTestingModule({ - declarations: [UnitDropdownComponent], - imports: [MatMenuModule], - providers: [{ provide: DateService, useValue: dateServiceStub }], - }).compileComponents(); - }) - ); + TestBed.configureTestingModule({ + declarations: [UnitDropdownComponent], + imports: [MatMenuModule], + providers: [{provide: DateService, useValue: dateServiceStub}], + }).compileComponents(); + })); beforeEach(() => { fixture = TestBed.createComponent(UnitDropdownComponent); diff --git a/src/app/common/header/unit-dropdown/unit-dropdown.component.ts b/src/app/common/header/unit-dropdown/unit-dropdown.component.ts index 778d75f85f..65acb26fa1 100644 --- a/src/app/common/header/unit-dropdown/unit-dropdown.component.ts +++ b/src/app/common/header/unit-dropdown/unit-dropdown.component.ts @@ -1,14 +1,14 @@ -import {Component, Input, OnInit} from '@angular/core'; -import {Project, Unit, UnitRole} from 'src/app/api/models/doubtfire-model'; import {MediaObserver} from 'ng-flex-layout'; +import {Project, Unit, UnitRole} from 'src/app/api/models/doubtfire-model'; +import {Component, Input} from '@angular/core'; @Component({ - selector: 'unit-dropdown', - templateUrl: './unit-dropdown.component.html', - styleUrls: ['./unit-dropdown.component.scss'], - standalone: false + selector: 'unit-dropdown', + templateUrl: './unit-dropdown.component.html', + styleUrls: ['./unit-dropdown.component.scss'], + standalone: false, }) -export class UnitDropdownComponent implements OnInit { +export class UnitDropdownComponent { @Input() unitRoles: UnitRole[]; @Input() projects: Project[]; @Input() unit: Unit; @@ -16,6 +16,4 @@ export class UnitDropdownComponent implements OnInit { unitTitle: string; constructor(public media: MediaObserver) {} - - ngOnInit(): void {} } diff --git a/src/app/common/hero-sidebar/hero-sidebar.component.html b/src/app/common/hero-sidebar/hero-sidebar.component.html index 99fba02150..12145dfff4 100644 --- a/src/app/common/hero-sidebar/hero-sidebar.component.html +++ b/src/app/common/hero-sidebar/hero-sidebar.component.html @@ -1,12 +1,17 @@
    -
    - Homepage Logo +
    + Homepage Logo

    {{ externalName.value }}

    Manage your learning, with feedback you'll want to receive.

    -
    +
    diff --git a/src/app/common/hero-sidebar/hero-sidebar.component.scss b/src/app/common/hero-sidebar/hero-sidebar.component.scss index aaf7e537d5..b49aa2b548 100644 --- a/src/app/common/hero-sidebar/hero-sidebar.component.scss +++ b/src/app/common/hero-sidebar/hero-sidebar.component.scss @@ -35,8 +35,20 @@ } .pattern { - -webkit-mask-image: -webkit-gradient(linear, left top, left bottom, to(rgba(0, 0, 0, 1)), from(rgba(0, 0, 0, 0))); - mask-image: -webkit-gradient(linear, left top, left bottom, to(rgba(0, 0, 0, 1)), from(rgba(0, 0, 0, 0))); + -webkit-mask-image: -webkit-gradient( + linear, + left top, + left bottom, + to(rgba(0, 0, 0, 1)), + from(rgba(0, 0, 0, 0)) + ); + mask-image: -webkit-gradient( + linear, + left top, + left bottom, + to(rgba(0, 0, 0, 1)), + from(rgba(0, 0, 0, 0)) + ); transition: 4s linear all; background-color: #e5e5f7; opacity: 1; diff --git a/src/app/common/hero-sidebar/hero-sidebar.component.spec.ts b/src/app/common/hero-sidebar/hero-sidebar.component.spec.ts index 5cc1ec36c0..aeefe2f6cd 100644 --- a/src/app/common/hero-sidebar/hero-sidebar.component.spec.ts +++ b/src/app/common/hero-sidebar/hero-sidebar.component.spec.ts @@ -1,6 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { HeroSidebarComponent } from './hero-sidebar.component'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {HeroSidebarComponent} from './hero-sidebar.component'; describe('HeroSidebarComponent', () => { let component: HeroSidebarComponent; @@ -8,9 +7,8 @@ describe('HeroSidebarComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ HeroSidebarComponent ] - }) - .compileComponents(); + declarations: [HeroSidebarComponent], + }).compileComponents(); }); beforeEach(() => { diff --git a/src/app/common/hero-sidebar/hero-sidebar.component.ts b/src/app/common/hero-sidebar/hero-sidebar.component.ts index ef02f8508e..395dfcf401 100644 --- a/src/app/common/hero-sidebar/hero-sidebar.component.ts +++ b/src/app/common/hero-sidebar/hero-sidebar.component.ts @@ -1,15 +1,13 @@ -import { Component, OnInit } from '@angular/core'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Component} from '@angular/core'; @Component({ - selector: 'f-hero-sidebar', - templateUrl: './hero-sidebar.component.html', - styleUrls: ['./hero-sidebar.component.scss'], - standalone: false + selector: 'f-hero-sidebar', + templateUrl: './hero-sidebar.component.html', + styleUrls: ['./hero-sidebar.component.scss'], + standalone: false, }) -export class HeroSidebarComponent implements OnInit { +export class HeroSidebarComponent { public externalName = this.constants.ExternalName; constructor(private constants: DoubtfireConstants) {} - - ngOnInit(): void {} } diff --git a/src/app/common/learning-outcome-editor/learning-outcome-editor.component.html b/src/app/common/learning-outcome-editor/learning-outcome-editor.component.html index c93603fa33..34110a1323 100644 --- a/src/app/common/learning-outcome-editor/learning-outcome-editor.component.html +++ b/src/app/common/learning-outcome-editor/learning-outcome-editor.component.html @@ -1,7 +1,7 @@

    @if (selectedOutcome) { -
    +
    -

    Edit Outcome

    +

    Edit Outcome

    diff --git a/src/app/common/learning-outcome-editor/learning-outcome-editor.component.ts b/src/app/common/learning-outcome-editor/learning-outcome-editor.component.ts index c348401d40..06d2827757 100644 --- a/src/app/common/learning-outcome-editor/learning-outcome-editor.component.ts +++ b/src/app/common/learning-outcome-editor/learning-outcome-editor.component.ts @@ -1,37 +1,37 @@ +import {isEqual} from 'lodash'; +import {Subscription} from 'rxjs'; +import { + FeedbackTemplateService, + LearningOutcome, + LearningOutcomeService, + TaskDefinition, + TaskService, + Unit, +} from 'src/app/api/models/doubtfire-model'; +import {AlertService} from 'src/app/common/services/alert.service'; +import API_URL from 'src/app/config/constants/apiUrl'; import {LiveAnnouncer} from '@angular/cdk/a11y'; import {COMMA, ENTER} from '@angular/cdk/keycodes'; import { AfterViewInit, Component, - computed, - effect, - inject, Input, - model, OnChanges, OnDestroy, OnInit, - signal, SimpleChanges, ViewChild, + computed, + effect, + inject, + model, + signal, } from '@angular/core'; import {MatAutocompleteSelectedEvent} from '@angular/material/autocomplete'; import {MatChipInputEvent} from '@angular/material/chips'; import {MatPaginator} from '@angular/material/paginator'; import {MatSort, Sort} from '@angular/material/sort'; import {MatTable, MatTableDataSource} from '@angular/material/table'; -import {isEqual} from 'lodash'; -import {Subscription} from 'rxjs'; -import { - FeedbackTemplateService, - LearningOutcome, - LearningOutcomeService, - TaskDefinition, - TaskService, - Unit, -} from 'src/app/api/models/doubtfire-model'; -import {AlertService} from 'src/app/common/services/alert.service'; -import API_URL from 'src/app/config/constants/apiUrl'; import {FileDownloaderService} from '../file-downloader/file-downloader.service'; import {ConfirmationModalService} from '../modals/confirmation-modal/confirmation-modal.service'; import { @@ -42,9 +42,9 @@ import {CsvUploadModalService} from '../modals/csv-upload-modal/csv-upload-modal import {NestedCsvDownloadModalService} from './nested-csv-download-modal/nested-csv-download-modal.service'; @Component({ - selector: 'f-learning-outcome-editor', - templateUrl: 'learning-outcome-editor.component.html', - standalone: false + selector: 'f-learning-outcome-editor', + templateUrl: 'learning-outcome-editor.component.html', + standalone: false, }) export class LearningOutcomeEditorComponent implements OnChanges, OnInit, AfterViewInit, OnDestroy { @Input() context?: TaskDefinition | Unit; @@ -53,7 +53,7 @@ export class LearningOutcomeEditorComponent implements OnChanges, OnInit, AfterV @ViewChild(MatSort, {static: false}) outcomeSort: MatSort; @ViewChild(MatPaginator, {static: false}) outcomePaginator: MatPaginator; - public outcomeSource = new MatTableDataSource([]); + public outcomeSource: MatTableDataSource = new MatTableDataSource([]); public outcomeColumns: string[] = [ 'abbreviation', 'shortDescription', @@ -143,7 +143,7 @@ export class LearningOutcomeEditorComponent implements OnChanges, OnInit, AfterV } } - ngOnChanges(changes: SimpleChanges): void { + ngOnChanges(_changes: SimpleChanges): void { this.setAbbreviationPrefix(); this.selectedOutcome = null; } diff --git a/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.html b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.html index a076bde450..d236474d37 100644 --- a/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.html +++ b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.html @@ -8,7 +8,7 @@

    Download the {{ data.type }} CSV

    -
    +
    diff --git a/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.ts b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.ts index 92cb486d97..1c072924cf 100644 --- a/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.ts +++ b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.ts @@ -3,9 +3,9 @@ import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {FileDownloaderService} from '../../file-downloader/file-downloader.service'; @Component({ - selector: 'f-nested-csv-download-modal', - templateUrl: './nested-csv-download-modal.component.html', - standalone: false + selector: 'f-nested-csv-download-modal', + templateUrl: './nested-csv-download-modal.component.html', + standalone: false, }) export class NestedCsvDownloadModalComponent { public includeNested = false; diff --git a/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.service.ts b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.service.ts index 91e34ff400..9aad82f209 100644 --- a/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.service.ts +++ b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.service.ts @@ -1,5 +1,5 @@ import {Injectable} from '@angular/core'; -import {MatDialogRef, MatDialog} from '@angular/material/dialog'; +import {MatDialog} from '@angular/material/dialog'; import {NestedCsvDownloadModalComponent} from './nested-csv-download-modal.component'; @Injectable({ @@ -9,7 +9,7 @@ export class NestedCsvDownloadModalService { constructor(public dialog: MatDialog) {} public show(url: string, name: string, type: string) { - const dialogRef: MatDialogRef = this.dialog.open( + this.dialog.open( NestedCsvDownloadModalComponent, { data: {url, name, type}, diff --git a/src/app/common/modals/about-doubtfire-modal/about-dialog-data.ts b/src/app/common/modals/about-doubtfire-modal/about-dialog-data.ts index e85e989082..e94c182df7 100644 --- a/src/app/common/modals/about-doubtfire-modal/about-dialog-data.ts +++ b/src/app/common/modals/about-doubtfire-modal/about-dialog-data.ts @@ -1,7 +1,7 @@ -import { GithubProfile } from './github-profile'; -import { ContributorData } from './contributor-data'; -import { BehaviorSubject } from 'rxjs'; -import { Sort } from '@angular/material/sort'; +import {BehaviorSubject} from 'rxjs'; +import {Sort} from '@angular/material/sort'; +import {ContributorData} from './contributor-data'; +import {GithubProfile} from './github-profile'; /** * The data shared between the AboutDoubtfireModal and its associated @@ -51,7 +51,7 @@ export class AboutDialogData { default: return 0; } - }) + }), ); } } diff --git a/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.component.ts b/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.component.ts index 26bf10dedc..ce01e3d284 100644 --- a/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.component.ts +++ b/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.component.ts @@ -1,19 +1,18 @@ // // Modal to show Doubtfire version info // -import { Injectable, Component, Inject } from '@angular/core'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; -import { AboutDoubtfireModalService } from '../about-doubtfire-modal/about-doubtfire-modal.service'; -import { GithubProfile } from './github-profile'; - -import { MatDialog, MAT_DIALOG_DATA } from '@angular/material/dialog'; -import { AboutDialogData } from './about-dialog-data'; -import { Sort } from '@angular/material/sort'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Component, Inject, Injectable} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialog} from '@angular/material/dialog'; +import {Sort} from '@angular/material/sort'; +import {AboutDoubtfireModalService} from '../about-doubtfire-modal/about-doubtfire-modal.service'; +import {AboutDialogData} from './about-dialog-data'; +import {GithubProfile} from './github-profile'; @Component({ - selector: 'about-doubtfire-dialog', - templateUrl: 'about-doubtfire-modal-content.tpl.html', - standalone: false + selector: 'about-doubtfire-dialog', + templateUrl: 'about-doubtfire-modal-content.tpl.html', + standalone: false, }) export class AboutDoubtfireModalContent { public displayedColumns: string[] = [ @@ -44,7 +43,7 @@ export class AboutDoubtfireModal { constructor( public dialog: MatDialog, private constants: DoubtfireConstants, - private aboutDoubtfireModalService: AboutDoubtfireModalService + private aboutDoubtfireModalService: AboutDoubtfireModalService, ) { this.loaded = false; this.aboutDialogData = new AboutDialogData(); diff --git a/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.service.ts b/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.service.ts index eeadc89f86..90cad12986 100644 --- a/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.service.ts +++ b/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.service.ts @@ -1,9 +1,8 @@ -import { Injectable } from '@angular/core'; -import { HttpClient } from '@angular/common/http'; - -import { GithubProfile } from './github-profile'; -import { ContributorData } from './contributor-data'; -import { AboutDialogData } from './about-dialog-data'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {AboutDialogData} from './about-dialog-data'; +import {ContributorData} from './contributor-data'; +import {GithubProfile} from './github-profile'; interface GithubContributors { login: string; @@ -35,7 +34,10 @@ export class AboutDoubtfireModalService { return this.http.get(`https://api.github.com/users/${handler}`); } - private findOrCreateContributor(data: AboutDialogData, profile: GithubContributors): ContributorData { + private findOrCreateContributor( + data: AboutDialogData, + profile: GithubContributors, + ): ContributorData { let contributor: ContributorData; contributor = data.allContributors.value.find((c) => { return c.login === profile.login; @@ -54,7 +56,7 @@ export class AboutDoubtfireModalService { const contributor = this.findOrCreateContributor(data, profile); contributor[key] = profile.contributions; }); - data.sortData({ active: 'contributions', direction: 'desc' }); + data.sortData({active: 'contributions', direction: 'desc'}); }); } @@ -62,7 +64,7 @@ export class AboutDoubtfireModalService { this.getContributors( 'https://api.github.com/repos/doubtfire-lms/doubtfire.io/contributors', data, - 'ioContributions' + 'ioContributions', ); } @@ -70,7 +72,7 @@ export class AboutDoubtfireModalService { this.getContributors( 'https://api.github.com/repos/doubtfire-lms/doubtfire-deploy/contributors', data, - 'deployContributions' + 'deployContributions', ); } @@ -78,7 +80,7 @@ export class AboutDoubtfireModalService { this.getContributors( 'https://api.github.com/repos/doubtfire-lms/doubtfire-web/contributors', data, - 'webContributions' + 'webContributions', ); } @@ -86,7 +88,7 @@ export class AboutDoubtfireModalService { this.getContributors( 'https://api.github.com/repos/doubtfire-lms/doubtfire-api/contributors', data, - 'apiContributions' + 'apiContributions', ); } } diff --git a/src/app/common/modals/about-doubtfire-modal/contributor-data.ts b/src/app/common/modals/about-doubtfire-modal/contributor-data.ts index 96f805cd2a..31ac133888 100644 --- a/src/app/common/modals/about-doubtfire-modal/contributor-data.ts +++ b/src/app/common/modals/about-doubtfire-modal/contributor-data.ts @@ -21,6 +21,11 @@ export class ContributorData { this.deployContributions = 0; } get totalContributions(): number { - return this.apiContributions + this.webContributions + this.ioContributions + this.deployContributions; + return ( + this.apiContributions + + this.webContributions + + this.ioContributions + + this.deployContributions + ); } } diff --git a/src/app/common/modals/about-doubtfire-modal/github-profile.ts b/src/app/common/modals/about-doubtfire-modal/github-profile.ts index 7e7364ddac..cddb26d0ae 100644 --- a/src/app/common/modals/about-doubtfire-modal/github-profile.ts +++ b/src/app/common/modals/about-doubtfire-modal/github-profile.ts @@ -3,4 +3,4 @@ export interface GithubProfile { name: string; html_url: string; login: string; -} \ No newline at end of file +} diff --git a/src/app/common/modals/calendar-modal/calendar-modal.component.html b/src/app/common/modals/calendar-modal/calendar-modal.component.html index cdd72ca70b..3af81bbb87 100644 --- a/src/app/common/modals/calendar-modal/calendar-modal.component.html +++ b/src/app/common/modals/calendar-modal/calendar-modal.component.html @@ -6,7 +6,9 @@

    Web calendar

    Web calendar
    @if (!webcal) { - - - - } + + + } + @if (webcal) { + Your web calendar is currently {{ webcal.enabled ? 'enabled' : 'disabled' }}. - Your web calendar is currently {{ webcal.enabled ? 'enabled' : 'disabled' }}. - - @if (!webcal.enabled) { -
    -

    - The web calendar displays due dates of your tasks as calendar events in an iCalendar that can be added to any - iCalendar client (e.g. Outlook/Google/iCloud calendar). -

    -
    - } - - - @if (webcal.enabled) { -
    -

    - The web calendar displays due dates of your tasks as calendar events. Use the following URL to subscribe to your - web calendar from your iCalendar client. -

    -
    -
    - {{ webcalUrl }} + @if (!webcal.enabled) { +
    +

    + The web calendar displays due dates of your tasks as calendar events in an iCalendar + that can be added to any iCalendar client (e.g. Outlook/Google/iCloud calendar). +

    -
    - - -
    -
    - + } + - -

    Options

    + @if (webcal.enabled) { +
    +

    + The web calendar displays due dates of your tasks as calendar events. Use the following + URL to subscribe to your web calendar from your iCalendar client. +

    +
    + +
    + + +
    +
    + -
    - Included units in my calendar: -
    + +

    Options

    -
    - - @for (project of includedProjects; track project) { - - {{ project.unit.code }} - cancel - - } @if (excludedProjects.length > 0) { - - add - - @for (project of excludedProjects; track project) { - +
    + Included units in my calendar: +
    + +
    + + @for (project of includedProjects; track project) { + + {{ project.unit.code }} + cancel + } - - - } - -
    - + @if (excludedProjects.length > 0) { + + add + + @for (project of excludedProjects; track project) { + + } + + + } +
    +
    + - - Remind me - - - Time - - - - Unit - - Weeks - Days - Hours - Minutes - - - before each event - - @if ( (!webcal.reminder && newReminderActive) || (webcal.reminder && (newReminderTime !== webcal.reminder.time - || newReminderUnit !== webcal.reminder.unit)) ) { - - - - } + @if ( + (!webcal.reminder && newReminderActive) || + (webcal.reminder && + (newReminderTime !== webcal.reminder.time || + newReminderUnit !== webcal.reminder.unit)) + ) { + + + } + -
    +
    - - Include task start dates in web calendar + + Include task start dates in web calendar -
    - +
    + +
    +
    -
    -
    + } + } - - } +
    diff --git a/src/app/common/modals/calendar-modal/calendar-modal.component.ts b/src/app/common/modals/calendar-modal/calendar-modal.component.ts index f66ed3779a..c9540a5250 100644 --- a/src/app/common/modals/calendar-modal/calendar-modal.component.ts +++ b/src/app/common/modals/calendar-modal/calendar-modal.component.ts @@ -1,15 +1,15 @@ -import {Component, OnInit, Inject, ViewChild, AfterViewInit} from '@angular/core'; -import {MAT_DIALOG_DATA} from '@angular/material/dialog'; -import {MatSlideToggle} from '@angular/material/slide-toggle'; import {Project, ProjectService, Webcal, WebcalService} from 'src/app/api/models/doubtfire-model'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {AfterViewInit, Component, Inject, OnInit, ViewChild} from '@angular/core'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {MatSlideToggle} from '@angular/material/slide-toggle'; import {AlertService} from '../../services/alert.service'; @Component({ - selector: 'calendar-modal', - templateUrl: './calendar-modal.component.html', - styleUrls: ['./calendar-modal.component.scss'], - standalone: false + selector: 'calendar-modal', + templateUrl: './calendar-modal.component.html', + styleUrls: ['./calendar-modal.component.scss'], + standalone: false, }) export class CalendarModalComponent implements OnInit, AfterViewInit { @ViewChild('webcalToggle') webcalToggle: MatSlideToggle; @@ -30,7 +30,7 @@ export class CalendarModalComponent implements OnInit, AfterViewInit { private constants: DoubtfireConstants, private alerts: AlertService, private projectService: ProjectService, - @Inject(MAT_DIALOG_DATA) public data: any, + @Inject(MAT_DIALOG_DATA) public data: object, ) {} ngOnInit() { diff --git a/src/app/common/modals/calendar-modal/calendar-modal.service.ts b/src/app/common/modals/calendar-modal/calendar-modal.service.ts index 37ddb1d51c..2f815ab338 100644 --- a/src/app/common/modals/calendar-modal/calendar-modal.service.ts +++ b/src/app/common/modals/calendar-modal/calendar-modal.service.ts @@ -1,6 +1,7 @@ -import { Injectable } from '@angular/core'; -import { MatDialogRef, MAT_DIALOG_DATA, MatDialog } from '@angular/material/dialog'; -import { CalendarModalComponent } from './calendar-modal.component'; +import {Task} from 'src/app/api/models/task'; +import {Injectable} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import {CalendarModalComponent} from './calendar-modal.component'; @Injectable({ providedIn: 'root', @@ -8,8 +9,7 @@ import { CalendarModalComponent } from './calendar-modal.component'; export class CalendarModalService { constructor(public dialog: MatDialog) {} - public show(task: any) { - let dialogRef: MatDialogRef; - dialogRef = this.dialog.open(CalendarModalComponent); + public show(_task?: Task) { + this.dialog.open(CalendarModalComponent); } } diff --git a/src/app/common/modals/comments-modal/comments-modal.component.html b/src/app/common/modals/comments-modal/comments-modal.component.html index 4236c93c2d..c4e73f0de0 100644 --- a/src/app/common/modals/comments-modal/comments-modal.component.html +++ b/src/app/common/modals/comments-modal/comments-modal.component.html @@ -1,7 +1,11 @@
    @if (taskComment.commentType === 'image') { - + Image attachment } @else if (taskComment.commentType === 'pdf') { - + }
    diff --git a/src/app/common/modals/comments-modal/comments-modal.component.ts b/src/app/common/modals/comments-modal/comments-modal.component.ts index ebad5e1695..671110b292 100644 --- a/src/app/common/modals/comments-modal/comments-modal.component.ts +++ b/src/app/common/modals/comments-modal/comments-modal.component.ts @@ -1,6 +1,6 @@ -import {Component, Input, Inject, OnInit} from '@angular/core'; -import {MAT_DIALOG_DATA} from '@angular/material/dialog'; import {TaskComment} from 'src/app/api/models/doubtfire-model'; +import {Component, Inject, Input, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; export interface CommentsModalData { comment: TaskComment; @@ -8,10 +8,10 @@ export interface CommentsModalData { } @Component({ - selector: 'comments-modal', - templateUrl: './comments-modal.component.html', - styleUrls: ['./comments-modal.component.scss'], - standalone: false + selector: 'comments-modal', + templateUrl: './comments-modal.component.html', + styleUrls: ['./comments-modal.component.scss'], + standalone: false, }) export class CommentsModalComponent implements OnInit { @Input() taskComment: TaskComment; diff --git a/src/app/common/modals/comments-modal/comments-modal.service.ts b/src/app/common/modals/comments-modal/comments-modal.service.ts index 353c9c6c37..c1a7d3e013 100644 --- a/src/app/common/modals/comments-modal/comments-modal.service.ts +++ b/src/app/common/modals/comments-modal/comments-modal.service.ts @@ -1,6 +1,6 @@ +import {TaskComment} from 'src/app/api/models/doubtfire-model'; import {Injectable} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; -import {TaskComment} from 'src/app/api/models/doubtfire-model'; import {CommentsModalComponent, CommentsModalData} from './comments-modal.component'; @Injectable({ diff --git a/src/app/common/modals/confirmation-modal/confirmation-modal.component.ts b/src/app/common/modals/confirmation-modal/confirmation-modal.component.ts index 59607b84c2..dea3e5fad4 100644 --- a/src/app/common/modals/confirmation-modal/confirmation-modal.component.ts +++ b/src/app/common/modals/confirmation-modal/confirmation-modal.component.ts @@ -1,6 +1,6 @@ -import {Component, OnInit, Input, Inject} from '@angular/core'; -import {AlertService} from '../../services/alert.service'; +import {Component, Inject, Input, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {AlertService} from '../../services/alert.service'; export interface ConfirmationModalData { title: string; @@ -12,10 +12,10 @@ export interface ConfirmationModalData { } @Component({ - selector: 'confirmation-modal', - templateUrl: './confirmation-modal.component.html', - styleUrls: ['./confirmation-modal.component.scss'], - standalone: false + selector: 'confirmation-modal', + templateUrl: './confirmation-modal.component.html', + styleUrls: ['./confirmation-modal.component.scss'], + standalone: false, }) export class ConfirmationModalComponent implements OnInit { @Input() title: string; diff --git a/src/app/common/modals/csv-result-modal/csv-result-modal.component.html b/src/app/common/modals/csv-result-modal/csv-result-modal.component.html index 1de2d91f66..a08ab98d77 100644 --- a/src/app/common/modals/csv-result-modal/csv-result-modal.component.html +++ b/src/app/common/modals/csv-result-modal/csv-result-modal.component.html @@ -70,7 +70,7 @@

    {{ data.title }}

    } - + @if (dataSource.data.length > 0) { ([]); - private columnKeyById = new Map(); + public dataSource: MatTableDataSource = new MatTableDataSource([]); + private columnKeyById: Map = new Map(); @ViewChild(MatPaginator) paginator?: MatPaginator; - public readonly csvResponseSelections: { key: CsvResultSelection; label: string }[] = [ + public readonly csvResponseSelections: {key: CsvResultSelection; label: string}[] = [ {key: 'success', label: 'Success'}, {key: 'errors', label: 'Errors'}, {key: 'ignored', label: 'Ignored'}, @@ -115,7 +111,7 @@ export class CsvResultModalComponent implements AfterViewInit { private rebuildTableData(): void { const items = this.itemData(this.activeCsvResponseSelection); const rowObjects = items.map((item) => this.toRowObject(item.row)); - const keyCounts = new Map(); + const keyCounts: Map = new Map(); rowObjects.forEach((rowObject) => { if (!rowObject) { @@ -186,9 +182,7 @@ export class CsvResultModalComponent implements AfterViewInit { if (Array.isArray(row)) { const entries = row.filter( (entry): entry is [string, unknown] => - Array.isArray(entry) && - entry.length >= 2 && - typeof entry[0] === 'string', + Array.isArray(entry) && entry.length >= 2 && typeof entry[0] === 'string', ); if (entries.length === row.length && entries.length > 0) { diff --git a/src/app/common/modals/csv-result-modal/csv-result-modal.service.ts b/src/app/common/modals/csv-result-modal/csv-result-modal.service.ts index b73eea3341..20a41f3fb8 100644 --- a/src/app/common/modals/csv-result-modal/csv-result-modal.service.ts +++ b/src/app/common/modals/csv-result-modal/csv-result-modal.service.ts @@ -1,7 +1,7 @@ import {Injectable} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; -import {CsvResultModalComponent} from './csv-result-modal.component'; import {AlertService} from '../../services/alert.service'; +import {CsvResultModalComponent} from './csv-result-modal.component'; export interface CsvRow { row: unknown; diff --git a/src/app/common/modals/csv-upload-modal/csv-upload-modal.component.ts b/src/app/common/modals/csv-upload-modal/csv-upload-modal.component.ts index 6e3cfffaed..76d58e1ac6 100644 --- a/src/app/common/modals/csv-upload-modal/csv-upload-modal.component.ts +++ b/src/app/common/modals/csv-upload-modal/csv-upload-modal.component.ts @@ -6,9 +6,7 @@ export interface CsvUploadFileSpec { type: string; } -export interface CsvUploadFileMap { - [uploadName: string]: CsvUploadFileSpec; -} +export type CsvUploadFileMap = Record; export interface CsvUploadModalData { title: string; @@ -19,10 +17,10 @@ export interface CsvUploadModalData { } @Component({ - selector: 'f-csv-upload-modal', - templateUrl: './csv-upload-modal.component.html', - styleUrls: ['./csv-upload-modal.component.scss'], - standalone: false + selector: 'f-csv-upload-modal', + templateUrl: './csv-upload-modal.component.html', + styleUrls: ['./csv-upload-modal.component.scss'], + standalone: false, }) export class CsvUploadModalComponent { constructor( diff --git a/src/app/common/modals/date-change-modal/task-date-slider.component.html b/src/app/common/modals/date-change-modal/task-date-slider.component.html index a67015f78b..5cd73218b1 100644 --- a/src/app/common/modals/date-change-modal/task-date-slider.component.html +++ b/src/app/common/modals/date-change-modal/task-date-slider.component.html @@ -70,13 +70,13 @@
    @if (editMode) { @if (afterDeadline()) { -
    + + + +
    Name @if (editing(group)) { - + } @else { @@ -74,7 +74,7 @@ Tutorial @if (editing(group)) { - + @for (tutorial of unit.tutorials; track tutorial) { {{ tutorial.abbreviation }} @@ -96,7 +96,7 @@ @if (unitRole) { @if (editing(group)) { - + @if (isPartOfGroup(project, group)) { -
    Joined
    +
    Joined
    } @else if (project && group.hasSpace() && selectedGroupSet.allowStudentsToManageGroups) { -
    +
    @if (!group.locked && !selectedGroupSet.locked) {
    } -

    Units you teach

    -
    - @if (!unitRole.unit.teachingPeriod || unitRole.unit.teachingPeriod?.active) { -
    - - - {{ unitRole.unit?.name }} - {{ unitRole.unit?.code }} - - - - - - - {{ unitRole.teachingPeriod?.name || showDate(unitRole.unit.startDate) }} - - - {{ unitRole.role }} - - - - - - -
    - } -
    + @for (unitRole of unitRoles | isActiveUnitRole; track unitRole) { +
    + @if (!unitRole.unit.teachingPeriod || unitRole.unit.teachingPeriod?.active) { +
    + + + {{ unitRole.unit?.name }} + {{ unitRole.unit?.code }} + + + + + + + {{ unitRole.teachingPeriod?.name || showDate(unitRole.unit.startDate) }} + + + {{ unitRole.role }} + + + + + + +
    + } +
    + } Units you teach
    + @if (unitRoles.length && projects?.length) { + + }

    Enrolled units

    diff --git a/src/app/home/states/home/home.component.ts b/src/app/home/states/home/home.component.ts index 5ff49cd0e5..7e1d2ba99f 100644 --- a/src/app/home/states/home/home.component.ts +++ b/src/app/home/states/home/home.component.ts @@ -1,16 +1,16 @@ -import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; -import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Subscription} from 'rxjs'; +import {Project, UnitRole, User, UserService} from 'src/app/api/models/doubtfire-model'; import {DateService} from 'src/app/common/services/date.service'; -import {Router} from '@angular/router'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global-state.service'; -import {Project, UnitRole, User, UserService} from 'src/app/api/models/doubtfire-model'; -import {Subscription} from 'rxjs'; +import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; +import {Router} from '@angular/router'; @Component({ - selector: 'home', - templateUrl: 'home.component.html', - styleUrls: ['home.component.scss'], - standalone: false + selector: 'home', + templateUrl: 'home.component.html', + styleUrls: ['home.component.scss'], + standalone: false, }) export class HomeComponent implements OnInit, OnDestroy { projects: Project[]; @@ -52,7 +52,6 @@ export class HomeComponent implements OnInit, OnDestroy { this.subscriptions.push( this.globalState.unitRolesSubject.subscribe({ next: (unitRoles) => this.unitRolesLoaded(unitRoles), - error: (err) => {}, }), ); @@ -62,7 +61,6 @@ export class HomeComponent implements OnInit, OnDestroy { projects = projects.filter((project) => project.unit.myRole === 'Student'); this.projectsLoaded(projects); }, - error: (err) => {}, }), ); diff --git a/src/app/home/states/lti-dashboard/lti-dashboard.component.html b/src/app/home/states/lti-dashboard/lti-dashboard.component.html index 0a31177529..880914025d 100644 --- a/src/app/home/states/lti-dashboard/lti-dashboard.component.html +++ b/src/app/home/states/lti-dashboard/lti-dashboard.component.html @@ -1,18 +1,18 @@ -
    -
    -
    +
    +
    +

    OnTrack

    @if (isLoading) { @if (unauthorised) { -
    +
    An error occurred. Please refresh the page.
    } @else { @@ -28,7 +28,7 @@

    OnTrack

    matTooltip="Sync enrolments" matTooltipPosition="above" aria-label="" - class="w-[60px] h-[60px] relative" + class="relative h-[60px] w-[60px]" [ngClass]="{'bg-gray-300': isSyncingEnrolments}" color="default" (click)="syncEnrolments()" @@ -36,7 +36,7 @@

    OnTrack

    @if (isSyncingEnrolments) { } people @@ -47,7 +47,7 @@

    OnTrack

    matTooltip="Sync grades" matTooltipPosition="above" aria-label="" - class="w-[60px] h-[60px] relative" + class="relative h-[60px] w-[60px]" [ngClass]="{'bg-gray-300': isSyncingGrades}" color="default" (click)="syncStudentsGrades()" @@ -57,7 +57,7 @@

    OnTrack

    @if (isSyncingGrades) { } @@ -67,19 +67,19 @@

    OnTrack

    mat-fab extended color="primary" - class="h-[50px] my-3 w-full max-w-lg" + class="my-3 h-[50px] w-full max-w-lg" (click)="launchApplication()" target="_blank" > rocket_launch Launch {{ linkedUnit ? linkedUnit.code : 'OnTrack' }} -
    +
    @if (linkedUnit) { {{ linkedUnit.code }} — {{ linkedUnit.name }} @if (currentUser?.systemRole === 'Convenor' || currentUser?.systemRole === 'Admin') {
    - } @@ -88,7 +88,7 @@

    OnTrack

    @if (currentUser?.systemRole === 'Convenor' || currentUser?.systemRole === 'Admin') {
    - } @else { diff --git a/src/app/home/states/lti-dashboard/lti-dashboard.component.ts b/src/app/home/states/lti-dashboard/lti-dashboard.component.ts index 4ae22095bc..222b359d9a 100644 --- a/src/app/home/states/lti-dashboard/lti-dashboard.component.ts +++ b/src/app/home/states/lti-dashboard/lti-dashboard.component.ts @@ -1,5 +1,3 @@ -import {AfterViewInit, Component, Input} from '@angular/core'; -import {ActivatedRoute, Router} from '@angular/router'; import {ProjectService, User} from 'src/app/api/models/doubtfire-model'; import {Unit} from 'src/app/api/models/unit'; import {AuthenticationService} from 'src/app/api/services/authentication.service'; @@ -10,12 +8,14 @@ import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal import {CsvResultModalService} from 'src/app/common/modals/csv-result-modal/csv-result-modal.service'; import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; +import {AfterViewInit, Component, Input} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; @Component({ - selector: 'f-lti-dashboard', - templateUrl: 'lti-dashboard.component.html', - styleUrls: ['lti-dashboard.component.scss'], - standalone: false + selector: 'f-lti-dashboard', + templateUrl: 'lti-dashboard.component.html', + styleUrls: ['lti-dashboard.component.scss'], + standalone: false, }) export class LtiDashboardComponent implements AfterViewInit { constructor( diff --git a/src/app/home/states/lti-unit-link/lti-unit-link.component.html b/src/app/home/states/lti-unit-link/lti-unit-link.component.html index 1020993ed1..9975e20cb0 100644 --- a/src/app/home/states/lti-unit-link/lti-unit-link.component.html +++ b/src/app/home/states/lti-unit-link/lti-unit-link.component.html @@ -1,11 +1,11 @@ -
    -
    -
    +
    +
    +

    OnTrack

    @@ -13,12 +13,12 @@

    OnTrack

    @if (loadingUnits) {

    Loading...

    } @else if (!activeUnits.length) { -

    +

    You must already be a Convenor or Admin to link a unit. You are not currently assigned to any units.

    } @else { -

    +

    Students will be automatically enrolled in this unit when they launch the OnTrack tool from this course.

    diff --git a/src/app/home/states/lti-unit-link/lti-unit-link.component.ts b/src/app/home/states/lti-unit-link/lti-unit-link.component.ts index 492151ab83..9eb9a5ff1f 100644 --- a/src/app/home/states/lti-unit-link/lti-unit-link.component.ts +++ b/src/app/home/states/lti-unit-link/lti-unit-link.component.ts @@ -1,5 +1,3 @@ -import {AfterViewInit, Component, Input} from '@angular/core'; -import {ActivatedRoute, Router} from '@angular/router'; import {CreateNewUnitModal} from 'src/app/admin/modals/create-new-unit-modal/create-new-unit-modal.component'; import {Unit} from 'src/app/api/models/unit'; import {AuthenticationService} from 'src/app/api/services/authentication.service'; @@ -8,12 +6,14 @@ import {UnitService} from 'src/app/api/services/unit.service'; import {UserService} from 'src/app/api/services/user.service'; import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; +import {AfterViewInit, Component, Input} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; @Component({ - selector: 'f-lti-unit-link', - templateUrl: 'lti-unit-link.component.html', - styleUrls: ['lti-unit-link.component.scss'], - standalone: false + selector: 'f-lti-unit-link', + templateUrl: 'lti-unit-link.component.html', + styleUrls: ['lti-unit-link.component.scss'], + standalone: false, }) export class LtiUnitLinkComponent implements AfterViewInit { constructor( @@ -120,7 +120,7 @@ export class LtiUnitLinkComponent implements AfterViewInit { ); this.loadingUnits = false; }, - error: (error) => { + error: (_error) => { this.alertsService.error(`Failed to fetch units`, 6000); }, }); diff --git a/src/app/legacy-route-placeholder.component.html b/src/app/legacy-route-placeholder.component.html new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/legacy-route-placeholder.component.scss b/src/app/legacy-route-placeholder.component.scss new file mode 100644 index 0000000000..cc36f78bfa --- /dev/null +++ b/src/app/legacy-route-placeholder.component.scss @@ -0,0 +1,3 @@ +:host { + display: none; +} diff --git a/src/app/legacy-route-placeholder.component.ts b/src/app/legacy-route-placeholder.component.ts index d3e62d9fad..a08dfc603c 100644 --- a/src/app/legacy-route-placeholder.component.ts +++ b/src/app/legacy-route-placeholder.component.ts @@ -1,15 +1,9 @@ import {Component} from '@angular/core'; @Component({ - selector: 'legacy-route-placeholder', - template: '', - styles: [ - ` - :host { - display: none; - } - `, - ], - standalone: false + selector: 'legacy-route-placeholder', + templateUrl: './legacy-route-placeholder.component.html', + styleUrl: './legacy-route-placeholder.component.scss', + standalone: false, }) export class LegacyRoutePlaceholderComponent {} diff --git a/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html index b450dfad58..a4c5164702 100644 --- a/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html +++ b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html @@ -1,8 +1,8 @@ @if (project$ | async; as project) { -
    +
    - +

    @@ -13,10 +13,10 @@

    - + - -

    Targetting

    + +

    Targetting

    info @@ -37,12 +37,12 @@

    Targetting

    - + Your progress -
    +
    ; @@ -37,7 +37,7 @@ export class ProjectProgressDashboardComponent implements OnInit { protected targetGradeClicked(grade: number): void { this.project.targetGrade = grade; this.projectService.update(this.project).subscribe({ - next: (project) => { + next: (_project) => { this.alertService.success('Target grade updated'); }, error: (error) => { diff --git a/src/app/projects/project.resolver.ts b/src/app/projects/project.resolver.ts index d5f16b2d0e..e588b4f096 100644 --- a/src/app/projects/project.resolver.ts +++ b/src/app/projects/project.resolver.ts @@ -1,8 +1,8 @@ -import {ResolveFn} from '@angular/router'; import {Observable} from 'rxjs'; import {Project, ProjectService} from 'src/app/api/models/doubtfire-model'; -import {GlobalStateService, ViewType} from './states/index/global-state.service'; import {inject} from '@angular/core'; +import {ResolveFn} from '@angular/router'; +import {GlobalStateService, ViewType} from './states/index/global-state.service'; export const resolveProject: ResolveFn = (route, state) => { const projectService = inject(ProjectService); diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html index 66174425af..93df2d92d1 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html @@ -1,21 +1,21 @@ -
    -
    -

    +
    +
    +

    Progress Dashboard @if (tutor) { for {{ project.student.name }} }

    -
    +
    -
    - +
    +
    - + Target Grade @@ -23,7 +23,7 @@

    - +
    Select Target Grade @@ -41,7 +41,7 @@

    To change your target grade, use the - + Task Planner
    @@ -55,45 +55,45 @@

    -
    +
    -
    +
    -
    -

    Progress Burndown

    -

    +

    +

    Progress Burndown

    +

    The burndown chart shows how much work remains for you to achieve your target grade.

    -
    +
    -
    +
    Aim to keep your - Complete + Complete line close to or ahead of the - Target + Target line to keep on track.
    -
    +
    -
    -

    Task Statuses

    -

    +

    +

    Task Statuses

    +

    Breakdown summary of each of your task statuses.

    -
    +
    (); + @Output() doUpdateTargetGrade: EventEmitter = new EventEmitter(); tutor: boolean; grades = { diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts index 3bb062d0a3..2703e333bd 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts @@ -1,11 +1,11 @@ -import {Component, Input} from '@angular/core'; import {Project} from 'src/app/api/models/project'; +import {Component, Input} from '@angular/core'; @Component({ - selector: 'f-task-planner-card', - templateUrl: './task-planner-card.component.html', - styleUrl: './task-planner-card.component.scss', - standalone: false + selector: 'f-task-planner-card', + templateUrl: './task-planner-card.component.html', + styleUrl: './task-planner-card.component.scss', + standalone: false, }) export class TaskPlannerCardComponent { @Input() project: Project; diff --git a/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.html b/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.html index 39825c6d7b..287515fb59 100644 --- a/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.html +++ b/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.html @@ -1,14 +1,14 @@ -
    -
    +
    +
    Create Portfolio
    - person + person
    Create and submit your portfolio
    diff --git a/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.ts b/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.ts index 56c0b423d3..bf1ce95251 100644 --- a/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.ts +++ b/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.ts @@ -1,11 +1,11 @@ +import {Project, Task} from 'src/app/api/models/doubtfire-model'; import {Component, Input} from '@angular/core'; -import { Project, Task } from 'src/app/api/models/doubtfire-model'; @Component({ - selector: 'create-portfolio-task-list-item', - templateUrl: 'create-portfolio-task-list-item.component.html', - styleUrls: ['create-portfolio-task-list-item.component.scss'], - standalone: false + selector: 'create-portfolio-task-list-item', + templateUrl: 'create-portfolio-task-list-item.component.html', + styleUrls: ['create-portfolio-task-list-item.component.scss'], + standalone: false, }) export class CreatePortfolioTaskListItemComponent { @Input() setSelectedTask: Task; diff --git a/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.component.html b/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.component.html index 763e84665a..46d732c34a 100644 --- a/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.component.html +++ b/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.component.html @@ -1 +1,2 @@ -

    student-task-list works!

    , +

    student-task-list works!

    +, diff --git a/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.component.ts b/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.component.ts index 034627414a..fae6805595 100644 --- a/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.component.ts +++ b/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.component.ts @@ -1,18 +1,11 @@ -import { CommonModule } from '@angular/common'; -import { ChangeDetectionStrategy, Component, type OnInit } from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; @Component({ selector: 'f-student-task-list', standalone: true, - imports: [ - CommonModule, - ], + imports: [], templateUrl: './student-task-list.component.html', styleUrl: './student-task-list.component.css', changeDetection: ChangeDetectionStrategy.OnPush, }) -export class StudentTaskListComponent implements OnInit { - - ngOnInit(): void { } - -} +export class StudentTaskListComponent {} diff --git a/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.tpl.html b/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.tpl.html index 93573d01c9..7b18638d41 100644 --- a/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.tpl.html +++ b/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.tpl.html @@ -28,8 +28,8 @@

    {{task.definition.name}}

    {{task.definition.abbreviation}} - - {{gradeNames[task.definition.targetGrade]}} Task + > + {{task.definition.abbreviation}} - {{gradeNames[task.definition.targetGrade]}} Task {{task.timeToStart()}}{{task.definition.n {{task.numNewComments}} - +

    - {{task.gradeDesc()}} + + {{task.gradeDesc()}} + {{task.qualityQts}}{{task.definition.maxQualityPts}} - + {{task.definition.n > - + !
    @@ -77,7 +88,10 @@

    {{task.definition.n -
  • +
  • No tasks to display.
  • diff --git a/src/app/projects/states/dashboard/directives/student-task-list/task-list-item/task-list-item.component.ts b/src/app/projects/states/dashboard/directives/student-task-list/task-list-item/task-list-item.component.ts index d6f86ce886..c521cdbfb1 100644 --- a/src/app/projects/states/dashboard/directives/student-task-list/task-list-item/task-list-item.component.ts +++ b/src/app/projects/states/dashboard/directives/student-task-list/task-list-item/task-list-item.component.ts @@ -1,19 +1,19 @@ -import {Component, Input, OnInit} from '@angular/core'; import {Task} from 'src/app/api/models/doubtfire-model'; import {GradeService} from 'src/app/common/services/grade.service'; +import {Component, Input, OnInit} from '@angular/core'; @Component({ - selector: 'task-list-item', - templateUrl: 'task-list-item.component.html', - styleUrls: ['task-list-item.component.scss'], - standalone: false + selector: 'task-list-item', + templateUrl: 'task-list-item.component.html', + styleUrls: ['task-list-item.component.scss'], + standalone: false, }) export class TaskListItemComponent implements OnInit { @Input() task: Task; - @Input() setSelectedTask: any; - @Input() isSelectedTask: any; + @Input() setSelectedTask: (task: Task) => void; + @Input() isSelectedTask: (task: Task) => boolean; - public gradeNames: {}; + public gradeNames: GradeService['grades']; constructor(private gs: GradeService) {} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html index 5636823212..781e0aa244 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.html @@ -1,4 +1,4 @@ -
    +
    comment

    Discussion Prompts for {{ project?.student?.name }}

    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts index 7acb2b19d7..43ae248427 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts @@ -1,10 +1,10 @@ import {Component, Input} from '@angular/core'; @Component({ - selector: 'f-discussion-prompts-view', - templateUrl: './discussion-prompts-view.component.html', - styleUrls: ['./discussion-prompts-view.component.scss'], - standalone: false + selector: 'f-discussion-prompts-view', + templateUrl: './discussion-prompts-view.component.html', + styleUrls: ['./discussion-prompts-view.component.scss'], + standalone: false, }) export class DiscussionPromptsViewComponent { @Input() project; diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html index f92fd644e5..92a3039c43 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html @@ -1,4 +1,4 @@ -
    +
    comment

    Staff Notes for {{ project?.student?.name }}

    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.ts index b10909f0f9..7f7d38039d 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.ts @@ -1,10 +1,10 @@ import {Component, Input} from '@angular/core'; @Component({ - selector: 'f-staff-notes-view', - templateUrl: './staff-notes-view.component.html', - styleUrls: ['./staff-notes-view.component.scss'], - standalone: false + selector: 'f-staff-notes-view', + templateUrl: './staff-notes-view.component.html', + styleUrls: ['./staff-notes-view.component.scss'], + standalone: false, }) export class StaffNotesViewComponent { @Input() project; diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.html index 54ca0810cb..7d56d7a386 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.html @@ -1,4 +1,7 @@ - + Assessment Information diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.spec.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.spec.ts index d9dc27547d..d1b100354a 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.spec.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.spec.ts @@ -1,6 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { TaskAssessmentCardComponent } from './task-assessment-card.component'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {TaskAssessmentCardComponent} from './task-assessment-card.component'; describe('TaskAssessmentCardComponent', () => { let component: TaskAssessmentCardComponent; @@ -8,9 +7,8 @@ describe('TaskAssessmentCardComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ TaskAssessmentCardComponent ] - }) - .compileComponents(); + declarations: [TaskAssessmentCardComponent], + }).compileComponents(); fixture = TestBed.createComponent(TaskAssessmentCardComponent); component = fixture.componentInstance; diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.ts index 10204c7956..f8eb8557c2 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.ts @@ -1,16 +1,19 @@ -import { Component, Input } from '@angular/core'; -import { Task } from 'src/app/api/models/task'; -import { TaskService } from 'src/app/api/services/task.service'; -import { GradeService } from 'src/app/common/services/grade.service'; +import {Task} from 'src/app/api/models/task'; +import {TaskService} from 'src/app/api/services/task.service'; +import {GradeService} from 'src/app/common/services/grade.service'; +import {Component, Input} from '@angular/core'; @Component({ - selector: 'f-task-assessment-card', - templateUrl: './task-assessment-card.component.html', - styleUrls: ['./task-assessment-card.component.scss'], - standalone: false + selector: 'f-task-assessment-card', + templateUrl: './task-assessment-card.component.html', + styleUrls: ['./task-assessment-card.component.scss'], + standalone: false, }) export class TaskAssessmentCardComponent { - constructor(private taskService: TaskService, private gradeService: GradeService) {} + constructor( + private taskService: TaskService, + private gradeService: GradeService, + ) {} @Input() task: Task; gradeNames = this.gradeService.grades; diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.tpl.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.tpl.html index c849365e0f..0aa6c58092 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.tpl.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.tpl.html @@ -1,4 +1,7 @@ -
    +

    Assessment Information

    @@ -7,38 +10,38 @@

    Assessment Information

    This task {{assessmentCards.hasBeenGraded ? 'has been' : 'will be'}} assigned a grade

    - This task will be graded against a grade standard. Your work will - be assessed and assigned a grade according to a Pass, Credit, - Distinction or High Distinction standard. + This task will be graded against a grade standard. Your work will be assessed and assigned + a grade according to a Pass, Credit, Distinction or High Distinction standard.

    Advice for achieving a {{task.project.targetGradeWord}}

    - As you are attempting to achieve a {{task.project.targetGradeWord}} in this unit, - you should attempt to achieve a {{task.project.targetGradeWord}} grade - on this task. Ask your tutor to find out more on what they are looking for when they are assessing - this work to a specific grade. + As you are attempting to achieve a {{task.project.targetGradeWord}} in this unit, you + should attempt to achieve a {{task.project.targetGradeWord}} grade on + this task. Ask your tutor to find out more on what they are looking for when they are + assessing this work to a specific grade.

    -
    +
    +
    Your tutor has marked you on this task to a {{task.gradeWord}} standard. -
    -
    -
    +
    + +
    + +
    This task will be assessed on a scale to {{task.definition.maxQualityPts}} - - This task has been assessed for quality - + This task has been assessed for quality

    This task will be graded against a quality scale from - 0 to {{task.definition.maxQualityPts}}. Your work will assessed - and assigned a star rating based on the quality of your submission. + 0 to {{task.definition.maxQualityPts}}. Your work will assessed and + assigned a star rating based on the quality of your submission.

    max="task.definition.maxQualityPts" state-on="'fa fa-star rating-outline'" state-off="'fa fa-star rating-disabled'" - readonly="true"> + readonly="true" + >

    You have been awarded out @@ -55,6 +59,9 @@

    avaliable points for this task.

    -
    -
    -
    +
    + +
    + +

    + diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html index b7548c3c90..acddda621a 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html @@ -1,6 +1,6 @@ -
    +
    {{ taskDef?.name }}
    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.ts index 0d4847623e..f01cb5131d 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.ts @@ -1,14 +1,13 @@ -import {Component, Input, Inject, EventEmitter, Output} from '@angular/core'; - import {Task, TaskDefinition, Unit} from 'src/app/api/models/doubtfire-model'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; import {GradeService} from 'src/app/common/services/grade.service'; +import {Component, EventEmitter, Inject, Input, Output} from '@angular/core'; @Component({ - selector: 'f-task-description-card', - templateUrl: 'task-description-card.component.html', - styleUrls: ['task-description-card.component.scss'], - standalone: false + selector: 'f-task-description-card', + templateUrl: 'task-description-card.component.html', + styleUrls: ['task-description-card.component.scss'], + standalone: false, }) export class TaskDescriptionCardComponent { @Output() switchView$: EventEmitter = new EventEmitter(); @@ -17,7 +16,10 @@ export class TaskDescriptionCardComponent { @Input() taskDef: TaskDefinition; @Input() unit: Unit; - public grades: {names: any; acronyms: any}; + public grades: { + names: GradeService['grades']; + acronyms: GradeService['gradeAcronyms']; + }; constructor( private GradeService: GradeService, diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html index 48fb963ad2..1bd23719a9 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html @@ -56,10 +56,12 @@ @if (task?.betweenDueDateAndDeadlineDate()) { - warning @if (flexibleDatesEnabled) { - Past Target Date By {{ task?.timePastDueDateDescription() }} + Past Target Date By {{ task?.timePastDueDateDescription() }} } @else { Past Due Date By {{ task?.timePastDueDateDescription() }} } @@ -116,7 +118,7 @@ @if (task?.isPastDeadline()) { - error Passed Due Date By {{ task?.timePastDueDateDescription() }} { let component: TaskDueCardComponent; @@ -8,9 +7,8 @@ describe('TaskDueCardComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ TaskDueCardComponent ] - }) - .compileComponents(); + declarations: [TaskDueCardComponent], + }).compileComponents(); fixture = TestBed.createComponent(TaskDueCardComponent); component = fixture.componentInstance; diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.ts index 7c67cb9f57..6a491c6a67 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.ts @@ -1,17 +1,14 @@ -import {Component, Input, OnInit} from '@angular/core'; import {Task} from 'src/app/api/models/task'; +import {Component, Input} from '@angular/core'; @Component({ - selector: 'f-task-due-card', - templateUrl: './task-due-card.component.html', - styleUrls: ['./task-due-card.component.scss'], - standalone: false + selector: 'f-task-due-card', + templateUrl: './task-due-card.component.html', + styleUrls: ['./task-due-card.component.scss'], + standalone: false, }) -export class TaskDueCardComponent implements OnInit { +export class TaskDueCardComponent { @Input() task: Task; - constructor() {} - - ngOnInit(): void {} public get flexibleDatesEnabled(): boolean { return this.task?.unit?.allowFlexibleDates; diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.tpl.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.tpl.html index 6f14f303b2..a4ea4b1999 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.tpl.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.tpl.html @@ -1,39 +1,47 @@ -
    -
    +
    + +
    +

    Aim To Complete Soon - Due in {{task.timeUntilDueDateDescription()}}

    -
    +
    +

    - This task's due date is {{task.localDueDateString()}}. - You should aim to complete this task before then to keep your progress on track. + This task's due date is {{task.localDueDateString()}}. You should aim to + complete this task before then to keep your progress on track.

    -
    +
    +

    - This task's due date is {{task.localDueDateString()}}. - Make sure to discuss this task with your tutor as soon as possible. + This task's due date is {{task.localDueDateString()}}. Make sure to + discuss this task with your tutor as soon as possible.

    - Tasks are only considered Completed once your tutor has Discussed your work - with you. + Tasks are only considered Completed once your tutor has + Discussed your work with you.

    -
    +
    +

    Past Due Date By {{task.timePastDueDateDescription()}}

    -
    +
    +

    - You should have completed this task by {{task.localDueDateString()}}. - Try and finish it as soon as possible to avoid falling behind. As you will submit this - task after the deadline for feedback, it will not be reviewed by a tutor and it is now - your sole responsibility to ensure that this submission meets the required standard. - The task will be assessed as part of the portfolio. + You should have completed this task by {{task.localDueDateString()}}. Try + and finish it as soon as possible to avoid falling behind. As you will submit this task + after the deadline for feedback, it will not be reviewed by a tutor and it is now your + sole responsibility to ensure that this submission meets the required standard. The task + will be assessed as part of the portfolio.

    Aim to submit future tasks before the deadline to make good use of the opportunity to @@ -41,11 +49,12 @@

    Past Due Date By {{task.timePastDueDateDescription()}}

    submission meets all the requirements.

    -
    +
    +

    You should have completed this task by {{task.localDueDateString()}}. - Make sure to discuss this task with your tutor as soon as possible. If this task remains on - this state for an extended period, it will be marked as Time Exceeded. + Make sure to discuss this task with your tutor as soon as possible. If this task remains + on this state for an extended period, it will be marked as Time Exceeded.

    Tasks are only considered completed once your tutor has @@ -53,33 +62,37 @@

    Past Due Date By {{task.timePastDueDateDescription()}}

    -
    +
    +

    Passed Due Date By {{task.timePastDueDateDescription()}}

    -
    +
    +

    You should have completed this task by {{task.localDueDateString()}}. - This task is now past the deadline and will be marked as Time Exceeded when submitted. You should - consult with the unit assessment details to determine the impact of failing to complete this task within - the allocated time. + This task is now past the deadline and will be marked as Time Exceeded when + submitted. You should consult with the unit assessment details to determine the impact of + failing to complete this task within the allocated time.

    -
    +
    +

    You should have completed this task by {{task.localDueDateString()}}. Make sure to discuss this task with your tutor as soon as possible.

    - Tasks are only considered Completed once it demonstrates the required standard, and it is - discussed with your tutor. + Tasks are only considered Completed once it demonstrates the required + standard, and it is discussed with your tutor.

    -
    +
    +

    Wait for Tutor Feedback

    @@ -87,8 +100,10 @@

    Wait for Tutor Feedback

    You have submitted this task and should now wait for feedback from your tutor. - Do not re-upload new files at this time as the status will be changed to - Time Exceeded. + Do not re-upload new files at this time as the status will be changed to + Time Exceeded.

    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-ilos-card/task-ilos-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-ilos-card/task-ilos-card.component.html index 31a7a8028b..6f0ae7a7bf 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-ilos-card/task-ilos-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-ilos-card/task-ilos-card.component.html @@ -10,10 +10,10 @@ @for (ilo of learningOutcomes; track ilo) { - - + + - - - - -
    {{ ilo.abbreviation }}
    {{ ilo.abbreviation }} {{ ilo.fullOutcomeDescription }} + @for (outcome of getLinkedOutcomes(ilo); track outcome.abbreviation) { {{ outcome.abbreviation diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-ilos-card/task-ilos-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-ilos-card/task-ilos-card.component.ts index 803e7ea998..719b99cd58 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-ilos-card/task-ilos-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-ilos-card/task-ilos-card.component.ts @@ -1,14 +1,14 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; import {LearningOutcome} from 'src/app/api/models/learning-outcome'; import {Project} from 'src/app/api/models/project'; import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Unit} from 'src/app/api/models/unit'; +import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; @Component({ - selector: 'f-task-ilos-card', - templateUrl: './task-ilos-card.component.html', - styleUrls: ['./task-ilos-card.component.scss'], - standalone: false + selector: 'f-task-ilos-card', + templateUrl: './task-ilos-card.component.html', + styleUrls: ['./task-ilos-card.component.scss'], + standalone: false, }) export class TaskIlosCardComponent implements OnInit, OnChanges { @Input() iloContextType: 'Unit' | 'TaskDefinition' | 'Course' | 'Global'; diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html index ae35bec796..7b30d385d6 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html @@ -16,20 +16,18 @@

    -
    +
    @if (isLoading) { -
    +
    } @else if (errorMessage) { -
    +
    {{ errorMessage }}
    } @else if (compareMode) { @if (archiveBlob && comparedArchiveBlob) { -
    +
    [ngTemplateOutletContext]="{ number: data.assessmentNumber, isMostRecent: data.assessmentIsMostRecent, - timestamp: data.assessment.timestamp + timestamp: data.assessment.timestamp, }" > [ngTemplateOutletContext]="{ number: data.comparedWithNumber, isMostRecent: data.comparedWithIsMostRecent, - timestamp: data.comparedWith?.timestamp + timestamp: data.comparedWith?.timestamp, }" > @if (primaryArchiveParsed) {
    @if (!bothSelectionsReady) { -
    +
    Select a file in both submissions to compare.
    } @else if (canShowDiffEditor) { -
    +
    -
    +
    {{ primarySelectedFile?.path ?? primarySelectedFile?.name }}
    -
    +
    {{ comparedSelectedFile?.path ?? comparedSelectedFile?.name }}
    } @else { -
    +
    @@ -125,33 +121,29 @@

    } @else { -
    +
    Unable to load one or both submission archives.
    } } @else if (archiveBlob) { -
    +
    } @else { -
    +
    Unable to load submission files.
    } @@ -173,10 +165,10 @@

    - + {{ file?.path ?? file?.name }} @if (selectedFilesMatch !== null) { @@ -191,14 +183,14 @@

    @if (isArchiveCodeOrTextFile(file)) { } @else if (isArchivePdfFile(file)) { - + } @else if (isArchiveImageFile(file)) { -
    +
    />
    } @else { -
    +
    Preview not available for this file type.
    } diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts index 1fe0454725..0a8a802524 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts @@ -1,7 +1,4 @@ -import {HttpResponse} from '@angular/common/http'; -import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; import * as monaco from 'monaco-editor'; -import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {OverseerAssessment} from 'src/app/api/models/doubtfire-model'; import { ArchiveFileEntry, @@ -11,6 +8,9 @@ import { } from 'src/app/common/archive-viewer/archive-viewer.helpers'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; import {AlertService} from 'src/app/common/services/alert.service'; +import {HttpResponse} from '@angular/common/http'; +import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; export interface SubmissionFilesModalData { assessment: OverseerAssessment; @@ -22,10 +22,10 @@ export interface SubmissionFilesModalData { } @Component({ - selector: 'f-submission-files-modal', - templateUrl: './submission-files-modal.component.html', - styleUrls: ['./submission-files-modal.component.scss'], - standalone: false + selector: 'f-submission-files-modal', + templateUrl: './submission-files-modal.component.html', + styleUrls: ['./submission-files-modal.component.scss'], + standalone: false, }) export class SubmissionFilesModalComponent implements OnInit, OnDestroy { private readonly diffOriginalUri = monaco.Uri.parse('inmemory://submission-compare/original'); diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html index 233333462b..668fb5daaf 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html @@ -1,4 +1,4 @@ -
    +
    @@ -9,7 +9,7 @@ [disabled]="!oa.reportReady" [expanded]="oa.id === loadOverseerAssessmentId && oa.reportReady" > - + Submission {{ overseerAssessments.length - idx }}: {{ oa.timestamp | humanizedDate }} @@ -21,7 +21,7 @@ } @if (oa.reportReady) { -
    +
    {{ oa.passedSteps }} / {{ oa.totalSteps }} @if (oa.passedSteps === oa.totalSteps) { done @@ -67,7 +67,7 @@ }
    } @else { -
    +
    Tests In Progress
    @@ -77,7 +77,7 @@ @for (result of oa.stepResultsCache.values | async; track result.id; let idx = $index) { - + Step {{ idx + 1 }}: {{ result.overseerStep?.displayName }} @@ -92,7 +92,7 @@ @if (!result.pass) { -

    +

    {{ result.feedbackMessage }}

    } @@ -102,7 +102,7 @@ result.expectedOutput !== result.stdout && (result.overseerStep?.stepType === 'output_diff' || !result.overseerStep) ) { -
    +
    - } @else if (similarity.type === 'TiiTaskSimilarity') { +
    + @for (part of similarity.parts; track part; let i = $index) { + + + + {{ similarity.friendlyTypeName }} + + {{ part.description }} + @if (similarity.readyForViewer) { + @if (similarity.type === 'JplagTaskSimilarity') { + + } @else if (similarity.type === 'TiiTaskSimilarity') { + + } + } + @if (i === 0) { } - } - @if (i === 0) { - - } - - @if (part.panelOpenState) { - @if (part.format) { - @if (part.format === 'html' || part.format === 'pdf') { - - } @else if (part.format === 'jplag') { - + + @if (part.panelOpenState) { + @if (part.format) { + @if (part.format === 'html' || part.format === 'pdf') { + + } @else if (part.format === 'jplag') { + + } + } @else { +

    There is no local similarity file for this.

    } - } @else { -

    There is no local similarity file for this.

    } - } -
    - } + + } +
    } @empty { -
    +
    There are no similarities for this submission
    } diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.ts index 3f199793c7..1f060d2164 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.ts @@ -1,19 +1,19 @@ -import {HttpResponse} from '@angular/common/http'; -import {Component, Input, OnChanges, SimpleChanges, ViewChild} from '@angular/core'; -import {MatAccordion} from '@angular/material/expansion'; import {Task} from 'src/app/api/models/task'; import {TaskSimilarity} from 'src/app/api/models/task-similarity'; import {TaskSimilarityService} from 'src/app/api/services/task-similarity.service'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {JplagReportViewerComponent} from 'src/app/projects/states/jplag/jplag-report-viewer.component'; +import {HttpResponse} from '@angular/common/http'; +import {Component, Input, OnChanges, SimpleChanges, ViewChild} from '@angular/core'; +import {MatAccordion} from '@angular/material/expansion'; import {SelectedTaskService} from '../../../../selected-task.service'; @Component({ - selector: 'f-task-similarity-view', - templateUrl: './task-similarity-view.component.html', - styleUrls: ['./task-similarity-view.component.scss'], - standalone: false + selector: 'f-task-similarity-view', + templateUrl: './task-similarity-view.component.html', + styleUrls: ['./task-similarity-view.component.scss'], + standalone: false, }) export class TaskSimilarityViewComponent implements OnChanges { @Input() task: Task; diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.html index c417537eca..0be1833ddb 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.html @@ -41,7 +41,7 @@
    {{ task?.statusLabel() }}
    } - +
    -
    +
    + +

    - Your submission is being processed and will be avaliable to view soon. You will also - be able to download your most recently submitted files. + Your submission is being processed and will be avaliable to view soon. You will also be able + to download your most recently submitted files.

    You can choose to download your previous @@ -18,15 +19,19 @@

    You uploaded this submission {{task.submissionDate | date: 'dd/MM/yyyy'}}.

    - If you feel there has been an error in your submission, you can request to - regenerate your submission under the "Actions" dropdown menu. + If you feel there has been an error in your submission, you can request to regenerate your + submission under the "Actions" dropdown menu.

    - If you would like to submit alternate evidence for use in your portfolio, you can - upload alternate files under the "Actions" dropdown menu. + If you would like to submit alternate evidence for use in your portfolio, you can upload + alternate files under the "Actions" dropdown menu.

    -

    - + + +
    -
    -
    +
    + +
    + +
    + diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.html index 808584c21a..456422ea90 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.html @@ -1,4 +1,4 @@ -
    +
    comment

    Tutor Notes for {{ unitRole?.user?.name }}

    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.ts index 1166595775..df83bb6cad 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.ts @@ -1,11 +1,11 @@ -import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; import {UnitRole} from 'src/app/api/models/unit-role'; +import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; @Component({ - selector: 'f-tutor-notes-view', - templateUrl: './tutor-notes-view.component.html', - styleUrls: ['./tutor-notes-view.component.scss'], - standalone: false + selector: 'f-tutor-notes-view', + templateUrl: './tutor-notes-view.component.html', + styleUrls: ['./tutor-notes-view.component.scss'], + standalone: false, }) export class TutorNotesViewComponent implements OnChanges { @Input() task?; diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html index 94534f8249..c980e95db5 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html @@ -1,4 +1,4 @@ -
    +
    {{ task.project.staffNoteCount }} @@ -115,7 +115,7 @@ @case (DashboardViews.task) { @if (task && task.blockedByPrerequisiteTasks()) {
    warning Warning: This task has @@ -129,7 +129,7 @@ @if (task.definition.hasTaskSheet) { } @else { -
    +
    subtitles_off
    } @@ -138,7 +138,7 @@ @if (task.hasPdf) { } @else { -
    +
    subtitles_off
    } @@ -189,7 +189,7 @@ -
    +
    subtitles_off
    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.spec.ts b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.spec.ts index abd4a08b1f..4695f366d0 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.spec.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.spec.ts @@ -1,6 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { TaskDashboardComponent } from './task-dashboard.component'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {TaskDashboardComponent} from './task-dashboard.component'; describe('TaskDashboardComponent', () => { let component: TaskDashboardComponent; @@ -8,9 +7,8 @@ describe('TaskDashboardComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ TaskDashboardComponent ] - }) - .compileComponents(); + declarations: [TaskDashboardComponent], + }).compileComponents(); fixture = TestBed.createComponent(TaskDashboardComponent); component = fixture.componentInstance; diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.ts index cae632e9c5..d2783af283 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.ts @@ -1,5 +1,3 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; import {UnitRole} from 'src/app/api/models/doubtfire-model'; import {Task} from 'src/app/api/models/task'; import {TaskService} from 'src/app/api/services/task.service'; @@ -7,22 +5,30 @@ import {UserService} from 'src/app/api/services/user.service'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; import {TaskAssessmentModalService} from 'src/app/common/modals/task-assessment-modal/task-assessment-modal.service'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import {MatTabChangeEvent} from '@angular/material/tabs'; +import {ActivatedRoute} from '@angular/router'; import {SelectedTaskService} from '../../selected-task.service'; import {DashboardViews} from '../../selected-task.service'; -import {MatTabChangeEvent} from '@angular/material/tabs'; @Component({ - selector: 'f-task-dashboard', - templateUrl: './task-dashboard.component.html', - styleUrls: ['./task-dashboard.component.scss'], - standalone: false + selector: 'f-task-dashboard', + templateUrl: './task-dashboard.component.html', + styleUrls: ['./task-dashboard.component.scss'], + standalone: false, }) export class TaskDashboardComponent implements OnInit, OnChanges { @Input() task: Task; @Input() pdfUrl: string; public DashboardViews = DashboardViews; - public taskStatusData: any; + public taskStatusData: { + keys: TaskService['markedStatuses']; + help: TaskService['helpDescriptions']; + icons: TaskService['statusIcons']; + labels: TaskService['statusLabels']; + class: TaskService['statusClass']; + }; public tutor = false; public urls: { taskSubmissionPdfAttachmentUrl: string; diff --git a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html index 769d93cbbb..b30e7dcc78 100644 --- a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html +++ b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html @@ -37,12 +37,12 @@ @if (project$ | async; as project) { -
    -
    +
    +
    @if (subs$ | async) { @if (isProjectTaskListReady(project)) { } @else { -
    +
    }
    } @if (selectedTaskDefinition$ | async; as selectedTaskDefinition) { -
    +
    -
    +
    } @else if (!isProjectTaskListReady(project)) { -
    +
    +
    } diff --git a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.ts b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.ts index eaff580905..864a741cf6 100644 --- a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.ts +++ b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.ts @@ -1,7 +1,4 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import {CdkDragEnd, CdkDragMove, CdkDragStart} from '@angular/cdk/drag-drop'; -import {Component, Input, OnInit} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; import { BehaviorSubject, Observable, @@ -13,11 +10,14 @@ import { tap, withLatestFrom, } from 'rxjs'; +import {Project, TaskDefinition} from 'src/app/api/models/doubtfire-model'; import {ProjectService} from 'src/app/api/services/project.service'; import {UnitService} from 'src/app/api/services/unit.service'; -import {GlobalStateService, ViewType} from '../../index/global-state.service'; import {UserService} from 'src/app/api/services/user.service'; -import {Project, TaskDefinition} from 'src/app/api/models/doubtfire-model'; +import {CdkDragEnd, CdkDragMove, CdkDragStart} from '@angular/cdk/drag-drop'; +import {Component, Input, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {GlobalStateService, ViewType} from '../../index/global-state.service'; @Component({ selector: 'f-project-dashboard', @@ -37,10 +37,10 @@ export class ProjectDashboardComponent implements OnInit { subs$: Observable; readonly skeletonRows = Array.from({length: 10}, (_, index) => index); - private readonly projectSubject = new BehaviorSubject(null); + private readonly projectSubject: BehaviorSubject = new BehaviorSubject(null); - private leftComponentStartSize$ = new Subject(); - private dragMove$ = new Subject<{event: CdkDragMove; div: HTMLDivElement}>(); + private leftComponentStartSize$: Subject = new Subject(); + private dragMove$: Subject<{event: CdkDragMove; div: HTMLDivElement}> = new Subject(); private dragMoveAudited$; private projectReady = false; diff --git a/src/app/projects/states/dashboard/selected-task.service.spec.ts b/src/app/projects/states/dashboard/selected-task.service.spec.ts index 7883cf970a..c1ce156e72 100644 --- a/src/app/projects/states/dashboard/selected-task.service.spec.ts +++ b/src/app/projects/states/dashboard/selected-task.service.spec.ts @@ -1,6 +1,5 @@ -import { TestBed } from '@angular/core/testing'; - -import { SelectedTaskService } from './selected-task.service'; +import {TestBed} from '@angular/core/testing'; +import {SelectedTaskService} from './selected-task.service'; describe('SelectedTaskService', () => { let service: SelectedTaskService; diff --git a/src/app/projects/states/dashboard/selected-task.service.ts b/src/app/projects/states/dashboard/selected-task.service.ts index 50502d9a02..5da81dd06f 100644 --- a/src/app/projects/states/dashboard/selected-task.service.ts +++ b/src/app/projects/states/dashboard/selected-task.service.ts @@ -1,7 +1,7 @@ -import {Injectable} from '@angular/core'; import {BehaviorSubject, Subject} from 'rxjs'; import {Task} from 'src/app/api/models/task'; import {TaskService} from 'src/app/api/services/task.service'; +import {Injectable} from '@angular/core'; import {GlobalStateService} from '../index/global-state.service'; export enum DashboardViews { @@ -24,10 +24,12 @@ export class SelectedTaskService { private globalState: GlobalStateService, ) {} - private task$ = new BehaviorSubject(null); - public currentPdfUrl$ = new BehaviorSubject(null); + private task$: BehaviorSubject = new BehaviorSubject(null); + public currentPdfUrl$: BehaviorSubject = new BehaviorSubject(null); - public currentView$ = new BehaviorSubject(DashboardViews.submission); + public currentView$: BehaviorSubject = new BehaviorSubject( + DashboardViews.submission, + ); public get hasTaskSheet(): boolean { return this.task$.value?.definition?.hasTaskSheet; diff --git a/src/app/projects/states/discussion-prompts/discussion-prompts.component.html b/src/app/projects/states/discussion-prompts/discussion-prompts.component.html index 3b3a2b5ef2..4172ea915a 100644 --- a/src/app/projects/states/discussion-prompts/discussion-prompts.component.html +++ b/src/app/projects/states/discussion-prompts/discussion-prompts.component.html @@ -1,9 +1,9 @@ -
    +
    @for (prompt of discussionPrompts; track prompt) { - +
    diff --git a/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts b/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts index adcf938409..e5a020891c 100644 --- a/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts +++ b/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts @@ -1,16 +1,16 @@ -import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core'; import {DiscussionPrompt} from 'src/app/api/models/discussion-prompt'; import {Project, TaskDefinition, UserService} from 'src/app/api/models/doubtfire-model'; import {StaffNote} from 'src/app/api/models/staff-note'; import {DiscussionPromptService} from 'src/app/api/services/discussion-prompt.service'; import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; +import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core'; @Component({ - selector: 'f-discussion-prompts', - templateUrl: './discussion-prompts.component.html', - styleUrl: './discussion-prompts.component.scss', - standalone: false + selector: 'f-discussion-prompts', + templateUrl: './discussion-prompts.component.html', + styleUrl: './discussion-prompts.component.scss', + standalone: false, }) export class DiscussionPromptsComponent implements OnInit { @ViewChild('staffNotesContainer') staffNotesContainer!: ElementRef; diff --git a/src/app/projects/states/groups/project-groups-state.component.ts b/src/app/projects/states/groups/project-groups-state.component.ts index 9743733163..8f6478a508 100644 --- a/src/app/projects/states/groups/project-groups-state.component.ts +++ b/src/app/projects/states/groups/project-groups-state.component.ts @@ -1,14 +1,14 @@ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; import {Observable, Subscription, of} from 'rxjs'; import {GroupSet, Project} from 'src/app/api/models/doubtfire-model'; -import {GlobalStateService, ViewType} from '../index/global-state.service'; +import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; +import {GlobalStateService} from '../index/global-state.service'; @Component({ - selector: 'f-project-groups-state', - templateUrl: './project-groups-state.component.html', - styleUrls: ['./project-groups-state.component.scss'], - standalone: false + selector: 'f-project-groups-state', + templateUrl: './project-groups-state.component.html', + styleUrls: ['./project-groups-state.component.scss'], + standalone: false, }) export class ProjectGroupsStateComponent implements OnInit, OnDestroy { @Input() public project$: Observable; diff --git a/src/app/projects/states/groups/project-groups/project-groups.component.html b/src/app/projects/states/groups/project-groups/project-groups.component.html index 6fd3e49648..a375726a37 100644 --- a/src/app/projects/states/groups/project-groups/project-groups.component.html +++ b/src/app/projects/states/groups/project-groups/project-groups.component.html @@ -1,12 +1,12 @@ -
    +
    @if (unit.hasGroupwork()) { } @else { -
    +
    groups

    No Group Work

    -

    There is no group work enabled for this unit.

    +

    There is no group work enabled for this unit.

    }
    diff --git a/src/app/projects/states/groups/project-groups/project-groups.component.ts b/src/app/projects/states/groups/project-groups/project-groups.component.ts index 18cdaab12e..3f1d39eea3 100644 --- a/src/app/projects/states/groups/project-groups/project-groups.component.ts +++ b/src/app/projects/states/groups/project-groups/project-groups.component.ts @@ -1,13 +1,13 @@ -import {Component, Input} from '@angular/core'; import {GroupSet, Project} from 'src/app/api/models/doubtfire-model'; import {Unit} from 'src/app/api/models/unit'; +import {Component, Input} from '@angular/core'; // This component is only displayed to students (projects) @Component({ - selector: 'f-project-groups', - templateUrl: './project-groups.component.html', - styleUrl: './project-groups.component.scss', - standalone: false + selector: 'f-project-groups', + templateUrl: './project-groups.component.html', + styleUrl: './project-groups.component.scss', + standalone: false, }) export class ProjectGroupsComponent { @Input() unit: Unit; diff --git a/src/app/projects/states/index/global-state.service.ts b/src/app/projects/states/index/global-state.service.ts index 2692d712b5..65584df544 100644 --- a/src/app/projects/states/index/global-state.service.ts +++ b/src/app/projects/states/index/global-state.service.ts @@ -1,5 +1,3 @@ -import {Injectable, OnDestroy} from '@angular/core'; -import {Router} from '@angular/router'; import {MediaObserver} from 'ng-flex-layout'; import {EntityCache} from 'ngx-entity-service'; import {BehaviorSubject, Observable, Subject, skip, take} from 'rxjs'; @@ -16,8 +14,10 @@ import { UserService, } from 'src/app/api/models/doubtfire-model'; import {AuthenticationService} from 'src/app/api/services/authentication.service'; -import {AlertService} from 'src/app/common/services/alert.service'; import {FeedbackTemplateService} from 'src/app/api/services/feedback-template.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {Injectable, OnDestroy} from '@angular/core'; +import {Router} from '@angular/router'; /** * The different types of views that can be shown. Used by the header to determine details to show. diff --git a/src/app/projects/states/jplag/jplag-report-viewer.component.html b/src/app/projects/states/jplag/jplag-report-viewer.component.html index c5c52c229e..4474b7d14e 100644 --- a/src/app/projects/states/jplag/jplag-report-viewer.component.html +++ b/src/app/projects/states/jplag/jplag-report-viewer.component.html @@ -4,6 +4,6 @@ src="/JPlag/" frameborder="0" style="overflow: hidden" - class="w-full h-screen overflow-hidden" + class="h-screen w-full overflow-hidden" [scrolling]="false" > diff --git a/src/app/projects/states/jplag/jplag-report-viewer.component.ts b/src/app/projects/states/jplag/jplag-report-viewer.component.ts index 09df22eb1b..844e46ce7e 100644 --- a/src/app/projects/states/jplag/jplag-report-viewer.component.ts +++ b/src/app/projects/states/jplag/jplag-report-viewer.component.ts @@ -1,10 +1,10 @@ -import {Component, ElementRef, Input, ViewChild} from '@angular/core'; import {AlertService} from 'src/app/common/services/alert.service'; +import {Component, ElementRef, Input, ViewChild} from '@angular/core'; @Component({ - selector: 'f-jplag-report-viewer', - templateUrl: './jplag-report-viewer.component.html', - standalone: false + selector: 'f-jplag-report-viewer', + templateUrl: './jplag-report-viewer.component.html', + standalone: false, }) export class JplagReportViewerComponent { @ViewChild('jplagIframe', {static: true}) jplagIframe!: ElementRef; diff --git a/src/app/projects/states/plan/project-plan.component.html b/src/app/projects/states/plan/project-plan.component.html index a29342d512..a1e861bcbd 100644 --- a/src/app/projects/states/plan/project-plan.component.html +++ b/src/app/projects/states/plan/project-plan.component.html @@ -1,5 +1,5 @@ @if (project) { -
    +

    Task Planner

    @if (unit.allowFlexibleDates) { @@ -16,8 +16,8 @@

    Task Planner

    -
    -
    +
    +
    Target Grade ; diff --git a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html index 5291b43dc6..d75f59aa58 100644 --- a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html +++ b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html @@ -1,5 +1,5 @@ - + {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} @@ -15,7 +15,7 @@ [task]="task" > @if (!task.hasPrerequisiteTasks()) { -
    This task has no prerequisites.
    +
    This task has no prerequisites.
    } @if (dependents.length) { @@ -71,7 +71,7 @@
    } @else { -
    +
    This task is not a prerequisite for any other tasks.
    } diff --git a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts index 1b19161dcf..af95011291 100644 --- a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts +++ b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts @@ -1,9 +1,9 @@ -import {Component, Inject, Input, OnInit} from '@angular/core'; -import {MAT_DIALOG_DATA} from '@angular/material/dialog'; -import {MatTableDataSource} from '@angular/material/table'; import {Project} from 'src/app/api/models/project'; import {TaskDefinition} from 'src/app/api/models/task-definition'; import {TaskPrerequisite} from 'src/app/api/models/task-prerequisite'; +import {Component, Inject, Input, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {MatTableDataSource} from '@angular/material/table'; export interface TaskPlannerPrerequisitesModalData { taskDefinition: TaskDefinition; @@ -12,17 +12,17 @@ export interface TaskPlannerPrerequisitesModalData { } @Component({ - selector: 'f-task-planner-prerequisites-modal', - templateUrl: './task-planner-prerequisites-modal.component.html', - styleUrl: './task-planner-prerequisites-modal.component.scss', - standalone: false + selector: 'f-task-planner-prerequisites-modal', + templateUrl: './task-planner-prerequisites-modal.component.html', + styleUrl: './task-planner-prerequisites-modal.component.scss', + standalone: false, }) export class TaskPlannerPrerequisitesModalComponent implements OnInit { @Input() taskDefinition: TaskDefinition; @Input() project: Project; @Input() dependents: TaskPrerequisite[]; - public dataSource = new MatTableDataSource(); + public dataSource: MatTableDataSource = new MatTableDataSource(); public displayedColumns: string[] = ['task-definition', 'current-status', 'required-status']; public get task() { diff --git a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.service.ts b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.service.ts index 4f12f4fd1f..354c891350 100644 --- a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.service.ts +++ b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.service.ts @@ -1,11 +1,11 @@ +import {Project, TaskDefinition} from 'src/app/api/models/doubtfire-model'; +import {TaskPrerequisite} from 'src/app/api/models/task-prerequisite'; import {Injectable} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; -import {Project, TaskDefinition} from 'src/app/api/models/doubtfire-model'; import { TaskPlannerPrerequisitesModalComponent, TaskPlannerPrerequisitesModalData, } from './task-planner-prerequisites-modal.component'; -import {TaskPrerequisite} from 'src/app/api/models/task-prerequisite'; @Injectable({ providedIn: 'root', diff --git a/src/app/projects/states/plan/task-planner/task-planner.component.html b/src/app/projects/states/plan/task-planner/task-planner.component.html index e17c06ff34..cc2a8e04fe 100644 --- a/src/app/projects/states/plan/task-planner/task-planner.component.html +++ b/src/app/projects/states/plan/task-planner/task-planner.component.html @@ -1,4 +1,4 @@ -
    +
    Show Task Dates
    @@ -39,12 +39,12 @@ class="flex items-center justify-between" [routerLink]="['/projects', project.id, 'dashboard', item.taskDefinition.abbreviation]" > -
    +
    -
    +
    {{ item.title }}
    @@ -79,13 +79,13 @@ [attr.data-gantt-id]="item.id" (mouseover)="onBarHover(item)" (mouseleave)="onBarLeave(item)" - class="gantt-bar w-full text-white flex gap-1 justify-between items-center p-1 h-[35px]" + class="gantt-bar flex h-[35px] w-full items-center justify-between gap-1 p-1 text-white" [ngClass]="getItemClasses(item)" [matTooltip]="getTooltip(item)" matTooltipShowDelay="500" matTooltipPosition="above" - >
    -
    + >
    +
    @if (unsavedChanges(item)) { change_circle } diff --git a/src/app/projects/states/plan/task-planner/task-planner.component.ts b/src/app/projects/states/plan/task-planner/task-planner.component.ts index d0e17b5fb4..9a3bcb36a6 100644 --- a/src/app/projects/states/plan/task-planner/task-planner.component.ts +++ b/src/app/projects/states/plan/task-planner/task-planner.component.ts @@ -1,5 +1,3 @@ -import {Component, Input, OnInit, ViewChild} from '@angular/core'; -import {ActivatedRoute, Router} from '@angular/router'; import { GanttBaselineItem, GanttDate, @@ -18,6 +16,8 @@ import {TaskPrerequisiteService} from 'src/app/api/services/task-prerequisite.se import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {GradeService} from 'src/app/common/services/grade.service'; +import {Component, Input, OnInit, ViewChild} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; import {TaskPlannerPrerequisitesModalService} from './task-planner-prerequisites-modal/task-planner-prerequisites-modal.service'; interface TaskGanttItem extends GanttItem { @@ -28,10 +28,10 @@ interface TaskGanttItem extends GanttItem { } @Component({ - selector: 'f-task-planner', - templateUrl: './task-planner.component.html', - styleUrl: './task-planner.component.scss', - standalone: false + selector: 'f-task-planner', + templateUrl: './task-planner.component.html', + styleUrl: './task-planner.component.scss', + standalone: false, }) export class TaskPlannerComponent implements OnInit { // Show a warning if the task's target end date is within this many days of the feedback deadline diff --git a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html index 84bd32601d..a596c34e0a 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html +++ b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html @@ -1,4 +1,4 @@ - + Upload Other Files @@ -10,7 +10,7 @@
      @for (file of extraFiles; track file) { -
    1. +
    2. {{ icons[file.kind] }} {{ file.name }} @@ -24,7 +24,7 @@ }
    -
    +
    Select type of file: @@ -45,7 +45,7 @@ > - + diff --git a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts index caaaff49ee..8e1afd4365 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts +++ b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts @@ -1,13 +1,13 @@ -import {Component, Input, OnInit} from '@angular/core'; -import {MatSelectChange} from '@angular/material/select'; import {Project} from 'src/app/api/models/project'; import {AlertService} from 'src/app/common/services/alert.service'; +import {Component, Input, OnInit} from '@angular/core'; +import {MatSelectChange} from '@angular/material/select'; @Component({ - selector: 'f-portfolio-add-extra-files-step', - templateUrl: 'portfolio-add-extra-files-step.component.html', - styleUrls: ['portfolio-add-extra-files-step.component.scss'], - standalone: false + selector: 'f-portfolio-add-extra-files-step', + templateUrl: 'portfolio-add-extra-files-step.component.html', + styleUrls: ['portfolio-add-extra-files-step.component.scss'], + standalone: false, }) export class PortfolioAddExtraFilesStepComponent implements OnInit { @Input() project: Project; diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html index ce69d3dcb3..e74d70a357 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html @@ -1,5 +1,5 @@
    - + @@ -14,7 +14,7 @@

    Select Grade

    - + warning @@ -40,7 +40,7 @@

    Select Grade

    @if (agreedToAssessmentCriteria) { - + Grade Application diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts index 41d75520a1..208f989460 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts @@ -1,14 +1,14 @@ -import {Component, Input} from '@angular/core'; import {Project, Unit} from 'src/app/api/models/doubtfire-model'; import {ProjectService} from 'src/app/api/services/project.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {GradeService} from 'src/app/common/services/grade.service'; +import {Component, Input} from '@angular/core'; @Component({ - selector: 'f-portfolio-grade-select-step', - templateUrl: 'portfolio-grade-select-step.component.html', - styleUrls: ['portfolio-grade-select-step.component.scss'], - standalone: false + selector: 'f-portfolio-grade-select-step', + templateUrl: 'portfolio-grade-select-step.component.html', + styleUrls: ['portfolio-grade-select-step.component.scss'], + standalone: false, }) export class PortfolioGradeSelectStepComponent { @Input() project: Project; diff --git a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.html index 74cb105802..00107890a2 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.html +++ b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.html @@ -1,4 +1,4 @@ - + Learning Summary Report @@ -12,7 +12,7 @@ summary of what you have learnt in this unit. It consists of two sections:

    -
      +
      1. a self-assessment, and
      2. your reflections on the unit.
      @@ -30,13 +30,13 @@ @if ( projectHasDraftLearningSummaryReport && !forceLSRSubmit && !acceptUploadNewLearningSummary ) { -
      -

    } @else {

    construction - } @else { -
    - - } -
    -
    - +

    + } diff --git a/src/app/projects/states/tutorials/tutorials.component.ts b/src/app/projects/states/tutorials/tutorials.component.ts index 2ff72a61a2..0284fbca42 100644 --- a/src/app/projects/states/tutorials/tutorials.component.ts +++ b/src/app/projects/states/tutorials/tutorials.component.ts @@ -1,15 +1,15 @@ +import {Observable, Subscription, of} from 'rxjs'; +import {Project, Tutorial, Unit} from 'src/app/api/models/doubtfire-model'; import {Component, Input, OnDestroy, OnInit} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; import {Sort} from '@angular/material/sort'; import {MatTableDataSource} from '@angular/material/table'; -import {Observable, Subscription, of} from 'rxjs'; -import {Project, Tutorial, Unit} from 'src/app/api/models/doubtfire-model'; +import {ActivatedRoute} from '@angular/router'; @Component({ - selector: 'f-tutorials', - templateUrl: './tutorials.component.html', - styleUrls: ['./tutorials.component.scss'], - standalone: false + selector: 'f-tutorials', + templateUrl: './tutorials.component.html', + styleUrls: ['./tutorials.component.scss'], + standalone: false, }) export class TutorialsComponent implements OnInit, OnDestroy { @Input() public project$: Observable; @@ -30,7 +30,7 @@ export class TutorialsComponent implements OnInit, OnDestroy { 'actions', ]; - dataSource = new MatTableDataSource([]); + dataSource: MatTableDataSource = new MatTableDataSource([]); private projectSub?: Subscription; diff --git a/src/app/sessions/service-worker-updater/check-for-update.service.ts b/src/app/sessions/service-worker-updater/check-for-update.service.ts index 409e444719..302af93ef1 100644 --- a/src/app/sessions/service-worker-updater/check-for-update.service.ts +++ b/src/app/sessions/service-worker-updater/check-for-update.service.ts @@ -1,13 +1,14 @@ -import { ApplicationRef, Injectable } from '@angular/core'; -import { SwUpdate } from '@angular/service-worker'; -import { interval } from 'rxjs'; -import { MatSnackBar } from '@angular/material/snack-bar'; -import { delay } from 'rxjs/operators'; -import { concat } from 'rxjs'; +import {ApplicationRef, Injectable} from '@angular/core'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {SwUpdate} from '@angular/service-worker'; @Injectable() export class CheckForUpdateService { - constructor(appRef: ApplicationRef, private updates: SwUpdate, private _snackBar: MatSnackBar) { + constructor( + appRef: ApplicationRef, + private updates: SwUpdate, + private _snackBar: MatSnackBar, + ) { // Allow the app to stabilize first, before starting polling for updates with `interval()`. // const appIsStable$ = appRef.isStable.pipe(delay(10000)); @@ -22,15 +23,15 @@ export class CheckForUpdateService { if (updateEvent.type === 'VERSION_READY') { const snackBarRef = _snackBar.open( 'An update to the app has been found, would you like to refresh now?', - 'refresh' + 'refresh', ); - snackBarRef.onAction().subscribe((result) => { + snackBarRef.onAction().subscribe((_result) => { updates.activateUpdate().then(() => document.location.reload()); }); } }); - this.updates.unrecoverable.subscribe((event) => { + this.updates.unrecoverable.subscribe((_event) => { _snackBar.open('An error occurred during update, please refresh the page'); }); } diff --git a/src/app/sessions/states/sign-in/sign-in.component.html b/src/app/sessions/states/sign-in/sign-in.component.html index 1d6d66633f..5eeb9fa752 100644 --- a/src/app/sessions/states/sign-in/sign-in.component.html +++ b/src/app/sessions/states/sign-in/sign-in.component.html @@ -1,9 +1,9 @@ -
    - -
    +
    + +
    @if (!isLoading) { @if (!isLoading) { -
    +
    Homepage Logo @@ -25,13 +25,13 @@

    class="sign-in-form flex flex-col" > @if (showCredentials) { - + Username } @if (showCredentials) { - + Password

    } } @else if (authMethodFailed) { -
    +
    } diff --git a/src/app/sessions/states/sign-in/sign-in.component.spec.ts b/src/app/sessions/states/sign-in/sign-in.component.spec.ts index e0d4c2f0d0..ccc7662322 100644 --- a/src/app/sessions/states/sign-in/sign-in.component.spec.ts +++ b/src/app/sessions/states/sign-in/sign-in.component.spec.ts @@ -1,6 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { SignInComponent } from './sign-in.component'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {SignInComponent} from './sign-in.component'; describe('SignInComponent', () => { let component: SignInComponent; @@ -8,9 +7,8 @@ describe('SignInComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ SignInComponent ] - }) - .compileComponents(); + declarations: [SignInComponent], + }).compileComponents(); }); beforeEach(() => { diff --git a/src/app/sessions/states/sign-in/sign-in.component.ts b/src/app/sessions/states/sign-in/sign-in.component.ts index eaecb6108f..7477ab3920 100644 --- a/src/app/sessions/states/sign-in/sign-in.component.ts +++ b/src/app/sessions/states/sign-in/sign-in.component.ts @@ -1,17 +1,15 @@ -import {HttpClient} from '@angular/common/http'; -import {Component, Input, OnInit} from '@angular/core'; -import {ActivatedRoute, Router} from '@angular/router'; import {BehaviorSubject} from 'rxjs'; import {AuthenticationService} from 'src/app/api/services/authentication.service'; import {UserService} from 'src/app/api/services/user.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {GlobalStateService} from 'src/app/projects/states/index/global-state.service'; +import {HttpClient} from '@angular/common/http'; +import {Component, Input, OnInit} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; // Add fallback to check url for query parameters -interface IParams { - [key: string]: string; -} +type IParams = Record; const paramReducer = (params: IParams, pair: string): IParams => { const [key, value] = `${pair}=`.split('=').map(decodeURIComponent); @@ -38,10 +36,10 @@ type signInData = autoLogin?: boolean; }; @Component({ - selector: 'f-sign-in', - templateUrl: './sign-in.component.html', - styleUrls: ['./sign-in.component.scss'], - standalone: false + selector: 'f-sign-in', + templateUrl: './sign-in.component.html', + styleUrls: ['./sign-in.component.scss'], + standalone: false, }) export class SignInComponent implements OnInit { public signingIn: boolean; @@ -130,11 +128,11 @@ export class SignInComponent implements OnInit { // wait 2 seconds with rxjs const wait = new Promise((resolve) => setTimeout(resolve, 3000)); this.http.get(`${this.constants.API_URL}/auth/method`).subscribe({ - next: (response: any) => { + next: (response: {redirect_to?: string}) => { this.isLoading = false; // if there is a string in response.data.redirect_to - this.SSOLoginUrl = response.redirect_to || false; + this.SSOLoginUrl = response.redirect_to || ''; if (this.authToken) { // We have an auth token - so attempt to convert to access token @@ -189,7 +187,7 @@ export class SignInComponent implements OnInit { return wait.then(); } }, - error: (err) => { + error: (_err) => { this.authMethodFailed = true; // this.error = err; diff --git a/src/app/sessions/transition-hooks.service.spec.ts b/src/app/sessions/transition-hooks.service.spec.ts index 90d821953b..3addee99f2 100644 --- a/src/app/sessions/transition-hooks.service.spec.ts +++ b/src/app/sessions/transition-hooks.service.spec.ts @@ -1,6 +1,5 @@ -import { TestBed } from '@angular/core/testing'; - -import { TransitionHooksService } from './transition-hooks.service'; +import {TestBed} from '@angular/core/testing'; +import {TransitionHooksService} from './transition-hooks.service'; describe('TransitionHooksService', () => { let service: TransitionHooksService; diff --git a/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.html b/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.html index ad6470153b..52898d0a79 100644 --- a/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.html +++ b/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.html @@ -17,7 +17,7 @@

    Request Feedback Review

    request will not be counted against your remaining total.

    - + Reason for review request - + Priority diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts index 331100ba99..ea9fbc10d2 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts @@ -1,6 +1,3 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; -import {UntypedFormControl, Validators} from '@angular/forms'; -import {MatTableDataSource} from '@angular/material/table'; import {Observable, Subscription} from 'rxjs'; import {DiscussionPrompt} from 'src/app/api/models/discussion-prompt'; import {Task} from 'src/app/api/models/task'; @@ -12,12 +9,15 @@ import {TaskDefinitionService} from 'src/app/api/services/task-definition.servic import {TaskPrerequisiteService} from 'src/app/api/services/task-prerequisite.service'; import {EntityFormComponent} from 'src/app/common/entity-form/entity-form.component'; import {AlertService} from 'src/app/common/services/alert.service'; +import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import {UntypedFormControl, Validators} from '@angular/forms'; +import {MatTableDataSource} from '@angular/material/table'; @Component({ - selector: 'f-task-definition-discussion-prompts', - templateUrl: 'task-definition-discussion-prompts.component.html', - styleUrls: ['task-definition-discussion-prompts.component.scss'], - standalone: false + selector: 'f-task-definition-discussion-prompts', + templateUrl: 'task-definition-discussion-prompts.component.html', + styleUrls: ['task-definition-discussion-prompts.component.scss'], + standalone: false, }) export class TaskDefinitionDiscussionPromptsComponent extends EntityFormComponent @@ -31,7 +31,7 @@ export class TaskDefinitionDiscussionPromptsComponent private prereqSub?: Subscription; - public dataSource = new MatTableDataSource(); + public dataSource: MatTableDataSource = new MatTableDataSource(); creatingNewDiscussionPrompt: boolean = false; diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html index cca24f04c2..773af87979 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html @@ -1,4 +1,4 @@ -
    +

    Details for {{ taskDefinition.abbreviation }} - {{ taskDefinition.name }}

    @@ -9,7 +9,7 @@

    Details for {{ taskDefinition.abbreviation }} - {{ taskDefinition.name }} +

    Task Details

    -

    Name the task and set target grade

    +

    Name the task and set target grade

    Task Learning Outcomes

    -

    Add learning outcomes for this task

    +

    Add learning outcomes for this task

    Inbox

    -

    +

    Who assesses {{ unit.hasGroupwork() ? 'and submits ' : '' }}this task?

    @@ -63,45 +63,45 @@

    Inbox

    Due Dates

    -

    When is the task due?

    +

    When is the task due?

    Upload Requirements

    -

    What do students need to upload?

    +

    What do students need to upload?

    Task Resources

    -

    Upload task descriptions and resources

    +

    Upload task descriptions and resources

    Prerequisite Tasks

    -

    +

    Select which tasks need to be submitted before {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} can be submitted @@ -112,12 +112,12 @@

    Prerequisite Tasks

    Discussion Prompts

    -

    +

    Discussion prompts for tutors to use when discussing student tasks in class

    @@ -127,24 +127,24 @@

    Discussion Prompts

    @if (overseerEnabled) {

    Task Assessment Automation

    -

    Configure automated assessment

    +

    Configure automated assessment

    }

    SCORM Test

    -

    +

    Upload the corresponding SCORM 2004 test (e.g. Numbas)

    @@ -152,12 +152,12 @@

    SCORM Test

    Optional Settings

    -

    Apply other options

    +

    Apply other options

    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts index 81ff3fb414..88063be511 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts @@ -1,3 +1,9 @@ +import {Subscription} from 'rxjs'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import { AfterViewInit, Component, @@ -12,12 +18,6 @@ import { ViewChild, ViewChildren, } from '@angular/core'; -import {Subscription} from 'rxjs'; -import {TaskDefinition} from 'src/app/api/models/task-definition'; -import {Unit} from 'src/app/api/models/unit'; -import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; -import {AlertService} from 'src/app/common/services/alert.service'; -import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; type TaskDefinitionSectionId = | 'task-details' @@ -38,10 +38,10 @@ interface TaskDefinitionSection { } @Component({ - selector: 'f-task-definition-editor', - templateUrl: 'task-definition-editor.component.html', - styleUrls: ['task-definition-editor.component.scss'], - standalone: false + selector: 'f-task-definition-editor', + templateUrl: 'task-definition-editor.component.html', + styleUrls: ['task-definition-editor.component.scss'], + standalone: false, }) export class TaskDefinitionEditorComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy { @Input() taskDefinition: TaskDefinition; @@ -65,7 +65,7 @@ export class TaskDefinitionEditorComponent implements OnInit, AfterViewInit, OnC {id: 'optional-settings', label: 'Optional Settings'}, ]; - private sectionElementMap = new Map(); + private sectionElementMap: Map = new Map(); private sectionChangesSubscription?: Subscription; private overseerEnabledSubscription?: Subscription; private readonly scrollTopOffsetPx: number = 112; diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.ts index aad3e6d649..0ae8ea3283 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.ts @@ -1,18 +1,18 @@ -import { Component, Input } from '@angular/core'; -import { TaskDefinition } from 'src/app/api/models/task-definition'; -import { Unit } from 'src/app/api/models/unit'; -import { GradeService } from 'src/app/common/services/grade.service'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; +import {GradeService} from 'src/app/common/services/grade.service'; +import {Component, Input} from '@angular/core'; @Component({ - selector: 'f-task-definition-general', - templateUrl: 'task-definition-general.component.html', - styleUrls: ['task-definition-general.component.scss'], - standalone: false + selector: 'f-task-definition-general', + templateUrl: 'task-definition-general.component.html', + styleUrls: ['task-definition-general.component.scss'], + standalone: false, }) export class TaskDefinitionGeneralComponent { @Input() taskDefinition: TaskDefinition; - public grades: { value: number; viewValue: string }[]; + public grades: {value: number; viewValue: string}[]; constructor(private gradeService: GradeService) { this.grades = this.gradeService.gradeViewData.filter((grade) => grade.value !== -1); diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html index 6a0b952c48..bd3109b9f2 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html @@ -1,5 +1,5 @@
    -
    +
    Restrict updates @@ -9,7 +9,7 @@
    -
    +
    -
    +
    Requires Discussion @@ -34,7 +34,7 @@
    -
    +
    Graded @@ -44,12 +44,12 @@
    -
    +
    Quality Stars - Provide a number of stars alongside the task status. Make sure you have a clear reason for each star within your task description. diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts index edba0f5051..16e5515a3a 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts @@ -1,13 +1,13 @@ -import {Component, Input} from '@angular/core'; import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Unit} from 'src/app/api/models/unit'; import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {Component, Input} from '@angular/core'; @Component({ - selector: 'f-task-definition-options', - templateUrl: 'task-definition-options.component.html', - styleUrls: ['task-definition-options.component.scss'], - standalone: false + selector: 'f-task-definition-options', + templateUrl: 'task-definition-options.component.html', + styleUrls: ['task-definition-options.component.scss'], + standalone: false, }) export class TaskDefinitionOptionsComponent { @Input() taskDefinition: TaskDefinition; diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html index 99782d94b6..415d4a14a6 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html @@ -1,4 +1,4 @@ -
    +

    {{ data.taskDefinition.abbreviation }} {{ data.taskDefinition.name }}

    Overseer script

    @@ -9,6 +9,6 @@
    @if (!loading) { - + }
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts index 9f44236d77..ee5c0c1e46 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts @@ -1,15 +1,15 @@ +import {CodeModel} from '@ngstack/code-editor'; +import {AlertService} from 'src/app/common/services/alert.service'; import {HttpClient} from '@angular/common/http'; import {Component, Inject, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; -import {CodeModel} from '@ngstack/code-editor'; -import {AlertService} from 'src/app/common/services/alert.service'; import {OverseerScriptEditorModalData} from './overseer-script-editor-modal.service'; @Component({ - selector: 'f-overseer-script-editor-modal', - templateUrl: './overseer-script-editor-modal.component.html', - styleUrls: ['./overseer-script-editor-modal.component.scss'], - standalone: false + selector: 'f-overseer-script-editor-modal', + templateUrl: './overseer-script-editor-modal.component.html', + styleUrls: ['./overseer-script-editor-modal.component.scss'], + standalone: false, }) export class OverseerScriptEditorModalComponent implements OnInit { constructor( diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.service.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.service.ts index c238db3eaf..4964a97b4e 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.service.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.service.ts @@ -1,7 +1,7 @@ +import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Injectable} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; import {OverseerScriptEditorModalComponent} from './overseer-script-editor-modal.component'; -import {TaskDefinition} from 'src/app/api/models/task-definition'; export interface OverseerScriptEditorModalData { taskDefinition: TaskDefinition; diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html index df2173bf35..164bd31aaf 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html @@ -86,7 +86,7 @@ color="primary" [disabled]="!taskDefinition.id" (click)="testSubmission()" - class="flex-grow me-4" + class="me-4 flex-grow" > upload_file Test Submission @@ -94,7 +94,7 @@ mat-flat-button color="accent" (click)="testSubmissionHistory()" - class="flex-grow ms-4" + class="ms-4 flex-grow" [disabled]="!this.currentUserTask?.project" > preview Submission History @@ -118,7 +118,7 @@
    Overseer Steps
    @if (!newOverseerStep) { @@ -132,7 +132,7 @@ cdkDrag (click)="selectStep(step)" [ngClass]="{ - 'bg-gray-100': selectedOverseerStep?.id === step.id + 'bg-gray-100': selectedOverseerStep?.id === step.id, }" > drag_indicator @@ -153,9 +153,9 @@ @if (selectedOverseerStep) { - - -
    + + +
    Step Name @@ -182,7 +182,7 @@ @if (selectedOverseerStep.stepType === 'output_diff') { -
    +
    Script Input File @@ -234,7 +234,7 @@
    } -
    +
    Execution Script
    Language @@ -260,7 +260,7 @@ [(ngModel)]="selectedOverseerStep.decodedRunCommand" (ngModelChange)="onRunCommandChange(selectedOverseerStep, $event)" > - + @if (selectedOverseerStep.stepType === 'status_check') { This step passes only if the script exits with status 0. Any non-zero exit code marks the step as failed. @@ -270,7 +270,7 @@ }
    - + Time Limit (s) -
    +
    @@ -335,7 +335,7 @@
    -
    +
    Test Name @@ -353,7 +353,7 @@ Shown to student in overseer report
    - + Feedback message } @else { -
    +
    No steps selected tab_unselected
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts index 747ea313d5..e6dac66379 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts @@ -1,9 +1,6 @@ -import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop'; -import {HttpClient, HttpResponse} from '@angular/common/http'; -import {Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from '@angular/core'; +import * as monaco from 'monaco-editor'; import {Observable} from 'rxjs'; import { - OverseerAssessment, OverseerImage, OverseerImageService, Task, @@ -21,14 +18,17 @@ import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloa import {TaskAssessmentModalService} from 'src/app/common/modals/task-assessment-modal/task-assessment-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {TaskSubmissionService} from 'src/app/common/services/task-submission.service'; -import {OverseerScriptEditorModalService} from './overseer-script-editor-modal/overseer-script-editor-modal.service'; -import * as monaco from 'monaco-editor'; +import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop'; +import {HttpClient, HttpResponse} from '@angular/common/http'; +import {Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from '@angular/core'; import {MatSelectChange} from '@angular/material/select'; +import {OverseerScriptEditorModalService} from './overseer-script-editor-modal/overseer-script-editor-modal.service'; + @Component({ - selector: 'f-task-definition-overseer', - templateUrl: 'task-definition-overseer.component.html', - styleUrls: ['task-definition-overseer.component.scss'], - standalone: false + selector: 'f-task-definition-overseer', + templateUrl: 'task-definition-overseer.component.html', + styleUrls: ['task-definition-overseer.component.scss'], + standalone: false, }) export class TaskDefinitionOverseerComponent implements OnChanges, OnInit { @Input() taskDefinition: TaskDefinition; @@ -229,7 +229,7 @@ export class TaskDefinitionOverseerComponent implements OnChanges, OnInit { }, ) .subscribe({ - next: (result) => { + next: (_result) => { this.alerts.success('Saved overseer step', 3000); }, error: (error) => { @@ -301,7 +301,6 @@ export class TaskDefinitionOverseerComponent implements OnChanges, OnInit { if (!this.currentUserTask) return; this.submissions.getLatestSubmissionsTimestamps(this.currentUserTask).subscribe({ - next: (result: OverseerAssessment[]) => {}, error: (error) => { this.alerts.error('Error: ' + error, 6000); }, diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html index 492b9bd9ac..740b01959e 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html @@ -1,5 +1,5 @@
    -
    +
    @@ -60,7 +60,7 @@ @@ -65,7 +65,7 @@

    Manage Target Dates

    Manage Target Dates Manage Target Dates @@ -176,13 +176,13 @@

    Manage Target Dates

    @if ((taskDefinitionSource?.filteredData ?? []).length === 0) { -
    No task definitions to display
    +
    No task definitions to display
    } @for ( taskDefinition of taskDefinitionSource?.filteredData ?? []; track taskDefinition ) { - +
    Manage Target Dates > @if (!isTaskListCollapsed) { -
    -

    +
    +

    {{ taskDefinition.name }}

    @@ -255,7 +255,7 @@

    [unit]="unit" > } @else { -
    +

    Select a task definition

    Pick a task from the left list to edit its details.

    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts index e09a279757..e2ea1486b3 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts @@ -1,5 +1,3 @@ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; -import {MatTableDataSource} from '@angular/material/table'; import {addWeeks} from 'date-fns'; import {Subscription} from 'rxjs'; import {Grade} from 'src/app/api/models/grade'; @@ -8,29 +6,34 @@ import {Unit} from 'src/app/api/models/unit'; import {FeedbackTemplateService} from 'src/app/api/services/feedback-template.service'; import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; -import {CsvResultModalService} from 'src/app/common/modals/csv-result-modal/csv-result-modal.service'; +import { + CsvResult, + CsvResultModalService, +} from 'src/app/common/modals/csv-result-modal/csv-result-modal.service'; import {CsvUploadModalService} from 'src/app/common/modals/csv-upload-modal/csv-upload-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; +import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {MatTableDataSource} from '@angular/material/table'; type GradeCol = 'p' | 'c' | 'd' | 'hd'; @Component({ - selector: 'f-unit-task-editor', - templateUrl: 'unit-task-editor.component.html', - styleUrls: ['unit-task-editor.component.scss'], - standalone: false + selector: 'f-unit-task-editor', + templateUrl: 'unit-task-editor.component.html', + styleUrls: ['unit-task-editor.component.scss'], + standalone: false, }) export class UnitTaskEditorComponent implements OnInit, OnDestroy { @Input() unit: Unit; - public taskDefinitionSource = new MatTableDataSource([]); + public taskDefinitionSource: MatTableDataSource = new MatTableDataSource([]); public filter: string = ''; public selectedTaskDefinition: TaskDefinition; public isTaskListCollapsed: boolean = false; public gradeColumns: string[] = ['p', 'c', 'd', 'hd']; public dueDateColumns: string[] = ['taskDefinition', 'p', 'c', 'd', 'hd']; - public dueDateSource = new MatTableDataSource([]); + public dueDateSource: MatTableDataSource = new MatTableDataSource([]); public manageDueDates: boolean = false; @@ -242,7 +245,7 @@ export class UnitTaskEditorComponent implements OnInit, OnDestroy { 'Upload a CSV of task definitions.', {file: {name: 'Task Definition CSV Data', type: 'csv'}}, this.unit.getTaskDefinitionBatchUploadUrl(), - (response: any) => { + (response: CsvResult) => { // at least one student? this.csvResultModalService.show('Task Definition Import Results', response); if (response.success.length > 0) { @@ -258,7 +261,7 @@ export class UnitTaskEditorComponent implements OnInit, OnDestroy { 'Upload a ZIP of task sheets and resources.', {file: {name: 'Task Sheets and Resources', type: 'zip'}}, this.unit.taskUploadUrl, - (response: any) => { + (response: CsvResult) => { // at least one student? this.csvResultModalService.show('Task Sheet and Resources Import Results', response); if (response.success.length > 0) { diff --git a/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.html b/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.html index e2fb26f382..0ae4331b86 100644 --- a/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.html +++ b/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.html @@ -1,39 +1,39 @@
    -
    -
    -

    {{ stream.name }} - {{ stream.abbreviation }}

    - -
    - - - - Name - - - - - - Abbreviation - - - - - - - -
    + @if (stream) { +
    + @if (!editingStream) { +
    +

    {{ stream.name }} - {{ stream.abbreviation }}

    + +
    + } @else { + + Name + + + - + + Abbreviation + + - + + + + } +
    + } @else {

    Tutorials without a stream

    - + }

    Task @if (staffView) { - + - - -} +
    + + +
    + } -
    +
    @if (taskDefinition.hasTaskResources) { -
    - - -
    -} +
    + + +
    + }
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.ts index 458e479a10..efea676697 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.ts @@ -1,15 +1,15 @@ -import {Component, Inject, Input} from '@angular/core'; import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Unit} from 'src/app/api/models/unit'; import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; import {AlertService} from 'src/app/common/services/alert.service'; +import {Component, Input} from '@angular/core'; @Component({ - selector: 'f-task-definition-resources', - templateUrl: 'task-definition-resources.component.html', - styleUrls: ['task-definition-resources.component.scss'], - standalone: false + selector: 'f-task-definition-resources', + templateUrl: 'task-definition-resources.component.html', + styleUrls: ['task-definition-resources.component.scss'], + standalone: false, }) export class TaskDefinitionResourcesComponent { @Input() taskDefinition: TaskDefinition; diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html index 1db7e15ffc..d05d59d67e 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html @@ -12,19 +12,24 @@ /> @if (taskDefinition.hasScormData) {
    - - -
    } -
    +
    Allow students to review completed test attempt @@ -45,7 +50,7 @@
    -
    +
    @if (taskDefinition.needsJplag) { -
    +
    Language used for JPLAG checks diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts index 11ad050c31..f1be61f3f3 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts @@ -1,14 +1,14 @@ -import { Component, Input, ViewChild } from '@angular/core'; -import { MatTable } from '@angular/material/table'; -import { TaskDefinition, UploadRequirement } from 'src/app/api/models/task-definition'; -import { Unit } from 'src/app/api/models/unit'; -import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; +import {TaskDefinition, UploadRequirement} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Component, Input, ViewChild} from '@angular/core'; +import {MatTable} from '@angular/material/table'; @Component({ - selector: 'f-task-definition-upload', - templateUrl: 'task-definition-upload.component.html', - styleUrls: ['task-definition-upload.component.scss'], - standalone: false + selector: 'f-task-definition-upload', + templateUrl: 'task-definition-upload.component.html', + styleUrls: ['task-definition-upload.component.scss'], + standalone: false, }) export class TaskDefinitionUploadComponent { @Input() public taskDefinition: TaskDefinition; diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html index 4f363e2b22..0a3be6d1ba 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html @@ -1,13 +1,13 @@ @if (unit.hasGroupwork()) { - - Is this an individual or group task? Select group that submits - - @for (gs of unit.groupSets; track gs) { - {{ gs.name }} -} - None - Individual Submission - - + + Is this an individual or group task? Select group that submits + + @for (gs of unit.groupSets; track gs) { + {{ gs.name }} + } + None - Individual Submission + + }
    @@ -19,8 +19,8 @@ (selectionChange)="onTutorialStreamChange()" > @for (stream of unit.tutorialStreams; track stream) { - {{ stream.name }} -} + {{ stream.name }} + } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts index 7e4dd5e770..17d58c3484 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts @@ -1,12 +1,12 @@ -import { Component, Input } from '@angular/core'; -import { TaskDefinition } from 'src/app/api/models/task-definition'; -import { Unit } from 'src/app/api/models/unit'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Unit} from 'src/app/api/models/unit'; +import {Component, Input} from '@angular/core'; @Component({ - selector: 'f-task-definition-who', - templateUrl: 'task-definition-who.component.html', - styleUrls: ['task-definition-who.component.scss'], - standalone: false + selector: 'f-task-definition-who', + templateUrl: 'task-definition-who.component.html', + styleUrls: ['task-definition-who.component.scss'], + standalone: false, }) export class TaskDefinitionWhoComponent { @Input() taskDefinition: TaskDefinition; diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html index 244ca01013..472c672b28 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html @@ -1,4 +1,4 @@ -
    +

    Task List

    @@ -29,7 +29,7 @@

    Task List

    -
    +
    @if (unit.allowFlexibleDates) { } @@ -56,8 +56,8 @@

    Manage Target Dates

    @for (g of gradeColumns; track g) { -
    -
    +
    +
    Tutorials without a stream @@ -99,14 +105,15 @@

    Tutorials without a stream

    @@ -149,10 +161,11 @@

    Tutorials without a stream

    @@ -205,14 +223,13 @@

    Tutorials without a stream

    - +
    Abbreviation -
    - {{ tutorial.abbreviation }} -
    - + @if (!editing(tutorial)) { +
    + {{ tutorial.abbreviation }} +
    + } @else { -
    + }
    @@ -67,29 +68,34 @@

    Tutorials without a stream

    Campus -
    - {{ tutorial.campus ? tutorial.campus.name : '' }} -
    - + @if (!editing(tutorial)) { +
    + {{ tutorial.campus ? tutorial.campus.name : '' }} +
    + } @else { Campus Not Specified - - {{ campus.name }} - + @for (campus of campuses; track campus) { + + {{ campus.name }} + + } -
    + }
    Campus Not Specified - - {{ campus.name }} - + @for (campus of campuses; track campus) { + + {{ campus.name }} + + } Location -
    - {{ tutorial.meetingLocation }} -
    - + @if (!editing(tutorial)) { +
    + {{ tutorial.meetingLocation }} +
    + } @else { -
    + }
    @@ -119,27 +126,32 @@

    Tutorials without a stream

    Day -
    - {{ tutorial.meetingDay }} -
    - + @if (!editing(tutorial)) { +
    + {{ tutorial.meetingDay }} +
    + } @else { Day - - {{ day }} - + @for (day of days; track day) { + + {{ day }} + + } -
    + }
    Day - - {{ day }} - + @for (day of days; track day) { + + {{ day }} + + } Time -
    - {{ tutorial.meetingTime }} -
    - + @if (!editing(tutorial)) { +
    + {{ tutorial.meetingTime }} +
    + } @else { Tutorials without a stream placeholder="Time" /> -
    + }
    @@ -175,27 +188,32 @@

    Tutorials without a stream

    Tutor -
    - {{ tutorial.tutor?.name }} -
    - + @if (!editing(tutorial)) { +
    + {{ tutorial.tutor?.name }} +
    + } @else { Tutor - - {{ tutor.name }} - + @for (tutor of unit.staffUsers; track tutor) { + + {{ tutor.name }} + + } -
    + }
    Tutor - - {{ tutor.name }} - + @for (tutor of unit.staffUsers; track tutor) { + + {{ tutor.name }} + + } Capacity -
    - {{ tutorial.numStudents }} / {{ tutorial.capacity }} -
    - + @if (!editing(tutorial)) { +
    {{ tutorial.numStudents }} / {{ tutorial.capacity }}
    + } @else { -
    + }
    @@ -225,12 +242,13 @@

    Tutorials without a stream

    -
    - -
    - + @if (!editing(tutorial)) { +
    + +
    + } @else {
    -
    + }
    diff --git a/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.ts b/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.ts index 6f87b1f1bf..f9c98dba88 100644 --- a/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.ts +++ b/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.ts @@ -1,21 +1,22 @@ -import {Component, Input, ViewChild, AfterViewInit} from '@angular/core'; -import {MatSort, Sort} from '@angular/material/sort'; -import {MatTableDataSource, MatTable} from '@angular/material/table'; +import {RequestOptions} from 'ngx-entity-service'; import { - Tutorial, - TutorialService, Campus, CampusService, - User, + Tutorial, + TutorialService, TutorialStream, TutorialStreamService, Unit, + User, } from 'src/app/api/models/doubtfire-model'; import {EntityFormComponent} from 'src/app/common/entity-form/entity-form.component'; -import {UntypedFormControl, Validators} from '@angular/forms'; -import {RequestOptions} from 'ngx-entity-service'; -import {AlertService} from 'src/app/common/services/alert.service'; import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {HttpErrorResponse} from '@angular/common/http'; +import {AfterViewInit, Component, Input, ViewChild} from '@angular/core'; +import {UntypedFormControl, Validators} from '@angular/forms'; +import {MatSort, Sort} from '@angular/material/sort'; +import {MatTable, MatTableDataSource} from '@angular/material/table'; @Component({ selector: 'df-unit-tutorials-list', @@ -27,7 +28,7 @@ export class UnitTutorialsListComponent extends EntityFormComponent implements AfterViewInit { - @ViewChild(MatTable, {static: true}) table: MatTable; + @ViewChild(MatTable, {static: true}) table: MatTable; @ViewChild(MatSort, {static: true}) sort: MatSort; @Input() stream: TutorialStream; @Input() unit: Unit; @@ -55,7 +56,7 @@ export class UnitTutorialsListComponent 'options', ]; tutorials: Tutorial[] = []; - dataSource = new MatTableDataSource(); + dataSource: MatTableDataSource = new MatTableDataSource(); private editingStream: boolean = false; @@ -120,7 +121,7 @@ export class UnitTutorialsListComponent this.editingStream = false; this.alerts.success('Stream updated successfully', 2000); }, - error: (error: any) => { + error: (error: HttpErrorResponse) => { this.alerts.error('Something went wrong - ' + JSON.stringify(error.error), 6000); }, }); @@ -146,7 +147,11 @@ export class UnitTutorialsListComponent // to the datasource private pushToTable(value: Tutorial | Tutorial[]) { if (!value) return; - value instanceof Array ? this.tutorials.push(...value) : this.tutorials.push(value); + if (value instanceof Array) { + this.tutorials.push(...value); + } else { + this.tutorials.push(value); + } this.renderTable(); } @@ -183,14 +188,14 @@ export class UnitTutorialsListComponent // tutorial. The function is bound to the compareFn attribute on the related // mat-selects. // See: https://angular.io/api/forms/SelectControlValueAccessor - compareSelection(aEntity: User | Campus | any, bEntity: User | Campus) { + compareSelection(aEntity: User | Campus | {user_id: number}, bEntity: User | Campus) { if (!aEntity || !bEntity) { return; } if (bEntity instanceof User) { - return aEntity.user_id === bEntity.id; + return 'user_id' in aEntity && aEntity.user_id === bEntity.id; } else { - return aEntity.id === bEntity.id; + return 'id' in aEntity && aEntity.id === bEntity.id; } } @@ -221,7 +226,7 @@ export class UnitTutorialsListComponent * Ensure that the unit is passed to the Tutorial entity when create it called. */ protected override optionsOnRequest( - kind: 'create' | 'update' | 'delete', + _kind: 'create' | 'update' | 'delete', ): RequestOptions { return { constructorParams: this.unit, diff --git a/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html b/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html index 752fb350e6..e56b409a73 100644 --- a/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html +++ b/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html @@ -4,16 +4,16 @@ } @empty {
    -
    +
    groups

    No Tutorials

    -

    +

    There are no tutorials yet. Create a tutorial stream to begin adding tutorials.

    } -
    +
    } -
    +
    @@ -164,10 +164,10 @@

    Mark portfolios

    Stats -
    +
    @for (bar of project.taskStats; track bar) {
    @if (bar.key === 'not_started') { - {{ bar.value }}% + {{ bar.value }}% } @if (bar.key === 'complete') { - {{ bar.value }}% + {{ bar.value }}% }
    } @@ -212,7 +212,7 @@

    Mark portfolios

    >
    No students foundNo students found
    diff --git a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts index 202acba79a..46e481e21a 100644 --- a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts +++ b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts @@ -1,3 +1,13 @@ +import {Project} from 'src/app/api/models/project'; +import {TaskStatusEnum} from 'src/app/api/models/task-status'; +import {Unit} from 'src/app/api/models/unit'; +import {TaskService} from 'src/app/api/services/task.service'; +import {UnitService} from 'src/app/api/services/unit.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {GradeService} from 'src/app/common/services/grade.service'; import { AfterViewInit, Component, @@ -11,36 +21,26 @@ import {MatButtonToggleChange} from '@angular/material/button-toggle'; import {MatPaginator} from '@angular/material/paginator'; import {MatSort, Sort} from '@angular/material/sort'; import {MatTableDataSource} from '@angular/material/table'; -import {Project} from 'src/app/api/models/project'; -import {TaskStatusEnum} from 'src/app/api/models/task-status'; -import {Unit} from 'src/app/api/models/unit'; -import {TaskService} from 'src/app/api/services/task.service'; -import {UnitService} from 'src/app/api/services/unit.service'; -import {UserService} from 'src/app/api/services/user.service'; -import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; -import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; -import {AlertService} from 'src/app/common/services/alert.service'; -import {GradeService} from 'src/app/common/services/grade.service'; import {D2lTransferModal} from '../../d2l-transfer-modal/d2l-transfer.component'; @Component({ - selector: 'f-portfolios-list', - templateUrl: './portfolios-list.component.html', - styleUrl: './portfolios-list.component.scss', - standalone: false + selector: 'f-portfolios-list', + templateUrl: './portfolios-list.component.html', + styleUrl: './portfolios-list.component.scss', + standalone: false, }) export class PortfoliosListComponent implements OnInit, AfterViewInit { @Input() unit: Unit; @Output() - public studentSelected = new EventEmitter(); + public studentSelected: EventEmitter = new EventEmitter(); displayedColumns: string[] = []; @ViewChild(MatPaginator) paginator!: MatPaginator; @ViewChild(MatSort) sort: MatSort; - dataSource = new MatTableDataSource([]); + dataSource: MatTableDataSource = new MatTableDataSource([]); public portfolioFilter: 'all' | 'submitted_only' = 'submitted_only'; public tutorialFilter: 'all' | 'mine' = 'all'; diff --git a/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.html b/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.html index c885e73b1f..abe9bf9a51 100644 --- a/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.html +++ b/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.html @@ -3,10 +3,10 @@

    Review portfolio of {{ project.student.name }}

    View or download portfolio for assessment.

    @if (project.portfolioAvailable) { - + } @else { -
    +
    menu_book

    No Portfolio Submitted

    diff --git a/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.ts b/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.ts index 3a1a59d153..d05528d57d 100644 --- a/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.ts +++ b/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.ts @@ -1,11 +1,11 @@ -import {Component, Input} from '@angular/core'; import {Project} from 'src/app/api/models/project'; +import {Component, Input} from '@angular/core'; @Component({ - selector: 'f-portfolios-portfolio-view', - templateUrl: './portfolios-portfolio-view.component.html', - styleUrl: './portfolios-portfolio-view.component.scss', - standalone: false + selector: 'f-portfolios-portfolio-view', + templateUrl: './portfolios-portfolio-view.component.html', + styleUrl: './portfolios-portfolio-view.component.scss', + standalone: false, }) export class PortfoliosPortfolioViewComponent { @Input() project: Project; diff --git a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html index da4eacf5a9..cdbdb593de 100644 --- a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html +++ b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html @@ -1,15 +1,15 @@

    Review progress of {{ project.student.name }}

    Review the students progress through the unit's tasks.

    -
    -
    +
    +
    Target Grade -
    -
    +
    +
    @for (grade of gradeValues; track grade) { Review progress of {{ project.student.name }}

    Submitted Grade -
    -
    +
    +
    Review progress of {{ project.student.name }} > -
    +
    Task Summary Chart @@ -82,7 +82,7 @@

    Review progress of {{ project.student.name }}

    Burndown Chart
    -
    +
    {{ project.student.name }} has completed {{ taskStats.numberOfTasksCompleted }} tasks and have {{ taskStats.numberOfTasksRemaining }} left to complete to achieve their target of a diff --git a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts index f3583509b6..bb8234ce2b 100644 --- a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts +++ b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts @@ -1,16 +1,16 @@ -import {Component, Input} from '@angular/core'; import {Project} from 'src/app/api/models/project'; import {Unit} from 'src/app/api/models/unit'; import {ProjectService} from 'src/app/api/services/project.service'; import {TaskService} from 'src/app/api/services/task.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {GradeService} from 'src/app/common/services/grade.service'; +import {Component, Input} from '@angular/core'; @Component({ - selector: 'f-portfolios-project-progress', - templateUrl: './portfolios-project-progress.component.html', - styleUrl: './portfolios-project-progress.component.scss', - standalone: false + selector: 'f-portfolios-project-progress', + templateUrl: './portfolios-project-progress.component.html', + styleUrl: './portfolios-project-progress.component.scss', + standalone: false, }) export class PortfoliosProjectProgressComponent { @Input() project: Project; diff --git a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts index ec143203e6..b0033d1785 100644 --- a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts +++ b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts @@ -1,12 +1,12 @@ -import {Component, Input, OnInit} from '@angular/core'; import {Unit} from 'src/app/api/models/unit'; import {AlertService} from 'src/app/common/services/alert.service'; +import {Component, Input, OnInit} from '@angular/core'; @Component({ - selector: 'f-download-staff-notes', - templateUrl: 'download-staff-notes.component.html', - styleUrl: 'download-staff-notes.component.scss', - standalone: false + selector: 'f-download-staff-notes', + templateUrl: 'download-staff-notes.component.html', + styleUrl: 'download-staff-notes.component.scss', + standalone: false, }) export class DownloadStaffNotesComponent implements OnInit { @Input() unit: Unit; diff --git a/src/app/units/states/portfolios/portfolios.component.html b/src/app/units/states/portfolios/portfolios.component.html index 29dcd42573..a4a05762a3 100644 --- a/src/app/units/states/portfolios/portfolios.component.html +++ b/src/app/units/states/portfolios/portfolios.component.html @@ -1,4 +1,4 @@ -
    +

    Student Portfolios

    @if (unit) { diff --git a/src/app/units/states/portfolios/portfolios.component.ts b/src/app/units/states/portfolios/portfolios.component.ts index 6b8bfc454c..398463d779 100644 --- a/src/app/units/states/portfolios/portfolios.component.ts +++ b/src/app/units/states/portfolios/portfolios.component.ts @@ -1,17 +1,17 @@ -import {Component, Input, OnInit, ViewChild} from '@angular/core'; -import {MatTabGroup} from '@angular/material/tabs'; -import {ActivatedRoute, Router} from '@angular/router'; import {Observable, first, of} from 'rxjs'; import {Project} from 'src/app/api/models/project'; import {Unit} from 'src/app/api/models/unit'; import {ProjectService} from 'src/app/api/services/project.service'; import {AlertService} from 'src/app/common/services/alert.service'; +import {Component, Input, OnInit, ViewChild} from '@angular/core'; +import {MatTabGroup} from '@angular/material/tabs'; +import {ActivatedRoute, Router} from '@angular/router'; @Component({ - selector: 'f-portfolios', - templateUrl: './portfolios.component.html', - styleUrl: './portfolios.component.scss', - standalone: false + selector: 'f-portfolios', + templateUrl: './portfolios.component.html', + styleUrl: './portfolios.component.scss', + standalone: false, }) export class PortfoliosComponent implements OnInit { @Input() unit$: Observable; diff --git a/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts b/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts index 5665cda90e..500440b850 100644 --- a/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts +++ b/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts @@ -1,16 +1,16 @@ -import {Component, Input, OnInit} from '@angular/core'; import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; import {Unit} from 'src/app/api/models/unit'; import {CsvResultModalService} from 'src/app/common/modals/csv-result-modal/csv-result-modal.service'; import {CsvUploadModalService} from 'src/app/common/modals/csv-upload-modal/csv-upload-modal.service'; import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; +import {Component, Input, OnInit} from '@angular/core'; @Component({ - selector: 'f-upload-grades', - templateUrl: 'upload-grades.component.html', - styleUrl: 'upload-grades.component.scss', - standalone: false + selector: 'f-upload-grades', + templateUrl: 'upload-grades.component.html', + styleUrl: 'upload-grades.component.scss', + standalone: false, }) export class UploadGradesComponent implements OnInit { @Input() unit: Unit; diff --git a/src/app/units/states/rollover/rollover.component.html b/src/app/units/states/rollover/rollover.component.html index 323cc3e9b1..1f55d654a7 100644 --- a/src/app/units/states/rollover/rollover.component.html +++ b/src/app/units/states/rollover/rollover.component.html @@ -1,5 +1,5 @@ -
    - +
    + Copy {{ unit?.code }} {{ unit?.nameAndPeriod }} diff --git a/src/app/units/states/rollover/rollover.component.ts b/src/app/units/states/rollover/rollover.component.ts index bd2d7efbd2..ceaa70b338 100644 --- a/src/app/units/states/rollover/rollover.component.ts +++ b/src/app/units/states/rollover/rollover.component.ts @@ -1,17 +1,17 @@ -import {Component, Input, OnInit} from '@angular/core'; -import {ActivatedRoute, Router} from '@angular/router'; import {TeachingPeriod} from 'src/app/api/models/teaching-period'; import {Unit} from 'src/app/api/models/unit'; import {TeachingPeriodService} from 'src/app/api/services/teaching-period.service'; import {UnitService} from 'src/app/api/services/unit.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global-state.service'; +import {Component, Input, OnInit} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; @Component({ - selector: 'f-rollover', - templateUrl: './rollover.component.html', - styleUrl: './rollover.component.scss', - standalone: false + selector: 'f-rollover', + templateUrl: './rollover.component.html', + styleUrl: './rollover.component.scss', + standalone: false, }) export class RolloverComponent implements OnInit { @Input() unitId: number; diff --git a/src/app/units/states/students-list/students-list.component.html b/src/app/units/states/students-list/students-list.component.html index e39309b75a..70d1d02aa5 100644 --- a/src/app/units/states/students-list/students-list.component.html +++ b/src/app/units/states/students-list/students-list.component.html @@ -1,4 +1,4 @@ -
    +

    Students

    @@ -21,7 +21,7 @@

    Students

    -
    +
    Students
    Stats -
    +
    @for (bar of project.taskStats; track bar.key) {
    +
    @if (task) {
    {{ task.project.staffNoteCount }} diff --git a/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.ts b/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.ts index 9c91ae71ee..38f63cfb46 100644 --- a/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.ts +++ b/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.ts @@ -1,9 +1,9 @@ -import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core'; -import {MatTabChangeEvent} from '@angular/material/tabs'; import {UnitRole} from 'src/app/api/models/doubtfire-model'; import {Task} from 'src/app/api/models/task'; import {UserService} from 'src/app/api/services/user.service'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core'; +import {MatTabChangeEvent} from '@angular/material/tabs'; enum InboxDashboardTab { submission = 0, @@ -22,7 +22,7 @@ enum InboxDashboardTab { }) export class InboxDashboardComponent implements OnChanges { @Input() task: Task; - @Output() visiblePdfUrlChange = new EventEmitter(); + @Output() visiblePdfUrlChange: EventEmitter = new EventEmitter(); public readonly InboxDashboardTab = InboxDashboardTab; public currentTab: InboxDashboardTab = InboxDashboardTab.submission; diff --git a/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.ts b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.ts index 22080d4703..94844b10bc 100644 --- a/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.ts +++ b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.ts @@ -1,16 +1,16 @@ -import {Component, Inject, OnInit} from '@angular/core'; -import {ConfirmModerationModalData} from './confirm-moderation-modal.service'; -import {MatDialogRef, MAT_DIALOG_DATA} from '@angular/material/dialog'; -import {TaskService} from 'src/app/api/services/task.service'; -import {AlertService} from 'src/app/common/services/alert.service'; import {FeedbackModerationActionType} from 'src/app/api/models/task'; import {Task} from 'src/app/api/models/task'; +import {TaskService} from 'src/app/api/services/task.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {ConfirmModerationModalData} from './confirm-moderation-modal.service'; @Component({ - selector: 'f-confirm-moderation-modal', - templateUrl: './confirm-moderation-modal.component.html', - styleUrl: './confirm-moderation-modal.component.scss', - standalone: false + selector: 'f-confirm-moderation-modal', + templateUrl: './confirm-moderation-modal.component.html', + styleUrl: './confirm-moderation-modal.component.scss', + standalone: false, }) export class ConfirmModerationModalComponent implements OnInit { task: Task; diff --git a/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.service.ts b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.service.ts index bd271f321c..2fa14ab3ec 100644 --- a/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.service.ts +++ b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.service.ts @@ -1,8 +1,8 @@ +import {FeedbackModerationActionType} from 'src/app/api/models/task'; +import {Task} from 'src/app/api/models/task'; import {Injectable} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; -import {FeedbackModerationActionType} from 'src/app/api/models/task'; import {ConfirmModerationModalComponent} from './confirm-moderation-modal.component'; -import {Task} from 'src/app/api/models/task'; export interface ConfirmModerationModalData { task: Task; diff --git a/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.html b/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.html index 29ed5137c1..ae11125495 100644 --- a/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.html +++ b/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.html @@ -1,5 +1,5 @@ - + @if (task.moderationType === 'random_sample' || task.moderationType === 'first_feedback') { @@ -22,7 +22,7 @@
    @if (collapsable) {
    -
    +
    Tutors @if (filteredTasks.length) { -
    {{ filteredTasks.length }} Tasks
    +
    {{ filteredTasks.length }} Tasks
    } -
    +

    @if (task.moderationType === 'escalation') { ; + @ViewChild('searchDialog') searchDialog: TemplateRef; @Input() task: Task; @Input() project: Project; @@ -71,7 +68,7 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { tutorials: Tutorial[]; forceStream: boolean; studentName: string; - tutorialIdSelected: any; + tutorialIdSelected: string | number; unitRoleIdSelected: number | string; taskDefinitionIdSelected: number | TaskDefinition; }>; @@ -101,7 +98,7 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { // hasJplagReport: boolean = false; - watchingTaskKey: any; + watchingTaskKey: boolean; panelOpenState = false; loading = true; @@ -123,7 +120,7 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { taskDefSort = 0; tutorialSort = 0; - originalFilteredTasks: any[] = null; + originalFilteredTasks: Task[] = null; allowHover = true; // Track if all tasks have already been fetched @@ -299,7 +296,7 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { this.sidekiqProgressModalService .show(`Downloading submission pdfs for ${taskDef.abbreviation}`, newJob.id) .subscribe({ - next: (job) => { + next: (_job) => { this.fileDownloaderService.downloadFile( `${AppInjector.get(DoubtfireConstants).API_URL}/submission/unit/${ this.unit.id @@ -322,7 +319,7 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { this.sidekiqProgressModalService .show(`Downloading submission files for ${taskDef.abbreviation}`, newJob.id) .subscribe({ - next: (job) => { + next: (_job) => { this.fileDownloaderService.downloadFile( `${AppInjector.get(DoubtfireConstants).API_URL}/submission/unit/${ this.unit.id @@ -405,7 +402,7 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { openDialog() { const dialogRef = this.dialog.open(this.searchDialog); - dialogRef.afterClosed().subscribe((result) => {}); + dialogRef.afterClosed().subscribe(); } refreshTasks(): void { @@ -452,9 +449,12 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { openTaskDefs() { // Automatically "open" the task definition select element if in task def mode - const selectEl: any = document.querySelector( + const selectEl = document.querySelector( 'select[ng-model="filters.taskDefinitionIdSelected"]', - ) as any; + ); + if (!selectEl) { + return; + } selectEl.size = 10; selectEl.focus(); } @@ -604,20 +604,20 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { } } - private scrollToTaskInList(task) { - const taskEl = document.querySelector(`#${task.taskKeyToIdString()}`) as any; + private scrollToTaskInList(task: Task) { + const taskEl = document.querySelector(`#${task.taskKeyToIdString()}`) as + | (HTMLElement & { + scrollIntoViewIfNeeded?: (options?: ScrollIntoViewOptions) => void; + }) + | null; if (!taskEl) { return; } - const funcName = taskEl.scrollIntoViewIfNeeded - ? 'scrollIntoViewIfNeeded' - : taskEl.scrollIntoView - ? 'scrollIntoView' - : ''; - if (!funcName) { - return; + if (taskEl.scrollIntoViewIfNeeded) { + taskEl.scrollIntoViewIfNeeded({behavior: 'smooth'}); + } else { + taskEl.scrollIntoView({behavior: 'smooth'}); } - taskEl[funcName]({behavior: 'smooth'}); } isSelectedTask(task: Task) { @@ -676,7 +676,11 @@ export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { return; } const refreshOrdering = () => this.applyFilters(); - task.pinned ? task.unpin(refreshOrdering) : task.pin(refreshOrdering); + if (task.pinned) { + task.unpin(refreshOrdering); + } else { + task.pin(refreshOrdering); + } } getWarningIcon(task: Task): 'warning' | 'overflow' | null { diff --git a/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.ts b/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.ts index 2b068096a4..574e38607c 100644 --- a/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.ts +++ b/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.ts @@ -1,16 +1,16 @@ -import {Component, Input} from '@angular/core'; -import {MatSnackBar} from '@angular/material/snack-bar'; import {Task} from 'src/app/api/models/task'; import {UnitRole} from 'src/app/api/models/unit-role'; import {TaskService} from 'src/app/api/services/task.service'; import {UserService} from 'src/app/api/services/user.service'; import {AlertService} from 'src/app/common/services/alert.service'; +import {Component, Input} from '@angular/core'; +import {MatSnackBar} from '@angular/material/snack-bar'; @Component({ - selector: 'f-task-claim', - templateUrl: './task-claim.component.html', - styleUrl: './task-claim.component.scss', - standalone: false + selector: 'f-task-claim', + templateUrl: './task-claim.component.html', + styleUrl: './task-claim.component.scss', + standalone: false, }) export class TaskClaimComponent { @Input() selectedTask: Task; diff --git a/src/app/units/states/tasks/inbox/inbox.component.html b/src/app/units/states/tasks/inbox/inbox.component.html index 1b29d83c9e..69d07a1205 100644 --- a/src/app/units/states/tasks/inbox/inbox.component.html +++ b/src/app/units/states/tasks/inbox/inbox.component.html @@ -32,7 +32,7 @@ diff --git a/src/app/units/states/tasks/inbox/inbox.component.scss b/src/app/units/states/tasks/inbox/inbox.component.scss index 0b0bc8df17..f8432b637f 100644 --- a/src/app/units/states/tasks/inbox/inbox.component.scss +++ b/src/app/units/states/tasks/inbox/inbox.component.scss @@ -1,42 +1,43 @@ -.staff-task-list {} +.staff-task-list { +} .task-comment-panel { - padding-left: 12px; - padding-bottom: 0px; + padding-left: 12px; + padding-bottom: 0px; - &.mobile { - padding-left: 0px; - padding-bottom: 0px; - margin-bottom: 10px; - } + &.mobile { + padding-left: 0px; + padding-bottom: 0px; + margin-bottom: 10px; + } } .resizer { - background-color: #f5f5f5; - z-index: 200; - width: 10px //css on hover + background-color: #f5f5f5; + z-index: 200; + width: 10px; //css on hover } .resizer:hover, .resizer.hovering { - cursor: col-resize; - background: linear-gradient(white, white) no-repeat center/2px 98%; + cursor: col-resize; + background: linear-gradient(white, white) no-repeat center/2px 98%; } .inbox-panel { - border-radius: 10px; - background-color: white; - padding: 8px; - min-width: 60px; - width: 350px; + border-radius: 10px; + background-color: white; + padding: 8px; + min-width: 60px; + width: 350px; - &.mobile { - max-width: 100%; - width: 100%; - padding: 0px; - } + &.mobile { + max-width: 100%; + width: 100%; + padding: 0px; + } } .task-comment-panel.inbox-panel { - // padding: 0px 0px 0px 5px !important; + // padding: 0px 0px 0px 5px !important; } diff --git a/src/app/units/states/tasks/inbox/inbox.component.spec.ts b/src/app/units/states/tasks/inbox/inbox.component.spec.ts index d90eb5cb30..9112a31a49 100644 --- a/src/app/units/states/tasks/inbox/inbox.component.spec.ts +++ b/src/app/units/states/tasks/inbox/inbox.component.spec.ts @@ -1,6 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { InboxComponent } from './inbox.component'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {InboxComponent} from './inbox.component'; describe('InboxComponent', () => { let component: InboxComponent; @@ -8,9 +7,8 @@ describe('InboxComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - declarations: [ InboxComponent ] - }) - .compileComponents(); + declarations: [InboxComponent], + }).compileComponents(); fixture = TestBed.createComponent(InboxComponent); component = fixture.componentInstance; diff --git a/src/app/units/states/tasks/inbox/inbox.component.ts b/src/app/units/states/tasks/inbox/inbox.component.ts index 1d0bd529d7..8ab1c89aa9 100644 --- a/src/app/units/states/tasks/inbox/inbox.component.ts +++ b/src/app/units/states/tasks/inbox/inbox.component.ts @@ -1,37 +1,37 @@ -import {CdkDragEnd, CdkDragStart, CdkDragMove} from '@angular/cdk/drag-drop'; -import {Component, ElementRef, Input, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {HotkeysHelpComponent, HotkeysService} from '@ngneat/hotkeys'; import {MediaObserver} from 'ng-flex-layout'; -import {auditTime, merge, Observable, of, Subject, tap, withLatestFrom} from 'rxjs'; +import {Observable, Subject, auditTime, merge, of, tap, withLatestFrom} from 'rxjs'; +import {Tutorial} from 'src/app/api/models/doubtfire-model'; import {Task} from 'src/app/api/models/task'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Unit} from 'src/app/api/models/unit'; import {UnitRole} from 'src/app/api/models/unit-role'; +import {UserService} from 'src/app/api/services/user.service'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {SelectedTaskService} from 'src/app/projects/states/dashboard/selected-task.service'; -import {HotkeysService, HotkeysHelpComponent} from '@ngneat/hotkeys'; +import {CdkDragEnd, CdkDragMove, CdkDragStart} from '@angular/cdk/drag-drop'; +import {Component, ElementRef, Input, OnDestroy, OnInit, ViewChild} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; -import {UserService} from 'src/app/api/services/user.service'; -import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; -import {Tutorial} from 'src/app/api/models/doubtfire-model'; -import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Router} from '@angular/router'; @Component({ - selector: 'f-inbox', - templateUrl: './inbox.component.html', - styleUrls: ['./inbox.component.scss'], - standalone: false + selector: 'f-inbox', + templateUrl: './inbox.component.html', + styleUrls: ['./inbox.component.scss'], + standalone: false, }) export class InboxComponent implements OnInit, OnDestroy { @Input() unit: Unit; @Input() unitRole: UnitRole; - @Input() taskData: {selectedTask: Task; any}; + @Input() taskData: {selectedTask: Task}; @Input() loading = false; @Input() filters: Partial<{ taskDefinition: TaskDefinition; tutorials: Tutorial[]; forceStream: boolean; studentName: string; - tutorialIdSelected: any; + tutorialIdSelected: string | number; taskDefinitionIdSelected: number | TaskDefinition; }>; @Input() showSearchOptions: boolean; @@ -42,8 +42,8 @@ export class InboxComponent implements OnInit, OnDestroy { subs$: Observable; - private inboxStartSize$ = new Subject(); - private dragMove$ = new Subject<{event: CdkDragMove; div: HTMLDivElement}>(); + private inboxStartSize$: Subject = new Subject(); + private dragMove$: Subject<{event: CdkDragMove; div: HTMLDivElement}> = new Subject(); private dragMoveAudited$; // protected filters; diff --git a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.html b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.html index fc283c02a6..066789a0b1 100644 --- a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.html +++ b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.html @@ -1,10 +1,10 @@ - + diff --git a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts index 7eaf74979d..67850ab1fe 100644 --- a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts +++ b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts @@ -1,5 +1,3 @@ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; -import {ActivatedRoute, Router} from '@angular/router'; import {Observable, first, of, tap} from 'rxjs'; import { ProjectService, @@ -12,8 +10,10 @@ import { } from 'src/app/api/models/doubtfire-model'; import {Task} from 'src/app/api/models/task'; import {TaskService} from 'src/app/api/services/task.service'; -import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global-state.service'; import {SelectedTaskService} from 'src/app/projects/states/dashboard/selected-task.service'; +import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global-state.service'; +import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ActivatedRoute, Router} from '@angular/router'; export type UnitTaskViewType = 'inbox' | 'explorer' | 'moderation' | 'overflow'; export type UnitTaskRouteMode = 'inbox' | 'definition' | 'moderation' | 'overflow'; @@ -46,7 +46,7 @@ type TaskSource = ( }) export class UnitTaskInboxStateComponent implements OnInit, OnDestroy { private static readonly UNIT_REFRESH_INTERVAL_MS = 60_000; - private static readonly lastUnitFetchAt = new Map(); + private static readonly lastUnitFetchAt: Map = new Map(); @Input() public unit$: Observable; @Input() public routeMode: UnitTaskRouteMode = 'inbox'; diff --git a/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.html b/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.html index 5ca7a38d06..61c3af38a0 100644 --- a/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.html +++ b/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.html @@ -1,4 +1,4 @@ -
    +
    - @switch (taskDef) { @case (taskDef) { @if (taskDef?.hasTaskSheet) { - - - - } @else { - -
    - subtitles_off No Task Sheet -
    - - } } } +
    + @switch (taskDef) { + @case (taskDef) { + @if (taskDef?.hasTaskSheet) { + + } @else { +
    + subtitles_off No Task Sheet +
    + } + } + } diff --git a/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.ts b/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.ts index 68df369f56..8c9460e9fd 100644 --- a/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.ts +++ b/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.ts @@ -1,13 +1,12 @@ -import { Component, Input, OnInit } from '@angular/core'; -import { TaskDefinition } from 'src/app/api/models/task-definition'; +import {TaskDefinition} from 'src/app/api/models/task-definition'; +import {Component, Input} from '@angular/core'; @Component({ - selector: 'f-task-sheet-view', - templateUrl: './task-sheet-view.component.html', - styleUrls: ['./task-sheet-view.component.scss'], - standalone: false + selector: 'f-task-sheet-view', + templateUrl: './task-sheet-view.component.html', + styleUrls: ['./task-sheet-view.component.scss'], + standalone: false, }) export class FTaskSheetViewComponent { @Input() taskDef: TaskDefinition; - } diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html index bd2daea1f6..3c473a0d1d 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html @@ -2,7 +2,7 @@
    -
    @@ -20,11 +20,11 @@
    -
    +
    @for (taskDef of filteredTaskDefinitions; track taskDef) { @if (taskDef) { -
    -
    -
    +
    +
    +
    {{ taskDef.name }}
    -
    +
    @if (taskDef.isGroupTask()) { - groups + groups } @else { - person + person } -
    +
    {{ taskDef.abbreviation }} - {{ gradeNames[taskDef.targetGrade] }} Task @@ -84,7 +84,7 @@
    @if (taskListItem(taskDef); as task) { -
    +
    @if (task.numNewComments > 0) { {{ task.numNewComments }} } @if (task.similaritiesDetected) { - visibility @@ -119,20 +119,20 @@ } @if (task.hasQualityPoints()) { - {{ task.qualityPts }} + {{ task.qualityPts }} - {{ + {{ task.definition.maxQualityPts }} } @if (task.isDueSoon() && !task.inFinalState()) { - schedule @@ -143,21 +143,21 @@ !task.inFinalState() ) { - schedule } @if (task.isPastDeadline() && !task.inFinalState()) { - schedule - ! + ! }
    @@ -167,12 +167,12 @@ } } @empty { -
    No tasks to display
    +
    No tasks to display
    } @if (mode === 'project' && project) { diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.spec.ts b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.spec.ts index 3ac584b5e7..09f4be518b 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.spec.ts +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.spec.ts @@ -1,6 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; - -import { FUnitTaskListComponent } from './unit-task-list.component'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {FUnitTaskListComponent} from './unit-task-list.component'; describe('FUnitTaskListComponent', () => { let component: FUnitTaskListComponent; diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts index 98b76d1036..f52eff58e5 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts @@ -1,16 +1,16 @@ +import {BehaviorSubject} from 'rxjs'; +import {Project, Task, TaskDefinition} from 'src/app/api/models/doubtfire-model'; +import {Grade} from 'src/app/api/models/grade'; +import {TaskDefinitionNamePipe} from 'src/app/common/filters/task-definition-name.pipe'; import {Location} from '@angular/common'; import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; -import {Grade} from 'src/app/api/models/grade'; -import {Project, TaskDefinition, Task} from 'src/app/api/models/doubtfire-model'; -import {TaskDefinitionNamePipe} from 'src/app/common/filters/task-definition-name.pipe'; -import {BehaviorSubject} from 'rxjs'; @Component({ - selector: 'f-unit-task-list', - templateUrl: './unit-task-list.component.html', - styleUrls: ['./unit-task-list.component.scss'], - standalone: false + selector: 'f-unit-task-list', + templateUrl: './unit-task-list.component.html', + styleUrls: ['./unit-task-list.component.scss'], + standalone: false, }) export class FUnitTaskListComponent implements OnChanges, OnInit { @Input() mode: 'project' | 'all-tasks'; @@ -152,9 +152,7 @@ export class FUnitTaskListComponent implements OnChanges, OnInit { const unitId = this.route.parent?.snapshot.paramMap.get('unitId'); if (this.route.parent?.snapshot.data.unit && unitId) { return this.angularRouter.createUrlTree( - taskDef - ? ['/units', unitId, 'tasks', taskDef.abbreviation] - : ['/units', unitId, 'tasks'], + taskDef ? ['/units', unitId, 'tasks', taskDef.abbreviation] : ['/units', unitId, 'tasks'], ); } diff --git a/src/app/units/task-viewer/task-viewer-state.component.html b/src/app/units/task-viewer/task-viewer-state.component.html index 3b54723add..ed0f00290b 100644 --- a/src/app/units/task-viewer/task-viewer-state.component.html +++ b/src/app/units/task-viewer/task-viewer-state.component.html @@ -13,9 +13,9 @@
    -
    +
    @if (selectedTaskDefinition$ | async; as selectedTaskDef) { -
    +
    ; @@ -30,9 +30,9 @@ export class TaskViewerStateComponent { } /** - * Monitor and publish the selected task definition for child components. - * We monitor the task definition list for changes in selected task definition. - */ + * Monitor and publish the selected task definition for child components. + * We monitor the task definition list for changes in selected task definition. + */ selectedTaskDefinition$: BehaviorSubject = new BehaviorSubject( null, ); diff --git a/src/app/units/unit-root-state.component.html b/src/app/units/unit-root-state.component.html index 44c6a074e3..c3d939bb5b 100644 --- a/src/app/units/unit-root-state.component.html +++ b/src/app/units/unit-root-state.component.html @@ -2,7 +2,7 @@ } @else {

    Loading unit details...

    diff --git a/src/app/units/unit-root-state.component.ts b/src/app/units/unit-root-state.component.ts index 087b7a7ae4..bdd56dd07d 100644 --- a/src/app/units/unit-root-state.component.ts +++ b/src/app/units/unit-root-state.component.ts @@ -1,14 +1,14 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import {Component, Input, OnInit} from '@angular/core'; -import {ActivatedRoute} from '@angular/router'; import {Observable} from 'rxjs'; import {Unit} from 'src/app/api/models/doubtfire-model'; +import {Component, Input, OnInit} from '@angular/core'; +import {ActivatedRoute} from '@angular/router'; @Component({ - selector: 'f-unit-root-state', - templateUrl: './unit-root-state.component.html', - styleUrl: './unit-root-state.component.css', - standalone: false + selector: 'f-unit-root-state', + templateUrl: './unit-root-state.component.html', + styleUrl: './unit-root-state.component.css', + standalone: false, }) export class UnitRootStateComponent implements OnInit { @Input() public unit$: Observable; diff --git a/src/app/units/unit.resolver.ts b/src/app/units/unit.resolver.ts index 181cafe4fa..a6b42b5ec0 100644 --- a/src/app/units/unit.resolver.ts +++ b/src/app/units/unit.resolver.ts @@ -1,9 +1,9 @@ -import {inject} from '@angular/core'; -import {ResolveFn} from '@angular/router'; import {Observable, first} from 'rxjs'; import {Unit, UnitRole, UnitService, UserService} from 'src/app/api/models/doubtfire-model'; import {AlertService} from 'src/app/common/services/alert.service'; import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global-state.service'; +import {inject} from '@angular/core'; +import {ResolveFn} from '@angular/router'; export const resolveUnit: ResolveFn = (route, state) => { const unitService = inject(UnitService); diff --git a/src/app/visualisations/progress-burndown-chart.scss b/src/app/visualisations/progress-burndown-chart.scss index a3f5591bae..b18611e1f0 100644 --- a/src/app/visualisations/progress-burndown-chart.scss +++ b/src/app/visualisations/progress-burndown-chart.scss @@ -1,13 +1,17 @@ progress-burndown-chart { // Dashed for time line .dashed { - stroke-dasharray: 5,5; + stroke-dasharray: 5, 5; } // :last-child applies to hide time line from legend .nv-legendWrap .nv-series:last-child { display: none; } // since we're hiding time line we can move the rest right - .nv-legend{ transform: translate(50px, -15px); } - .nv-legendWrap{ transform: translate(50px, -15px); } + .nv-legend { + transform: translate(50px, -15px); + } + .nv-legendWrap { + transform: translate(50px, -15px); + } } diff --git a/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html index 25726a1383..15ed9a8795 100644 --- a/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html +++ b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html @@ -1,6 +1,6 @@ -
    +
    = {}; constructor(public viewContainerRef: ViewContainerRef) { super(viewContainerRef); @@ -100,7 +121,7 @@ export class ProgressBurndownChartComponent extends ChartBaseComponent implement this.data = formattedData; } - onSelect(event): void { + onSelect(event: string | BurndownPoint): void { if (this.isLegend(event)) { const tempData = JSON.parse(JSON.stringify(this.data)); if (this.isDataShown(event)) { @@ -120,7 +141,7 @@ export class ProgressBurndownChartComponent extends ChartBaseComponent implement } } - isLegend(event: any): boolean { + isLegend(event: string | BurndownPoint): event is string { return typeof event === 'string'; } @@ -129,7 +150,7 @@ export class ProgressBurndownChartComponent extends ChartBaseComponent implement return series && series.series.some((point) => point.value !== 0); } - public formatPerc(input) { + public formatPerc(input: number) { return `${input}%`; } } diff --git a/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.ts b/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.ts index 9b53ff2a30..b7131a9c9a 100644 --- a/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.ts +++ b/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.ts @@ -1,14 +1,14 @@ -import {Component, OnInit, Input, SimpleChanges} from '@angular/core'; import {Project, TaskStatus} from 'src/app/api/models/doubtfire-model'; import {ChartBaseComponent} from 'src/app/common/chart-base/chart-base-component/chart-base-component.component'; +import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; @Component({ - selector: 'f-task-status-pie-chart', - templateUrl: './task-status-pie-chart.component.html', - styleUrls: ['./task-status-pie-chart.component.scss'], - standalone: false + selector: 'f-task-status-pie-chart', + templateUrl: './task-status-pie-chart.component.html', + styleUrls: ['./task-status-pie-chart.component.scss'], + standalone: false, }) -export class TaskStatusPieChartComponent extends ChartBaseComponent implements OnInit { +export class TaskStatusPieChartComponent extends ChartBaseComponent implements OnChanges, OnInit { @Input() project: Project; @Input() grade: number; diff --git a/src/app/visualisations/task-visualisation/task-visualisation.component.ts b/src/app/visualisations/task-visualisation/task-visualisation.component.ts index 49327c71ff..98948da80d 100644 --- a/src/app/visualisations/task-visualisation/task-visualisation.component.ts +++ b/src/app/visualisations/task-visualisation/task-visualisation.component.ts @@ -1,13 +1,13 @@ -import {Component, OnInit, Input, SimpleChanges} from '@angular/core'; -import {Color} from 'd3'; -import {Project, TaskStatus, TaskStatusEnum} from 'src/app/api/models/doubtfire-model'; +import {Project, TaskStatus} from 'src/app/api/models/doubtfire-model'; +import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; + @Component({ - selector: 'f-task-visualisation', - templateUrl: './task-visualisation.component.html', - styleUrls: ['./task-visualisation.component.scss'], - standalone: false + selector: 'f-task-visualisation', + templateUrl: './task-visualisation.component.html', + styleUrls: ['./task-visualisation.component.scss'], + standalone: false, }) -export class TaskVisualisationComponent implements OnInit { +export class TaskVisualisationComponent implements OnChanges, OnInit { @Input() project: Project; @Input() grade: number; diff --git a/src/app/welcome/welcome.component.html b/src/app/welcome/welcome.component.html index 8d3222ed0d..427ebdb6e2 100644 --- a/src/app/welcome/welcome.component.html +++ b/src/app/welcome/welcome.component.html @@ -2,9 +2,15 @@
    -
    +
    -
    +
    Homepage Logo

    {{ externalName.value }}

    diff --git a/src/app/welcome/welcome.component.spec.ts b/src/app/welcome/welcome.component.spec.ts index 59c1c8d8ef..8c834e5b2b 100644 --- a/src/app/welcome/welcome.component.spec.ts +++ b/src/app/welcome/welcome.component.spec.ts @@ -1,5 +1,5 @@ -import { ComponentFixture, TestBed } from '@angular/core/testing'; -import { WelcomeComponent } from './welcome.component'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {WelcomeComponent} from './welcome.component'; describe('WelcomeComponent', () => { let component: WelcomeComponent; diff --git a/src/app/welcome/welcome.component.ts b/src/app/welcome/welcome.component.ts index 3509c456b6..994da25ff3 100644 --- a/src/app/welcome/welcome.component.ts +++ b/src/app/welcome/welcome.component.ts @@ -1,9 +1,9 @@ -import {Component, OnInit} from '@angular/core'; -import {Router} from '@angular/router'; import {AuthenticationService} from 'src/app/api/services/authentication.service'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; -import {GlobalStateService} from '../projects/states/index/global-state.service'; +import {Component, OnInit} from '@angular/core'; +import {Router} from '@angular/router'; import {UserService} from '../api/services/user.service'; +import {GlobalStateService} from '../projects/states/index/global-state.service'; @Component({ selector: 'f-welcome', diff --git a/src/assets/images/formatif-isolated-lottie.json b/src/assets/images/formatif-isolated-lottie.json index f934cfb0a7..9b32225328 100644 --- a/src/assets/images/formatif-isolated-lottie.json +++ b/src/assets/images/formatif-isolated-lottie.json @@ -1 +1,3019 @@ -{"v":"4.8.0","meta":{"g":"LottieFiles AE 3.4.3","a":"","k":"","d":"","tc":""},"fr":24,"ip":0,"op":92,"w":3840,"h":2160,"nm":"icon - isolated","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"NULL","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1920,1080,0],"ix":2},"a":{"a":0,"k":[50,50,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":33,"s":[100,100,100]},{"t":59,"s":[165,165,100]}],"ix":6}},"ao":0,"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"main position","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.167,"y":0.167},"t":36,"s":[50,50,0],"to":[0,0,0],"ti":[0,0,0]},{"t":54,"s":[464,50,0]}],"ix":2},"a":{"a":0,"k":[50,50,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":0,"op":240,"st":0,"bm":0},{"ddd":0,"ind":3,"ty":3,"nm":"scale","parent":2,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[50,50,0],"ix":2},"a":{"a":0,"k":[50,50,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":23,"s":[200,200,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":35,"s":[118,118,100]},{"i":{"x":[0.667,0.667,0.667],"y":[1,1,1]},"o":{"x":[0.333,0.333,0.333],"y":[0,0,0]},"t":38,"s":[90,90,100]},{"t":49,"s":[100,100,100]}],"ix":6}},"ao":0,"ip":23,"op":240,"st":0,"bm":0},{"ddd":0,"ind":4,"ty":3,"nm":"arrow position","parent":3,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.107,"y":1},"o":{"x":0.533,"y":0},"t":23,"s":[50,-8,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.19,"y":0.642},"o":{"x":0.333,"y":0},"t":35,"s":[119.897,36,0],"to":[0,0,0],"ti":[392.376,75.374,0]},{"i":{"x":0.833,"y":0.874},"o":{"x":1,"y":0.713},"t":38,"s":[-307.61,-289.928,0],"to":[-832.969,-114.56,0],"ti":[20.667,921.704,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.115,"y":1},"t":49,"s":[-374,-134,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.538,"y":1},"o":{"x":1,"y":0},"t":53,"s":[-374,-175,0],"to":[0,0,0],"ti":[1.605,-28.883,0]},{"i":{"x":0.538,"y":1},"o":{"x":0.167,"y":0},"t":59,"s":[-374,37,0],"to":[0,0,0],"ti":[1.605,-28.883,0]},{"t":65,"s":[-374,-8,0]}],"ix":2},"a":{"a":0,"k":[50,50,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":23,"op":243,"st":3,"bm":0},{"ddd":0,"ind":5,"ty":3,"nm":"rotation","parent":4,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.303],"y":[0]},"t":23,"s":[-45]},{"i":{"x":[0.773],"y":[0.886]},"o":{"x":[0.333],"y":[0]},"t":35,"s":[-45]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.06]},"t":38,"s":[-71]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.089]},"t":42,"s":[-118.941]},{"i":{"x":[0.667],"y":[1]},"o":{"x":[0.167],"y":[0.087]},"t":45,"s":[-186.591]},{"t":49,"s":[-360]}],"ix":10},"p":{"a":0,"k":[18.883,127.949,0],"ix":2},"a":{"a":0,"k":[50,50,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ip":23,"op":243,"st":3,"bm":0},{"ddd":0,"ind":6,"ty":3,"nm":"rough edges","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1920,1080,0],"ix":2},"a":{"a":0,"k":[1920,1080,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Roughen Edges","np":17,"mn":"ADBE Roughen Edges","ix":1,"en":1,"ef":[{"ty":7,"nm":"Edge Type","mn":"ADBE Roughen Edges-0001","ix":1,"v":{"a":0,"k":1,"ix":1}},{"ty":2,"nm":"Edge Color","mn":"ADBE Roughen Edges-0010","ix":2,"v":{"a":0,"k":[0.6,0.2,0,1],"ix":2}},{"ty":0,"nm":"Border","mn":"ADBE Roughen Edges-0002","ix":3,"v":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[17.4]},{"t":19,"s":[2.7]}],"ix":3}},{"ty":0,"nm":"Edge Sharpness","mn":"ADBE Roughen Edges-0003","ix":4,"v":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":12,"s":[1]},{"t":19,"s":[0.1]}],"ix":4}},{"ty":0,"nm":"Fractal Influence","mn":"ADBE Roughen Edges-0004","ix":5,"v":{"a":0,"k":1,"ix":5}},{"ty":0,"nm":"Scale","mn":"ADBE Roughen Edges-0005","ix":6,"v":{"a":0,"k":1000,"ix":6}},{"ty":0,"nm":"Stretch Width or Height","mn":"ADBE Roughen Edges-0006","ix":7,"v":{"a":0,"k":0,"ix":7}},{"ty":3,"nm":"Offset (Turbulence)","mn":"ADBE Roughen Edges-0007","ix":8,"v":{"a":0,"k":[0,0],"ix":8}},{"ty":0,"nm":"Complexity","mn":"ADBE Roughen Edges-0008","ix":9,"v":{"a":0,"k":2,"ix":9}},{"ty":0,"nm":"Evolution","mn":"ADBE Roughen Edges-0009","ix":10,"v":{"a":0,"k":0,"ix":10}},{"ty":6,"nm":"Evolution Options","mn":"ADBE Roughen Edges-0011","ix":11,"v":0},{"ty":7,"nm":"Cycle Evolution","mn":"ADBE Roughen Edges-0012","ix":12,"v":{"a":0,"k":0,"ix":12}},{"ty":0,"nm":"Cycle (in Revolutions)","mn":"ADBE Roughen Edges-0013","ix":13,"v":{"a":0,"k":1,"ix":13}},{"ty":0,"nm":"Random Seed","mn":"ADBE Roughen Edges-0014","ix":14,"v":{"a":0,"k":0,"ix":14}},{"ty":6,"nm":"Random Seed","mn":"ADBE Roughen Edges-0015","ix":15,"v":0}]}],"ip":0,"op":19,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"echo","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[1920,1080,0],"ix":2},"a":{"a":0,"k":[1920,1080,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"Echo","np":7,"mn":"ADBE Echo","ix":1,"en":1,"ef":[{"ty":0,"nm":"Echo Time (seconds)","mn":"ADBE Echo-0001","ix":1,"v":{"a":0,"k":-0.001,"ix":1}},{"ty":0,"nm":"Number Of Echoes","mn":"ADBE Echo-0002","ix":2,"v":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":31,"s":[10]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":34,"s":[67]},{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":49,"s":[67]},{"t":53,"s":[10]}],"ix":2}},{"ty":0,"nm":"Starting Intensity","mn":"ADBE Echo-0003","ix":3,"v":{"a":0,"k":1,"ix":3}},{"ty":0,"nm":"Decay","mn":"ADBE Echo-0004","ix":4,"v":{"a":0,"k":1,"ix":4}},{"ty":7,"nm":"Echo Operator","mn":"ADBE Echo-0005","ix":5,"v":{"a":0,"k":5,"ix":5}}]}],"ip":31,"op":53,"st":3,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"top 2","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[73.565,-23.785,0],"ix":2},"a":{"a":0,"k":[1488.448,1026.164,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"ShapeNir Slider","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":100,"ix":1}}]}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.17,"y":1},"o":{"x":0.167,"y":0},"t":58,"s":[{"i":[[0,0],[0,0],[-13.503,-13.506],[0,0],[9.065,-9.068],[0,0],[0,0],[9.068,9.071],[0,0],[0,0]],"o":[[0,0],[13.506,-13.506],[0,0],[9.065,9.068],[0,0],[0,0],[-9.068,9.074],[0,0],[0,0],[0,0]],"v":[[-61.716,-44.574],[-57.525,-48.766],[-21.582,-61.577],[-24.345,-64.482],[-24.342,-31.648],[-24.342,-31.648],[-24.342,-31.648],[-57.186,-31.645],[-65.907,-40.383],[-61.716,-44.574]],"c":false}]},{"t":64,"s":[{"i":[[0,0],[0,0],[-13.503,-13.506],[0,0],[9.065,-9.068],[0,0],[0,0],[9.068,9.071],[0,0],[0,0]],"o":[[0,0],[13.506,-13.506],[0,0],[9.065,9.068],[0,0],[0,0],[-9.068,9.074],[0,0],[0,0],[0,0]],"v":[[-74.672,-57.386],[-70.481,-61.577],[-21.582,-61.577],[72.063,32.066],[72.066,64.9],[72.066,64.9],[72.066,64.9],[39.223,64.903],[-78.863,-53.195],[-74.672,-57.386]],"c":false}]}],"ix":2},"nm":"Tracciato 1_forAnimation","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.211764708161,0.568627476692,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Riempimento 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1542.448,1082.164],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Gruppo 3","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1,"x":"var $bm_rt;\nvar mN01 = 52.2496645130989;\nvar mN02 = 100;\nvar mN01Edt = 52.2496645130989;\nvar mN02Edt = 98.6485408913042;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosF = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosF[$bm_sub(i, 1)], mRatiosF[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;"},"e":{"a":0,"k":100,"ix":2,"x":"var $bm_rt;\nvar mN01 = 52.2496645130989;\nvar mN02 = 0;\nvar mN01Edt = 52.2496645130989;\nvar mN02Edt = 1.35145910869578;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosL = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosL[$bm_sub(i, 1)], mRatiosL[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;"},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Taglia tracciati 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":1,"k":[{"i":{"x":0.17,"y":1},"o":{"x":0.167,"y":0},"t":58,"s":[{"i":[[0,0],[5.418,5.419],[17.468,17.469],[25.537,-25.537]],"o":[[-3.662,6.731],[0,0],[-25.536,-25.537],[0,0]],"v":[[1518.105,1050.515],[1501.682,1034.099],[1545.158,1077.713],[1480.731,1037.589]],"c":false}]},{"t":64,"s":[{"i":[[0,0],[5.418,5.419],[17.468,17.469],[25.537,-25.537]],"o":[[-3.662,6.731],[0,0],[-25.536,-25.537],[0,0]],"v":[[1614.514,1147.064],[1598.091,1130.648],[1545.158,1077.713],[1467.776,1024.778]],"c":false}]}],"ix":2},"nm":"Tracciato 1_Bone","mn":"ADBE Vector Shape - Group","hd":false}],"ip":53,"op":126,"st":6,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"top_extra","parent":10,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":45,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":29,"s":[1502.093,1035.094,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34,"s":[1495.062,1036.428,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[1495.062,1036.428,0],"to":[0,0,0],"ti":[0,0,0]},{"t":53,"s":[1502.312,1036.428,0]}],"ix":2},"a":{"a":0,"k":[-98.5,-102,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":29,"s":[46.5,46.5,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":32,"s":[50,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":49,"s":[50,50,100]},{"t":53,"s":[45.2,45.2,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[94,94],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracciato ellisse 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.211761474609,0.568603515625,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Riempimento 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-98.5,-102],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellisse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":29,"op":53,"st":0,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"top","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[73.565,-23.785,0],"ix":2},"a":{"a":0,"k":[1488.448,1026.164,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"ShapeNir Slider","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":1,"k":[{"i":{"x":[0.17],"y":[1]},"o":{"x":[0.55],"y":[0]},"t":6,"s":[0]},{"t":23,"s":[100]}],"ix":1}}]}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.17,"y":1},"o":{"x":0.55,"y":0},"t":6,"s":[{"i":[[0,0],[0,0],[-13.503,-13.506],[0,0],[9.065,-9.068],[0,0],[0,0],[9.068,9.071],[0,0],[0,0]],"o":[[0,0],[13.506,-13.506],[0,0],[9.065,9.068],[0,0],[0,0],[-9.068,9.074],[0,0],[0,0],[0,0]],"v":[[-74.672,-57.386],[-70.481,-61.577],[-21.582,-61.577],[194.283,154.505],[194.286,187.34],[194.286,187.34],[194.286,187.34],[161.442,187.343],[-78.863,-53.195],[-74.672,-57.386]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.55,"y":0},"t":23,"s":[{"i":[[0,0],[0,0],[-13.503,-13.506],[0,0],[9.065,-9.068],[0,0],[0,0],[9.068,9.071],[0,0],[0,0]],"o":[[0,0],[13.506,-13.506],[0,0],[9.065,9.068],[0,0],[0,0],[-9.068,9.074],[0,0],[0,0],[0,0]],"v":[[-74.672,-57.386],[-70.481,-61.577],[-21.582,-61.577],[72.063,32.066],[72.066,64.9],[72.066,64.9],[72.066,64.9],[39.223,64.903],[-78.863,-53.195],[-74.672,-57.386]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":26,"s":[{"i":[[0,0],[0,0],[-13.503,-13.506],[0,0],[9.065,-9.068],[0,0],[0,0],[9.068,9.071],[2.122,2.171],[0,0]],"o":[[0,0],[13.506,-13.506],[0,0],[9.065,9.068],[0,0],[0,0],[-9.068,9.074],[0,0],[-2.122,-2.171],[0,0]],"v":[[-70.801,-53.558],[-66.61,-57.749],[-21.582,-61.577],[43.259,3.22],[43.262,36.055],[43.262,36.055],[43.262,36.055],[10.419,36.058],[-66.621,-43.95],[-70.801,-53.558]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":29,"s":[{"i":[[0,0],[0,0],[-13.503,-13.506],[0,0],[9.065,-9.068],[0,0],[0,0],[9.068,9.071],[0,0],[0,0]],"o":[[0,0],[13.506,-13.506],[0,0],[9.065,9.068],[0,0],[0,0],[-9.068,9.074],[0,0],[0,0],[0,0]],"v":[[-61.716,-44.574],[-57.525,-48.766],[-21.582,-61.577],[-24.345,-64.482],[-24.342,-31.648],[-24.342,-31.648],[-24.342,-31.648],[-57.186,-31.645],[-65.907,-40.383],[-61.716,-44.574]],"c":false}]},{"i":{"x":0.45,"y":1},"o":{"x":0.167,"y":0},"t":53,"s":[{"i":[[0,0],[0,0],[-13.503,-13.506],[0,0],[9.065,-9.068],[0,0],[0,0],[9.068,9.071],[0,0],[0,0]],"o":[[0,0],[13.506,-13.506],[0,0],[9.065,9.068],[0,0],[0,0],[-9.068,9.074],[0,0],[0,0],[0,0]],"v":[[-61.716,-44.574],[-57.525,-48.766],[-21.582,-61.577],[-24.345,-64.482],[-24.342,-31.648],[-24.342,-31.648],[-24.342,-31.648],[-57.186,-31.645],[-65.907,-40.383],[-61.716,-44.574]],"c":false}]},{"t":59,"s":[{"i":[[0,0],[0,0],[-13.503,-13.506],[0,0],[9.065,-9.068],[0,0],[0,0],[9.068,9.071],[0,0],[0,0]],"o":[[0,0],[13.506,-13.506],[0,0],[9.065,9.068],[0,0],[0,0],[-9.068,9.074],[0,0],[0,0],[0,0]],"v":[[-74.672,-57.386],[-70.481,-61.577],[-21.582,-61.577],[72.063,32.066],[72.066,64.9],[72.066,64.9],[72.066,64.9],[39.223,64.903],[-78.863,-53.195],[-74.672,-57.386]],"c":false}]}],"ix":2},"nm":"Tracciato 1_forAnimation","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.211764708161,0.568627476692,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Riempimento 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1542.448,1082.164],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Gruppo 3","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1,"x":"var $bm_rt;\nvar mN01 = 52.2496645130989;\nvar mN02 = 100;\nvar mN01Edt = 52.2496645130989;\nvar mN02Edt = 98.6485408913042;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosF = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosF[$bm_sub(i, 1)], mRatiosF[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;"},"e":{"a":0,"k":100,"ix":2,"x":"var $bm_rt;\nvar mN01 = 52.2496645130989;\nvar mN02 = 0;\nvar mN01Edt = 52.2496645130989;\nvar mN02Edt = 1.35145910869578;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosL = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosL[$bm_sub(i, 1)], mRatiosL[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;"},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Taglia tracciati 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":1,"k":[{"i":{"x":0.17,"y":1},"o":{"x":0.55,"y":0},"t":6,"s":[{"i":[[0,0],[5.418,5.419],[17.468,17.469],[25.537,-25.537]],"o":[[-3.662,6.731],[0,0],[-25.536,-25.537],[0,0]],"v":[[1736.734,1269.504],[1720.31,1253.088],[1545.158,1077.713],[1467.776,1024.778]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.55,"y":0},"t":23,"s":[{"i":[[0,0],[5.418,5.419],[17.468,17.469],[25.537,-25.537]],"o":[[-3.662,6.731],[0,0],[-25.536,-25.537],[0,0]],"v":[[1614.514,1147.064],[1598.091,1130.648],[1545.158,1077.713],[1467.776,1024.778]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":29,"s":[{"i":[[0,0],[5.418,5.419],[17.468,17.469],[25.537,-25.537]],"o":[[-3.662,6.731],[0,0],[-25.536,-25.537],[0,0]],"v":[[1518.105,1050.515],[1501.682,1034.099],[1545.158,1077.713],[1480.731,1037.589]],"c":false}]},{"i":{"x":0.45,"y":1},"o":{"x":0.167,"y":0},"t":53,"s":[{"i":[[0,0],[5.418,5.419],[17.468,17.469],[25.537,-25.537]],"o":[[-3.662,6.731],[0,0],[-25.536,-25.537],[0,0]],"v":[[1518.105,1050.515],[1501.682,1034.099],[1545.158,1077.713],[1480.731,1037.589]],"c":false}]},{"t":59,"s":[{"i":[[0,0],[5.418,5.419],[17.468,17.469],[25.537,-25.537]],"o":[[-3.662,6.731],[0,0],[-25.536,-25.537],[0,0]],"v":[[1614.514,1147.064],[1598.091,1130.648],[1545.158,1077.713],[1467.776,1024.778]],"c":false}]}],"ix":2},"nm":"Tracciato 1_Bone","mn":"ADBE Vector Shape - Group","hd":false}],"ip":6,"op":29,"st":6,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"mid 2","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,16,0],"ix":2},"a":{"a":0,"k":[1429.883,1065.949,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"ShapeNir Slider","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":100,"ix":1}}]}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.45,"y":1},"o":{"x":0.167,"y":0},"t":55.5,"s":[{"i":[[0,0],[0,0],[0,0],[6.673,-6.673],[0,0],[0,0],[6.673,6.673],[0,0],[0,0]],"o":[[0,0],[0,0],[6.671,6.673],[0,0],[0,0],[-6.673,6.671],[0,0],[0,0],[0,0]],"v":[[-30.953,-29.75],[-18.872,-41.83],[-9.362,-32.208],[-9.362,-8.045],[-9.362,-8.045],[-9.362,-8.045],[-33.522,-8.045],[-43.033,-17.67],[-30.953,-29.75]],"c":false}]},{"t":61.5,"s":[{"i":[[0,0],[0,0],[0,0],[9.068,-9.068],[0,0],[0,0],[9.068,9.068],[0,0],[0,0]],"o":[[0,0],[0,0],[9.065,9.068],[0,0],[0,0],[-9.068,9.065],[0,0],[0,0],[0,0]],"v":[[-36.143,-36.135],[-19.727,-52.551],[45.759,12.917],[45.759,45.751],[45.759,45.751],[45.759,45.751],[12.927,45.751],[-52.559,-19.719],[-36.143,-36.135]],"c":false}]}],"ix":2},"nm":"Tracciato 1_forAnimation","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.223529413342,0.223529413342,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Riempimento 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1464.883,1099.949],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Gruppo 2","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1,"x":"var $bm_rt;\nvar mN01 = 50.0000976522834;\nvar mN02 = 100;\nvar mN01Edt = 50.0000976522834;\nvar mN02Edt = 92.3777446239903;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosF = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosF[$bm_sub(i, 1)], mRatiosF[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;"},"e":{"a":0,"k":100,"ix":2,"x":"var $bm_rt;\nvar mN01 = 50.0000976522834;\nvar mN02 = 0;\nvar mN01Edt = 50.0000976522834;\nvar mN02Edt = 7.62225537600966;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosL = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosL[$bm_sub(i, 1)], mRatiosL[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;"},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Taglia tracciati 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":1,"k":[{"i":{"x":0.45,"y":1},"o":{"x":0.167,"y":0},"t":55.5,"s":[{"i":[[0,0],[11.939,11.936],[0,0]],"o":[[-0.527,-16.874],[-7.951,-7.949],[0,0]],"v":[[1455.522,1091.904],[1458.026,1094.288],[1433.931,1070.199]],"c":false}]},{"t":61.5,"s":[{"i":[[0,0],[16.224,16.22],[0,0]],"o":[[-0.717,-22.93],[-10.805,-10.802],[0,0]],"v":[[1510.642,1145.701],[1461.483,1096.548],[1428.74,1063.814]],"c":false}]}],"ix":2},"nm":"Tracciato 1_Bone","mn":"ADBE Vector Shape - Group","hd":false}],"ip":53,"op":126,"st":3,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"mid_extra","parent":13,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":45,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":29,"s":[1442.756,1079.784,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34,"s":[1450.145,1086.357,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[1450.145,1086.357,0],"to":[0,0,0],"ti":[0,0,0]},{"t":53,"s":[1443.895,1080.232,0]}],"ix":2},"a":{"a":0,"k":[-120,40,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":29,"s":[37.2,37.2,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":34,"s":[50,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":49,"s":[50,50,100]},{"t":53,"s":[35.7,35.7,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[93,93],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracciato ellisse 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.223510742188,0.223510742188,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Riempimento 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-120,40],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellisse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":29,"op":53,"st":0,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"mid","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[15,16,0],"ix":2},"a":{"a":0,"k":[1429.883,1065.949,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"ShapeNir Slider","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":1,"k":[{"i":{"x":[0.17],"y":[1]},"o":{"x":[0.55],"y":[0]},"t":3,"s":[0]},{"t":23,"s":[100]}],"ix":1}}]}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.17,"y":1},"o":{"x":0.55,"y":0},"t":3,"s":[{"i":[[0,0],[0,0],[0,0],[9.068,-9.068],[0,0],[0,0],[9.068,9.068],[0,0],[0,0]],"o":[[0,0],[0,0],[9.065,9.068],[0,0],[0,0],[-9.068,9.065],[0,0],[0,0],[0,0]],"v":[[-36.143,-36.135],[-19.727,-52.551],[119.506,86.956],[119.506,119.79],[119.506,119.79],[119.506,119.79],[86.674,119.79],[-52.559,-19.719],[-36.143,-36.135]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.55,"y":0},"t":23,"s":[{"i":[[0,0],[0,0],[0,0],[9.068,-9.068],[0,0],[0,0],[9.068,9.068],[0,0],[0,0]],"o":[[0,0],[0,0],[9.065,9.068],[0,0],[0,0],[-9.068,9.065],[0,0],[0,0],[0,0]],"v":[[-36.143,-36.135],[-19.727,-52.551],[45.759,12.917],[45.759,45.751],[45.759,45.751],[45.759,45.751],[12.927,45.751],[-52.559,-19.719],[-36.143,-36.135]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":29,"s":[{"i":[[0,0],[0,0],[0,0],[6.673,-6.673],[0,0],[0,0],[6.673,6.673],[0,0],[0,0]],"o":[[0,0],[0,0],[6.671,6.673],[0,0],[0,0],[-6.673,6.671],[0,0],[0,0],[0,0]],"v":[[-30.953,-29.75],[-18.872,-41.83],[-9.362,-32.208],[-9.362,-8.045],[-9.362,-8.045],[-9.362,-8.045],[-33.522,-8.045],[-43.033,-17.67],[-30.953,-29.75]],"c":false}]},{"i":{"x":0.45,"y":1},"o":{"x":0.167,"y":0},"t":53,"s":[{"i":[[0,0],[0,0],[0,0],[6.673,-6.673],[0,0],[0,0],[6.673,6.673],[0,0],[0,0]],"o":[[0,0],[0,0],[6.671,6.673],[0,0],[0,0],[-6.673,6.671],[0,0],[0,0],[0,0]],"v":[[-30.953,-29.75],[-18.872,-41.83],[-9.362,-32.208],[-9.362,-8.045],[-9.362,-8.045],[-9.362,-8.045],[-33.522,-8.045],[-43.033,-17.67],[-30.953,-29.75]],"c":false}]},{"t":59,"s":[{"i":[[0,0],[0,0],[0,0],[9.068,-9.068],[0,0],[0,0],[9.068,9.068],[0,0],[0,0]],"o":[[0,0],[0,0],[9.065,9.068],[0,0],[0,0],[-9.068,9.065],[0,0],[0,0],[0,0]],"v":[[-36.143,-36.135],[-19.727,-52.551],[45.759,12.917],[45.759,45.751],[45.759,45.751],[45.759,45.751],[12.927,45.751],[-52.559,-19.719],[-36.143,-36.135]],"c":false}]}],"ix":2},"nm":"Tracciato 1_forAnimation","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.223529413342,0.223529413342,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Riempimento 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1464.883,1099.949],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Gruppo 2","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1,"x":"var $bm_rt;\nvar mN01 = 50.0000976522834;\nvar mN02 = 100;\nvar mN01Edt = 50.0000976522834;\nvar mN02Edt = 92.3777446239903;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosF = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosF[$bm_sub(i, 1)], mRatiosF[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;"},"e":{"a":0,"k":100,"ix":2,"x":"var $bm_rt;\nvar mN01 = 50.0000976522834;\nvar mN02 = 0;\nvar mN01Edt = 50.0000976522834;\nvar mN02Edt = 7.62225537600966;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosL = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosL[$bm_sub(i, 1)], mRatiosL[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;"},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Taglia tracciati 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":1,"k":[{"i":{"x":0.17,"y":1},"o":{"x":0.55,"y":0},"t":3,"s":[{"i":[[0,0],[16.224,16.22],[0,0]],"o":[[-0.717,-22.93],[-10.805,-10.802],[0,0]],"v":[[1584.389,1219.739],[1461.483,1096.548],[1428.74,1063.814]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.55,"y":0},"t":23,"s":[{"i":[[0,0],[16.224,16.22],[0,0]],"o":[[-0.717,-22.93],[-10.805,-10.802],[0,0]],"v":[[1510.642,1145.701],[1461.483,1096.548],[1428.74,1063.814]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0},"t":29,"s":[{"i":[[0,0],[11.939,11.936],[0,0]],"o":[[-0.527,-16.874],[-7.951,-7.949],[0,0]],"v":[[1455.522,1091.904],[1458.026,1094.288],[1433.931,1070.199]],"c":false}]},{"i":{"x":0.45,"y":1},"o":{"x":0.167,"y":0},"t":53,"s":[{"i":[[0,0],[11.939,11.936],[0,0]],"o":[[-0.527,-16.874],[-7.951,-7.949],[0,0]],"v":[[1455.522,1091.904],[1458.026,1094.288],[1433.931,1070.199]],"c":false}]},{"t":59,"s":[{"i":[[0,0],[16.224,16.22],[0,0]],"o":[[-0.717,-22.93],[-10.805,-10.802],[0,0]],"v":[[1510.642,1145.701],[1461.483,1096.548],[1428.74,1063.814]],"c":false}]}],"ix":2},"nm":"Tracciato 1_Bone","mn":"ADBE Vector Shape - Group","hd":false}],"ip":3,"op":29,"st":3,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"bottom 2","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.559,65.635,0],"ix":2},"a":{"a":0,"k":[1412.324,1115.584,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"ShapeNir Slider","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":0,"k":100,"ix":1}}]}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.45,"y":1},"o":{"x":0.167,"y":0},"t":53,"s":[{"i":[[0,0],[0,0],[0,0],[6.334,6.334],[-6.333,6.334],[0,0],[0,0]],"o":[[0,0],[0,0],[-6.334,6.333],[-6.334,-6.334],[0,0],[0,0],[0,0]],"v":[[6.738,-2.735],[18.731,9.258],[7.38,20.609],[-16.081,20.083],[-16.606,-3.378],[-5.255,-14.728],[6.738,-2.735]],"c":false}]},{"t":59,"s":[{"i":[[0,0],[0,0],[0,0],[9.068,9.068],[-9.068,9.068],[0,0],[0,0]],"o":[[0,0],[0,0],[-9.068,9.068],[-9.068,-9.068],[0,0],[0,0],[0,0]],"v":[[11.444,-11.445],[28.615,5.726],[12.364,21.977],[-21.225,21.225],[-21.977,-12.364],[-5.726,-28.615],[11.444,-11.445]],"c":false}]}],"ix":2},"nm":"Tracciato 1_forAnimation","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254911661,0.223529413342,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Riempimento 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1399.865,1127.029],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Gruppo 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1,"x":"var $bm_rt;\nvar mN01 = 50.0000191622908;\nvar mN02 = 100;\nvar mN01Edt = 50.0000191622908;\nvar mN02Edt = 85.6245824308121;\nvar mRatiosM = [\n 0,\n 0.1472024328579,\n 0.50257634091374,\n 1\n ];\nvar mRatiosF = [\n 0,\n 0.31314999326651,\n 0.62416910908086,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosF[$bm_sub(i, 1)], mRatiosF[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;"},"e":{"a":0,"k":100,"ix":2,"x":"var $bm_rt;\nvar mN01 = 50.0000191622908;\nvar mN02 = 0;\nvar mN01Edt = 50.0000191622908;\nvar mN02Edt = 14.3754175691879;\nvar mRatiosM = [\n 0,\n 0.1472024328579,\n 0.50257634091374,\n 1\n ];\nvar mRatiosL = [\n 0,\n 0.31314966173997,\n 0.62416844828369,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosL[$bm_sub(i, 1)], mRatiosL[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;"},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Taglia tracciati 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":1,"k":[{"i":{"x":0.45,"y":1},"o":{"x":0.167,"y":0},"t":53,"s":[{"i":[[0,0],[-1.108,1.108],[-2.676,2.676],[-1.873,1.873],[0,0]],"o":[[0,0],[2.676,-2.676],[0,0],[1.873,-1.873],[0,0]],"v":[[1383.785,1147.112],[1387.144,1143.753],[1395.253,1135.644],[1400.928,1129.969],[1406.603,1124.294]],"c":false}]},{"t":59,"s":[{"i":[[0,0],[-1.587,1.587],[-3.831,3.831],[-2.681,2.681],[0,0]],"o":[[0,0],[3.831,-3.831],[0,0],[2.681,-2.681],[0,0]],"v":[[1378.641,1148.253],[1383.45,1143.444],[1395.059,1131.835],[1403.185,1123.709],[1411.31,1115.584]],"c":false}]}],"ix":2},"nm":"Tracciato 1_Bone","mn":"ADBE Vector Shape - Group","hd":false}],"ip":53,"op":126,"st":0,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"bottom_extra","parent":16,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":45,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":29,"s":[1395.693,1135.648,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":34,"s":[1398.671,1131.534,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":51,"s":[1398.671,1131.534,0],"to":[0,0,0],"ti":[0,0,0]},{"t":53,"s":[1396.171,1134.409,0]}],"ix":2},"a":{"a":0,"k":[-114,181,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":29,"s":[38.5,38.5,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":34,"s":[50,50,100]},{"i":{"x":[0.833,0.833,0.833],"y":[0.833,0.833,0.833]},"o":{"x":[0.167,0.167,0.167],"y":[0.167,0.167,0.167]},"t":49,"s":[50,50,100]},{"t":53,"s":[37,37,100]}],"ix":6}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":0,"k":[91,91],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Tracciato ellisse 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337249755859,0.223510742188,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Riempimento 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[-114,181],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellisse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":29,"op":53,"st":0,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"bottom","parent":5,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-2.559,65.635,0],"ix":2},"a":{"a":0,"k":[1412.324,1115.584,0],"ix":1},"s":{"a":0,"k":[100,100,100],"ix":6}},"ao":0,"ef":[{"ty":5,"nm":"ShapeNir Slider","np":3,"mn":"ADBE Slider Control","ix":1,"en":1,"ef":[{"ty":0,"nm":"Slider","mn":"ADBE Slider Control-0001","ix":1,"v":{"a":1,"k":[{"i":{"x":[0.17],"y":[1]},"o":{"x":[0.55],"y":[0]},"t":0,"s":[0]},{"t":23,"s":[100]}],"ix":1}}]}],"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.17,"y":1},"o":{"x":0.55,"y":0},"t":0,"s":[{"i":[[0,0],[0,0],[0,0],[9.068,9.068],[-9.068,9.068],[0,0],[0,0]],"o":[[0,0],[0,0],[-9.068,9.068],[-9.068,-9.068],[0,0],[0,0],[0,0]],"v":[[11.444,-11.445],[28.615,5.726],[-95.63,130.357],[-129.219,129.605],[-129.971,96.016],[-5.726,-28.615],[11.444,-11.445]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.55,"y":0},"t":23,"s":[{"i":[[0,0],[0,0],[0,0],[9.068,9.068],[-9.068,9.068],[0,0],[0,0]],"o":[[0,0],[0,0],[-9.068,9.068],[-9.068,-9.068],[0,0],[0,0],[0,0]],"v":[[11.444,-11.445],[28.615,5.726],[12.364,21.977],[-21.225,21.225],[-21.977,-12.364],[-5.726,-28.615],[11.444,-11.445]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":28,"s":[{"i":[[-3.749,-3.55],[1.525,-6.804],[0,0],[6.838,6.838],[-6.838,6.838],[-5.985,0.184],[0,0]],"o":[[3.749,3.55],[-1.525,6.804],[-6.838,6.838],[-6.838,-6.838],[0,0],[5.985,-0.184],[0,0]],"v":[[12.19,-8.82],[20.555,8.606],[8.3,20.861],[-17.03,20.294],[-17.597,-5.036],[-5.342,-17.291],[12.19,-8.82]],"c":false}]},{"t":29,"s":[{"i":[[0,0],[0,0],[0,0],[6.334,6.334],[-6.333,6.334],[0,0],[0,0]],"o":[[0,0],[0,0],[-6.334,6.333],[-6.334,-6.334],[0,0],[0,0],[0,0]],"v":[[6.738,-2.735],[18.731,9.258],[7.38,20.609],[-16.081,20.083],[-16.606,-3.378],[-5.255,-14.728],[6.738,-2.735]],"c":false}]}],"ix":2},"nm":"Tracciato 1_forAnimation","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.337254911661,0.223529413342,1,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Riempimento 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[1399.865,1127.029],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Gruppo 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1,"x":"var $bm_rt;\nvar mN01 = 50.0000191622908;\nvar mN02 = 100;\nvar mN01Edt = 50.0000191622908;\nvar mN02Edt = 85.6245824308121;\nvar mRatiosM = [\n 0,\n 0.1472024328579,\n 0.50257634091374,\n 1\n ];\nvar mRatiosF = [\n 0,\n 0.31314999326651,\n 0.62416910908086,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosF[$bm_sub(i, 1)], mRatiosF[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;"},"e":{"a":0,"k":100,"ix":2,"x":"var $bm_rt;\nvar mN01 = 50.0000191622908;\nvar mN02 = 0;\nvar mN01Edt = 50.0000191622908;\nvar mN02Edt = 14.3754175691879;\nvar mRatiosM = [\n 0,\n 0.1472024328579,\n 0.50257634091374,\n 1\n ];\nvar mRatiosL = [\n 0,\n 0.31314966173997,\n 0.62416844828369,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosL[$bm_sub(i, 1)], mRatiosL[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;"},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Taglia tracciati 1","mn":"ADBE Vector Filter - Trim","hd":false},{"ind":2,"ty":"sh","ix":3,"ks":{"a":1,"k":[{"i":{"x":0.17,"y":1},"o":{"x":0.55,"y":0},"t":0,"s":[{"i":[[0,0],[-1.587,1.587],[-3.831,3.831],[-2.681,2.681],[0,0]],"o":[[0,0],[3.831,-3.831],[0,0],[2.681,-2.681],[0,0]],"v":[[1270.646,1256.634],[1275.455,1251.825],[1287.065,1240.215],[1403.185,1123.709],[1411.31,1115.584]],"c":false}]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.55,"y":0},"t":23,"s":[{"i":[[0,0],[-1.587,1.587],[-3.831,3.831],[-2.681,2.681],[0,0]],"o":[[0,0],[3.831,-3.831],[0,0],[2.681,-2.681],[0,0]],"v":[[1378.641,1148.253],[1383.45,1143.444],[1395.059,1131.835],[1403.185,1123.709],[1411.31,1115.584]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.167,"y":0.167},"t":28,"s":[{"i":[[0,0],[-1.197,1.197],[-2.889,2.889],[-2.022,2.022],[0,0]],"o":[[0,0],[2.889,-2.889],[0,0],[2.022,-2.022],[0,0]],"v":[[1382.835,1147.323],[1386.462,1143.696],[1395.217,1134.941],[1401.345,1128.813],[1412.057,1118.207]],"c":false}]},{"t":29,"s":[{"i":[[0,0],[-1.108,1.108],[-2.676,2.676],[-1.873,1.873],[0,0]],"o":[[0,0],[2.676,-2.676],[0,0],[1.873,-1.873],[0,0]],"v":[[1383.785,1147.112],[1387.144,1143.753],[1395.253,1135.644],[1400.928,1129.969],[1406.603,1124.294]],"c":false}]}],"ix":2},"nm":"Tracciato 1_Bone","mn":"ADBE Vector Shape - Group","hd":false}],"ip":0,"op":29,"st":0,"bm":0}],"markers":[]} \ No newline at end of file +{ + "v": "4.8.0", + "meta": {"g": "LottieFiles AE 3.4.3", "a": "", "k": "", "d": "", "tc": ""}, + "fr": 24, + "ip": 0, + "op": 92, + "w": 3840, + "h": 2160, + "nm": "icon - isolated", + "ddd": 0, + "assets": [], + "layers": [ + { + "ddd": 0, + "ind": 1, + "ty": 3, + "nm": "NULL", + "sr": 1, + "ks": { + "o": {"a": 0, "k": 0, "ix": 11}, + "r": {"a": 0, "k": 0, "ix": 10}, + "p": {"a": 0, "k": [1920, 1080, 0], "ix": 2}, + "a": {"a": 0, "k": [50, 50, 0], "ix": 1}, + "s": { + "a": 1, + "k": [ + { + "i": {"x": [0.833, 0.833, 0.833], "y": [0.833, 0.833, 0.833]}, + "o": {"x": [0.167, 0.167, 0.167], "y": [0.167, 0.167, 0.167]}, + "t": 33, + "s": [100, 100, 100] + }, + {"t": 59, "s": [165, 165, 100]} + ], + "ix": 6 + } + }, + "ao": 0, + "ip": 0, + "op": 240, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 2, + "ty": 3, + "nm": "main position", + "parent": 1, + "sr": 1, + "ks": { + "o": {"a": 0, "k": 0, "ix": 11}, + "r": {"a": 0, "k": 0, "ix": 10}, + "p": { + "a": 1, + "k": [ + { + "i": {"x": 0.2, "y": 1}, + "o": {"x": 0.167, "y": 0.167}, + "t": 36, + "s": [50, 50, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + {"t": 54, "s": [464, 50, 0]} + ], + "ix": 2 + }, + "a": {"a": 0, "k": [50, 50, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100, 100], "ix": 6} + }, + "ao": 0, + "ip": 0, + "op": 240, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 3, + "ty": 3, + "nm": "scale", + "parent": 2, + "sr": 1, + "ks": { + "o": {"a": 0, "k": 0, "ix": 11}, + "r": {"a": 0, "k": 0, "ix": 10}, + "p": {"a": 0, "k": [50, 50, 0], "ix": 2}, + "a": {"a": 0, "k": [50, 50, 0], "ix": 1}, + "s": { + "a": 1, + "k": [ + { + "i": {"x": [0.667, 0.667, 0.667], "y": [1, 1, 1]}, + "o": {"x": [0.333, 0.333, 0.333], "y": [0, 0, 0]}, + "t": 23, + "s": [200, 200, 100] + }, + { + "i": {"x": [0.667, 0.667, 0.667], "y": [1, 1, 1]}, + "o": {"x": [0.333, 0.333, 0.333], "y": [0, 0, 0]}, + "t": 35, + "s": [118, 118, 100] + }, + { + "i": {"x": [0.667, 0.667, 0.667], "y": [1, 1, 1]}, + "o": {"x": [0.333, 0.333, 0.333], "y": [0, 0, 0]}, + "t": 38, + "s": [90, 90, 100] + }, + {"t": 49, "s": [100, 100, 100]} + ], + "ix": 6 + } + }, + "ao": 0, + "ip": 23, + "op": 240, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 4, + "ty": 3, + "nm": "arrow position", + "parent": 3, + "sr": 1, + "ks": { + "o": {"a": 0, "k": 0, "ix": 11}, + "r": {"a": 0, "k": 0, "ix": 10}, + "p": { + "a": 1, + "k": [ + { + "i": {"x": 0.107, "y": 1}, + "o": {"x": 0.533, "y": 0}, + "t": 23, + "s": [50, -8, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": {"x": 0.19, "y": 0.642}, + "o": {"x": 0.333, "y": 0}, + "t": 35, + "s": [119.897, 36, 0], + "to": [0, 0, 0], + "ti": [392.376, 75.374, 0] + }, + { + "i": {"x": 0.833, "y": 0.874}, + "o": {"x": 1, "y": 0.713}, + "t": 38, + "s": [-307.61, -289.928, 0], + "to": [-832.969, -114.56, 0], + "ti": [20.667, 921.704, 0] + }, + { + "i": {"x": 0.667, "y": 1}, + "o": {"x": 0.115, "y": 1}, + "t": 49, + "s": [-374, -134, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": {"x": 0.538, "y": 1}, + "o": {"x": 1, "y": 0}, + "t": 53, + "s": [-374, -175, 0], + "to": [0, 0, 0], + "ti": [1.605, -28.883, 0] + }, + { + "i": {"x": 0.538, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 59, + "s": [-374, 37, 0], + "to": [0, 0, 0], + "ti": [1.605, -28.883, 0] + }, + {"t": 65, "s": [-374, -8, 0]} + ], + "ix": 2 + }, + "a": {"a": 0, "k": [50, 50, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100, 100], "ix": 6} + }, + "ao": 0, + "ip": 23, + "op": 243, + "st": 3, + "bm": 0 + }, + { + "ddd": 0, + "ind": 5, + "ty": 3, + "nm": "rotation", + "parent": 4, + "sr": 1, + "ks": { + "o": {"a": 0, "k": 0, "ix": 11}, + "r": { + "a": 1, + "k": [ + {"i": {"x": [0.667], "y": [1]}, "o": {"x": [0.303], "y": [0]}, "t": 23, "s": [-45]}, + {"i": {"x": [0.773], "y": [0.886]}, "o": {"x": [0.333], "y": [0]}, "t": 35, "s": [-45]}, + { + "i": {"x": [0.833], "y": [0.833]}, + "o": {"x": [0.167], "y": [0.06]}, + "t": 38, + "s": [-71] + }, + { + "i": {"x": [0.833], "y": [0.833]}, + "o": {"x": [0.167], "y": [0.089]}, + "t": 42, + "s": [-118.941] + }, + { + "i": {"x": [0.667], "y": [1]}, + "o": {"x": [0.167], "y": [0.087]}, + "t": 45, + "s": [-186.591] + }, + {"t": 49, "s": [-360]} + ], + "ix": 10 + }, + "p": {"a": 0, "k": [18.883, 127.949, 0], "ix": 2}, + "a": {"a": 0, "k": [50, 50, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100, 100], "ix": 6} + }, + "ao": 0, + "ip": 23, + "op": 243, + "st": 3, + "bm": 0 + }, + { + "ddd": 0, + "ind": 6, + "ty": 3, + "nm": "rough edges", + "sr": 1, + "ks": { + "o": {"a": 0, "k": 100, "ix": 11}, + "r": {"a": 0, "k": 0, "ix": 10}, + "p": {"a": 0, "k": [1920, 1080, 0], "ix": 2}, + "a": {"a": 0, "k": [1920, 1080, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100, 100], "ix": 6} + }, + "ao": 0, + "ef": [ + { + "ty": 5, + "nm": "Roughen Edges", + "np": 17, + "mn": "ADBE Roughen Edges", + "ix": 1, + "en": 1, + "ef": [ + { + "ty": 7, + "nm": "Edge Type", + "mn": "ADBE Roughen Edges-0001", + "ix": 1, + "v": {"a": 0, "k": 1, "ix": 1} + }, + { + "ty": 2, + "nm": "Edge Color", + "mn": "ADBE Roughen Edges-0010", + "ix": 2, + "v": {"a": 0, "k": [0.6, 0.2, 0, 1], "ix": 2} + }, + { + "ty": 0, + "nm": "Border", + "mn": "ADBE Roughen Edges-0002", + "ix": 3, + "v": { + "a": 1, + "k": [ + { + "i": {"x": [0.833], "y": [0.833]}, + "o": {"x": [0.167], "y": [0.167]}, + "t": 12, + "s": [17.4] + }, + {"t": 19, "s": [2.7]} + ], + "ix": 3 + } + }, + { + "ty": 0, + "nm": "Edge Sharpness", + "mn": "ADBE Roughen Edges-0003", + "ix": 4, + "v": { + "a": 1, + "k": [ + { + "i": {"x": [0.833], "y": [0.833]}, + "o": {"x": [0.167], "y": [0.167]}, + "t": 12, + "s": [1] + }, + {"t": 19, "s": [0.1]} + ], + "ix": 4 + } + }, + { + "ty": 0, + "nm": "Fractal Influence", + "mn": "ADBE Roughen Edges-0004", + "ix": 5, + "v": {"a": 0, "k": 1, "ix": 5} + }, + { + "ty": 0, + "nm": "Scale", + "mn": "ADBE Roughen Edges-0005", + "ix": 6, + "v": {"a": 0, "k": 1000, "ix": 6} + }, + { + "ty": 0, + "nm": "Stretch Width or Height", + "mn": "ADBE Roughen Edges-0006", + "ix": 7, + "v": {"a": 0, "k": 0, "ix": 7} + }, + { + "ty": 3, + "nm": "Offset (Turbulence)", + "mn": "ADBE Roughen Edges-0007", + "ix": 8, + "v": {"a": 0, "k": [0, 0], "ix": 8} + }, + { + "ty": 0, + "nm": "Complexity", + "mn": "ADBE Roughen Edges-0008", + "ix": 9, + "v": {"a": 0, "k": 2, "ix": 9} + }, + { + "ty": 0, + "nm": "Evolution", + "mn": "ADBE Roughen Edges-0009", + "ix": 10, + "v": {"a": 0, "k": 0, "ix": 10} + }, + {"ty": 6, "nm": "Evolution Options", "mn": "ADBE Roughen Edges-0011", "ix": 11, "v": 0}, + { + "ty": 7, + "nm": "Cycle Evolution", + "mn": "ADBE Roughen Edges-0012", + "ix": 12, + "v": {"a": 0, "k": 0, "ix": 12} + }, + { + "ty": 0, + "nm": "Cycle (in Revolutions)", + "mn": "ADBE Roughen Edges-0013", + "ix": 13, + "v": {"a": 0, "k": 1, "ix": 13} + }, + { + "ty": 0, + "nm": "Random Seed", + "mn": "ADBE Roughen Edges-0014", + "ix": 14, + "v": {"a": 0, "k": 0, "ix": 14} + }, + {"ty": 6, "nm": "Random Seed", "mn": "ADBE Roughen Edges-0015", "ix": 15, "v": 0} + ] + } + ], + "ip": 0, + "op": 19, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 7, + "ty": 3, + "nm": "echo", + "sr": 1, + "ks": { + "o": {"a": 0, "k": 100, "ix": 11}, + "r": {"a": 0, "k": 0, "ix": 10}, + "p": {"a": 0, "k": [1920, 1080, 0], "ix": 2}, + "a": {"a": 0, "k": [1920, 1080, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100, 100], "ix": 6} + }, + "ao": 0, + "ef": [ + { + "ty": 5, + "nm": "Echo", + "np": 7, + "mn": "ADBE Echo", + "ix": 1, + "en": 1, + "ef": [ + { + "ty": 0, + "nm": "Echo Time (seconds)", + "mn": "ADBE Echo-0001", + "ix": 1, + "v": {"a": 0, "k": -0.001, "ix": 1} + }, + { + "ty": 0, + "nm": "Number Of Echoes", + "mn": "ADBE Echo-0002", + "ix": 2, + "v": { + "a": 1, + "k": [ + { + "i": {"x": [0.833], "y": [0.833]}, + "o": {"x": [0.167], "y": [0.167]}, + "t": 31, + "s": [10] + }, + { + "i": {"x": [0.833], "y": [0.833]}, + "o": {"x": [0.167], "y": [0.167]}, + "t": 34, + "s": [67] + }, + { + "i": {"x": [0.833], "y": [0.833]}, + "o": {"x": [0.167], "y": [0.167]}, + "t": 49, + "s": [67] + }, + {"t": 53, "s": [10]} + ], + "ix": 2 + } + }, + { + "ty": 0, + "nm": "Starting Intensity", + "mn": "ADBE Echo-0003", + "ix": 3, + "v": {"a": 0, "k": 1, "ix": 3} + }, + { + "ty": 0, + "nm": "Decay", + "mn": "ADBE Echo-0004", + "ix": 4, + "v": {"a": 0, "k": 1, "ix": 4} + }, + { + "ty": 7, + "nm": "Echo Operator", + "mn": "ADBE Echo-0005", + "ix": 5, + "v": {"a": 0, "k": 5, "ix": 5} + } + ] + } + ], + "ip": 31, + "op": 53, + "st": 3, + "bm": 0 + }, + { + "ddd": 0, + "ind": 8, + "ty": 4, + "nm": "top 2", + "parent": 5, + "sr": 1, + "ks": { + "o": {"a": 0, "k": 100, "ix": 11}, + "r": {"a": 0, "k": 0, "ix": 10}, + "p": {"a": 0, "k": [73.565, -23.785, 0], "ix": 2}, + "a": {"a": 0, "k": [1488.448, 1026.164, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100, 100], "ix": 6} + }, + "ao": 0, + "ef": [ + { + "ty": 5, + "nm": "ShapeNir Slider", + "np": 3, + "mn": "ADBE Slider Control", + "ix": 1, + "en": 1, + "ef": [ + { + "ty": 0, + "nm": "Slider", + "mn": "ADBE Slider Control-0001", + "ix": 1, + "v": {"a": 0, "k": 100, "ix": 1} + } + ] + } + ], + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": {"x": 0.17, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 58, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [-13.503, -13.506], + [0, 0], + [9.065, -9.068], + [0, 0], + [0, 0], + [9.068, 9.071], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [13.506, -13.506], + [0, 0], + [9.065, 9.068], + [0, 0], + [0, 0], + [-9.068, 9.074], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-61.716, -44.574], + [-57.525, -48.766], + [-21.582, -61.577], + [-24.345, -64.482], + [-24.342, -31.648], + [-24.342, -31.648], + [-24.342, -31.648], + [-57.186, -31.645], + [-65.907, -40.383], + [-61.716, -44.574] + ], + "c": false + } + ] + }, + { + "t": 64, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [-13.503, -13.506], + [0, 0], + [9.065, -9.068], + [0, 0], + [0, 0], + [9.068, 9.071], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [13.506, -13.506], + [0, 0], + [9.065, 9.068], + [0, 0], + [0, 0], + [-9.068, 9.074], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-74.672, -57.386], + [-70.481, -61.577], + [-21.582, -61.577], + [72.063, 32.066], + [72.066, 64.9], + [72.066, 64.9], + [72.066, 64.9], + [39.223, 64.903], + [-78.863, -53.195], + [-74.672, -57.386] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Tracciato 1_forAnimation", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": {"a": 0, "k": [0.211764708161, 0.568627476692, 1, 1], "ix": 4}, + "o": {"a": 0, "k": 100, "ix": 5}, + "r": 1, + "bm": 0, + "nm": "Riempimento 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": {"a": 0, "k": [1542.448, 1082.164], "ix": 2}, + "a": {"a": 0, "k": [0, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100], "ix": 3}, + "r": {"a": 0, "k": 0, "ix": 6}, + "o": {"a": 0, "k": 100, "ix": 7}, + "sk": {"a": 0, "k": 0, "ix": 4}, + "sa": {"a": 0, "k": 0, "ix": 5}, + "nm": "Transform" + } + ], + "nm": "Gruppo 3", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "tm", + "s": { + "a": 0, + "k": 0, + "ix": 1, + "x": "var $bm_rt;\nvar mN01 = 52.2496645130989;\nvar mN02 = 100;\nvar mN01Edt = 52.2496645130989;\nvar mN02Edt = 98.6485408913042;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosF = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosF[$bm_sub(i, 1)], mRatiosF[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;" + }, + "e": { + "a": 0, + "k": 100, + "ix": 2, + "x": "var $bm_rt;\nvar mN01 = 52.2496645130989;\nvar mN02 = 0;\nvar mN01Edt = 52.2496645130989;\nvar mN02Edt = 1.35145910869578;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosL = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosL[$bm_sub(i, 1)], mRatiosL[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;" + }, + "o": {"a": 0, "k": 0, "ix": 3}, + "m": 1, + "ix": 2, + "nm": "Taglia tracciati 1", + "mn": "ADBE Vector Filter - Trim", + "hd": false + }, + { + "ind": 2, + "ty": "sh", + "ix": 3, + "ks": { + "a": 1, + "k": [ + { + "i": {"x": 0.17, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 58, + "s": [ + { + "i": [ + [0, 0], + [5.418, 5.419], + [17.468, 17.469], + [25.537, -25.537] + ], + "o": [ + [-3.662, 6.731], + [0, 0], + [-25.536, -25.537], + [0, 0] + ], + "v": [ + [1518.105, 1050.515], + [1501.682, 1034.099], + [1545.158, 1077.713], + [1480.731, 1037.589] + ], + "c": false + } + ] + }, + { + "t": 64, + "s": [ + { + "i": [ + [0, 0], + [5.418, 5.419], + [17.468, 17.469], + [25.537, -25.537] + ], + "o": [ + [-3.662, 6.731], + [0, 0], + [-25.536, -25.537], + [0, 0] + ], + "v": [ + [1614.514, 1147.064], + [1598.091, 1130.648], + [1545.158, 1077.713], + [1467.776, 1024.778] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Tracciato 1_Bone", + "mn": "ADBE Vector Shape - Group", + "hd": false + } + ], + "ip": 53, + "op": 126, + "st": 6, + "bm": 0 + }, + { + "ddd": 0, + "ind": 9, + "ty": 4, + "nm": "top_extra", + "parent": 10, + "sr": 1, + "ks": { + "o": {"a": 0, "k": 100, "ix": 11}, + "r": {"a": 0, "k": 45, "ix": 10}, + "p": { + "a": 1, + "k": [ + { + "i": {"x": 0.833, "y": 0.833}, + "o": {"x": 0.167, "y": 0.167}, + "t": 29, + "s": [1502.093, 1035.094, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": {"x": 0.833, "y": 0.833}, + "o": {"x": 0.167, "y": 0.167}, + "t": 34, + "s": [1495.062, 1036.428, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": {"x": 0.833, "y": 0.833}, + "o": {"x": 0.167, "y": 0.167}, + "t": 51, + "s": [1495.062, 1036.428, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + {"t": 53, "s": [1502.312, 1036.428, 0]} + ], + "ix": 2 + }, + "a": {"a": 0, "k": [-98.5, -102, 0], "ix": 1}, + "s": { + "a": 1, + "k": [ + { + "i": {"x": [0.833, 0.833, 0.833], "y": [0.833, 0.833, 0.833]}, + "o": {"x": [0.167, 0.167, 0.167], "y": [0.167, 0.167, 0.167]}, + "t": 29, + "s": [46.5, 46.5, 100] + }, + { + "i": {"x": [0.833, 0.833, 0.833], "y": [0.833, 0.833, 0.833]}, + "o": {"x": [0.167, 0.167, 0.167], "y": [0.167, 0.167, 0.167]}, + "t": 32, + "s": [50, 50, 100] + }, + { + "i": {"x": [0.833, 0.833, 0.833], "y": [0.833, 0.833, 0.833]}, + "o": {"x": [0.167, 0.167, 0.167], "y": [0.167, 0.167, 0.167]}, + "t": 49, + "s": [50, 50, 100] + }, + {"t": 53, "s": [45.2, 45.2, 100]} + ], + "ix": 6 + } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "d": 1, + "ty": "el", + "s": {"a": 0, "k": [94, 94], "ix": 2}, + "p": {"a": 0, "k": [0, 0], "ix": 3}, + "nm": "Tracciato ellisse 1", + "mn": "ADBE Vector Shape - Ellipse", + "hd": false + }, + { + "ty": "fl", + "c": {"a": 0, "k": [0.211761474609, 0.568603515625, 1, 1], "ix": 4}, + "o": {"a": 0, "k": 100, "ix": 5}, + "r": 1, + "bm": 0, + "nm": "Riempimento 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": {"a": 0, "k": [-98.5, -102], "ix": 2}, + "a": {"a": 0, "k": [0, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100], "ix": 3}, + "r": {"a": 0, "k": 0, "ix": 6}, + "o": {"a": 0, "k": 100, "ix": 7}, + "sk": {"a": 0, "k": 0, "ix": 4}, + "sa": {"a": 0, "k": 0, "ix": 5}, + "nm": "Transform" + } + ], + "nm": "Ellisse 1", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 29, + "op": 53, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 10, + "ty": 4, + "nm": "top", + "parent": 5, + "sr": 1, + "ks": { + "o": {"a": 0, "k": 100, "ix": 11}, + "r": {"a": 0, "k": 0, "ix": 10}, + "p": {"a": 0, "k": [73.565, -23.785, 0], "ix": 2}, + "a": {"a": 0, "k": [1488.448, 1026.164, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100, 100], "ix": 6} + }, + "ao": 0, + "ef": [ + { + "ty": 5, + "nm": "ShapeNir Slider", + "np": 3, + "mn": "ADBE Slider Control", + "ix": 1, + "en": 1, + "ef": [ + { + "ty": 0, + "nm": "Slider", + "mn": "ADBE Slider Control-0001", + "ix": 1, + "v": { + "a": 1, + "k": [ + {"i": {"x": [0.17], "y": [1]}, "o": {"x": [0.55], "y": [0]}, "t": 6, "s": [0]}, + {"t": 23, "s": [100]} + ], + "ix": 1 + } + } + ] + } + ], + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": {"x": 0.17, "y": 1}, + "o": {"x": 0.55, "y": 0}, + "t": 6, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [-13.503, -13.506], + [0, 0], + [9.065, -9.068], + [0, 0], + [0, 0], + [9.068, 9.071], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [13.506, -13.506], + [0, 0], + [9.065, 9.068], + [0, 0], + [0, 0], + [-9.068, 9.074], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-74.672, -57.386], + [-70.481, -61.577], + [-21.582, -61.577], + [194.283, 154.505], + [194.286, 187.34], + [194.286, 187.34], + [194.286, 187.34], + [161.442, 187.343], + [-78.863, -53.195], + [-74.672, -57.386] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.833, "y": 0.833}, + "o": {"x": 0.55, "y": 0}, + "t": 23, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [-13.503, -13.506], + [0, 0], + [9.065, -9.068], + [0, 0], + [0, 0], + [9.068, 9.071], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [13.506, -13.506], + [0, 0], + [9.065, 9.068], + [0, 0], + [0, 0], + [-9.068, 9.074], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-74.672, -57.386], + [-70.481, -61.577], + [-21.582, -61.577], + [72.063, 32.066], + [72.066, 64.9], + [72.066, 64.9], + [72.066, 64.9], + [39.223, 64.903], + [-78.863, -53.195], + [-74.672, -57.386] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.833, "y": 1}, + "o": {"x": 0.167, "y": 0.167}, + "t": 26, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [-13.503, -13.506], + [0, 0], + [9.065, -9.068], + [0, 0], + [0, 0], + [9.068, 9.071], + [2.122, 2.171], + [0, 0] + ], + "o": [ + [0, 0], + [13.506, -13.506], + [0, 0], + [9.065, 9.068], + [0, 0], + [0, 0], + [-9.068, 9.074], + [0, 0], + [-2.122, -2.171], + [0, 0] + ], + "v": [ + [-70.801, -53.558], + [-66.61, -57.749], + [-21.582, -61.577], + [43.259, 3.22], + [43.262, 36.055], + [43.262, 36.055], + [43.262, 36.055], + [10.419, 36.058], + [-66.621, -43.95], + [-70.801, -53.558] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.833, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 29, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [-13.503, -13.506], + [0, 0], + [9.065, -9.068], + [0, 0], + [0, 0], + [9.068, 9.071], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [13.506, -13.506], + [0, 0], + [9.065, 9.068], + [0, 0], + [0, 0], + [-9.068, 9.074], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-61.716, -44.574], + [-57.525, -48.766], + [-21.582, -61.577], + [-24.345, -64.482], + [-24.342, -31.648], + [-24.342, -31.648], + [-24.342, -31.648], + [-57.186, -31.645], + [-65.907, -40.383], + [-61.716, -44.574] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.45, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 53, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [-13.503, -13.506], + [0, 0], + [9.065, -9.068], + [0, 0], + [0, 0], + [9.068, 9.071], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [13.506, -13.506], + [0, 0], + [9.065, 9.068], + [0, 0], + [0, 0], + [-9.068, 9.074], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-61.716, -44.574], + [-57.525, -48.766], + [-21.582, -61.577], + [-24.345, -64.482], + [-24.342, -31.648], + [-24.342, -31.648], + [-24.342, -31.648], + [-57.186, -31.645], + [-65.907, -40.383], + [-61.716, -44.574] + ], + "c": false + } + ] + }, + { + "t": 59, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [-13.503, -13.506], + [0, 0], + [9.065, -9.068], + [0, 0], + [0, 0], + [9.068, 9.071], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [13.506, -13.506], + [0, 0], + [9.065, 9.068], + [0, 0], + [0, 0], + [-9.068, 9.074], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-74.672, -57.386], + [-70.481, -61.577], + [-21.582, -61.577], + [72.063, 32.066], + [72.066, 64.9], + [72.066, 64.9], + [72.066, 64.9], + [39.223, 64.903], + [-78.863, -53.195], + [-74.672, -57.386] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Tracciato 1_forAnimation", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": {"a": 0, "k": [0.211764708161, 0.568627476692, 1, 1], "ix": 4}, + "o": {"a": 0, "k": 100, "ix": 5}, + "r": 1, + "bm": 0, + "nm": "Riempimento 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": {"a": 0, "k": [1542.448, 1082.164], "ix": 2}, + "a": {"a": 0, "k": [0, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100], "ix": 3}, + "r": {"a": 0, "k": 0, "ix": 6}, + "o": {"a": 0, "k": 100, "ix": 7}, + "sk": {"a": 0, "k": 0, "ix": 4}, + "sa": {"a": 0, "k": 0, "ix": 5}, + "nm": "Transform" + } + ], + "nm": "Gruppo 3", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "tm", + "s": { + "a": 0, + "k": 0, + "ix": 1, + "x": "var $bm_rt;\nvar mN01 = 52.2496645130989;\nvar mN02 = 100;\nvar mN01Edt = 52.2496645130989;\nvar mN02Edt = 98.6485408913042;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosF = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosF[$bm_sub(i, 1)], mRatiosF[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;" + }, + "e": { + "a": 0, + "k": 100, + "ix": 2, + "x": "var $bm_rt;\nvar mN01 = 52.2496645130989;\nvar mN02 = 0;\nvar mN01Edt = 52.2496645130989;\nvar mN02Edt = 1.35145910869578;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosL = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosL[$bm_sub(i, 1)], mRatiosL[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;" + }, + "o": {"a": 0, "k": 0, "ix": 3}, + "m": 1, + "ix": 2, + "nm": "Taglia tracciati 1", + "mn": "ADBE Vector Filter - Trim", + "hd": false + }, + { + "ind": 2, + "ty": "sh", + "ix": 3, + "ks": { + "a": 1, + "k": [ + { + "i": {"x": 0.17, "y": 1}, + "o": {"x": 0.55, "y": 0}, + "t": 6, + "s": [ + { + "i": [ + [0, 0], + [5.418, 5.419], + [17.468, 17.469], + [25.537, -25.537] + ], + "o": [ + [-3.662, 6.731], + [0, 0], + [-25.536, -25.537], + [0, 0] + ], + "v": [ + [1736.734, 1269.504], + [1720.31, 1253.088], + [1545.158, 1077.713], + [1467.776, 1024.778] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.833, "y": 1}, + "o": {"x": 0.55, "y": 0}, + "t": 23, + "s": [ + { + "i": [ + [0, 0], + [5.418, 5.419], + [17.468, 17.469], + [25.537, -25.537] + ], + "o": [ + [-3.662, 6.731], + [0, 0], + [-25.536, -25.537], + [0, 0] + ], + "v": [ + [1614.514, 1147.064], + [1598.091, 1130.648], + [1545.158, 1077.713], + [1467.776, 1024.778] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.833, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 29, + "s": [ + { + "i": [ + [0, 0], + [5.418, 5.419], + [17.468, 17.469], + [25.537, -25.537] + ], + "o": [ + [-3.662, 6.731], + [0, 0], + [-25.536, -25.537], + [0, 0] + ], + "v": [ + [1518.105, 1050.515], + [1501.682, 1034.099], + [1545.158, 1077.713], + [1480.731, 1037.589] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.45, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 53, + "s": [ + { + "i": [ + [0, 0], + [5.418, 5.419], + [17.468, 17.469], + [25.537, -25.537] + ], + "o": [ + [-3.662, 6.731], + [0, 0], + [-25.536, -25.537], + [0, 0] + ], + "v": [ + [1518.105, 1050.515], + [1501.682, 1034.099], + [1545.158, 1077.713], + [1480.731, 1037.589] + ], + "c": false + } + ] + }, + { + "t": 59, + "s": [ + { + "i": [ + [0, 0], + [5.418, 5.419], + [17.468, 17.469], + [25.537, -25.537] + ], + "o": [ + [-3.662, 6.731], + [0, 0], + [-25.536, -25.537], + [0, 0] + ], + "v": [ + [1614.514, 1147.064], + [1598.091, 1130.648], + [1545.158, 1077.713], + [1467.776, 1024.778] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Tracciato 1_Bone", + "mn": "ADBE Vector Shape - Group", + "hd": false + } + ], + "ip": 6, + "op": 29, + "st": 6, + "bm": 0 + }, + { + "ddd": 0, + "ind": 11, + "ty": 4, + "nm": "mid 2", + "parent": 5, + "sr": 1, + "ks": { + "o": {"a": 0, "k": 100, "ix": 11}, + "r": {"a": 0, "k": 0, "ix": 10}, + "p": {"a": 0, "k": [15, 16, 0], "ix": 2}, + "a": {"a": 0, "k": [1429.883, 1065.949, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100, 100], "ix": 6} + }, + "ao": 0, + "ef": [ + { + "ty": 5, + "nm": "ShapeNir Slider", + "np": 3, + "mn": "ADBE Slider Control", + "ix": 1, + "en": 1, + "ef": [ + { + "ty": 0, + "nm": "Slider", + "mn": "ADBE Slider Control-0001", + "ix": 1, + "v": {"a": 0, "k": 100, "ix": 1} + } + ] + } + ], + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": {"x": 0.45, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 55.5, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [0, 0], + [6.673, -6.673], + [0, 0], + [0, 0], + [6.673, 6.673], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [6.671, 6.673], + [0, 0], + [0, 0], + [-6.673, 6.671], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-30.953, -29.75], + [-18.872, -41.83], + [-9.362, -32.208], + [-9.362, -8.045], + [-9.362, -8.045], + [-9.362, -8.045], + [-33.522, -8.045], + [-43.033, -17.67], + [-30.953, -29.75] + ], + "c": false + } + ] + }, + { + "t": 61.5, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [0, 0], + [9.068, -9.068], + [0, 0], + [0, 0], + [9.068, 9.068], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [9.065, 9.068], + [0, 0], + [0, 0], + [-9.068, 9.065], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-36.143, -36.135], + [-19.727, -52.551], + [45.759, 12.917], + [45.759, 45.751], + [45.759, 45.751], + [45.759, 45.751], + [12.927, 45.751], + [-52.559, -19.719], + [-36.143, -36.135] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Tracciato 1_forAnimation", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": {"a": 0, "k": [0.223529413342, 0.223529413342, 1, 1], "ix": 4}, + "o": {"a": 0, "k": 100, "ix": 5}, + "r": 1, + "bm": 0, + "nm": "Riempimento 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": {"a": 0, "k": [1464.883, 1099.949], "ix": 2}, + "a": {"a": 0, "k": [0, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100], "ix": 3}, + "r": {"a": 0, "k": 0, "ix": 6}, + "o": {"a": 0, "k": 100, "ix": 7}, + "sk": {"a": 0, "k": 0, "ix": 4}, + "sa": {"a": 0, "k": 0, "ix": 5}, + "nm": "Transform" + } + ], + "nm": "Gruppo 2", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "tm", + "s": { + "a": 0, + "k": 0, + "ix": 1, + "x": "var $bm_rt;\nvar mN01 = 50.0000976522834;\nvar mN02 = 100;\nvar mN01Edt = 50.0000976522834;\nvar mN02Edt = 92.3777446239903;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosF = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosF[$bm_sub(i, 1)], mRatiosF[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;" + }, + "e": { + "a": 0, + "k": 100, + "ix": 2, + "x": "var $bm_rt;\nvar mN01 = 50.0000976522834;\nvar mN02 = 0;\nvar mN01Edt = 50.0000976522834;\nvar mN02Edt = 7.62225537600966;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosL = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosL[$bm_sub(i, 1)], mRatiosL[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;" + }, + "o": {"a": 0, "k": 0, "ix": 3}, + "m": 1, + "ix": 2, + "nm": "Taglia tracciati 1", + "mn": "ADBE Vector Filter - Trim", + "hd": false + }, + { + "ind": 2, + "ty": "sh", + "ix": 3, + "ks": { + "a": 1, + "k": [ + { + "i": {"x": 0.45, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 55.5, + "s": [ + { + "i": [ + [0, 0], + [11.939, 11.936], + [0, 0] + ], + "o": [ + [-0.527, -16.874], + [-7.951, -7.949], + [0, 0] + ], + "v": [ + [1455.522, 1091.904], + [1458.026, 1094.288], + [1433.931, 1070.199] + ], + "c": false + } + ] + }, + { + "t": 61.5, + "s": [ + { + "i": [ + [0, 0], + [16.224, 16.22], + [0, 0] + ], + "o": [ + [-0.717, -22.93], + [-10.805, -10.802], + [0, 0] + ], + "v": [ + [1510.642, 1145.701], + [1461.483, 1096.548], + [1428.74, 1063.814] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Tracciato 1_Bone", + "mn": "ADBE Vector Shape - Group", + "hd": false + } + ], + "ip": 53, + "op": 126, + "st": 3, + "bm": 0 + }, + { + "ddd": 0, + "ind": 12, + "ty": 4, + "nm": "mid_extra", + "parent": 13, + "sr": 1, + "ks": { + "o": {"a": 0, "k": 100, "ix": 11}, + "r": {"a": 0, "k": 45, "ix": 10}, + "p": { + "a": 1, + "k": [ + { + "i": {"x": 0.833, "y": 0.833}, + "o": {"x": 0.167, "y": 0.167}, + "t": 29, + "s": [1442.756, 1079.784, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": {"x": 0.833, "y": 0.833}, + "o": {"x": 0.167, "y": 0.167}, + "t": 34, + "s": [1450.145, 1086.357, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": {"x": 0.833, "y": 0.833}, + "o": {"x": 0.167, "y": 0.167}, + "t": 51, + "s": [1450.145, 1086.357, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + {"t": 53, "s": [1443.895, 1080.232, 0]} + ], + "ix": 2 + }, + "a": {"a": 0, "k": [-120, 40, 0], "ix": 1}, + "s": { + "a": 1, + "k": [ + { + "i": {"x": [0.833, 0.833, 0.833], "y": [0.833, 0.833, 0.833]}, + "o": {"x": [0.167, 0.167, 0.167], "y": [0.167, 0.167, 0.167]}, + "t": 29, + "s": [37.2, 37.2, 100] + }, + { + "i": {"x": [0.833, 0.833, 0.833], "y": [0.833, 0.833, 0.833]}, + "o": {"x": [0.167, 0.167, 0.167], "y": [0.167, 0.167, 0.167]}, + "t": 34, + "s": [50, 50, 100] + }, + { + "i": {"x": [0.833, 0.833, 0.833], "y": [0.833, 0.833, 0.833]}, + "o": {"x": [0.167, 0.167, 0.167], "y": [0.167, 0.167, 0.167]}, + "t": 49, + "s": [50, 50, 100] + }, + {"t": 53, "s": [35.7, 35.7, 100]} + ], + "ix": 6 + } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "d": 1, + "ty": "el", + "s": {"a": 0, "k": [93, 93], "ix": 2}, + "p": {"a": 0, "k": [0, 0], "ix": 3}, + "nm": "Tracciato ellisse 1", + "mn": "ADBE Vector Shape - Ellipse", + "hd": false + }, + { + "ty": "fl", + "c": {"a": 0, "k": [0.223510742188, 0.223510742188, 1, 1], "ix": 4}, + "o": {"a": 0, "k": 100, "ix": 5}, + "r": 1, + "bm": 0, + "nm": "Riempimento 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": {"a": 0, "k": [-120, 40], "ix": 2}, + "a": {"a": 0, "k": [0, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100], "ix": 3}, + "r": {"a": 0, "k": 0, "ix": 6}, + "o": {"a": 0, "k": 100, "ix": 7}, + "sk": {"a": 0, "k": 0, "ix": 4}, + "sa": {"a": 0, "k": 0, "ix": 5}, + "nm": "Transform" + } + ], + "nm": "Ellisse 1", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 29, + "op": 53, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 13, + "ty": 4, + "nm": "mid", + "parent": 5, + "sr": 1, + "ks": { + "o": {"a": 0, "k": 100, "ix": 11}, + "r": {"a": 0, "k": 0, "ix": 10}, + "p": {"a": 0, "k": [15, 16, 0], "ix": 2}, + "a": {"a": 0, "k": [1429.883, 1065.949, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100, 100], "ix": 6} + }, + "ao": 0, + "ef": [ + { + "ty": 5, + "nm": "ShapeNir Slider", + "np": 3, + "mn": "ADBE Slider Control", + "ix": 1, + "en": 1, + "ef": [ + { + "ty": 0, + "nm": "Slider", + "mn": "ADBE Slider Control-0001", + "ix": 1, + "v": { + "a": 1, + "k": [ + {"i": {"x": [0.17], "y": [1]}, "o": {"x": [0.55], "y": [0]}, "t": 3, "s": [0]}, + {"t": 23, "s": [100]} + ], + "ix": 1 + } + } + ] + } + ], + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": {"x": 0.17, "y": 1}, + "o": {"x": 0.55, "y": 0}, + "t": 3, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [0, 0], + [9.068, -9.068], + [0, 0], + [0, 0], + [9.068, 9.068], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [9.065, 9.068], + [0, 0], + [0, 0], + [-9.068, 9.065], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-36.143, -36.135], + [-19.727, -52.551], + [119.506, 86.956], + [119.506, 119.79], + [119.506, 119.79], + [119.506, 119.79], + [86.674, 119.79], + [-52.559, -19.719], + [-36.143, -36.135] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.833, "y": 1}, + "o": {"x": 0.55, "y": 0}, + "t": 23, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [0, 0], + [9.068, -9.068], + [0, 0], + [0, 0], + [9.068, 9.068], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [9.065, 9.068], + [0, 0], + [0, 0], + [-9.068, 9.065], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-36.143, -36.135], + [-19.727, -52.551], + [45.759, 12.917], + [45.759, 45.751], + [45.759, 45.751], + [45.759, 45.751], + [12.927, 45.751], + [-52.559, -19.719], + [-36.143, -36.135] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.833, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 29, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [0, 0], + [6.673, -6.673], + [0, 0], + [0, 0], + [6.673, 6.673], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [6.671, 6.673], + [0, 0], + [0, 0], + [-6.673, 6.671], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-30.953, -29.75], + [-18.872, -41.83], + [-9.362, -32.208], + [-9.362, -8.045], + [-9.362, -8.045], + [-9.362, -8.045], + [-33.522, -8.045], + [-43.033, -17.67], + [-30.953, -29.75] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.45, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 53, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [0, 0], + [6.673, -6.673], + [0, 0], + [0, 0], + [6.673, 6.673], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [6.671, 6.673], + [0, 0], + [0, 0], + [-6.673, 6.671], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-30.953, -29.75], + [-18.872, -41.83], + [-9.362, -32.208], + [-9.362, -8.045], + [-9.362, -8.045], + [-9.362, -8.045], + [-33.522, -8.045], + [-43.033, -17.67], + [-30.953, -29.75] + ], + "c": false + } + ] + }, + { + "t": 59, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [0, 0], + [9.068, -9.068], + [0, 0], + [0, 0], + [9.068, 9.068], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [9.065, 9.068], + [0, 0], + [0, 0], + [-9.068, 9.065], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [-36.143, -36.135], + [-19.727, -52.551], + [45.759, 12.917], + [45.759, 45.751], + [45.759, 45.751], + [45.759, 45.751], + [12.927, 45.751], + [-52.559, -19.719], + [-36.143, -36.135] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Tracciato 1_forAnimation", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": {"a": 0, "k": [0.223529413342, 0.223529413342, 1, 1], "ix": 4}, + "o": {"a": 0, "k": 100, "ix": 5}, + "r": 1, + "bm": 0, + "nm": "Riempimento 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": {"a": 0, "k": [1464.883, 1099.949], "ix": 2}, + "a": {"a": 0, "k": [0, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100], "ix": 3}, + "r": {"a": 0, "k": 0, "ix": 6}, + "o": {"a": 0, "k": 100, "ix": 7}, + "sk": {"a": 0, "k": 0, "ix": 4}, + "sa": {"a": 0, "k": 0, "ix": 5}, + "nm": "Transform" + } + ], + "nm": "Gruppo 2", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "tm", + "s": { + "a": 0, + "k": 0, + "ix": 1, + "x": "var $bm_rt;\nvar mN01 = 50.0000976522834;\nvar mN02 = 100;\nvar mN01Edt = 50.0000976522834;\nvar mN02Edt = 92.3777446239903;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosF = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosF[$bm_sub(i, 1)], mRatiosF[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;" + }, + "e": { + "a": 0, + "k": 100, + "ix": 2, + "x": "var $bm_rt;\nvar mN01 = 50.0000976522834;\nvar mN02 = 0;\nvar mN01Edt = 50.0000976522834;\nvar mN02Edt = 7.62225537600966;\nvar mRatiosM = [\n 0,\n 1\n ];\nvar mRatiosL = [\n 0,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosL[$bm_sub(i, 1)], mRatiosL[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;" + }, + "o": {"a": 0, "k": 0, "ix": 3}, + "m": 1, + "ix": 2, + "nm": "Taglia tracciati 1", + "mn": "ADBE Vector Filter - Trim", + "hd": false + }, + { + "ind": 2, + "ty": "sh", + "ix": 3, + "ks": { + "a": 1, + "k": [ + { + "i": {"x": 0.17, "y": 1}, + "o": {"x": 0.55, "y": 0}, + "t": 3, + "s": [ + { + "i": [ + [0, 0], + [16.224, 16.22], + [0, 0] + ], + "o": [ + [-0.717, -22.93], + [-10.805, -10.802], + [0, 0] + ], + "v": [ + [1584.389, 1219.739], + [1461.483, 1096.548], + [1428.74, 1063.814] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.833, "y": 1}, + "o": {"x": 0.55, "y": 0}, + "t": 23, + "s": [ + { + "i": [ + [0, 0], + [16.224, 16.22], + [0, 0] + ], + "o": [ + [-0.717, -22.93], + [-10.805, -10.802], + [0, 0] + ], + "v": [ + [1510.642, 1145.701], + [1461.483, 1096.548], + [1428.74, 1063.814] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.833, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 29, + "s": [ + { + "i": [ + [0, 0], + [11.939, 11.936], + [0, 0] + ], + "o": [ + [-0.527, -16.874], + [-7.951, -7.949], + [0, 0] + ], + "v": [ + [1455.522, 1091.904], + [1458.026, 1094.288], + [1433.931, 1070.199] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.45, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 53, + "s": [ + { + "i": [ + [0, 0], + [11.939, 11.936], + [0, 0] + ], + "o": [ + [-0.527, -16.874], + [-7.951, -7.949], + [0, 0] + ], + "v": [ + [1455.522, 1091.904], + [1458.026, 1094.288], + [1433.931, 1070.199] + ], + "c": false + } + ] + }, + { + "t": 59, + "s": [ + { + "i": [ + [0, 0], + [16.224, 16.22], + [0, 0] + ], + "o": [ + [-0.717, -22.93], + [-10.805, -10.802], + [0, 0] + ], + "v": [ + [1510.642, 1145.701], + [1461.483, 1096.548], + [1428.74, 1063.814] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Tracciato 1_Bone", + "mn": "ADBE Vector Shape - Group", + "hd": false + } + ], + "ip": 3, + "op": 29, + "st": 3, + "bm": 0 + }, + { + "ddd": 0, + "ind": 14, + "ty": 4, + "nm": "bottom 2", + "parent": 5, + "sr": 1, + "ks": { + "o": {"a": 0, "k": 100, "ix": 11}, + "r": {"a": 0, "k": 0, "ix": 10}, + "p": {"a": 0, "k": [-2.559, 65.635, 0], "ix": 2}, + "a": {"a": 0, "k": [1412.324, 1115.584, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100, 100], "ix": 6} + }, + "ao": 0, + "ef": [ + { + "ty": 5, + "nm": "ShapeNir Slider", + "np": 3, + "mn": "ADBE Slider Control", + "ix": 1, + "en": 1, + "ef": [ + { + "ty": 0, + "nm": "Slider", + "mn": "ADBE Slider Control-0001", + "ix": 1, + "v": {"a": 0, "k": 100, "ix": 1} + } + ] + } + ], + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": {"x": 0.45, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 53, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [0, 0], + [6.334, 6.334], + [-6.333, 6.334], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [-6.334, 6.333], + [-6.334, -6.334], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [6.738, -2.735], + [18.731, 9.258], + [7.38, 20.609], + [-16.081, 20.083], + [-16.606, -3.378], + [-5.255, -14.728], + [6.738, -2.735] + ], + "c": false + } + ] + }, + { + "t": 59, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [0, 0], + [9.068, 9.068], + [-9.068, 9.068], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [-9.068, 9.068], + [-9.068, -9.068], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [11.444, -11.445], + [28.615, 5.726], + [12.364, 21.977], + [-21.225, 21.225], + [-21.977, -12.364], + [-5.726, -28.615], + [11.444, -11.445] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Tracciato 1_forAnimation", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": {"a": 0, "k": [0.337254911661, 0.223529413342, 1, 1], "ix": 4}, + "o": {"a": 0, "k": 100, "ix": 5}, + "r": 1, + "bm": 0, + "nm": "Riempimento 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": {"a": 0, "k": [1399.865, 1127.029], "ix": 2}, + "a": {"a": 0, "k": [0, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100], "ix": 3}, + "r": {"a": 0, "k": 0, "ix": 6}, + "o": {"a": 0, "k": 100, "ix": 7}, + "sk": {"a": 0, "k": 0, "ix": 4}, + "sa": {"a": 0, "k": 0, "ix": 5}, + "nm": "Transform" + } + ], + "nm": "Gruppo 1", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "tm", + "s": { + "a": 0, + "k": 0, + "ix": 1, + "x": "var $bm_rt;\nvar mN01 = 50.0000191622908;\nvar mN02 = 100;\nvar mN01Edt = 50.0000191622908;\nvar mN02Edt = 85.6245824308121;\nvar mRatiosM = [\n 0,\n 0.1472024328579,\n 0.50257634091374,\n 1\n ];\nvar mRatiosF = [\n 0,\n 0.31314999326651,\n 0.62416910908086,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosF[$bm_sub(i, 1)], mRatiosF[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;" + }, + "e": { + "a": 0, + "k": 100, + "ix": 2, + "x": "var $bm_rt;\nvar mN01 = 50.0000191622908;\nvar mN02 = 0;\nvar mN01Edt = 50.0000191622908;\nvar mN02Edt = 14.3754175691879;\nvar mRatiosM = [\n 0,\n 0.1472024328579,\n 0.50257634091374,\n 1\n ];\nvar mRatiosL = [\n 0,\n 0.31314966173997,\n 0.62416844828369,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosL[$bm_sub(i, 1)], mRatiosL[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;" + }, + "o": {"a": 0, "k": 0, "ix": 3}, + "m": 1, + "ix": 2, + "nm": "Taglia tracciati 1", + "mn": "ADBE Vector Filter - Trim", + "hd": false + }, + { + "ind": 2, + "ty": "sh", + "ix": 3, + "ks": { + "a": 1, + "k": [ + { + "i": {"x": 0.45, "y": 1}, + "o": {"x": 0.167, "y": 0}, + "t": 53, + "s": [ + { + "i": [ + [0, 0], + [-1.108, 1.108], + [-2.676, 2.676], + [-1.873, 1.873], + [0, 0] + ], + "o": [ + [0, 0], + [2.676, -2.676], + [0, 0], + [1.873, -1.873], + [0, 0] + ], + "v": [ + [1383.785, 1147.112], + [1387.144, 1143.753], + [1395.253, 1135.644], + [1400.928, 1129.969], + [1406.603, 1124.294] + ], + "c": false + } + ] + }, + { + "t": 59, + "s": [ + { + "i": [ + [0, 0], + [-1.587, 1.587], + [-3.831, 3.831], + [-2.681, 2.681], + [0, 0] + ], + "o": [ + [0, 0], + [3.831, -3.831], + [0, 0], + [2.681, -2.681], + [0, 0] + ], + "v": [ + [1378.641, 1148.253], + [1383.45, 1143.444], + [1395.059, 1131.835], + [1403.185, 1123.709], + [1411.31, 1115.584] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Tracciato 1_Bone", + "mn": "ADBE Vector Shape - Group", + "hd": false + } + ], + "ip": 53, + "op": 126, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 15, + "ty": 4, + "nm": "bottom_extra", + "parent": 16, + "sr": 1, + "ks": { + "o": {"a": 0, "k": 100, "ix": 11}, + "r": {"a": 0, "k": 45, "ix": 10}, + "p": { + "a": 1, + "k": [ + { + "i": {"x": 0.833, "y": 0.833}, + "o": {"x": 0.167, "y": 0.167}, + "t": 29, + "s": [1395.693, 1135.648, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": {"x": 0.833, "y": 0.833}, + "o": {"x": 0.167, "y": 0.167}, + "t": 34, + "s": [1398.671, 1131.534, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + { + "i": {"x": 0.833, "y": 0.833}, + "o": {"x": 0.167, "y": 0.167}, + "t": 51, + "s": [1398.671, 1131.534, 0], + "to": [0, 0, 0], + "ti": [0, 0, 0] + }, + {"t": 53, "s": [1396.171, 1134.409, 0]} + ], + "ix": 2 + }, + "a": {"a": 0, "k": [-114, 181, 0], "ix": 1}, + "s": { + "a": 1, + "k": [ + { + "i": {"x": [0.833, 0.833, 0.833], "y": [0.833, 0.833, 0.833]}, + "o": {"x": [0.167, 0.167, 0.167], "y": [0.167, 0.167, 0.167]}, + "t": 29, + "s": [38.5, 38.5, 100] + }, + { + "i": {"x": [0.833, 0.833, 0.833], "y": [0.833, 0.833, 0.833]}, + "o": {"x": [0.167, 0.167, 0.167], "y": [0.167, 0.167, 0.167]}, + "t": 34, + "s": [50, 50, 100] + }, + { + "i": {"x": [0.833, 0.833, 0.833], "y": [0.833, 0.833, 0.833]}, + "o": {"x": [0.167, 0.167, 0.167], "y": [0.167, 0.167, 0.167]}, + "t": 49, + "s": [50, 50, 100] + }, + {"t": 53, "s": [37, 37, 100]} + ], + "ix": 6 + } + }, + "ao": 0, + "shapes": [ + { + "ty": "gr", + "it": [ + { + "d": 1, + "ty": "el", + "s": {"a": 0, "k": [91, 91], "ix": 2}, + "p": {"a": 0, "k": [0, 0], "ix": 3}, + "nm": "Tracciato ellisse 1", + "mn": "ADBE Vector Shape - Ellipse", + "hd": false + }, + { + "ty": "fl", + "c": {"a": 0, "k": [0.337249755859, 0.223510742188, 1, 1], "ix": 4}, + "o": {"a": 0, "k": 100, "ix": 5}, + "r": 1, + "bm": 0, + "nm": "Riempimento 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": {"a": 0, "k": [-114, 181], "ix": 2}, + "a": {"a": 0, "k": [0, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100], "ix": 3}, + "r": {"a": 0, "k": 0, "ix": 6}, + "o": {"a": 0, "k": 100, "ix": 7}, + "sk": {"a": 0, "k": 0, "ix": 4}, + "sa": {"a": 0, "k": 0, "ix": 5}, + "nm": "Transform" + } + ], + "nm": "Ellisse 1", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + } + ], + "ip": 29, + "op": 53, + "st": 0, + "bm": 0 + }, + { + "ddd": 0, + "ind": 16, + "ty": 4, + "nm": "bottom", + "parent": 5, + "sr": 1, + "ks": { + "o": {"a": 0, "k": 100, "ix": 11}, + "r": {"a": 0, "k": 0, "ix": 10}, + "p": {"a": 0, "k": [-2.559, 65.635, 0], "ix": 2}, + "a": {"a": 0, "k": [1412.324, 1115.584, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100, 100], "ix": 6} + }, + "ao": 0, + "ef": [ + { + "ty": 5, + "nm": "ShapeNir Slider", + "np": 3, + "mn": "ADBE Slider Control", + "ix": 1, + "en": 1, + "ef": [ + { + "ty": 0, + "nm": "Slider", + "mn": "ADBE Slider Control-0001", + "ix": 1, + "v": { + "a": 1, + "k": [ + {"i": {"x": [0.17], "y": [1]}, "o": {"x": [0.55], "y": [0]}, "t": 0, "s": [0]}, + {"t": 23, "s": [100]} + ], + "ix": 1 + } + } + ] + } + ], + "shapes": [ + { + "ty": "gr", + "it": [ + { + "ind": 0, + "ty": "sh", + "ix": 1, + "ks": { + "a": 1, + "k": [ + { + "i": {"x": 0.17, "y": 1}, + "o": {"x": 0.55, "y": 0}, + "t": 0, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [0, 0], + [9.068, 9.068], + [-9.068, 9.068], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [-9.068, 9.068], + [-9.068, -9.068], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [11.444, -11.445], + [28.615, 5.726], + [-95.63, 130.357], + [-129.219, 129.605], + [-129.971, 96.016], + [-5.726, -28.615], + [11.444, -11.445] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.833, "y": 0.833}, + "o": {"x": 0.55, "y": 0}, + "t": 23, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [0, 0], + [9.068, 9.068], + [-9.068, 9.068], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [-9.068, 9.068], + [-9.068, -9.068], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [11.444, -11.445], + [28.615, 5.726], + [12.364, 21.977], + [-21.225, 21.225], + [-21.977, -12.364], + [-5.726, -28.615], + [11.444, -11.445] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.833, "y": 1}, + "o": {"x": 0.167, "y": 0.167}, + "t": 28, + "s": [ + { + "i": [ + [-3.749, -3.55], + [1.525, -6.804], + [0, 0], + [6.838, 6.838], + [-6.838, 6.838], + [-5.985, 0.184], + [0, 0] + ], + "o": [ + [3.749, 3.55], + [-1.525, 6.804], + [-6.838, 6.838], + [-6.838, -6.838], + [0, 0], + [5.985, -0.184], + [0, 0] + ], + "v": [ + [12.19, -8.82], + [20.555, 8.606], + [8.3, 20.861], + [-17.03, 20.294], + [-17.597, -5.036], + [-5.342, -17.291], + [12.19, -8.82] + ], + "c": false + } + ] + }, + { + "t": 29, + "s": [ + { + "i": [ + [0, 0], + [0, 0], + [0, 0], + [6.334, 6.334], + [-6.333, 6.334], + [0, 0], + [0, 0] + ], + "o": [ + [0, 0], + [0, 0], + [-6.334, 6.333], + [-6.334, -6.334], + [0, 0], + [0, 0], + [0, 0] + ], + "v": [ + [6.738, -2.735], + [18.731, 9.258], + [7.38, 20.609], + [-16.081, 20.083], + [-16.606, -3.378], + [-5.255, -14.728], + [6.738, -2.735] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Tracciato 1_forAnimation", + "mn": "ADBE Vector Shape - Group", + "hd": false + }, + { + "ty": "fl", + "c": {"a": 0, "k": [0.337254911661, 0.223529413342, 1, 1], "ix": 4}, + "o": {"a": 0, "k": 100, "ix": 5}, + "r": 1, + "bm": 0, + "nm": "Riempimento 1", + "mn": "ADBE Vector Graphic - Fill", + "hd": false + }, + { + "ty": "tr", + "p": {"a": 0, "k": [1399.865, 1127.029], "ix": 2}, + "a": {"a": 0, "k": [0, 0], "ix": 1}, + "s": {"a": 0, "k": [100, 100], "ix": 3}, + "r": {"a": 0, "k": 0, "ix": 6}, + "o": {"a": 0, "k": 100, "ix": 7}, + "sk": {"a": 0, "k": 0, "ix": 4}, + "sa": {"a": 0, "k": 0, "ix": 5}, + "nm": "Transform" + } + ], + "nm": "Gruppo 1", + "np": 3, + "cix": 2, + "bm": 0, + "ix": 1, + "mn": "ADBE Vector Group", + "hd": false + }, + { + "ty": "tm", + "s": { + "a": 0, + "k": 0, + "ix": 1, + "x": "var $bm_rt;\nvar mN01 = 50.0000191622908;\nvar mN02 = 100;\nvar mN01Edt = 50.0000191622908;\nvar mN02Edt = 85.6245824308121;\nvar mRatiosM = [\n 0,\n 0.1472024328579,\n 0.50257634091374,\n 1\n ];\nvar mRatiosF = [\n 0,\n 0.31314999326651,\n 0.62416910908086,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosF[$bm_sub(i, 1)], mRatiosF[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;" + }, + "e": { + "a": 0, + "k": 100, + "ix": 2, + "x": "var $bm_rt;\nvar mN01 = 50.0000191622908;\nvar mN02 = 0;\nvar mN01Edt = 50.0000191622908;\nvar mN02Edt = 14.3754175691879;\nvar mRatiosM = [\n 0,\n 0.1472024328579,\n 0.50257634091374,\n 1\n ];\nvar mRatiosL = [\n 0,\n 0.31314966173997,\n 0.62416844828369,\n 1\n ];\nfunction mLinear(aInput, aInNumF, aInNumL, aOutNumF, aOutNumL) {\n var mInputLgt = $bm_sub(aInNumL, aInNumF);\n var mOutputLgt = $bm_sub(aOutNumL, aOutNumF);\n var mRatio = $bm_div(mOutputLgt, mInputLgt);\n if (aInNumF <= aInput && aInput <= aInNumL) {\n var mOutput = $bm_sum($bm_mul($bm_sub(aInput, aInNumF), mRatio), aOutNumF);\n } else {\n var mOutput = aInput;\n }\n return mOutput;\n}\nvar mSld = $bm_div(thisLayer('ADBE Effect Parade')('ShapeNir Slider')('ADBE Slider Control-0001'), 100);\nif (mSld <= 0) {\n var mRst = mN01;\n} else if (mSld >= 1) {\n var mRst = mN02;\n} else {\n for (var i = 1; i < mRatiosM.length; i++) {\n if (mRatiosM[i - 1] <= mSld && mSld < mRatiosM[i]) {\n var mCtl = mLinear(mSld, mRatiosM[$bm_sub(i, 1)], mRatiosM[i], mRatiosL[$bm_sub(i, 1)], mRatiosL[i]);\n break;\n }\n }\n var mRst = mLinear(mCtl, 0, 1, mN01Edt, mN02Edt);\n}\n$bm_rt = mRst;" + }, + "o": {"a": 0, "k": 0, "ix": 3}, + "m": 1, + "ix": 2, + "nm": "Taglia tracciati 1", + "mn": "ADBE Vector Filter - Trim", + "hd": false + }, + { + "ind": 2, + "ty": "sh", + "ix": 3, + "ks": { + "a": 1, + "k": [ + { + "i": {"x": 0.17, "y": 1}, + "o": {"x": 0.55, "y": 0}, + "t": 0, + "s": [ + { + "i": [ + [0, 0], + [-1.587, 1.587], + [-3.831, 3.831], + [-2.681, 2.681], + [0, 0] + ], + "o": [ + [0, 0], + [3.831, -3.831], + [0, 0], + [2.681, -2.681], + [0, 0] + ], + "v": [ + [1270.646, 1256.634], + [1275.455, 1251.825], + [1287.065, 1240.215], + [1403.185, 1123.709], + [1411.31, 1115.584] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.833, "y": 0.833}, + "o": {"x": 0.55, "y": 0}, + "t": 23, + "s": [ + { + "i": [ + [0, 0], + [-1.587, 1.587], + [-3.831, 3.831], + [-2.681, 2.681], + [0, 0] + ], + "o": [ + [0, 0], + [3.831, -3.831], + [0, 0], + [2.681, -2.681], + [0, 0] + ], + "v": [ + [1378.641, 1148.253], + [1383.45, 1143.444], + [1395.059, 1131.835], + [1403.185, 1123.709], + [1411.31, 1115.584] + ], + "c": false + } + ] + }, + { + "i": {"x": 0.833, "y": 1}, + "o": {"x": 0.167, "y": 0.167}, + "t": 28, + "s": [ + { + "i": [ + [0, 0], + [-1.197, 1.197], + [-2.889, 2.889], + [-2.022, 2.022], + [0, 0] + ], + "o": [ + [0, 0], + [2.889, -2.889], + [0, 0], + [2.022, -2.022], + [0, 0] + ], + "v": [ + [1382.835, 1147.323], + [1386.462, 1143.696], + [1395.217, 1134.941], + [1401.345, 1128.813], + [1412.057, 1118.207] + ], + "c": false + } + ] + }, + { + "t": 29, + "s": [ + { + "i": [ + [0, 0], + [-1.108, 1.108], + [-2.676, 2.676], + [-1.873, 1.873], + [0, 0] + ], + "o": [ + [0, 0], + [2.676, -2.676], + [0, 0], + [1.873, -1.873], + [0, 0] + ], + "v": [ + [1383.785, 1147.112], + [1387.144, 1143.753], + [1395.253, 1135.644], + [1400.928, 1129.969], + [1406.603, 1124.294] + ], + "c": false + } + ] + } + ], + "ix": 2 + }, + "nm": "Tracciato 1_Bone", + "mn": "ADBE Vector Shape - Group", + "hd": false + } + ], + "ip": 0, + "op": 29, + "st": 0, + "bm": 0 + } + ], + "markers": [] +} diff --git a/src/assets/wav-worker.js b/src/assets/wav-worker.js index 85948edd13..9f0f1651ec 100644 --- a/src/assets/wav-worker.js +++ b/src/assets/wav-worker.js @@ -72,4 +72,4 @@ onmessage = function (e) { } else if (e.data[0] === 'close') { self.close(); } -}; \ No newline at end of file +}; diff --git a/src/environments/environment.prod.ts b/src/environments/environment.prod.ts index 3612073bc3..c9669790be 100644 --- a/src/environments/environment.prod.ts +++ b/src/environments/environment.prod.ts @@ -1,3 +1,3 @@ export const environment = { - production: true + production: true, }; diff --git a/src/environments/environment.ts b/src/environments/environment.ts index 72cd63978b..85db3caf2d 100644 --- a/src/environments/environment.ts +++ b/src/environments/environment.ts @@ -3,7 +3,7 @@ // The list of file replacements can be found in `angular.json`. export const environment = { - production: false + production: false, }; /* diff --git a/src/i18n/resources-locale_default.js b/src/i18n/resources-locale_default.js index 40adeca3f1..02afa75d4b 100644 --- a/src/i18n/resources-locale_default.js +++ b/src/i18n/resources-locale_default.js @@ -1,4 +1,4 @@ [ - { "key":"_Home_", "value":"Home" }, - { "key":"_User_", "value":"User" } -] + {'key': '_Home_', 'value': 'Home'}, + {'key': '_User_', 'value': 'User'}, +]; diff --git a/src/i18n/resources-locale_en-AU.js b/src/i18n/resources-locale_en-AU.js index 6a2a83110e..02afa75d4b 100644 --- a/src/i18n/resources-locale_en-AU.js +++ b/src/i18n/resources-locale_en-AU.js @@ -1,4 +1,4 @@ [ - { "key":"_Home_", "value":"Home" }, - { "key":"_User_", "value":"User" } -] + {'key': '_Home_', 'value': 'Home'}, + {'key': '_User_', 'value': 'User'}, +]; diff --git a/src/i18n/resources-locale_en-GB.js b/src/i18n/resources-locale_en-GB.js index 40adeca3f1..02afa75d4b 100644 --- a/src/i18n/resources-locale_en-GB.js +++ b/src/i18n/resources-locale_en-GB.js @@ -1,4 +1,4 @@ [ - { "key":"_Home_", "value":"Home" }, - { "key":"_User_", "value":"User" } -] + {'key': '_Home_', 'value': 'Home'}, + {'key': '_User_', 'value': 'User'}, +]; diff --git a/src/i18n/resources-locale_en-US.js b/src/i18n/resources-locale_en-US.js index 40adeca3f1..02afa75d4b 100644 --- a/src/i18n/resources-locale_en-US.js +++ b/src/i18n/resources-locale_en-US.js @@ -1,4 +1,4 @@ [ - { "key":"_Home_", "value":"Home" }, - { "key":"_User_", "value":"User" } -] + {'key': '_Home_', 'value': 'Home'}, + {'key': '_User_', 'value': 'User'}, +]; diff --git a/src/main.ts b/src/main.ts index 75742be059..65f4e67189 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,6 +1,5 @@ import {enableProdMode, provideZoneChangeDetection} from '@angular/core'; import {platformBrowserDynamic} from '@angular/platform-browser-dynamic'; - import {environment} from 'src/environments/environment'; import {DoubtfireAngularModule} from './app/doubtfire-angular.module'; diff --git a/src/polyfills.ts b/src/polyfills.ts index b602050f34..c5f35359ae 100644 --- a/src/polyfills.ts +++ b/src/polyfills.ts @@ -19,7 +19,7 @@ * Zone JS is required by default for Angular itself. */ import 'zone.js'; // Included with Angular CLI. -(window as any).global = window; +window.global = globalThis; /*************************************************************************************************** * APPLICATION IMPORTS diff --git a/src/styles/common/doubtfire-cards.scss b/src/styles/common/doubtfire-cards.scss index 6646ba5a2c..a2edcc816f 100644 --- a/src/styles/common/doubtfire-cards.scss +++ b/src/styles/common/doubtfire-cards.scss @@ -1,4 +1,3 @@ - @mixin doubtfire-card { border-radius: 10px; } diff --git a/src/styles/common/extensions/col-xl.scss b/src/styles/common/extensions/col-xl.scss index 2b1c99052e..e7cee6aff7 100644 --- a/src/styles/common/extensions/col-xl.scss +++ b/src/styles/common/extensions/col-xl.scss @@ -1,11 +1,11 @@ // From https://gist.github.com/juukie/d71133e69877b46f060e -$screen-xl: 1560px !default; -$screen-xl-min: $screen-xl !default; -$screen-xl-desktop: $screen-xl-min !default; -$screen-lg-max: ($screen-xl-min - 1) !default; -$container-xlarge-desktop: (1530px + $grid-gutter-width) !default; -$container-xl: $container-xlarge-desktop !default; +$screen-xl: 1560px !default; +$screen-xl-min: $screen-xl !default; +$screen-xl-desktop: $screen-xl-min !default; +$screen-lg-max: ($screen-xl-min - 1) !default; +$container-xlarge-desktop: (1530px + $grid-gutter-width) !default; +$container-xl: $container-xlarge-desktop !default; .container { // @include container-fixed; No need for, already done. @@ -26,7 +26,7 @@ $container-xl: $container-xlarge-desktop !default; @mixin make-xl-column($columns, $gutter: $grid-gutter-width) { position: relative; min-height: 1px; - padding-left: ($gutter / 2); + padding-left: ($gutter / 2); padding-right: ($gutter / 2); @media (min-width: $screen-xl-min) { @@ -50,16 +50,16 @@ $container-xl: $container-xlarge-desktop !default; } } -@mixin make-grid-columns($i: 1, $list: ".col-xl-#{$i}") { +@mixin make-grid-columns($i: 1, $list: '.col-xl-#{$i}') { @for $i from (1 + 1) through $grid-columns { - $list: "#{$list}, .col-xl-#{$i}"; + $list: '#{$list}, .col-xl-#{$i}'; } #{$list} { position: relative; // Prevent columns from collapsing when empty min-height: 1px; // Inner gutter via padding - padding-left: ($grid-gutter-width / 2); + padding-left: ($grid-gutter-width / 2); padding-right: ($grid-gutter-width / 2); } } diff --git a/src/styles/common/extensions/fa-document-o.scss b/src/styles/common/extensions/fa-document-o.scss index 3427b08681..62c97e0d4d 100644 --- a/src/styles/common/extensions/fa-document-o.scss +++ b/src/styles/common/extensions/fa-document-o.scss @@ -1,2 +1,4 @@ // Alias for .fa-file-pdf-o -.#{$fa-css-prefix}-file-document-o:before { content: $fa-var-file-pdf-o; } +.#{$fa-css-prefix}-file-document-o:before { + content: $fa-var-file-pdf-o; +} diff --git a/src/styles/common/extensions/panel-footer-toolbar.scss b/src/styles/common/extensions/panel-footer-toolbar.scss index 325dc960c8..dd6ffaa97d 100644 --- a/src/styles/common/extensions/panel-footer-toolbar.scss +++ b/src/styles/common/extensions/panel-footer-toolbar.scss @@ -1,37 +1,29 @@ -.panel .panel-footer -{ +.panel .panel-footer { // With buttons in a small screen - @media (max-width: $screen-sm) - { + @media (max-width: $screen-sm) { // Increase tapping area - & > * - { + & > * { width: 100%; } .btn-group, .btn, - input - { + input { height: 4em; width: 100%; } - .btn - { + .btn { margin-top: 1em; } - ul.pagination - { + ul.pagination { margin-top: 1em; width: 100%; flex: 1; display: flex; overflow: auto; - li - { + li { flex: 1; } - li > a - { + li > a { width: 100%; height: 4em; display: flex; diff --git a/src/styles/common/extensions/panel-heading-toolbar.scss b/src/styles/common/extensions/panel-heading-toolbar.scss index d3a2e6621c..cc8d10e8d2 100644 --- a/src/styles/common/extensions/panel-heading-toolbar.scss +++ b/src/styles/common/extensions/panel-heading-toolbar.scss @@ -6,7 +6,9 @@ & > * { width: 100%; } - .btn-group, .btn, input { + .btn-group, + .btn, + input { height: 4em; width: 100%; } @@ -17,7 +19,8 @@ width: 100%; text-align: left; } - .btn-group, .buttons > .btn { + .btn-group, + .buttons > .btn { @media (min-width: $screen-sm-max) { margin-right: 1ex; } @@ -33,7 +36,7 @@ float: right; clear: both; .btn { - flex: 1 + flex: 1; } .btn { @include flex-center; @@ -41,7 +44,7 @@ } } } - form[role="search"] { + form[role='search'] { float: right; margin-right: 1.5ex; @media (max-width: $screen-sm) { diff --git a/src/styles/common/extensions/pointer.scss b/src/styles/common/extensions/pointer.scss index 88a143e2c3..0840082215 100644 --- a/src/styles/common/extensions/pointer.scss +++ b/src/styles/common/extensions/pointer.scss @@ -1,6 +1,7 @@ // // All anchors are pointers, as well as anything with the .pointer class // -a, .pointer { +a, +.pointer { cursor: pointer; } diff --git a/src/styles/common/five-cols.scss b/src/styles/common/five-cols.scss index 8ce22d31a0..de94a27e74 100644 --- a/src/styles/common/five-cols.scss +++ b/src/styles/common/five-cols.scss @@ -1,25 +1,25 @@ .col-xs-15 { - width: 20%; - float: left; + width: 20%; + float: left; } @media (min-width: 768px) { -.col-sm-15 { - width: 20%; - float: left; - } + .col-sm-15 { + width: 20%; + float: left; + } } @media (min-width: 992px) { - .col-md-15 { - width: 20%; - float: left; - } + .col-md-15 { + width: 20%; + float: left; + } } @media (min-width: 1200px) { - .col-lg-15 { - width: 20%; - float: left; - } -} \ No newline at end of file + .col-lg-15 { + width: 20%; + float: left; + } +} diff --git a/src/styles/common/grade-colors.scss b/src/styles/common/grade-colors.scss index 84fccae215..45e498c0eb 100644 --- a/src/styles/common/grade-colors.scss +++ b/src/styles/common/grade-colors.scss @@ -9,7 +9,7 @@ // ******************************************************** // -$grade-color-p: color.adjust(#FF0000, $lightness: -10%); -$grade-color-c: color.adjust(#FF8000, $lightness: -5%); -$grade-color-d: color.adjust(#0080FF, $lightness: -10%); -$grade-color-hd: color.adjust(#80FF00, $lightness: -15%); +$grade-color-p: color.adjust(#ff0000, $lightness: -10%); +$grade-color-c: color.adjust(#ff8000, $lightness: -5%); +$grade-color-d: color.adjust(#0080ff, $lightness: -10%); +$grade-color-hd: color.adjust(#80ff00, $lightness: -15%); diff --git a/src/styles/common/hero-sidebar-layout.scss b/src/styles/common/hero-sidebar-layout.scss index aa5f6ac4fc..ce68a9efd7 100644 --- a/src/styles/common/hero-sidebar-layout.scss +++ b/src/styles/common/hero-sidebar-layout.scss @@ -77,7 +77,7 @@ f-welcome .content-container { .sidebar { display: none; /* Hide the element */ } - .wordmark{ + .wordmark { display: flex; /* Show the element */ } } diff --git a/src/styles/common/overrides/header-overrides.scss b/src/styles/common/overrides/header-overrides.scss index 970bfd5e06..cb4237edfc 100644 --- a/src/styles/common/overrides/header-overrides.scss +++ b/src/styles/common/overrides/header-overrides.scss @@ -2,6 +2,11 @@ // Sets all font weights to the headers as 400 // -h1, h2, h3, h4, h5, h6 { +h1, +h2, +h3, +h4, +h5, +h6 { font-weight: 400; } diff --git a/src/styles/common/overrides/panel-overrides.scss b/src/styles/common/overrides/panel-overrides.scss index 43c1472658..f1ed83d293 100644 --- a/src/styles/common/overrides/panel-overrides.scss +++ b/src/styles/common/overrides/panel-overrides.scss @@ -3,11 +3,13 @@ // // Global overrides for panels // -.panel-footer .pagination, .modal-footer .pagination { +.panel-footer .pagination, +.modal-footer .pagination { margin: 0; } -.panel-body + .panel-heading, .panel-body + * > .panel-heading { +.panel-body + .panel-heading, +.panel-body + * > .panel-heading { border-top: 1px solid #ddd !important; border-radius: 0 !important; } @@ -29,7 +31,9 @@ .panel > *:not(.panel-heading):not(.panel-footer):not(.panel-toolbar) { flex: 1; } - .panel-heading, .panel-body, .panel-footer { + .panel-heading, + .panel-body, + .panel-footer { width: 100%; } .panel + .panel { @@ -43,7 +47,8 @@ margin-top: 0; font-size: 1em; } - .panel .drop.well, .panel .file-uploader { + .panel .drop.well, + .panel .file-uploader { margin: 0; } } @@ -79,7 +84,8 @@ } // Two panel bodies next to eachother (include those with one nested in custom element) -.panel-body:not(.ng-hide) + * > .panel-body, .panel-body:not(.ng-hide) + .panel-body { +.panel-body:not(.ng-hide) + * > .panel-body, +.panel-body:not(.ng-hide) + .panel-body { padding-top: 0; } // Remove extra margin for callouts in padding @@ -93,7 +99,8 @@ // Full screen set of panels .panel-full-screen { height: $main-view-max-height; - & > *, & > * > .panel { + & > *, + & > * > .panel { height: 100%; } } diff --git a/src/styles/common/overrides/rating-overrides.scss b/src/styles/common/overrides/rating-overrides.scss index 56c8c806e2..0c9e44aa6f 100644 --- a/src/styles/common/overrides/rating-overrides.scss +++ b/src/styles/common/overrides/rating-overrides.scss @@ -1,7 +1,7 @@ @use 'sass:color'; // The generated from ui-bootstrap becomes this -span[role="slider"] { +span[role='slider'] { outline: none; } .rating-outline { diff --git a/src/styles/common/overrides/table-overrides.scss b/src/styles/common/overrides/table-overrides.scss index 4a9d444e8c..2b03bc8575 100644 --- a/src/styles/common/overrides/table-overrides.scss +++ b/src/styles/common/overrides/table-overrides.scss @@ -8,7 +8,8 @@ table.table-pointer { } table > tbody > tr { - & > td, & > th { + & > td, + & > th { vertical-align: middle !important; } } diff --git a/src/styles/common/text.scss b/src/styles/common/text.scss index 9b97f6c291..69586f5d2e 100644 --- a/src/styles/common/text.scss +++ b/src/styles/common/text.scss @@ -1,4 +1,4 @@ .with-icon { display: flex; align-items: center; -} \ No newline at end of file +} diff --git a/src/styles/common/typeface.scss b/src/styles/common/typeface.scss index dbd24f4d3c..c45e90c1aa 100644 --- a/src/styles/common/typeface.scss +++ b/src/styles/common/typeface.scss @@ -6,49 +6,70 @@ $roboto-path: '/assets/fonts/roboto'; font-family: 'Roboto'; font-style: normal; font-weight: 300; - src: local('Roboto Light'), local('Roboto-Light'), url('#{$roboto-path}/Roboto-Light.woff') format('woff'); + src: + local('Roboto Light'), + local('Roboto-Light'), + url('#{$roboto-path}/Roboto-Light.woff') format('woff'); } @font-face { font-family: 'Roboto'; font-style: normal; font-weight: 400; - src: local('Roboto'), local('Roboto-Regular'), url('#{$roboto-path}/Roboto-Regular.woff') format('woff'); + src: + local('Roboto'), + local('Roboto-Regular'), + url('#{$roboto-path}/Roboto-Regular.woff') format('woff'); } @font-face { font-family: 'Roboto'; font-style: normal; font-weight: 500; - src: local('Roboto Medium'), local('Roboto-Medium'), url('#{$roboto-path}/Roboto-Medium.woff') format('woff'); + src: + local('Roboto Medium'), + local('Roboto-Medium'), + url('#{$roboto-path}/Roboto-Medium.woff') format('woff'); } @font-face { font-family: 'Roboto'; font-style: normal; font-weight: 700; - src: local('Roboto Bold'), local('Roboto-Bold'), url('#{$roboto-path}/Roboto-Bold.woff') format('woff'); + src: + local('Roboto Bold'), + local('Roboto-Bold'), + url('#{$roboto-path}/Roboto-Bold.woff') format('woff'); } @font-face { font-family: 'Roboto'; font-style: italic; font-weight: 400; - src: local('Roboto Italic'), local('Roboto-Italic'), url('#{$roboto-path}/Roboto-Italic.woff') format('woff'); + src: + local('Roboto Italic'), + local('Roboto-Italic'), + url('#{$roboto-path}/Roboto-Italic.woff') format('woff'); } @font-face { font-family: 'Grotesk'; font-style: normal; - src: local('Grotesk'), url(/assets/fonts/grotesk/grotesk-regular.otf) format('opentype'); + src: + local('Grotesk'), + url(/assets/fonts/grotesk/grotesk-regular.otf) format('opentype'); } @font-face { font-family: 'Grotesk'; font-style: italic; - src: local('Grotesk'), url(/assets/fonts/grotesk/grotesk-italic.otf) format('opentype'); + src: + local('Grotesk'), + url(/assets/fonts/grotesk/grotesk-italic.otf) format('opentype'); } @font-face { font-family: 'Grotesk'; font-style: bold; - src: local('Grotesk'), url(/assets/fonts/grotesk/grotesk-bold.otf) format('opentype'); + src: + local('Grotesk'), + url(/assets/fonts/grotesk/grotesk-bold.otf) format('opentype'); } .mat-icon { diff --git a/src/styles/m3-theme.scss b/src/styles/m3-theme.scss index cc5594c47e..1e094b5f2f 100644 --- a/src/styles/m3-theme.scss +++ b/src/styles/m3-theme.scss @@ -129,45 +129,49 @@ $_palettes: ( $_rest: ( secondary: map.get($_palettes, secondary), neutral: map.get($_palettes, neutral), - neutral-variant: map.get($_palettes, neutral-variant), + neutral-variant: map.get($_palettes, neutral-variant), error: map.get($_palettes, error), ); $_primary: map.merge(map.get($_palettes, primary), $_rest); $_tertiary: map.merge(map.get($_palettes, tertiary), $_rest); -$light-theme: mat.define-theme(( - color: ( - theme-type: light, - primary: $_primary, - tertiary: $_tertiary, - use-system-variables: true, - system-variables-prefix: sys, - ), - typography: ( - use-system-variables: true, - system-variables-prefix: sys, - plain-family: "Inter, 'open-sans', 'Roboto'", - brand-family: "'Grotesk'", - bold-weight: 900, - medium-weight: 500, - regular-weight: 300, - ), -)); -$dark-theme: mat.define-theme(( - color: ( - theme-type: dark, - primary: $_primary, - tertiary: $_tertiary, - use-system-variables: true, - system-variables-prefix: sys, - ), - typography: ( - use-system-variables: true, - system-variables-prefix: sys, - plain-family: "Inter, 'open-sans', 'Roboto'", - brand-family: "'Grotesk'", - bold-weight: 900, - medium-weight: 500, - regular-weight: 300, - ), -)); +$light-theme: mat.define-theme( + ( + color: ( + theme-type: light, + primary: $_primary, + tertiary: $_tertiary, + use-system-variables: true, + system-variables-prefix: sys, + ), + typography: ( + use-system-variables: true, + system-variables-prefix: sys, + plain-family: "Inter, 'open-sans', 'Roboto'", + brand-family: "'Grotesk'", + bold-weight: 900, + medium-weight: 500, + regular-weight: 300, + ), + ) +); +$dark-theme: mat.define-theme( + ( + color: ( + theme-type: dark, + primary: $_primary, + tertiary: $_tertiary, + use-system-variables: true, + system-variables-prefix: sys, + ), + typography: ( + use-system-variables: true, + system-variables-prefix: sys, + plain-family: "Inter, 'open-sans', 'Roboto'", + brand-family: "'Grotesk'", + bold-weight: 900, + medium-weight: 500, + regular-weight: 300, + ), + ) +); diff --git a/src/styles/mixins/animations/fade-in.scss b/src/styles/mixins/animations/fade-in.scss index 9bf65d7f79..008d7a6ead 100644 --- a/src/styles/mixins/animations/fade-in.scss +++ b/src/styles/mixins/animations/fade-in.scss @@ -2,8 +2,12 @@ // A fade in animation // @keyframes animation-fade-in { - from { opacity: 0; } - to { opacity: 1; } + from { + opacity: 0; + } + to { + opacity: 1; + } } @mixin animation-fade-in($seconds) { animation: animation-fade-in $seconds; diff --git a/src/styles/mixins/animations/grow.scss b/src/styles/mixins/animations/grow.scss index 73222c87c6..e8cef776ce 100644 --- a/src/styles/mixins/animations/grow.scss +++ b/src/styles/mixins/animations/grow.scss @@ -4,7 +4,7 @@ @keyframes animation-grow { 0% { opacity: 0; - transform: scale(.3); + transform: scale(0.3); } 50% { @@ -13,7 +13,7 @@ } 70% { - transform: scale(.9); + transform: scale(0.9); } 100% { diff --git a/src/styles/mixins/animations/slide-down.scss b/src/styles/mixins/animations/slide-down.scss index cf741fc82b..1bb14c5d1c 100644 --- a/src/styles/mixins/animations/slide-down.scss +++ b/src/styles/mixins/animations/slide-down.scss @@ -2,8 +2,12 @@ // Slide animation from -2em to initial top // @keyframes animation-slide-down { - from { margin-top: -2em; } - to { margin-top: inherit; } + from { + margin-top: -2em; + } + to { + margin-top: inherit; + } } @mixin animation-slide-down($seconds) { animation: animation-slide-down $seconds; diff --git a/src/styles/mixins/animations/wobble.scss b/src/styles/mixins/animations/wobble.scss index 89f12fa8f3..e06fbdfecb 100644 --- a/src/styles/mixins/animations/wobble.scss +++ b/src/styles/mixins/animations/wobble.scss @@ -2,16 +2,24 @@ // Animation to wobble an element side to side // @keyframes animation-wobble { - 0%, 100% { transform: translateX(+5px); } - 25%, 75% { transform: translateX(0); } - 50% { transform: translateX(-5px); } + 0%, + 100% { + transform: translateX(+5px); + } + 25%, + 75% { + transform: translateX(0); + } + 50% { + transform: translateX(-5px); + } } @mixin animation-wobble { animation-duration: 1s; animation-fill-mode: both; animation-timing-function: ease-in-out; - animation-iteration-count:infinite; + animation-iteration-count: infinite; animation-name: animation-wobble; } @@ -19,9 +27,16 @@ // Animation to wobble an element side but only once // @keyframes animation-wobble-once { - 0%, 100% { transform: translateX(0); } - 25% { transform: translateX(+5px); } - 75% { transform: translateX(-5px); } + 0%, + 100% { + transform: translateX(0); + } + 25% { + transform: translateX(+5px); + } + 75% { + transform: translateX(-5px); + } } @mixin animation-wobble-once { diff --git a/src/styles/mixins/callout.scss b/src/styles/mixins/callout.scss index 44b66f66af..fa9d52c3b2 100644 --- a/src/styles/mixins/callout.scss +++ b/src/styles/mixins/callout.scss @@ -4,19 +4,25 @@ // A callout // @mixin callout($color, $bgcolor: color.adjust($color, $lightness: 35%)) { - display: block; - margin: 20px 0; - padding: 15px 30px 15px 15px; - border-left: 5px solid $color; - background-color: $bgcolor; - h1, h2, h3, h4, h5, h6 { - margin-top: 0; - color: $color; - } - p:last-child { - margin-bottom: 0; - } - code, .highlight { - background-color: #fff; - } + display: block; + margin: 20px 0; + padding: 15px 30px 15px 15px; + border-left: 5px solid $color; + background-color: $bgcolor; + h1, + h2, + h3, + h4, + h5, + h6 { + margin-top: 0; + color: $color; + } + p:last-child { + margin-bottom: 0; + } + code, + .highlight { + background-color: #fff; + } } diff --git a/src/styles/mixins/dropdown-selector.scss b/src/styles/mixins/dropdown-selector.scss index 01036b0cca..c5ca2742a2 100644 --- a/src/styles/mixins/dropdown-selector.scss +++ b/src/styles/mixins/dropdown-selector.scss @@ -6,7 +6,8 @@ & > button { height: 100%; width: 100%; - label, i { + label, + i { text-align: center; } label { diff --git a/src/styles/mixins/task-list.scss b/src/styles/mixins/task-list.scss index c33aca0065..f89e866b82 100644 --- a/src/styles/mixins/task-list.scss +++ b/src/styles/mixins/task-list.scss @@ -44,22 +44,30 @@ text-decoration: none; // background-color: $list-group-hover-bg; &.ready-for-feedback { - @include custom-box-shadow(color.adjust(task-status-color('ready-for-feedback'), $lightness: 15%)); + @include custom-box-shadow( + color.adjust(task-status-color('ready-for-feedback'), $lightness: 15%) + ); } &.not-started { @include custom-box-shadow(color.adjust(task-status-color('not-started'), $lightness: 5%)); } &.working-on-it { - @include custom-box-shadow(color.adjust(task-status-color('working-on-it'), $lightness: 15%)); + @include custom-box-shadow( + color.adjust(task-status-color('working-on-it'), $lightness: 15%) + ); } &.need-help { @include custom-box-shadow(color.adjust(task-status-color('need-help'), $lightness: 15%)); } &.fix-and-resubmit { - @include custom-box-shadow(color.adjust(task-status-color('fix-and-resubmit'), $lightness: 15%)); + @include custom-box-shadow( + color.adjust(task-status-color('fix-and-resubmit'), $lightness: 15%) + ); } &.feedback-exceeded { - @include custom-box-shadow(color.adjust(task-status-color('feedback-exceeded'), $lightness: 15%)); + @include custom-box-shadow( + color.adjust(task-status-color('feedback-exceeded'), $lightness: 15%) + ); } &.fail { @include custom-box-shadow(color.adjust(task-status-color('fail'), $lightness: 15%)); @@ -77,13 +85,19 @@ @include custom-box-shadow(color.adjust(task-status-color('complete'), $lightness: 15%)); } &.time-exceeded { - @include custom-box-shadow(color.adjust(task-status-color('time-exceeded'), $lightness: 15%)); + @include custom-box-shadow( + color.adjust(task-status-color('time-exceeded'), $lightness: 15%) + ); } &.assess-in-portfolio { - @include custom-box-shadow(color.adjust(task-status-color('assess-in-portfolio'), $lightness: 15%)); + @include custom-box-shadow( + color.adjust(task-status-color('assess-in-portfolio'), $lightness: 15%) + ); } &.attention-required { - @include custom-box-shadow(color.adjust(task-status-color('attention-required'), $lightness: 15%)); + @include custom-box-shadow( + color.adjust(task-status-color('attention-required'), $lightness: 15%) + ); } } &.selected { diff --git a/src/styles/modules/cards.scss b/src/styles/modules/cards.scss index 9b381e445e..2114a71f81 100644 --- a/src/styles/modules/cards.scss +++ b/src/styles/modules/cards.scss @@ -10,18 +10,35 @@ margin-bottom: $card-footer-padding; background-color: color.adjust(#fff, $lightness: -0.75%); - transition: box-shadow .25s; - box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.14), - 0 1px 5px 0 rgba(0, 0, 0, 0.12), - 0 3px 1px -2px rgba(0, 0, 0, 0.2); + transition: box-shadow 0.25s; + box-shadow: + 0 2px 2px 0 rgba(0, 0, 0, 0.14), + 0 1px 5px 0 rgba(0, 0, 0, 0.12), + 0 3px 1px -2px rgba(0, 0, 0, 0.2); - &.card-default > .card-heading { background-color: $panel-default-heading-bg; } - &.card-primary > .card-heading { background-color: $brand-primary; } - &.card-danger > .card-heading { background-color: $brand-danger; } - &.card-success > .card-heading { background-color: $brand-success; } - &.card-warning > .card-heading { background-color: $brand-warning; } - &.card-info > .card-heading { background-color: $brand-info; } - &.card-danger, &.card-success, &.card-warning, &.card-info, &.card-primary { + &.card-default > .card-heading { + background-color: $panel-default-heading-bg; + } + &.card-primary > .card-heading { + background-color: $brand-primary; + } + &.card-danger > .card-heading { + background-color: $brand-danger; + } + &.card-success > .card-heading { + background-color: $brand-success; + } + &.card-warning > .card-heading { + background-color: $brand-warning; + } + &.card-info > .card-heading { + background-color: $brand-info; + } + &.card-danger, + &.card-success, + &.card-warning, + &.card-info, + &.card-primary { .card-heading { color: #fff; .text-muted { diff --git a/src/styles/modules/doubtfire-logo.scss b/src/styles/modules/doubtfire-logo.scss index 395918c8e8..aaf9cf1fc9 100644 --- a/src/styles/modules/doubtfire-logo.scss +++ b/src/styles/modules/doubtfire-logo.scss @@ -19,9 +19,10 @@ i.logo { .welcome-to-doubtfire { margin-top: 6em; margin-bottom: 3em; - h1, p { + h1, + p { @include logo-font-rendering; - font-family: "Grotesk"; + font-family: 'Grotesk'; } p.lead { color: #000; diff --git a/src/styles/modules/panel-fullscreen.scss b/src/styles/modules/panel-fullscreen.scss index d9abc44ad3..7e6ff08b3e 100644 --- a/src/styles/modules/panel-fullscreen.scss +++ b/src/styles/modules/panel-fullscreen.scss @@ -37,7 +37,8 @@ padding: 0px; } - .panel, .panel-heading { + .panel, + .panel-heading { border-radius: 0; } @@ -51,7 +52,8 @@ font-size: 3em; text-align: center; font-weight: 300; - i, p { + i, + p { display: block; width: 100%; margin-bottom: 0.75em; diff --git a/src/styles/modules/tabset-icon.scss b/src/styles/modules/tabset-icon.scss index a1f721008d..0a1a4004d6 100644 --- a/src/styles/modules/tabset-icon.scss +++ b/src/styles/modules/tabset-icon.scss @@ -11,7 +11,8 @@ i:not(:last-child) { margin-right: 1ex; } - i:not(:last-child), i + i:last-child { + i:not(:last-child), + i + i:last-child { display: inline-block; width: inherit; } diff --git a/src/test.ts b/src/test.ts index 280230b87b..5f03b6f001 100644 --- a/src/test.ts +++ b/src/test.ts @@ -9,11 +9,15 @@ import 'zone.js/dist/fake-async-test'; import { getTestBed } from '@angular/core/testing'; import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; -// Unfortunately there's no typing for the `__karma__` variable. Just declare it as any. -declare const __karma__: any; +declare const __karma__: { + loaded: () => void; + start: () => void; +}; // Prevent Karma from running prematurely. -__karma__.loaded = () => {}; +__karma__.loaded = () => { + /* empty */ +}; // First, initialize the Angular testing environment. getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { diff --git a/src/theme.scss b/src/theme.scss index f0dd8c1d8c..e3bd33aba1 100644 --- a/src/theme.scss +++ b/src/theme.scss @@ -108,9 +108,27 @@ $font-family-primary: "'Grotesk'"; $font-family-accent: "Inter, 'open-sans', 'Roboto'"; $mat-typography-primary-config: mat.m2-define-typography-config( - $headline-1: mat.m2-define-typography-level(112px, 112px, 300, $font-family-primary, $letter-spacing: -0.05em), - $headline-2: mat.m2-define-typography-level(56px, 56px, 400, $font-family-primary, $letter-spacing: -0.02em), - $headline-3: mat.m2-define-typography-level(45px, 48px, 400, $font-family-primary, $letter-spacing: -0.005em), + $headline-1: mat.m2-define-typography-level( + 112px, + 112px, + 300, + $font-family-primary, + $letter-spacing: -0.05em + ), + $headline-2: mat.m2-define-typography-level( + 56px, + 56px, + 400, + $font-family-primary, + $letter-spacing: -0.02em + ), + $headline-3: mat.m2-define-typography-level( + 45px, + 48px, + 400, + $font-family-primary, + $letter-spacing: -0.005em + ), $headline-4: mat.m2-define-typography-level(34px, 40px, 400, $font-family-primary), $headline-5: mat.m2-define-typography-level(24px, 32px, 400, $font-family-primary), $headline-6: mat.m2-define-typography-level(20px, 32px, 500, $font-family-primary), diff --git a/src/tsconfig.spec.json b/src/tsconfig.spec.json index aabc7e3d73..70add2d529 100644 --- a/src/tsconfig.spec.json +++ b/src/tsconfig.spec.json @@ -2,17 +2,8 @@ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/spec", - "types": [ - "jasmine", - "node" - ] + "types": ["jasmine", "node"] }, - "files": [ - "test.ts", - "polyfills.ts" - ], - "include": [ - "**/*.spec.ts", - "**/*.d.ts" - ] -} \ No newline at end of file + "files": ["test.ts", "polyfills.ts"], + "include": ["**/*.spec.ts", "**/*.d.ts"] +} From b13b6461dd4c89fa4a72ecb48c4cce7d09a2a6a9 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 8 Jun 2026 12:58:27 +1000 Subject: [PATCH 1085/1280] chore: update README --- README.md | 248 ++---------------------------------------------------- 1 file changed, 5 insertions(+), 243 deletions(-) diff --git a/README.md b/README.md index 8a1f9dc167..b050cbf4a6 100644 --- a/README.md +++ b/README.md @@ -1,245 +1,14 @@ -![Doubtfire Logo](src/assets/icons/android-chrome-192x192.png) +

    + OnTrack logo +

    -# Doubtfire Web [![CI](https://img.shields.io/github/workflow/status/doubtfire-lms/doubtfire-web/Node.js%20CI?label=CI&logo=GitHub)](https://github.com/doubtfire-lms/doubtfire-web/actions/workflows/nodejs-ci.yml) +# OnTrack Web [![CI](https://img.shields.io/github/workflow/status/doubtfire-lms/doubtfire-web/Node.js%20CI?label=CI&logo=GitHub)](https://github.com/doubtfire-lms/doubtfire-web/actions/workflows/nodejs-ci.yml) A modern, lightweight learning management system. -> ## 🛠 Migration Status: In Development -> -> Doubtfire web migration from AngularJS/Coffeescript to Angular/Typescript, including refactoring all components, is currently in development. -> -> See the progress of component migration below. - -## Migration Progress - -Important: When completing a frontend migration, please update the below list regarding the component you have migrated. - -### SUMMARY: - -- `89 / 183` components migrated -- `19` components no longer in the doubtfire-lms/9.x branch - -### NO LONGER IN doubtfire-lms/9.x - -- [x] ./src/app/projects/states/all/directives/all-projects-list/all-projects-list.coffee -- [x] ./src/app/projects/states/all/all.coffee -- [x] ./src/app/groups/tutor-group-manager/tutor-group-manager.coffee -- [x] ./src/app/tasks/task-definition-selector/task-definition-selector.coffee -- [x] ./src/app/tasks/task-status-selector/task-status-selector.coffee -- [x] ./src/app/config/debug/debug.coffee -- [x] ./src/app/projects/states/all/directives/directives.coffee -- [x] ./src/app/projects/states/dashboard/directives/task-dashboard/directives/directives.coffee -- [x] ./src/app/projects/states/dashboard/directives/task-dashboard/directives/task-outcomes-card/task-outcomes-card.coffee -- [x] ./src/app/admin/states/states.coffee -- [x] ./src/app/admin/admin.coffee -- [x] ./src/app/units/states/tasks/viewer/directives/directives.coffee -- [x] ./src/app/units/states/tasks/viewer/viewer.coffee -- [x] ./src/app/units/states/all/directives/all-units-list/all-units-list.coffee -- [x] ./src/app/units/states/all/directives/directives.coffee -- [x] ./src/app/units/states/all/all.coffee -- [x] ./src/app/common/alert-list/alert-list.coffee -- [x] ./src/app/common/modals/progress-modal/progress-modal.coffee -- [x] ./src/app/errors/states/not-found/not-found.coffee -- [x] ./src/app/groups/tutor-group-manager/tutor-group-manager.coffee - -### MIGRATED: - -- [x] ./src/app/home/splash-screen/splash-screen.component.ts -- [x] ./src/app/home/states/home/home.component.ts -- [x] ./src/app/tasks/task-submission-history/task-submission-history.component.ts -- [x] ./src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts -- [x] ./src/app/tasks/task-comments-viewer/extension-comment/extension-comment.component.ts -- [x] ./src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-player.component.ts -- [x] ./src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-recorder/intelligent-discussion-recorder.component.ts -- [x] ./src/app/tasks/project-tasks-list/project-tasks-list.coffee -- [x] ./src/app/tasks/task-comments-viewer/pdf-image-comment/pdf-image-comment.component.ts -- [x] ./src/app/tasks/task-comments-viewer/comment-bubble-action/comment-bubble-action.component.ts -- [x] ./src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts -- [x] ./src/app/tasks/task-comment-composer/task-comment-composer.component.ts -- [x] ./src/app/tasks/task-comment-composer/discussion-prompt-composer/discussion-prompt-composer.component.ts -- [x] ./src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.ts -- [x] ./src/app/projects/states/dashboard/directives/student-task-list/task-list-item/task-list-item.component.ts -- [x] ./src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.ts -- [x] ./src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.ts -- [x] ./src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.ts -- [x] ./src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.ts -- [x] ./src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.ts -- [x] ./src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts -- [x] ./src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.ts -- [x] ./src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts -- [x] ./src/app/admin/institution-settings/institution-settings.component.ts -- [x] ./src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts -- [x] ./src/app/admin/institution-settings/activity-type-list/activity-type-list.component.ts -- [x] ./src/app/admin/tii-action-log/tii-action-log.component.ts -- [x] ./src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.ts -- [x] ./src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts -- [x] ./src/app/admin/modals/create-unit-modal/create-new-unit-modal.component.ts -- [x] ./src/app/eula/accept-eula/accept-eula.component.ts -- [x] ./src/app/welcome/welcome.component.ts -- [x] ./src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.ts -- [x] ./src/app/units/states/edit/directives/unit-students-editor/student-tutorial-select/student-tutorial-select.component.ts -- [x] ./src/app/units/states/edit/directives/unit-students-editor/unit-students-editor.component.ts -- [x] ./src/app/units/states/edit/directives/unit-students-editor/student-campus-select/student-campus-select.component.ts -- [x] ./src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.ts -- [x] ./src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.ts -- [x] ./src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts -- [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts -- [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.ts -- [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts -- [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.ts -- [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts -- [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts -- [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.ts -- [x] ./src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts -- [x] ./src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts -- [x] ./src/app/units/states/analytics/unit-analytics-route.component.ts -- [x] ./src/app/common/footer/footer.component.ts -- [x] ./src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.ts -- [x] ./src/app/common/audio-recorder/audio/microphone-tester/microphone-tester.component.ts -- [x] ./src/app/common/audio-player/audio-player.component.ts -- [x] ./src/app/common/edit-profile-form/edit-profile-form.component.ts -- [x] ./src/app/common/file-drop/file-drop.component.ts -- [x] ./src/app/common/modals/extension-modal/extension-modal.component.ts -- [x] ./src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.component.ts -- [x] ./src/app/common/modals/calendar-modal/calendar-modal.component.ts -- [x] ./src/app/common/modals/task-assessment-modal/task-assessment-modal.component.ts -- [x] ./src/app/common/pdf-viewer/pdf-viewer.component.ts -- [x] ./src/app/common/obect-select/object-select.component.ts -- [x] ./src/app/common/hero-sidebar/hero-sidebar.component.ts -- [x] ./src/app/common/project-progress-bar/project-progress-bar.component.ts -- [x] ./src/app/common/f-chip/f-chip.component.ts -- [x] ./src/app/common/status-icon/status-icon.component.ts -- [x] ./src/app/common/user-badge/user-badge.component.ts -- [x] ./src/app/common/file-viewer/file-viewer.component.ts -- [x] ./src/app/common/user-icon/user-icon.component.ts -- [x] ./src/app/common/pdf-viewer-panel/pdf-viewer-panel.component.ts -- [x] ./src/app/common/header/header.component.ts -- [x] ./src/app/common/header/task-dropdown/task-dropdown.component.ts -- [x] ./src/app/common/header/unit-dropdown/unit-dropdown.component.ts -- [x] ./src/app/common/services/alert.service.ts -- [x] ./src/app/sessions/states/sign-in/sign-in.component.ts -- [x] ./src/app/account/edit-profile/edit-profile.component.ts -- [x] ./src/app/tasks/modals/grade-task-modal/grade-task-modal.component.ts -- [x] ./src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts -- [x] ./src/app/visualisations/progress-burndown-chart/progressburndownchart.component.ts -- [x] ./src/app/config/privacy-policy/privacy-policy.coffee -- [x] ./src/app/units/states/tasks/viewer/directives/task-sheet-view/task-sheet-view.coffee -- [x] ./src/app/units/states/tasks/viewer/directives/task-details-view/task-details-view.coffee -- [x] ./src/app/units/states/tasks/viewer/directives/unit-task-list/unit-task-list.coffee -- [x] ./src/app/projects/states/dashboard/directives/student-task-list/student-task-list.coffee -- [x] ./src/app/units/states/tasks/inbox/inbox.coffee -- [x] ./src/app/admin/states/units/units.component.ts -- [x] ./src/app/admin/states/users/users.component.ts -- [x] ./src/app/common/grade-icon/grade-icon.component.ts -- [x] ./src/app/common/services/grade.service.ts -- [x] ./src/app/common/services/alert.service.ts -- [x] ./src/app/errors/states/unauthorised/unauthorised.component.ts -- [x] ./src/app/groups/group-set-selector/group-set-selector.component.ts -- [x] ./src/app/admin/modals/create-unit-modal/create-unit-modal.coffee -- [x] ./src/app/common/services/date.service.ts -- [x] ./src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.coffee (IN 10.0.x) -- [x] ./src/app/groups/group-member-list/group-member-list.coffee -- [x] ./src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.coffee -- [x] ./src/app/common/modals/confirmation-modal/confirmation-modal.coffee -- [x] ./src/app/common/modals/comments-modal/comments-modal.coffee (IN 10.0.x) -- [x] ./src/app/groups/group-selector/group-selector.coffee -- [x] ./src/app/groups/group-set-manager/group-set-manager.coffee -- [x] ./src/app/common/file-uploader/file-uploader.coffee -- [x] ./src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.coffee -- [x] ./src/app/sessions/auth/http-auth-injector.coffee -- [x] ./src/app/sessions/sessions.coffee -- [x] ./src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.coffee -- [x] ./src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.coffee -- [x] ./src/app/projects/project-progress-dashboard/project-progress-dashboard.coffee -- [x] ./src/app/units/states/portfolios/portfolios.coffee -- [x] ./src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.coffee -- [x] ./src/app/config/local-storage/local-storage.coffee (Removed in 10.0.x) -- [x] ./src/app/projects/states/tutorials/tutorials.coffee -- [x] ./src/app/admin/modals/modals.coffee -- [x] ./src/app/common/services/date-service.coffee -- [ ] ./src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/task-ilo-alignment-modal.coffee (Removed in 10.0.x) -- [x] ./src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment.coffee (Removed in 10.0.x) -- [x] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-editor/task-ilo-alignment-editor.coffee (Removed in 10.0.x) -- [x] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-rater/task-ilo-alignment-rater.coffee (Removed in 10.0.x) -- [x] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.coffee (Removed in 10.0.x) -- [x] ./src/app/tasks/task-ilo-alignment/task-ilo-alignment.coffee (Removed in 10.0.x) -- [x] ./src/app/projects/project-outcome-alignment/project-outcome-alignment.coffee (Removed in 10.0.x) -- [x] ./src/app/units/modals/unit-ilo-edit-modal/unit-ilo-edit-modal.coffee (Removed in 10.0.x) -- [x] ./src/app/units/states/edit/directives/unit-ilo-editor/unit-ilo-editor.coffee (Removed in 10.0.x) -- [x] ./src/app/projects/states/outcomes/outcomes.coffee (Removed in 10.0.x) -- [x] ./src/app/projects/states/portfolio/directives/portfolio-tasks-step/portfolio-tasks-step.coffee (Removed in 10.0.x) -- [x] ./src/app/units/states/rollover/directives/directives.coffee -- [x] ./src/app/units/states/rollover/directives/unit-dates-selector/unit-dates-selector.coffee -- [x] ./src/app/units/states/rollover/rollover.coffee -- [x] ./src/app/visualisations/task-status-pie-chart.coffee -- [x] ./src/app/visualisations/student-task-status-pie-chart.coffee -- [ ] ./src/app/visualisations/achievement-box-plot.coffee (ILO Alignments removed) -- [ ] ./src/app/visualisations/achievement-custom-bar-chart.coffee (ILO Alignments removed) -- [ ] ./src/app/visualisations/alignment-bar-chart.coffee (ILO Alignments removed) -- [ ] ./src/app/visualisations/alignment-bullet-chart.coffee (ILO Alignments removed) -- [x] ./src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.coffee -- [x] ./src/app/groups/groups.coffee -- [x] ./src/app/common/modals/csv-result-modal/csv-result-modal.coffee -- [x] ./src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.coffee -- [x] ./src/app/units/states/students-list/students-list.coffee -- [x] ./src/app/common/modals/modals.coffee -- [x] ./src/app/tasks/modals/upload-submission-modal/upload-submission-modal.coffee -- [x] ./src/app/tasks/modals/modals.coffee -- [x] ./src/app/tasks/tasks.coffee -- [x] ./src/app/units/modals/modals.coffee -- [x] ./src/app/units/states/edit/directives/directives.coffee -- [x] ./src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.coffee (Migrate this in 10.0.x) -- [x] ./src/app/projects/states/portfolio/directives/directives.coffee -- [x] ./src/app/projects/states/portfolio/portfolio.coffee -- [x] ./src/app/units/states/tasks/definition/definition.coffee -- [x] ./src/app/units/states/tasks/tasks.coffee -- [x] ./src/app/units/states/tasks/moderation.coffee -- [x] ./src/app/units/states/tasks/overflow.coffee -- [x] ./src/app/errors/states/timeout/timeout.coffee -- [x] ./src/app/projects/states/groups/groups.coffee (State only -> "project-groups") -- [x] ./src/app/units/states/groups/groups.coffee (State only -> "unit-groups") -- [x] ./src/app/units/states/analytics/analytics.coffee (Just the routing, since the TypeScript f-analytics component has been expanded in 10.0.x) -- [x] ./src/app/projects/states/feedback/feedback.coffee -- [x] ./src/app/common/content-editable/content-editable.coffee -- [x] ./src/app/common/services/outcome-service.coffee -- [ ] ./src/app/common/filters/filters.coffee -- [x] ./src/app/common/services/analytics-service.coffee -- [x] ./src/app/config/analytics/analytics.coffee -- [x] ./src/app/common/services/recorder-service.coffee -- [x] ./src/app/projects/projects.coffee -- [x] ./src/app/projects/states/dashboard/dashboard.coffee -- [x] ./src/app/projects/states/dashboard/directives/directives.coffee -- [x] ./src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.coffee -- [x] ./src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.coffee -- [x] ./src/app/projects/states/index/index.coffee -- [x] ./src/app/projects/states/states.coffee -- [ ] ./src/app/common/services/listener-service.coffee -- [x] ./src/app/config/root-controller/root-controller.coffee -- [ ] ./src/app/config/vendor-dependencies/vendor-dependencies.coffee -- [x] ./src/app/common/services/media-service.coffee -- [x] ./src/app/common/services/services.coffee -- [x] ./src/app/common/common.coffee -- [x] ./src/app/config/routing/routing.coffee -- [x] ./src/app/config/runtime/runtime.coffee -- [x] ./src/app/errors/errors.coffee -- [x] ./src/app/errors/states/states.coffee -- [x] ./src/app/units/states/edit/edit.coffee -- [x] ./src/app/units/states/index/index.coffee -- [x] ./src/app/units/states/states.coffee -- [x] ./src/app/units/units.coffee -- [x] ./src/app/config/config.coffee - -### TODO: - -- [ ] ./src/app/visualisations/summary-task-status-scatter.coffee (Unit task status summary) -- [ ] ./src/app/visualisations/target-grade-pie-chart.coffee -- [ ] ./src/app/visualisations/task-completion-box-plot.coffee -- [ ] ./src/app/visualisations/visualisations.coffee - ## Table of Contents - [Doubtfire Web ![CI](https://github.com/doubtfire-lms/doubtfire-web/actions/workflows/nodejs-ci.yml)](#doubtfire-web-) - - [Migration Progress](#migration-progress) - [Table of Contents](#table-of-contents) - [Getting Started](#getting-started) - [Deployment](#deployment) @@ -332,18 +101,11 @@ You may prefix this command with the following environment variables: ## Resources -Doubtfire Web is an [Angular](http://angularjs.org) application built using [Bootstrap](http://getbootstrap.com). It uses many Open Source libraries, which you can read up on: +Doubtfire Web is an [Angular](https://angular.dev) application built using [Material UI]https://material.angular.dev). It uses many Open Source libraries, which you can read up on: - [Lodash](http://lodash.com/docs) - [Moment.js](http://momentjs.com) -- [Font Awesome](http://fontawesome.io) -- [UI Router](https://github.com/angular-ui/ui-router) -- [UI Bootstrap](http://angular-ui.github.io/bootstrap/versioned-docs/0.13.4/) -- [UI Select](https://github.com/angular-ui/ui-select) - [NVD3 Charts](http://krispo.github.io/angular-nvd3/#/) -- [Angular X-Editable](http://vitalets.github.io/angular-xeditable/) -- [Angular Filters](https://github.com/a8m/angular-filter) -- [Angular Markdown Filter](https://github.com/vpegado/angular-markdown-filter) ## Contributing From 82e5175ce74f009991470f85774bc16645a34daf Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 8 Jun 2026 14:12:44 +1000 Subject: [PATCH 1086/1280] chore(release): 11.0.0-21 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fc9e5e4f89..a572423099 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-21](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-20...v11.0.0-21) (2026-06-08) + + +### Bug Fixes + +* ensure unit dates map correctly ([532f185](https://github.com/b0ink/doubtfire-deploy/commit/532f185d2bc6839549a06a2f9e625c676cc280a6)) + ## [11.0.0-20](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-19...v11.0.0-20) (2026-06-04) ## [11.0.0-19](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-18...v11.0.0-19) (2026-06-03) diff --git a/package-lock.json b/package-lock.json index 791cc1e7c4..96eec16671 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-20", + "version": "11.0.0-21", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-20", + "version": "11.0.0-21", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index 933be8f1ac..92e285615b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-20", + "version": "11.0.0-21", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 2fa3b71b6635d1148a3a28deea53a587b422273b Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Mon, 8 Jun 2026 14:26:13 +1000 Subject: [PATCH 1087/1280] chore: fix portfolio submission date sorting --- .../portfolios-list/portfolios-list.component.ts | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts index 46e481e21a..9047047eda 100644 --- a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts +++ b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts @@ -193,6 +193,15 @@ export class PortfoliosListComponent implements OnInit, AfterViewInit { return (aValue < bValue ? -1 : 1) * (isAsc ? 1 : -1); } + private sortDateValue(value: Date | string | number | null | undefined): number { + if (value === null || value === undefined || value === '') { + return 0; + } + + const time = new Date(value).getTime(); + return Number.isFinite(time) ? time : 0; + } + sortTableData(sort: Sort) { if (!sort.active || sort.direction === '') { return; @@ -223,8 +232,8 @@ export class PortfoliosListComponent implements OnInit, AfterViewInit { return this.sortCompare(a.submittedGrade, b.submittedGrade, sort.direction === 'asc'); case 'submission-date': return this.sortCompare( - a.portfolioSubmissionDate?.getTime() ?? 0, - b.portfolioSubmissionDate?.getTime() ?? 0, + this.sortDateValue(a.portfolioSubmissionDate), + this.sortDateValue(b.portfolioSubmissionDate), sort.direction === 'asc', ); case 'has-portfolio': From b55bcfc8f84f381beb7d62f41031db3ba6a38193 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Tue, 9 Jun 2026 11:54:20 +1000 Subject: [PATCH 1088/1280] feat: communications system (#1239) * chore: init communication system editor * feat: add core communications logic * refactor: improve ui layout * refactor: preview email * refactor: ability to edit conditions and actions * refactor: clean up ui layout * feat: enable set execution * refactor: improve layout * refactor: improve ui layout * feat: add confirmation modals to execute rule and set * feat: add scheduling ui * chore: remove duplicate header * fix: ensure students are loaded * refactor: move buttons * fix: disable horizontal scrolling * refactor: improve ui * chore: revert full width change * chore: improve current week ui * chore: format * feat: add spec con days condition * feat: add task comment action * chore: fix layout * chore: remove unnecessary shortcuts * refactor: use server side current week number * refactor: modularise components * chore: fix styling --- src/app/api/models/communication.ts | 142 ++ src/app/api/models/doubtfire-model.ts | 5 + src/app/api/models/teaching-period.ts | 85 + .../models/tutorial-stream/tutorial-stream.ts | 1 + src/app/api/models/unit.ts | 33 + .../services/communication-action.service.ts | 49 + .../communication-condition.service.ts | 51 + .../services/communication-rule.service.ts | 67 + .../api/services/communication-set.service.ts | 67 + .../api/services/tutorial-stream.service.ts | 2 +- src/app/api/services/unit.service.ts | 1 + src/app/doubtfire-angular.module.ts | 40 +- .../change-target-grade-action.component.html | 23 + .../change-target-grade-action.component.ts | 15 + .../communication-actions.component.html | 194 +++ .../communication-actions.component.ts | 13 + .../email-staff-action.component.html | 122 ++ .../email-staff-action.component.ts | 15 + .../email-student-action.component.html | 113 ++ .../email-student-action.component.ts | 15 + .../task-comment-action.component.html | 86 ++ .../task-comment-action.component.ts | 15 + ...ommunication-schedule-modal.component.html | 91 ++ .../communication-schedule-modal.component.ts | 187 +++ .../communication-schedules.component.html | 71 + .../communication-schedules.component.ts | 13 + .../communication-conditions.component.html | 497 ++++++ .../communication-conditions.component.ts | 13 + .../unit-communications-editor.component.html | 345 +++++ .../unit-communications-editor.component.scss | 0 .../unit-communications-editor.component.ts | 1365 +++++++++++++++++ .../edit/unit-admin-state.component.html | 16 +- .../states/edit/unit-admin-state.component.ts | 4 +- 33 files changed, 3750 insertions(+), 6 deletions(-) create mode 100644 src/app/api/models/communication.ts create mode 100644 src/app/api/services/communication-action.service.ts create mode 100644 src/app/api/services/communication-condition.service.ts create mode 100644 src/app/api/services/communication-rule.service.ts create mode 100644 src/app/api/services/communication-set.service.ts create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/actions/change-target-grade-action/change-target-grade-action.component.html create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/actions/change-target-grade-action/change-target-grade-action.component.ts create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/actions/communication-actions.component.html create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/actions/communication-actions.component.ts create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/actions/email-staff-action/email-staff-action.component.html create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/actions/email-staff-action/email-staff-action.component.ts create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/actions/email-student-action/email-student-action.component.html create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/actions/email-student-action/email-student-action.component.ts create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/actions/task-comment-action/task-comment-action.component.html create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/actions/task-comment-action/task-comment-action.component.ts create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedule-modal.component.html create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedule-modal.component.ts create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedules.component.html create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedules.component.ts create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/conditions/communication-conditions.component.html create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/conditions/communication-conditions.component.ts create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.html create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.scss create mode 100644 src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.ts diff --git a/src/app/api/models/communication.ts b/src/app/api/models/communication.ts new file mode 100644 index 0000000000..cbc5990a96 --- /dev/null +++ b/src/app/api/models/communication.ts @@ -0,0 +1,142 @@ +import {Entity} from 'ngx-entity-service'; + +export type CommunicationScheduleRecurrence = 'none' | 'daily' | 'weekly' | 'monthly'; + +export class CommunicationSetSchedule extends Entity { + id?: number; + client_key?: string; + communication_set_id?: number; + name?: string; + active = true; + anchor_week = 1; + anchor_day = 'Monday'; + hour = 8; + minute = 0; + timezone = 'UTC'; + recurrence: CommunicationScheduleRecurrence = 'none'; + interval = 1; + repeat_count?: number; + until_at?: string; + ice_cube_schedule?: Record; + next_run_at?: string; + last_run_at?: string; + last_enqueued_at?: string; + + constructor(json?: Partial) { + super(); + Object.assign(this, json); + } +} + +export class CommunicationCondition extends Entity { + id: number; + type: string; + communication_rule_id: number; + operator: string; + target_grade?: number; + task_definition_id?: number; + task_statuses?: string[]; + task_status_count?: number; + task_target_grade?: number; + last_sign_in_at?: string; + spec_con_days?: number; + tutorial_id?: number; + tutorial_stream_id?: number; + campus_id?: number; + + constructor(json?: Partial) { + super(); + Object.assign(this, json); + } +} + +export interface CommunicationRulePreviewStudent { + first_name?: string; + last_name?: string; + preferred_name?: string; + full_name?: string; + username?: string; + student_id?: string; + campus?: string; + target_grade?: number; + spec_con_days?: number; + last_sign_in_at?: string; +} + +export interface CommunicationRulePreviewAllocation { + rule_id: number; + rule_name: string; + position: number; + students: CommunicationRulePreviewStudent[]; +} + +export interface CommunicationRulePreviewResponse { + target_rule_id: number; + allocations: CommunicationRulePreviewAllocation[]; +} + +export interface CommunicationSetPreviewResponse { + id: number; + unit_id: number; + name: string; + active: boolean; + schedules?: Partial[]; + rules: Partial[]; + previews: CommunicationRulePreviewResponse[]; +} + +export class CommunicationAction extends Entity { + id: number; + type: string; + communication_rule_id: number; + task_definition_id?: number; + subject?: string; + body?: string; + email_tutors?: boolean; + email_convenors?: boolean; + target_grade?: number; + + constructor(json?: Partial) { + super(); + Object.assign(this, json); + } +} + +export class CommunicationRule extends Entity { + id: number; + communication_set_id: number; + name: string; + operator: 'and' | 'or'; + position: number; + active: boolean; + send_log_to_convenors: boolean; + conditions: CommunicationCondition[] = []; + actions: CommunicationAction[] = []; + + constructor(json?: Partial) { + super(); + Object.assign(this, json); + + this.conditions = + json?.conditions?.map((condition) => new CommunicationCondition(condition)) ?? []; + this.actions = json?.actions?.map((action) => new CommunicationAction(action)) ?? []; + } +} + +export class CommunicationSet extends Entity { + id: number; + unit_id: number; + name: string; + active: boolean; + schedules: CommunicationSetSchedule[] = []; + rules: CommunicationRule[] = []; + + constructor(json?: Partial) { + super(); + Object.assign(this, json); + + this.schedules = + json?.schedules?.map((schedule) => new CommunicationSetSchedule(schedule)) ?? []; + this.rules = json?.rules?.map((rule) => new CommunicationRule(rule)) ?? []; + } +} diff --git a/src/app/api/models/doubtfire-model.ts b/src/app/api/models/doubtfire-model.ts index 200f234bee..9ee73db62a 100644 --- a/src/app/api/models/doubtfire-model.ts +++ b/src/app/api/models/doubtfire-model.ts @@ -38,6 +38,7 @@ export * from './test-attempt'; export * from './task-comment/scorm-comment'; export * from './task-comment/scorm-extension-comment'; export * from './feedback-template'; +export * from './communication'; // Users -- are students or staff export * from './user/user'; @@ -65,3 +66,7 @@ export * from '../../common/services/grade.service'; export * from '../services/test-attempt.service'; export * from '../models/d2l/d2l_assessment_mapping.service'; export * from '../services/feedback-template.service'; +export * from '../services/communication-set.service'; +export * from '../services/communication-rule.service'; +export * from '../services/communication-condition.service'; +export * from '../services/communication-action.service'; diff --git a/src/app/api/models/teaching-period.ts b/src/app/api/models/teaching-period.ts index f8e11f5f8e..0c676ccc05 100644 --- a/src/app/api/models/teaching-period.ts +++ b/src/app/api/models/teaching-period.ts @@ -110,4 +110,89 @@ export class TeachingPeriod extends Entity { }, ); } + + public weekNumber(date: Date | string): number | null { + if (!date || !this.startDate) return null; + + const targetDate = this.normalizeDay(date); + const startDate = this.normalizeDay(this.startDate); + if (!targetDate || !startDate) return null; + + const millisecondsPerWeek = 1000 * 60 * 60 * 24 * 7; + let result = Math.floor((targetDate.getTime() - startDate.getTime()) / millisecondsPerWeek) + 1; + + for (const teachingBreak of this.breaks) { + const breakStart = this.normalizeDay(teachingBreak.startDate); + const breakEnd = this.breakEndDate(teachingBreak); + const firstMonday = this.firstMonday(teachingBreak); + const mondayAfterBreak = this.mondayAfterBreak(teachingBreak); + + if (!breakStart || !breakEnd || !firstMonday || !mondayAfterBreak) continue; + + if (targetDate >= breakStart) { + if (targetDate >= breakEnd) { + result -= teachingBreak.numberOfWeeks; + } else if (targetDate.getTime() === breakStart.getTime()) { + if (targetDate >= firstMonday) { + result -= 1; + } + } else if (targetDate >= firstMonday) { + result -= Math.ceil((targetDate.getTime() - firstMonday.getTime()) / millisecondsPerWeek); + } + + if (targetDate >= breakEnd && targetDate < mondayAfterBreak) { + result += 1; + } + } + } + + return result; + } + + private normalizeDay(date: Date | string | null | undefined): Date | null { + if (!date) return null; + + const parsed = date instanceof Date ? date : new Date(date); + if (Number.isNaN(parsed.valueOf())) return null; + + return new Date(parsed.getFullYear(), parsed.getMonth(), parsed.getDate()); + } + + private breakEndDate(teachingBreak: TeachingPeriodBreak): Date | null { + const startDate = this.normalizeDay(teachingBreak.startDate); + if (!startDate || !teachingBreak.numberOfWeeks) return null; + + return new Date( + startDate.getFullYear(), + startDate.getMonth(), + startDate.getDate() + teachingBreak.numberOfWeeks * 7, + ); + } + + private firstMonday(teachingBreak: TeachingPeriodBreak): Date | null { + const startDate = this.normalizeDay(teachingBreak.startDate); + if (!startDate) return null; + + if (startDate.getDay() === 1) return startDate; + if (startDate.getDay() === 0) { + return new Date(startDate.getFullYear(), startDate.getMonth(), startDate.getDate() + 1); + } + + return new Date( + startDate.getFullYear(), + startDate.getMonth(), + startDate.getDate() + (8 - startDate.getDay()), + ); + } + + private mondayAfterBreak(teachingBreak: TeachingPeriodBreak): Date | null { + const firstMonday = this.firstMonday(teachingBreak); + if (!firstMonday || !teachingBreak.numberOfWeeks) return null; + + return new Date( + firstMonday.getFullYear(), + firstMonday.getMonth(), + firstMonday.getDate() + teachingBreak.numberOfWeeks * 7, + ); + } } diff --git a/src/app/api/models/tutorial-stream/tutorial-stream.ts b/src/app/api/models/tutorial-stream/tutorial-stream.ts index 2ba8c4db36..17c101fa0e 100644 --- a/src/app/api/models/tutorial-stream/tutorial-stream.ts +++ b/src/app/api/models/tutorial-stream/tutorial-stream.ts @@ -2,6 +2,7 @@ import {Entity} from 'ngx-entity-service'; import {Tutorial, Unit} from '../doubtfire-model'; export class TutorialStream extends Entity { + id: number; name: string; abbreviation: string; activityType: string; diff --git a/src/app/api/models/unit.ts b/src/app/api/models/unit.ts index a976538d4f..5bd4289862 100644 --- a/src/app/api/models/unit.ts +++ b/src/app/api/models/unit.ts @@ -58,6 +58,7 @@ export class Unit extends Entity { startDate: Date; //TODO: or string endDate: Date; //TODO: or string portfolioAutoGenerationDate: Date; + currentUnitWeek: number | null; assessmentEnabled: boolean; overseerImageId: number = null; // image needs to be lazy loadaed @@ -272,6 +273,38 @@ export class Unit extends Entity { return Math.ceil(this.totalDuration / (1000 * 60 * 60 * 24 * 7)); } + /** + * Calculate the teaching week number for a given date. + * Mirrors the Rails fallback in Unit#week_number when a teaching period + * helper is not being used on the frontend. + */ + public weekNumber(date: Date | string): number | null { + if (!date || !this.startDate) return null; + + if (this.teachingPeriod) { + return this.teachingPeriod.weekNumber(date); + } + + const targetDate = date instanceof Date ? date : new Date(date); + if (Number.isNaN(targetDate.valueOf())) return null; + const normalizedTargetDate = new Date( + targetDate.getFullYear(), + targetDate.getMonth(), + targetDate.getDate(), + ); + const normalizedStartDate = new Date( + this.startDate.getFullYear(), + this.startDate.getMonth(), + this.startDate.getDate(), + ); + const millisecondsPerWeek = 1000 * 60 * 60 * 24 * 7; + return ( + Math.floor( + (normalizedTargetDate.valueOf() - normalizedStartDate.valueOf()) / millisecondsPerWeek, + ) + 1 + ); + } + /** * Calculate how much time has elapsed in the teaching period, based on the start and * end date of the unit relative to the current date. diff --git a/src/app/api/services/communication-action.service.ts b/src/app/api/services/communication-action.service.ts new file mode 100644 index 0000000000..caa66352ca --- /dev/null +++ b/src/app/api/services/communication-action.service.ts @@ -0,0 +1,49 @@ +import {Observable, map} from 'rxjs'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CommunicationAction} from '../models/communication'; + +@Injectable() +export class CommunicationActionService { + constructor(private httpClient: HttpClient) {} + + public getForRule(unitId: number, ruleId: number): Observable { + return this.httpClient + .get[]>(this.endpoint(unitId, ruleId)) + .pipe(map((actions) => actions.map((action) => new CommunicationAction(action)))); + } + + public create( + unitId: number, + ruleId: number, + action: Partial, + ): Observable { + return this.httpClient + .post>(this.endpoint(unitId, ruleId), { + communication_action: action, + }) + .pipe(map((created) => new CommunicationAction(created))); + } + + public delete(unitId: number, ruleId: number, actionId: number): Observable { + return this.httpClient.delete(`${this.endpoint(unitId, ruleId)}/${actionId}`); + } + + public update( + unitId: number, + ruleId: number, + actionId: number, + action: Partial, + ): Observable { + return this.httpClient + .put>(`${this.endpoint(unitId, ruleId)}/${actionId}`, { + communication_action: action, + }) + .pipe(map((updated) => new CommunicationAction(updated))); + } + + private endpoint(unitId: number, ruleId: number): string { + return `${API_URL}/units/${unitId}/communication_rules/${ruleId}/actions`; + } +} diff --git a/src/app/api/services/communication-condition.service.ts b/src/app/api/services/communication-condition.service.ts new file mode 100644 index 0000000000..f8811e21eb --- /dev/null +++ b/src/app/api/services/communication-condition.service.ts @@ -0,0 +1,51 @@ +import {Observable, map} from 'rxjs'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CommunicationCondition} from '../models/communication'; + +@Injectable() +export class CommunicationConditionService { + constructor(private httpClient: HttpClient) {} + + public getForRule(unitId: number, ruleId: number): Observable { + return this.httpClient + .get[]>(this.endpoint(unitId, ruleId)) + .pipe( + map((conditions) => conditions.map((condition) => new CommunicationCondition(condition))), + ); + } + + public create( + unitId: number, + ruleId: number, + condition: Partial, + ): Observable { + return this.httpClient + .post>(this.endpoint(unitId, ruleId), { + communication_condition: condition, + }) + .pipe(map((created) => new CommunicationCondition(created))); + } + + public delete(unitId: number, ruleId: number, conditionId: number): Observable { + return this.httpClient.delete(`${this.endpoint(unitId, ruleId)}/${conditionId}`); + } + + public update( + unitId: number, + ruleId: number, + conditionId: number, + condition: Partial, + ): Observable { + return this.httpClient + .put>(`${this.endpoint(unitId, ruleId)}/${conditionId}`, { + communication_condition: condition, + }) + .pipe(map((updated) => new CommunicationCondition(updated))); + } + + private endpoint(unitId: number, ruleId: number): string { + return `${API_URL}/units/${unitId}/communication_rules/${ruleId}/conditions`; + } +} diff --git a/src/app/api/services/communication-rule.service.ts b/src/app/api/services/communication-rule.service.ts new file mode 100644 index 0000000000..a1f2d20c3c --- /dev/null +++ b/src/app/api/services/communication-rule.service.ts @@ -0,0 +1,67 @@ +import {Observable, map} from 'rxjs'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {CommunicationRule, CommunicationRulePreviewResponse} from '../models/communication'; +import {SidekiqJob} from '../models/sidekiq-job'; + +@Injectable() +export class CommunicationRuleService { + constructor(private httpClient: HttpClient) {} + + public getForSet(unitId: number, setId: number): Observable { + return this.httpClient + .get[]>(this.setEndpoint(unitId, setId)) + .pipe(map((rules) => rules.map((rule) => new CommunicationRule(rule)))); + } + + public createForSet( + unitId: number, + setId: number, + rule: Pick, + ): Observable { + return this.httpClient + .post>(this.setEndpoint(unitId, setId), { + communication_rule: rule, + }) + .pipe(map((created) => new CommunicationRule(created))); + } + + public updateForUnit( + unitId: number, + ruleId: number, + rule: Partial>, + ): Observable { + return this.httpClient + .put>(`${this.endpoint(unitId)}/${ruleId}`, { + communication_rule: rule, + }) + .pipe(map((updated) => new CommunicationRule(updated))); + } + + public deleteForUnit(unitId: number, ruleId: number): Observable { + return this.httpClient.delete(`${this.endpoint(unitId)}/${ruleId}`); + } + + public previewForUnit( + unitId: number, + ruleId: number, + ): Observable { + return this.httpClient.post( + `${this.endpoint(unitId)}/${ruleId}/preview`, + {}, + ); + } + + public executeForUnit(unitId: number, ruleId: number): Observable { + return this.httpClient.post(`${this.endpoint(unitId)}/${ruleId}/execute`, {}); + } + + private endpoint(unitId: number): string { + return `${API_URL}/units/${unitId}/communication_rules`; + } + + private setEndpoint(unitId: number, setId: number): string { + return `${API_URL}/units/${unitId}/communication_sets/${setId}/rules`; + } +} diff --git a/src/app/api/services/communication-set.service.ts b/src/app/api/services/communication-set.service.ts new file mode 100644 index 0000000000..eed9c7779c --- /dev/null +++ b/src/app/api/services/communication-set.service.ts @@ -0,0 +1,67 @@ +import {Observable, map} from 'rxjs'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import { + CommunicationSet, + CommunicationSetPreviewResponse, + CommunicationSetSchedule, +} from '../models/communication'; +import {SidekiqJob} from '../models/sidekiq-job'; + +@Injectable() +export class CommunicationSetService { + constructor(private httpClient: HttpClient) {} + + public getForUnit(unitId: number): Observable { + return this.httpClient + .get[]>(this.endpoint(unitId)) + .pipe(map((sets) => sets.map((set) => new CommunicationSet(set)))); + } + + public createForUnit( + unitId: number, + set: Pick & Partial>, + ): Observable { + return this.httpClient + .post>(this.endpoint(unitId), { + communication_set: set, + }) + .pipe(map((created) => new CommunicationSet(created))); + } + + public deleteForUnit(unitId: number, setId: number): Observable { + return this.httpClient.delete(`${this.endpoint(unitId)}/${setId}`); + } + + public updateForUnit( + unitId: number, + setId: number, + set: Partial> & { + schedules?: Partial[]; + }, + ): Observable { + return this.httpClient + .put>(`${this.endpoint(unitId)}/${setId}`, { + communication_set: set, + }) + .pipe(map((updated) => new CommunicationSet(updated))); + } + + public getForUnitById( + unitId: number, + setId: number, + ): Observable { + return this.httpClient.get( + `${this.endpoint(unitId)}/${setId}`, + ); + } + + public executeForUnit(unitId: number, setId: number): Observable { + return this.httpClient.post(`${this.endpoint(unitId)}/${setId}/execute`, {}); + } + + private endpoint(unitId: number): string { + return `${API_URL}/units/${unitId}/communication_sets`; + } +} diff --git a/src/app/api/services/tutorial-stream.service.ts b/src/app/api/services/tutorial-stream.service.ts index 0f17efcb7c..573d831854 100644 --- a/src/app/api/services/tutorial-stream.service.ts +++ b/src/app/api/services/tutorial-stream.service.ts @@ -11,7 +11,7 @@ export class TutorialStreamService extends CachedEntityService { constructor(httpClient: HttpClient) { super(httpClient, API_URL); - this.mapping.addKeys('name', 'abbreviation', 'activityType'); + this.mapping.addKeys('id', 'name', 'abbreviation', 'activityType'); this.mapping.mapAllKeysToJson(); } diff --git a/src/app/api/services/unit.service.ts b/src/app/api/services/unit.service.ts index 150f99ba38..8dafda21af 100644 --- a/src/app/api/services/unit.service.ts +++ b/src/app/api/services/unit.service.ts @@ -154,6 +154,7 @@ export class UnitService extends CachedEntityService { }, toJsonFn: MappingFunctions.mapDayToJson, }, + 'currentUnitWeek', { keys: 'portfolioAutoGenerationDate', toEntityFn: (data, key, _entity, _params?) => { diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index f6d671883d..4fefb44031 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -4,8 +4,6 @@ import {PickerModule} from '@ctrl/ngx-emoji-mart'; import {EmojiModule} from '@ctrl/ngx-emoji-mart/ngx-emoji'; import {CodeEditorModule} from '@ngstack/code-editor'; import {NgxChartsModule} from '@swimlane/ngx-charts'; -// import {GradeTaskModalComponent} from './tasks/modals/grade-task-modal/grade-task-modal.component'; -// import {PrivacyPolicy} from './config/privacy-policy/privacy-policy'; import {GANTT_GLOBAL_CONFIG, GanttLinkLineType, NgxGanttModule} from '@worktile/gantt'; import {DateAdapter as CalendarDateAdapter, CalendarModule} from 'angular-calendar'; import {adapterFactory} from 'angular-calendar/date-adapters/date-fns'; @@ -31,6 +29,8 @@ import { TaskCommentComposerComponent, } from 'src/app/tasks/task-comment-composer/task-comment-composer.component'; import {environment} from 'src/environments/environment'; +// import {GradeTaskModalComponent} from './tasks/modals/grade-task-modal/grade-task-modal.component'; +// import {PrivacyPolicy} from './config/privacy-policy/privacy-policy'; import {ClipboardModule} from '@angular/cdk/clipboard'; import {DragDropModule} from '@angular/cdk/drag-drop'; import {ScrollingModule} from '@angular/cdk/scrolling'; @@ -49,9 +49,9 @@ import { DateAdapter, MAT_DATE_FORMATS, MAT_DATE_LOCALE, + MatNativeDateModule, MatOptionModule, } from '@angular/material/core'; -import {MatNativeDateModule} from '@angular/material/core'; import {MatDatepickerModule} from '@angular/material/datepicker'; import {MatDialogModule} from '@angular/material/dialog'; import {MatDividerModule} from '@angular/material/divider'; @@ -77,10 +77,16 @@ import {MatTableModule} from '@angular/material/table'; import {MatTabsModule} from '@angular/material/tabs'; import {MatToolbarModule} from '@angular/material/toolbar'; import {MatTooltipModule} from '@angular/material/tooltip'; +import {MatTreeModule} from '@angular/material/tree'; import {BrowserModule, DomSanitizer, Title} from '@angular/platform-browser'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; import {RouterModule} from '@angular/router'; import {ServiceWorkerModule} from '@angular/service-worker'; +// import {GradeTaskModalComponent} from './tasks/modals/grade-task-modal/grade-task-modal.component'; +// import {PrivacyPolicy} from './config/privacy-policy/privacy-policy'; +// import {GradeTaskModalComponent} from './tasks/modals/grade-task-modal/grade-task-modal.component'; +// import {PrivacyPolicy} from './config/privacy-policy/privacy-policy'; +import {UpgradeModule} from '@angular/upgrade/static'; import {take} from 'rxjs/operators'; import {EditProfileComponent} from './account/edit-profile/edit-profile.component'; import {ActivityTypeListComponent} from './admin/institution-settings/activity-type-list/activity-type-list.component'; @@ -122,6 +128,10 @@ import { UserService, WebcalService, } from './api/models/doubtfire-model'; +import {CommunicationActionService} from './api/services/communication-action.service'; +import {CommunicationConditionService} from './api/services/communication-condition.service'; +import {CommunicationRuleService} from './api/services/communication-rule.service'; +import {CommunicationSetService} from './api/services/communication-set.service'; import {DiscussionPromptService} from './api/services/discussion-prompt.service'; import {FeedbackTemplateService} from './api/services/feedback-template.service'; import {GroupService} from './api/services/group.service'; @@ -291,6 +301,15 @@ import {TaskSubmissionHistoryComponent} from './tasks/task-submission-history/ta import {UnitStudentEnrolmentModalComponent} from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component'; import {AnalyticsTutorTimesComponent} from './units/states/analytics/directives/analytics-tutor-times.component'; import {UnitAnalyticsComponent} from './units/states/analytics/unit-analytics-route.component'; +import {ChangeTargetGradeActionComponent} from './units/states/edit/directives/unit-communications-editor/actions/change-target-grade-action/change-target-grade-action.component'; +import {CommunicationActionsComponent} from './units/states/edit/directives/unit-communications-editor/actions/communication-actions.component'; +import {EmailStaffActionComponent} from './units/states/edit/directives/unit-communications-editor/actions/email-staff-action/email-staff-action.component'; +import {EmailStudentActionComponent} from './units/states/edit/directives/unit-communications-editor/actions/email-student-action/email-student-action.component'; +import {TaskCommentActionComponent} from './units/states/edit/directives/unit-communications-editor/actions/task-comment-action/task-comment-action.component'; +import {CommunicationScheduleModalComponent} from './units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedule-modal.component'; +import {CommunicationSchedulesComponent} from './units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedules.component'; +import {CommunicationConditionsComponent} from './units/states/edit/directives/unit-communications-editor/conditions/communication-conditions.component'; +import {UnitCommunicationsEditorComponent} from './units/states/edit/directives/unit-communications-editor/unit-communications-editor.component'; import { D2lUnitDetailsFormComponent, D2lUnitDetailsModal, @@ -576,6 +595,15 @@ const GANTT_CHART_CONFIG = { UploadSubmissionModalComponent, ConfirmModerationModalComponent, TaskClaimComponent, + ChangeTargetGradeActionComponent, + CommunicationActionsComponent, + CommunicationConditionsComponent, + CommunicationScheduleModalComponent, + CommunicationSchedulesComponent, + EmailStaffActionComponent, + EmailStudentActionComponent, + TaskCommentActionComponent, + UnitCommunicationsEditorComponent, TutorialsComponent, UnitStaffEditorComponent, PortfolioGradeSelectStepComponent, @@ -682,6 +710,10 @@ const GANTT_CHART_CONFIG = { OverseerStepService, OverseerStepResultService, TutorNoteService, + CommunicationActionService, + CommunicationConditionService, + CommunicationRuleService, + CommunicationSetService, CsvResultModalService, CsvUploadModalService, ], @@ -728,6 +760,8 @@ const GANTT_CHART_CONFIG = { MatExpansionModule, MatGridListModule, MatTabsModule, + MatTreeModule, + UpgradeModule, MatTableModule, MatChipsModule, MatSnackBarModule, diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/change-target-grade-action/change-target-grade-action.component.html b/src/app/units/states/edit/directives/unit-communications-editor/actions/change-target-grade-action/change-target-grade-action.component.html new file mode 100644 index 0000000000..205949ae2f --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/change-target-grade-action/change-target-grade-action.component.html @@ -0,0 +1,23 @@ +@if (mode === 'edit') { + + Target grade + + @for (grade of editor.targetGrades; track grade.value) { + + {{ grade.label }} + + } + + +} @else { + + Target grade + + @for (grade of editor.targetGrades; track grade.value) { + + {{ grade.label }} + + } + + +} diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/change-target-grade-action/change-target-grade-action.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/actions/change-target-grade-action/change-target-grade-action.component.ts new file mode 100644 index 0000000000..2dad58259f --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/change-target-grade-action/change-target-grade-action.component.ts @@ -0,0 +1,15 @@ +import {CommunicationRule} from 'src/app/api/models/doubtfire-model'; +import {Component, Input} from '@angular/core'; +import type {UnitCommunicationsEditorComponent} from '../../unit-communications-editor.component'; + +@Component({ + selector: 'f-change-target-grade-action', + standalone: false, + templateUrl: './change-target-grade-action.component.html', + host: {class: 'flex w-full flex-col items-center'}, +}) +export class ChangeTargetGradeActionComponent { + @Input({required: true}) editor: UnitCommunicationsEditorComponent; + @Input({required: true}) rule: CommunicationRule; + @Input({required: true}) mode: 'add' | 'edit'; +} diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/communication-actions.component.html b/src/app/units/states/edit/directives/unit-communications-editor/actions/communication-actions.component.html new file mode 100644 index 0000000000..bed8d2313f --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/communication-actions.component.html @@ -0,0 +1,194 @@ +
    + + @for (action of rule.actions; track action.id) { + + @if (editor.editingActionId[rule.id] === action.id) { +
    + + Action + + @for (type of editor.actionTypes; track type) { + + {{ editor.actionTypeLabel(type) }} + + } + + + @switch (editor.actionFor(rule).type) { + @case ('EmailStudentAction') { + + } + @case ('EmailStaffAction') { + + } + @case ('TaskCommentAction') { + + } + @case ('ChangeTargetGradeAction') { + + } + } +
    + + +
    +
    + } @else { +
    +
    +
    + {{ editor.actionTypeLabel(action.type) }} +
    +
    + @switch (action.type) { + @case ('ChangeTargetGradeAction') { + Change student's target grade to + + {{ editor.targetGradeName(action.target_grade) }} + + } + @case ('EmailStudentAction') { + @if (action.subject || action.body) { +
    + @if (action.subject) { +
    +
    Subject
    +
    +
    + } + @if (action.body) { +
    +
    Body
    +
    +
    + } +
    + } + } + @case ('EmailStaffAction') { + Send email to + + {{ editor.staffAudienceLabel(action) }} + + @if (action.subject || action.body) { +
    + @if (action.subject) { +
    +
    Subject
    +
    +
    + } + @if (action.body) { +
    +
    Body
    +
    +
    + } +
    + } + } + @case ('TaskCommentAction') { + Add comment to + + {{ editor.taskDefinitionLabel(action.task_definition_id) }} + + @if (action.body) { +
    +
    +
    Comment
    +
    +
    +
    + } + } + @default { + {{ editor.actionSummary(action) }} + } + } +
    +
    +
    + + +
    +
    + } +
    + } +
    + + @if (editor.actionFormOpen[rule.id] && !editor.editingActionId[rule.id]) { +
    + + Action + + @for (type of editor.actionTypes; track type) { + + {{ editor.actionTypeLabel(type) }} + + } + + + + @switch (editor.actionFor(rule).type) { + @case ('EmailStudentAction') { + + } + + @case ('EmailStaffAction') { + + } + + @case ('TaskCommentAction') { + + } + + @case ('ChangeTargetGradeAction') { + + } + } + + + + +
    + } @else { +
    + +
    + } +
    diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/communication-actions.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/actions/communication-actions.component.ts new file mode 100644 index 0000000000..65e8dab8c5 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/communication-actions.component.ts @@ -0,0 +1,13 @@ +import {CommunicationRule} from 'src/app/api/models/doubtfire-model'; +import {Component, Input} from '@angular/core'; +import type {UnitCommunicationsEditorComponent} from '../unit-communications-editor.component'; + +@Component({ + selector: 'f-communication-actions', + standalone: false, + templateUrl: './communication-actions.component.html', +}) +export class CommunicationActionsComponent { + @Input({required: true}) editor: UnitCommunicationsEditorComponent; + @Input({required: true}) rule: CommunicationRule; +} diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/email-staff-action/email-staff-action.component.html b/src/app/units/states/edit/directives/unit-communications-editor/actions/email-staff-action/email-staff-action.component.html new file mode 100644 index 0000000000..f9b756c6fc --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/email-staff-action/email-staff-action.component.html @@ -0,0 +1,122 @@ +@if (mode === 'edit') { +
    + + Subject + + + + + @for (variable of editor.emailVariables; track variable.token) { + + } + + @if (editor.actionFor(rule).subject) { +
    +
    Subject Preview
    +
    +
    + } +
    + + Body + + + +
    +
    Body Preview
    +
    + @if (editor.actionFor(rule).body) { +
    + } @else { +
    Preview will appear here.
    + } +
    +
    +
    + + @for (variable of editor.emailVariables; track variable.token) { + + } + +
    + Tutors + Convenors +
    +
    Sent from the main convenor.
    +
    +} @else { +
    + + Subject + + + + + @for (variable of editor.emailVariables; track variable.token) { + + } + + + @if (editor.actionFor(rule).subject) { +
    +
    Subject Preview
    +
    +
    + } + +
    + + Body + + + +
    +
    Body Preview
    +
    + @if (editor.actionFor(rule).body) { +
    + } @else { +
    Preview will appear here.
    + } +
    +
    +
    + + @for (variable of editor.emailVariables; track variable.token) { + + } + + +
    + Tutors + Convenors +
    +
    Sent from the main convenor.
    +
    +} diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/email-staff-action/email-staff-action.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/actions/email-staff-action/email-staff-action.component.ts new file mode 100644 index 0000000000..00f5f42d57 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/email-staff-action/email-staff-action.component.ts @@ -0,0 +1,15 @@ +import {CommunicationRule} from 'src/app/api/models/doubtfire-model'; +import {Component, Input} from '@angular/core'; +import type {UnitCommunicationsEditorComponent} from '../../unit-communications-editor.component'; + +@Component({ + selector: 'f-email-staff-action', + standalone: false, + templateUrl: './email-staff-action.component.html', + host: {class: 'block w-full'}, +}) +export class EmailStaffActionComponent { + @Input({required: true}) editor: UnitCommunicationsEditorComponent; + @Input({required: true}) rule: CommunicationRule; + @Input({required: true}) mode: 'add' | 'edit'; +} diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/email-student-action/email-student-action.component.html b/src/app/units/states/edit/directives/unit-communications-editor/actions/email-student-action/email-student-action.component.html new file mode 100644 index 0000000000..90bdbf0273 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/email-student-action/email-student-action.component.html @@ -0,0 +1,113 @@ +@if (mode === 'edit') { +
    + + Subject + + + + + @for (variable of editor.emailVariables; track variable.token) { + + } + + @if (editor.actionFor(rule).subject) { +
    +
    Subject Preview
    +
    +
    + } +
    + + Body + + + +
    +
    Body Preview
    +
    + @if (editor.actionFor(rule).body) { +
    + } @else { +
    Preview will appear here.
    + } +
    +
    +
    + + @for (variable of editor.emailVariables; track variable.token) { + + } + +
    Sent from the main convenor.
    +
    +} @else { +
    + + Subject + + + + + @for (variable of editor.emailVariables; track variable.token) { + + } + + + @if (editor.actionFor(rule).subject) { +
    +
    Subject Preview
    +
    +
    + } + +
    + + Body + + + +
    +
    Body Preview
    +
    + @if (editor.actionFor(rule).body) { +
    + } @else { +
    Preview will appear here.
    + } +
    +
    +
    + + @for (variable of editor.emailVariables; track variable.token) { + + } + +
    Sent from the main convenor.
    +
    +} diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/email-student-action/email-student-action.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/actions/email-student-action/email-student-action.component.ts new file mode 100644 index 0000000000..d25b2bbe3f --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/email-student-action/email-student-action.component.ts @@ -0,0 +1,15 @@ +import {CommunicationRule} from 'src/app/api/models/doubtfire-model'; +import {Component, Input} from '@angular/core'; +import type {UnitCommunicationsEditorComponent} from '../../unit-communications-editor.component'; + +@Component({ + selector: 'f-email-student-action', + standalone: false, + templateUrl: './email-student-action.component.html', + host: {class: 'block w-full'}, +}) +export class EmailStudentActionComponent { + @Input({required: true}) editor: UnitCommunicationsEditorComponent; + @Input({required: true}) rule: CommunicationRule; + @Input({required: true}) mode: 'add' | 'edit'; +} diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/task-comment-action/task-comment-action.component.html b/src/app/units/states/edit/directives/unit-communications-editor/actions/task-comment-action/task-comment-action.component.html new file mode 100644 index 0000000000..ab8034b1a1 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/task-comment-action/task-comment-action.component.html @@ -0,0 +1,86 @@ +@if (mode === 'edit') { +
    + + Task + + @for (taskDefinition of editor.taskDefinitions; track taskDefinition.id) { + + {{ taskDefinition.abbreviation }} + {{ taskDefinition.name }} + + } + + +
    + + Comment + + + +
    +
    Comment Preview
    +
    + @if (editor.actionFor(rule).body) { +
    + } @else { +
    Preview will appear here.
    + } +
    +
    +
    + + @for (variable of editor.emailVariables; track variable.token) { + + } + +
    Sent from the main convenor.
    +
    +} @else { +
    + + Task + + @for (taskDefinition of editor.taskDefinitions; track taskDefinition.id) { + + {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} + + } + + +
    + + Comment + + + +
    +
    Comment Preview
    +
    + @if (editor.actionFor(rule).body) { +
    + } @else { +
    Preview will appear here.
    + } +
    +
    +
    + + @for (variable of editor.emailVariables; track variable.token) { + + } + +
    Sent from the main convenor.
    +
    +} diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/task-comment-action/task-comment-action.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/actions/task-comment-action/task-comment-action.component.ts new file mode 100644 index 0000000000..c95831579e --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/task-comment-action/task-comment-action.component.ts @@ -0,0 +1,15 @@ +import {CommunicationRule} from 'src/app/api/models/doubtfire-model'; +import {Component, Input} from '@angular/core'; +import type {UnitCommunicationsEditorComponent} from '../../unit-communications-editor.component'; + +@Component({ + selector: 'f-task-comment-action', + standalone: false, + templateUrl: './task-comment-action.component.html', + host: {class: 'block w-full'}, +}) +export class TaskCommentActionComponent { + @Input({required: true}) editor: UnitCommunicationsEditorComponent; + @Input({required: true}) rule: CommunicationRule; + @Input({required: true}) mode: 'add' | 'edit'; +} diff --git a/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedule-modal.component.html b/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedule-modal.component.html new file mode 100644 index 0000000000..a4b227f91e --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedule-modal.component.html @@ -0,0 +1,91 @@ +

    + {{ draft.id ? 'Edit communication schedule' : 'Add communication schedule' }} +

    + + +
    + + Name + + + + + Timezone + + +
    + + Schedule active + +
    + + Week + + + + + Day + + @for (weekday of weekdays; track weekday.value) { + {{ weekday.label }} + } + + + + + Hour + + + + + Minute + + +
    + + + Repeat + + One time only + Daily + Weekly + Monthly + + + + @if (draft.recurrence !== 'none') { +
    + + Every + + + + + Stop after runs + + + + + Or stop on + + +
    + } + +
    +
    Summary
    +
    {{ scheduleSummary() }}
    +
    + + +
    + + + + + diff --git a/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedule-modal.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedule-modal.component.ts new file mode 100644 index 0000000000..be1b88c489 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedule-modal.component.ts @@ -0,0 +1,187 @@ +import { + Campus, + CampusService, + CommunicationSetSchedule, + Unit, +} from 'src/app/api/models/doubtfire-model'; +import {Component, Inject, OnInit} from '@angular/core'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; + +export interface CommunicationScheduleModalData { + schedule?: CommunicationSetSchedule; + unit?: Unit; +} + +export const SCHEDULE_WEEKDAYS = [ + {value: 0, label: 'Sunday', shortLabel: 'Sun'}, + {value: 1, label: 'Monday', shortLabel: 'Mon'}, + {value: 2, label: 'Tuesday', shortLabel: 'Tue'}, + {value: 3, label: 'Wednesday', shortLabel: 'Wed'}, + {value: 4, label: 'Thursday', shortLabel: 'Thu'}, + {value: 5, label: 'Friday', shortLabel: 'Fri'}, + {value: 6, label: 'Saturday', shortLabel: 'Sat'}, +] as const; + +@Component({ + selector: 'f-communication-schedule-modal', + standalone: false, + templateUrl: './communication-schedule-modal.component.html', +}) +export class CommunicationScheduleModalComponent implements OnInit { + readonly weekdays = SCHEDULE_WEEKDAYS; + campuses: Campus[] = []; + timezonePlaceholder = 'UTC'; + draft = new CommunicationSetSchedule({ + name: 'Schedule 1', + active: true, + anchor_week: 1, + anchor_day: 'Monday', + recurrence: 'none', + interval: 1, + timezone: 'UTC', + hour: 8, + minute: 0, + }); + untilDateTime = ''; + + constructor( + private campusService: CampusService, + public dialogRef: MatDialogRef, + @Inject(MAT_DIALOG_DATA) public data: CommunicationScheduleModalData, + ) { + if (data.schedule) { + this.draft = new CommunicationSetSchedule({ + ...data.schedule, + }); + } + + this.untilDateTime = this.asDateTimeLocal(this.draft.until_at); + } + + ngOnInit(): void { + this.campusService.query().subscribe((campuses) => { + this.campuses = campuses; + const defaultTimezone = campuses[0]?.timezone; + if (!defaultTimezone) return; + + this.timezonePlaceholder = defaultTimezone; + if (!this.draft.timezone || this.draft.timezone === 'UTC') { + this.draft.timezone = defaultTimezone; + } + }); + } + + canSave(): boolean { + return !!this.draft.anchor_week && !!this.draft.anchor_day; + } + + save(): void { + const schedule = new CommunicationSetSchedule({ + ...this.draft, + name: this.draft.name?.trim() || 'Untitled schedule', + until_at: this.untilDateTime || undefined, + anchor_week: Math.max(1, Number(this.draft.anchor_week || 1)), + anchor_day: this.draft.anchor_day || 'Monday', + hour: this.safeHour(), + minute: this.safeMinute(), + }); + + schedule.ice_cube_schedule = this.toIceCubePayload(schedule); + this.dialogRef.close(schedule); + } + + scheduleSummary(): string { + const parts: string[] = []; + parts.push( + `Starts Week ${this.draft.anchor_week || 1} ${this.draft.anchor_day || 'Monday'} at ${this.timeLabel(this.safeHour(), this.safeMinute())}`, + ); + + switch (this.draft.recurrence) { + case 'daily': + parts.push(`Repeats every ${this.draft.interval || 1} day(s)`); + break; + case 'weekly': + parts.push(`Repeats every ${this.draft.interval || 1} week(s)`); + break; + case 'monthly': + parts.push(`Repeats every ${this.draft.interval || 1} month(s)`); + break; + default: + parts.push('Runs once'); + } + + if (this.draft.repeat_count) parts.push(`up to ${this.draft.repeat_count} times`); + if (this.untilDateTime) parts.push(`until ${this.untilDateTime}`); + + return parts.join(' | '); + } + + iceCubePreview(): string { + return JSON.stringify(this.toIceCubePayload(this.draft), null, 2); + } + + private safeHour(): number { + return Math.min(23, Math.max(0, Number(this.draft.hour ?? 8))); + } + + private safeMinute(): number { + return Math.min(59, Math.max(0, Number(this.draft.minute ?? 0))); + } + + private toIceCubePayload(schedule: CommunicationSetSchedule): Record { + const payload: Record = { + timezone: schedule.timezone || 'UTC', + anchor: this.anchorPayload(schedule), + recurrence: schedule.recurrence, + interval: schedule.interval || 1, + limits: { + count: schedule.repeat_count || null, + until: schedule.until_at || null, + }, + rules: [], + }; + + const rules = payload.rules as Record[]; + switch (schedule.recurrence) { + case 'daily': + rules.push({ + type: 'daily', + interval: schedule.interval || 1, + }); + break; + case 'weekly': + rules.push({ + type: 'weekly', + interval: schedule.interval || 1, + }); + break; + case 'monthly': + rules.push({ + type: 'monthly', + interval: schedule.interval || 1, + }); + break; + default: + rules.push({type: 'one_off'}); + } + + return payload; + } + + private anchorPayload(schedule: CommunicationSetSchedule): Record { + return { + week: schedule.anchor_week || 1, + day: schedule.anchor_day || 'Monday', + time_of_day: this.timeLabel(schedule.hour || 0, schedule.minute || 0), + }; + } + + private asDateTimeLocal(value?: string): string { + if (!value) return ''; + return value.length >= 16 ? value.slice(0, 16) : value; + } + + private timeLabel(hour: number, minute: number): string { + return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`; + } +} diff --git a/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedules.component.html b/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedules.component.html new file mode 100644 index 0000000000..b2da72c454 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedules.component.html @@ -0,0 +1,71 @@ +@if (editor.setPreviewLoading) { + +} + +
    +
    +
    +
    Schedules
    +
    Build one-off or recurring schedules for this set.
    +
    + +
    + + @if ((set.schedules || []).length) { +
    + @for (schedule of set.schedules || []; track editor.scheduleTrackId(schedule)) { +
    +
    +
    +
    {{ schedule.name || 'Untitled schedule' }}
    +
    {{ editor.scheduleSummary(schedule) }}
    +
    + +
    + + {{ schedule.active ? 'Active' : 'Inactive' }} + + + +
    +
    + +
    +
    +
    Anchor
    +
    {{ editor.scheduleAnchorSummary(schedule) }}
    +
    +
    +
    Time
    +
    {{ editor.scheduleTimeSummary(schedule) }}
    +
    +
    +
    Next Run
    +
    {{ editor.scheduleNextRunSummary(schedule) }}
    +
    +
    +
    Last Run
    +
    {{ editor.scheduleLastRunSummary(schedule) }}
    +
    +
    +
    + } +
    + } @else { +
    + No schedules yet. Add one to run this set on a fixed date or on a repeating cadence. +
    + } +
    diff --git a/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedules.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedules.component.ts new file mode 100644 index 0000000000..b80c98e2f3 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedules.component.ts @@ -0,0 +1,13 @@ +import {CommunicationSet} from 'src/app/api/models/doubtfire-model'; +import {Component, Input} from '@angular/core'; +import type {UnitCommunicationsEditorComponent} from '../unit-communications-editor.component'; + +@Component({ + selector: 'f-communication-schedules', + standalone: false, + templateUrl: './communication-schedules.component.html', +}) +export class CommunicationSchedulesComponent { + @Input({required: true}) editor: UnitCommunicationsEditorComponent; + @Input({required: true}) set: CommunicationSet; +} diff --git a/src/app/units/states/edit/directives/unit-communications-editor/conditions/communication-conditions.component.html b/src/app/units/states/edit/directives/unit-communications-editor/conditions/communication-conditions.component.html new file mode 100644 index 0000000000..83c935cac4 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/conditions/communication-conditions.component.html @@ -0,0 +1,497 @@ +
    +
    + + Conditions + + @for (option of editor.logicalOperatorOptions; track option.value) { + + {{ option.label }} + + } + + +
    + + + @for (condition of rule.conditions; track condition.id) { + + @if (editor.editingConditionId[rule.id] === condition.id) { +
    + + Condition + + @for (type of editor.conditionTypes; track type) { + + {{ editor.conditionTypeLabel(type) }} + + } + + + + @if (editor.conditionFor(rule).type === 'TaskDefinitionStatusCondition') { + + Task + + @for (taskDefinition of editor.taskDefinitions; track taskDefinition.id) { + + {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} + + } + + + } + + + Operator + + @for ( + operator of editor.operatorsFor(editor.conditionFor(rule).type); + track operator + ) { + + {{ editor.operatorLabel(operator) }} + + } + + + + @if (editor.conditionFor(rule).type === 'TaskStatusCountCondition') { + + Count + + + + + Task grade + + @for (grade of editor.targetGrades; track grade.value) { + + {{ grade.label }} + + } + + + } + + @switch (editor.conditionFor(rule).type) { + @case ('TargetGradeCondition') { + + Target grade + + @for (grade of editor.targetGrades; track grade.value) { + + {{ grade.label }} + + } + + + } + @case ('TaskDefinitionStatusCondition') { + + Statuses + + @for (status of editor.taskStatuses; track status) { + + {{ editor.taskStatusLabel(status) }} + + } + + + } + @case ('TaskStatusCountCondition') { + + Statuses + + @for (status of editor.taskStatuses; track status) { + + {{ editor.taskStatusLabel(status) }} + + } + + + } + @case ('LoginStatusCondition') { + + Last sign in + + + } + @case ('SpecConCondition') { + + Days + + + } + @case ('TutorialEnrolmentCondition') { + + Tutorial + + @for (tutorial of editor.tutorials; track tutorial.id) { + + {{ tutorial.abbreviation }} {{ tutorial.description }} + + } + + + } + @case ('TutorialStreamEnrolmentCondition') { + + Tutorial stream + + @for (stream of editor.tutorialStreams; track stream.id) { + + {{ stream.abbreviation }} {{ stream.name }} + + } + + + } + @case ('CampusCondition') { + + Campus + + @for (campus of editor.campuses; track campus.id) { + + {{ campus.abbreviation }} {{ campus.name }} + + } + + + } + } + + + +
    + } @else { +
    +
    +
    + {{ editor.conditionTypeLabel(condition.type) }} +
    +
    + @switch (condition.type) { + @case ('TargetGradeCondition') { + Students with a + Target Grade + + {{ editor.operatorLabel(condition.operator) }} + + + {{ editor.targetGradeName(condition.target_grade) }} + + } + @case ('TaskDefinitionStatusCondition') { + Students that have + + {{ editor.taskDefinitionLabel(condition.task_definition_id) }} + + + {{ editor.taskStatusPredicate(condition.operator) }} + + + {{ editor.taskStatusesLabel(condition.task_statuses) }} + + } + @case ('TaskStatusCountCondition') { + Students with + Task Status Count + + {{ editor.operatorLabel(condition.operator) }} + + + {{ condition.task_status_count }} + + + {{ editor.targetGradeName(condition.task_target_grade) }} + + tasks in + + {{ editor.taskStatusesLabel(condition.task_statuses) }} + + } + @case ('LoginStatusCondition') { + Students with a + Last Sign In + + {{ editor.operatorLabel(condition.operator) }} + + + {{ editor.dateLabel(condition.last_sign_in_at) }} + + } + @case ('SpecConCondition') { + Students with + Special Consideration Days + + {{ editor.operatorLabel(condition.operator) }} + + + {{ condition.spec_con_days }} + + } + @case ('TutorialEnrolmentCondition') { + Students + + {{ editor.enrolmentPredicate(condition.operator) }} + + + {{ editor.tutorialLabel(condition.tutorial_id) }} + + } + @case ('TutorialStreamEnrolmentCondition') { + Students + + {{ editor.enrolmentPredicate(condition.operator) }} + + + {{ editor.tutorialStreamLabel(condition.tutorial_stream_id) }} + + } + @case ('CampusCondition') { + Students + + {{ editor.enrolmentPredicate(condition.operator) }} + + + {{ editor.campusLabel(condition.campus_id) }} + + } + @default { + {{ editor.operatorLabel(condition.operator) }} + {{ editor.labelFor(condition) }} + } + } +
    +
    +
    + + +
    +
    + } +
    + } +
    + + @if (editor.conditionFormOpen[rule.id] && !editor.editingConditionId[rule.id]) { +
    + + Condition + + @for (type of editor.conditionTypes; track type) { + + {{ editor.conditionTypeLabel(type) }} + + } + + + + @if (editor.conditionFor(rule).type === 'TaskDefinitionStatusCondition') { + + Task + + @for (taskDefinition of editor.taskDefinitions; track taskDefinition.id) { + + {{ taskDefinition.abbreviation }} {{ taskDefinition.name }} + + } + + + } + + + Operator + + @for (operator of editor.operatorsFor(editor.conditionFor(rule).type); track operator) { + + {{ editor.operatorLabel(operator) }} + + } + + + + @if (editor.conditionFor(rule).type === 'TaskStatusCountCondition') { + + Count + + + + + Task grade + + @for (grade of editor.targetGrades; track grade.value) { + + {{ grade.label }} + + } + + + } + + @switch (editor.conditionFor(rule).type) { + @case ('TargetGradeCondition') { + + Target grade + + @for (grade of editor.targetGrades; track grade.value) { + + {{ grade.label }} + + } + + + } + + @case ('TaskDefinitionStatusCondition') { + + Statuses + + @for (status of editor.taskStatuses; track status) { + + {{ editor.taskStatusLabel(status) }} + + } + + + } + + @case ('TaskStatusCountCondition') { + + Statuses + + @for (status of editor.taskStatuses; track status) { + + {{ editor.taskStatusLabel(status) }} + + } + + + } + + @case ('LoginStatusCondition') { + + Last sign in + + + } + @case ('SpecConCondition') { + + Days + + + } + + @case ('TutorialEnrolmentCondition') { + + Tutorial + + @for (tutorial of editor.tutorials; track tutorial.id) { + + {{ tutorial.abbreviation }} {{ tutorial.description }} + + } + + + } + + @case ('TutorialStreamEnrolmentCondition') { + + Tutorial stream + + @for (stream of editor.tutorialStreams; track stream.id) { + + {{ stream.abbreviation }} {{ stream.name }} + + } + + + } + + @case ('CampusCondition') { + + Campus + + @for (campus of editor.campuses; track campus.id) { + + {{ campus.abbreviation }} {{ campus.name }} + + } + + + } + } + + + + +
    + } @else { +
    + +
    + } +
    diff --git a/src/app/units/states/edit/directives/unit-communications-editor/conditions/communication-conditions.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/conditions/communication-conditions.component.ts new file mode 100644 index 0000000000..4d9d8003a7 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/conditions/communication-conditions.component.ts @@ -0,0 +1,13 @@ +import {CommunicationRule} from 'src/app/api/models/doubtfire-model'; +import {Component, Input} from '@angular/core'; +import type {UnitCommunicationsEditorComponent} from '../unit-communications-editor.component'; + +@Component({ + selector: 'f-communication-conditions', + standalone: false, + templateUrl: './communication-conditions.component.html', +}) +export class CommunicationConditionsComponent { + @Input({required: true}) editor: UnitCommunicationsEditorComponent; + @Input({required: true}) rule: CommunicationRule; +} diff --git a/src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.html b/src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.html new file mode 100644 index 0000000000..fe605bc0b5 --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.html @@ -0,0 +1,345 @@ +
    +
    +

    Current unit week: {{ currentUnitWeek <= 0 ? 'Not started' : currentUnitWeek }}

    +
    +
    + +
    + + @if (loading) { + + } + + + + + + + +
    +
    + + +
    +
    +
    + + +
    +
    + + + +
    + + @if (treeControl.isExpanded(node)) { +
    + + + +
    + } +
    +
    +
    +
    + + + @if (selectedSet(); as set) { +
    +
    +
    + @if (editingSetNameId === set.id) { + + Set name + + + + + } @else { +

    {{ set.name }}

    + + } +
    +
    + + + + +
    +
    + + +
    + + + @if (selectedRule(); as rule) { +
    +
    + @if (editingRuleNameId === rule.id) { + + Rule name + + + + + } @else { +
    +
    {{ rule.name }}
    + +
    + } +
    + +
    + +
    +
    + + + + + + + + + + + +
    + + Send action log to convenors after execution + + +
    + +
    +
    +
    + + +
    +
    + +
    + + @if (setPreviewLoading || previewLoading[rule.id]) { + + } @else if (previewLoaded[rule.id]) { +
    + Selected for {{ rule.name }} ({{ studentsFor(rule).length }}) +
    + + @if (studentsFor(rule).length === 0) { +
    No students currently match this rule.
    + } @else { + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
    Preferred Name + {{ student.preferred_name || '-' }} + First Name + {{ student.first_name || '-' }} + Last Name + {{ student.last_name || '-' }} + Full Name + {{ student.full_name || '-' }} + Username + {{ student.username || '-' }} + Student ID + {{ student.student_id || '-' }} + Campus + {{ student.campus || '-' }} + Target Grade + {{ + student.target_grade ? targetGradeName(student.target_grade) : '-' + }} + Spec Con Days + {{ student.spec_con_days ?? '-' }} + Last Sign In + {{ + student.last_sign_in_at ? dateLabel(student.last_sign_in_at) : '-' + }} +
    + } + } @else { +
    + Preview data will load when you select a communication set. +
    + } +
    +
    +
    + } @else { +
    + Select a communication rule to edit its conditions, actions, and preview. +
    + } +
    +
    + } @else { +
    + Create or select a communication set to begin. +
    + } +
    +
    +
    diff --git a/src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.scss b/src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.ts new file mode 100644 index 0000000000..427dd2dc9c --- /dev/null +++ b/src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.ts @@ -0,0 +1,1365 @@ +import {Subscription} from 'rxjs'; +import { + Campus, + CampusService, + CommunicationAction, + CommunicationActionService, + CommunicationCondition, + CommunicationConditionService, + CommunicationRule, + CommunicationRulePreviewAllocation, + CommunicationRulePreviewResponse, + CommunicationRulePreviewStudent, + CommunicationRuleService, + CommunicationSet, + CommunicationSetPreviewResponse, + CommunicationSetSchedule, + CommunicationSetService, + ProjectService, + TaskDefinition, + Tutorial, + TutorialStream, + Unit, +} from 'src/app/api/models/doubtfire-model'; +import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {NestedTreeControl} from '@angular/cdk/tree'; +import {Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import {MatTreeNestedDataSource} from '@angular/material/tree'; +import { + CommunicationScheduleModalComponent, + CommunicationScheduleModalData, +} from './communication-schedule-modal/communication-schedule-modal.component'; + +interface CommunicationTreeNode { + type: 'set' | 'rule'; + id: number; + label: string; + set?: CommunicationSet; + rule?: CommunicationRule; + children?: CommunicationTreeNode[]; +} + +@Component({ + selector: 'f-unit-communications-editor', + standalone: false, + templateUrl: './unit-communications-editor.component.html', + styleUrl: './unit-communications-editor.component.scss', +}) +export class UnitCommunicationsEditorComponent implements OnInit, OnChanges, OnDestroy { + @Input() unit: Unit; + + readonly editorContext = this; + sets: CommunicationSet[] = []; + selectedSetId?: number; + selectedRuleId?: number; + rules: CommunicationRule[] = []; + campuses: Campus[] = []; + taskDefinitions: readonly TaskDefinition[] = []; + tutorials: readonly Tutorial[] = []; + tutorialStreams: readonly TutorialStream[] = []; + loading = false; + setPreviewLoading = false; + readonly previewStudentColumns = [ + 'preferred_name', + 'first_name', + 'last_name', + 'full_name', + 'username', + 'student_id', + 'campus', + 'target_grade', + 'spec_con_days', + 'last_sign_in_at', + ]; + + readonly logicalOperators = ['and', 'or']; + readonly logicalOperatorOptions = [ + {value: 'and', label: 'All the following conditions'}, + {value: 'or', label: 'Any of the following conditions'}, + ] as const; + readonly conditionTypes = [ + 'TargetGradeCondition', + 'TaskDefinitionStatusCondition', + 'TaskStatusCountCondition', + 'LoginStatusCondition', + 'SpecConCondition', + 'TutorialEnrolmentCondition', + 'TutorialStreamEnrolmentCondition', + 'CampusCondition', + ]; + readonly conditionTypeLabels: Record = { + TargetGradeCondition: 'Target Grade', + TaskDefinitionStatusCondition: 'Task Status', + TaskStatusCountCondition: 'Task Status Count', + LoginStatusCondition: 'Login Status', + SpecConCondition: 'Special Consideration Days', + TutorialEnrolmentCondition: 'Tutorial Enrolment', + TutorialStreamEnrolmentCondition: 'Tutorial Stream Enrolment', + CampusCondition: 'Campus', + }; + readonly actionTypes = [ + 'EmailStudentAction', + 'EmailStaffAction', + 'ChangeTargetGradeAction', + 'TaskCommentAction', + ]; + readonly actionTypeLabels: Record = { + EmailStudentAction: 'Send email to student', + EmailStaffAction: 'Send email to staff', + ChangeTargetGradeAction: 'Change Target Grade', + TaskCommentAction: 'Task Comment', + }; + readonly gradeOperators = [ + 'greater_than', + 'greater_than_or_equal_to', + 'less_than', + 'less_than_or_equal_to', + 'equal_to', + 'not_equal_to', + ]; + readonly equalityOperators = ['equal_to', 'not_equal_to']; + readonly dateOperators = ['before', 'after']; + readonly enrolmentOperators = ['enrolled_in', 'not_enrolled_in']; + readonly operatorLabels: Record = { + greater_than: 'Greater Than', + greater_than_or_equal_to: 'Greater Than Or Equal To', + less_than: 'Less Than', + less_than_or_equal_to: 'Less Than Or Equal To', + equal_to: 'Equal To', + not_equal_to: 'Not Equal To', + before: 'Before', + after: 'After', + enrolled_in: 'Enrolled In', + not_enrolled_in: 'Not Enrolled In', + }; + readonly targetGrades = [ + {value: 0, label: 'P'}, + {value: 1, label: 'C'}, + {value: 2, label: 'D'}, + {value: 3, label: 'HD'}, + ]; + readonly targetGradeLabels: Record = { + 0: 'P', + 1: 'C', + 2: 'D', + 3: 'HD', + }; + readonly targetGradeNames: Record = { + 0: 'Pass', + 1: 'Credit', + 2: 'Distinction', + 3: 'High Distinction', + }; + readonly emailVariables = [ + {token: '{{student.first_name}}', label: 'Student First Name'}, + {token: '{{student.last_name}}', label: 'Student Last Name'}, + {token: '{{student.preferred_name}}', label: 'Student Preferred Name'}, + {token: '{{student.full_name}}', label: 'Student Full Name'}, + {token: '{{student.username}}', label: 'Student Username'}, + {token: '{{student.student_id}}', label: 'Student ID'}, + {token: '{{affected_students_count}}', label: 'Affected Students Count'}, + {token: '{{unit.code}}', label: 'Unit Code'}, + {token: '{{unit.name}}', label: 'Unit Name'}, + {token: '{{rule.name}}', label: 'Rule Name'}, + {token: '{{target_grade}}', label: 'Target Grade'}, + // {token: '{{conditions_summary}}', label: 'Conditions Summary'}, + // {token: '{{actions_summary}}', label: 'Actions Summary'}, + ]; + readonly taskStatuses = [ + 'not_started', + 'complete', + 'need_help', + 'working_on_it', + 'fix_and_resubmit', + 'feedback_exceeded', + 'redo', + 'discuss', + 'ready_for_feedback', + 'demonstrate', + 'fail', + 'time_exceeded', + 'assess_in_portfolio', + 'attention_required', + ]; + + newConditions: Record> = {}; + conditionFormOpen: Record = {}; + editingConditionId: Record = {}; + newActions: Record> = {}; + actionFormOpen: Record = {}; + editingActionId: Record = {}; + previewTabIndex: Record = {}; + previewLoading: Record = {}; + previewLoaded: Record = {}; + previewStudents: Record = {}; + previewAllocations: Record = {}; + editingSetNameId?: number; + editingRuleNameId?: number; + setNameDraft = ''; + ruleNameDraft = ''; + readonly treeControl: NestedTreeControl = new NestedTreeControl( + (node) => node.children, + ); + readonly treeDataSource: MatTreeNestedDataSource = + new MatTreeNestedDataSource(); + private expandedSetIds: Set = new Set(); + + private subscriptions: Subscription[] = []; + + get currentUnitWeek(): number | null { + return this.unit?.currentUnitWeek ?? null; + } + + constructor( + private ruleService: CommunicationRuleService, + private conditionService: CommunicationConditionService, + private actionService: CommunicationActionService, + private setService: CommunicationSetService, + private projectService: ProjectService, + private dialog: MatDialog, + private campusService: CampusService, + private alerts: AlertService, + private sidekiqProgressModalService: SidekiqProgressModalService, + private confirmationModalService: ConfirmationModalService, + ) {} + + ngOnInit(): void { + this.campusService.query().subscribe((campuses) => { + this.campuses = campuses; + }); + this.refreshUnitLookups(); + this.loadSets(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.unit && this.unit) { + this.refreshUnitLookups(); + this.loadSets(); + } + } + + addSet(): void { + if (!this.unit) return; + + const newSet = { + name: this.defaultSetName(), + active: true, + } as Pick & Partial>; + + this.setService.createForUnit(this.unit.id, newSet).subscribe({ + next: (set) => { + this.sets.push(set); + this.expandedSetIds.add(set.id); + this.selectedSetId = set.id; + this.selectSet(); + }, + error: (error) => this.showError(error), + }); + } + + deleteSet(set: CommunicationSet): void { + this.setService.deleteForUnit(this.unit.id, set.id).subscribe({ + next: () => { + this.sets = this.sets.filter((item) => item.id !== set.id); + this.expandedSetIds.delete(set.id); + if (this.selectedSetId === set.id) { + this.selectedSetId = undefined; + } + this.selectSet(); + }, + error: (error) => this.showError(error), + }); + } + + beginEditSetName(set: CommunicationSet): void { + this.editingSetNameId = set.id; + this.setNameDraft = set.name; + } + + cancelEditSetName(): void { + this.editingSetNameId = undefined; + this.setNameDraft = ''; + } + + saveSetName(set: CommunicationSet): void { + const name = this.setNameDraft.trim(); + if (!name) return; + + this.setService.updateForUnit(this.unit.id, set.id, {name}).subscribe({ + next: (updated) => { + set.name = updated.name; + const matchingSet = this.sets.find((item) => item.id === set.id); + if (matchingSet) { + matchingSet.name = updated.name; + } + this.cancelEditSetName(); + this.rebuildTree(); + }, + error: (error) => this.showError(error), + }); + } + + confirmExecuteSet(set: CommunicationSet): void { + this.confirmationModalService.show( + 'Execute Set?', + 'This will execute every rule in this set, in sequence. Once a student is matched by an earlier rule, they are removed from consideration for the remaining rules, so each student can only be picked up once during the set run.', + () => this.executeSet(set), + undefined, + 'Execute Set', + ); + } + + executeSet(set: CommunicationSet): void { + this.setService.executeForUnit(this.unit.id, set.id).subscribe({ + next: (job) => this.showExecutionProgress(job, `Executing ${set.name}`), + error: (error) => this.showError(error), + }); + } + + addSchedule(set: CommunicationSet): void { + this.openScheduleModal(set); + } + + editSchedule(set: CommunicationSet, schedule: CommunicationSetSchedule): void { + this.openScheduleModal(set, schedule); + } + + deleteSchedule(set: CommunicationSet, schedule: CommunicationSetSchedule): void { + const updatedSchedules = (set.schedules || []).filter( + (item) => (item.id || item.client_key) !== (schedule.id || schedule.client_key), + ); + this.persistSchedules(set, updatedSchedules, 'Schedule removed'); + } + + scheduleTrackId(schedule: CommunicationSetSchedule): string | number { + return ( + schedule.id || + schedule.client_key || + `${schedule.name || 'schedule'}-${schedule.anchor_week}-${schedule.anchor_day}` + ); + } + + scheduleSummary(schedule: CommunicationSetSchedule): string { + const cadence = this.scheduleCadence(schedule); + const ending = this.scheduleEnding(schedule); + return [cadence, ending].filter(Boolean).join(' | '); + } + + scheduleAnchorSummary(schedule: CommunicationSetSchedule): string { + return `Week ${schedule.anchor_week || 1} on ${schedule.anchor_day || 'Monday'}`; + } + + scheduleTimeSummary(schedule: CommunicationSetSchedule): string { + return `${this.formatTime(schedule.hour, schedule.minute)} ${schedule.timezone || 'UTC'}`; + } + + scheduleNextRunSummary(schedule: CommunicationSetSchedule): string { + return schedule.next_run_at ? this.dateLabel(schedule.next_run_at) : 'Not scheduled'; + } + + scheduleLastRunSummary(schedule: CommunicationSetSchedule): string { + return schedule.last_run_at ? this.dateLabel(schedule.last_run_at) : 'Not yet run'; + } + + iceCubePreview(schedule: CommunicationSetSchedule): string { + return JSON.stringify(schedule.ice_cube_schedule || {}, null, 2); + } + + selectSet(): void { + const set = this.selectedSet(); + if (set) { + this.activateSet(set); + } else { + this.rules = []; + this.selectedRuleId = undefined; + this.rebuildTree(); + } + } + + ngOnDestroy(): void { + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); + } + + addRule(): void { + if (!this.unit) return; + const set = this.selectedSet(); + if (!set) return; + + const newRule = { + name: this.defaultRuleName(), + operator: 'and', + } as Pick; + + this.ruleService.createForSet(this.unit.id, set.id, newRule).subscribe({ + next: (rule) => { + this.rules.push(rule); + set.rules = this.rules; + this.selectedRuleId = rule.id; + this.expandedSetIds.add(set.id); + this.loadPreviewForSet(set); + }, + error: (error) => this.showError(error), + }); + } + + deleteRule(rule: CommunicationRule): void { + this.ruleService.deleteForUnit(this.unit.id, rule.id).subscribe({ + next: () => { + this.rules = this.rules.filter((item) => item.id !== rule.id); + const set = this.selectedSet(); + if (set) { + set.rules = this.rules; + this.selectedRuleId = this.rules[0]?.id; + this.loadPreviewForSet(set); + } + }, + error: (error) => this.showError(error), + }); + } + + updateRuleOperator(rule: CommunicationRule): void { + this.ruleService.updateForUnit(this.unit.id, rule.id, {operator: rule.operator}).subscribe({ + next: (updated) => { + rule.operator = updated.operator; + this.refreshPreview(rule); + }, + error: (error) => this.showError(error), + }); + } + + updateRule(rule: CommunicationRule): void { + this.ruleService + .updateForUnit(this.unit.id, rule.id, { + name: rule.name, + operator: rule.operator, + send_log_to_convenors: rule.send_log_to_convenors, + }) + .subscribe({ + next: (updated) => { + rule.name = updated.name; + rule.operator = updated.operator; + rule.send_log_to_convenors = updated.send_log_to_convenors; + const set = this.selectedSet(); + if (set) { + set.rules = this.rules; + } + this.refreshPreview(rule); + }, + error: (error) => this.showError(error), + }); + } + + beginEditRuleName(rule: CommunicationRule): void { + this.editingRuleNameId = rule.id; + this.ruleNameDraft = rule.name; + } + + cancelEditRuleName(): void { + this.editingRuleNameId = undefined; + this.ruleNameDraft = ''; + } + + saveRuleName(rule: CommunicationRule): void { + const name = this.ruleNameDraft.trim(); + if (!name) return; + + this.ruleService + .updateForUnit(this.unit.id, rule.id, { + name, + operator: rule.operator, + send_log_to_convenors: rule.send_log_to_convenors, + }) + .subscribe({ + next: (updated) => { + rule.name = updated.name; + const set = this.selectedSet(); + if (set) { + set.rules = this.rules; + } + this.cancelEditRuleName(); + this.rebuildTree(); + }, + error: (error) => this.showError(error), + }); + } + + confirmExecuteRule(rule: CommunicationRule): void { + this.confirmationModalService.show( + 'Execute Rule?', + 'This will execute only this rule. However, any earlier rules in the set are still taken into account first, so students who would already have been matched earlier are excluded before this rule is applied.', + () => this.executeRule(rule), + undefined, + 'Execute Rule', + ); + } + + executeRule(rule: CommunicationRule): void { + this.ruleService.executeForUnit(this.unit.id, rule.id).subscribe({ + next: (job) => this.showExecutionProgress(job, `Executing ${rule.name}`), + error: (error) => this.showError(error), + }); + } + + previewRule(rule: CommunicationRule, activateStudentsTab = true): void { + if (activateStudentsTab) { + this.previewTabIndex[rule.id] = 2; + } + } + + addCondition(rule: CommunicationRule): void { + const condition = this.newConditions[rule.id] || this.blankCondition(); + this.conditionService.create(this.unit.id, rule.id, condition).subscribe({ + next: (created) => { + rule.conditions ||= []; + rule.conditions.push(created); + this.newConditions[rule.id] = this.blankCondition(); + this.conditionFormOpen[rule.id] = false; + this.editingConditionId[rule.id] = undefined; + this.refreshPreview(rule); + }, + error: (error) => this.showError(error), + }); + } + + updateCondition(rule: CommunicationRule): void { + const conditionId = this.editingConditionId[rule.id]; + if (!conditionId) return; + + const condition = this.newConditions[rule.id] || this.blankCondition(); + this.conditionService.update(this.unit.id, rule.id, conditionId, condition).subscribe({ + next: (updated) => { + rule.conditions = rule.conditions.map((item) => (item.id === updated.id ? updated : item)); + this.newConditions[rule.id] = this.blankCondition(); + this.conditionFormOpen[rule.id] = false; + this.editingConditionId[rule.id] = undefined; + this.refreshPreview(rule); + }, + error: (error) => this.showError(error), + }); + } + + showConditionForm(rule: CommunicationRule): void { + this.newConditions[rule.id] = this.blankCondition(); + this.conditionFormOpen[rule.id] = true; + this.editingConditionId[rule.id] = undefined; + } + + cancelCondition(rule: CommunicationRule): void { + this.newConditions[rule.id] = this.blankCondition(); + this.conditionFormOpen[rule.id] = false; + this.editingConditionId[rule.id] = undefined; + } + + editCondition(rule: CommunicationRule, condition: CommunicationCondition): void { + this.newConditions[rule.id] = { + ...condition, + task_statuses: condition.task_statuses ? [...condition.task_statuses] : [], + }; + this.conditionFormOpen[rule.id] = true; + this.editingConditionId[rule.id] = condition.id; + } + + deleteCondition(rule: CommunicationRule, condition: CommunicationCondition): void { + this.conditionService.delete(this.unit.id, rule.id, condition.id).subscribe({ + next: () => { + rule.conditions = rule.conditions.filter((item) => item.id !== condition.id); + this.refreshPreview(rule); + }, + error: (error) => this.showError(error), + }); + } + + addAction(rule: CommunicationRule): void { + const action = this.newActions[rule.id] || this.blankAction(); + this.actionService.create(this.unit.id, rule.id, action).subscribe({ + next: (created) => { + rule.actions ||= []; + rule.actions.push(created); + this.newActions[rule.id] = this.blankAction(); + this.actionFormOpen[rule.id] = false; + this.editingActionId[rule.id] = undefined; + }, + error: (error) => this.showError(error), + }); + } + + updateAction(rule: CommunicationRule): void { + const actionId = this.editingActionId[rule.id]; + if (!actionId) return; + + const action = this.newActions[rule.id] || this.blankAction(); + this.actionService.update(this.unit.id, rule.id, actionId, action).subscribe({ + next: (updated) => { + rule.actions = rule.actions.map((item) => (item.id === updated.id ? updated : item)); + this.newActions[rule.id] = this.blankAction(); + this.actionFormOpen[rule.id] = false; + this.editingActionId[rule.id] = undefined; + }, + error: (error) => this.showError(error), + }); + } + + showActionForm(rule: CommunicationRule, _mode: 'standard' | 'post_execution' = 'standard'): void { + this.newActions[rule.id] = this.blankAction(); + this.actionFormOpen[rule.id] = true; + this.editingActionId[rule.id] = undefined; + } + + cancelAction(rule: CommunicationRule): void { + this.newActions[rule.id] = this.blankAction(); + this.actionFormOpen[rule.id] = false; + this.editingActionId[rule.id] = undefined; + } + + editAction(rule: CommunicationRule, action: CommunicationAction): void { + this.newActions[rule.id] = {...action}; + this.actionFormOpen[rule.id] = true; + this.editingActionId[rule.id] = action.id; + } + + deleteAction(rule: CommunicationRule, action: CommunicationAction): void { + this.actionService.delete(this.unit.id, rule.id, action.id).subscribe({ + next: () => { + rule.actions = rule.actions.filter((item) => item.id !== action.id); + }, + error: (error) => this.showError(error), + }); + } + + conditionFor(rule: CommunicationRule): Partial { + this.newConditions[rule.id] ||= this.blankCondition(); + return this.newConditions[rule.id]; + } + + actionFor(rule: CommunicationRule): Partial { + this.newActions[rule.id] ||= this.blankAction(); + return this.newActions[rule.id]; + } + + selectRule(rule: CommunicationRule): void { + this.selectedRuleId = rule.id; + } + + hasTreeChild = (_: number, node: CommunicationTreeNode): boolean => node.type === 'set'; + + isSelectedSetNode(node: CommunicationTreeNode): boolean { + return node.type === 'set' && node.id === this.selectedSetId; + } + + isSelectedRuleNode(node: CommunicationTreeNode): boolean { + return node.type === 'rule' && node.id === this.selectedRuleId; + } + + toggleSetNode(node: CommunicationTreeNode, event?: Event): void { + event?.stopPropagation(); + if (!node.set) return; + + if (this.treeControl.isExpanded(node)) { + this.treeControl.collapse(node); + this.expandedSetIds.delete(node.set.id); + } else { + this.treeControl.expand(node); + this.expandedSetIds.add(node.set.id); + } + } + + selectSetNode(set: CommunicationSet): void { + this.selectedSetId = set.id; + this.expandedSetIds.add(set.id); + this.activateSet(set); + } + + selectRuleNode(set: CommunicationSet, rule: CommunicationRule): void { + const setChanged = this.selectedSetId !== set.id; + this.selectedSetId = set.id; + this.expandedSetIds.add(set.id); + + if (setChanged) { + this.activateSet(set, rule.id); + return; + } + + this.selectedRuleId = rule.id; + } + + selectedRule(): CommunicationRule | undefined { + return this.rules.find((rule) => rule.id === this.selectedRuleId); + } + + onRuleTabChange(rule: CommunicationRule, index: number): void { + this.previewTabIndex[rule.id] = index; + } + + studentsFor(rule: CommunicationRule): CommunicationRulePreviewStudent[] { + return this.previewStudents[rule.id] || []; + } + + previewAllocationsFor(rule: CommunicationRule): CommunicationRulePreviewAllocation[] { + return this.previewAllocations[rule.id] || []; + } + + isTargetPreviewAllocation( + rule: CommunicationRule, + allocation: CommunicationRulePreviewAllocation, + ): boolean { + return allocation.rule_id === rule.id; + } + + studentsTabLabel(rule: CommunicationRule): string { + const matchedCount = this.previewLoaded[rule.id] ? this.studentsFor(rule).length : 0; + const totalStudents = this.availableStudentsForRule(rule); + + return `Students (${matchedCount}/${totalStudents})`; + } + + operatorsFor(conditionType: string): string[] { + switch (conditionType) { + case 'TargetGradeCondition': + case 'TaskStatusCountCondition': + case 'SpecConCondition': + return this.gradeOperators; + case 'TaskDefinitionStatusCondition': + return this.equalityOperators; + case 'LoginStatusCondition': + return this.dateOperators; + default: + return this.enrolmentOperators; + } + } + + labelFor(record: CommunicationCondition | CommunicationAction): string { + const hiddenKeys = this.hiddenKeysForRecord(record); + + return Object.entries(record) + .filter( + ([key, value]) => + !hiddenKeys.includes(key) && value !== undefined && value !== null && value !== '', + ) + .map(([key, value]) => `${this.prettyKey(key)}: ${this.prettyValue(key, value)}`) + .join(', '); + } + + conditionTypeLabel(type: string): string { + return this.conditionTypeLabels[type] || type; + } + + operatorLabel(operator: string): string { + return this.operatorLabels[operator] || operator; + } + + actionTypeLabel(type: string): string { + return this.actionTypeLabels[type] || type; + } + + actionSummary(action: CommunicationAction): string { + switch (action.type) { + case 'ChangeTargetGradeAction': + return `Change student's target grade to ${this.targetGradeName(action.target_grade)}`; + case 'EmailStudentAction': + return 'Send email to student'; + case 'EmailStaffAction': + return `Send email to ${this.staffAudienceLabel(action)}`; + case 'TaskCommentAction': + return `Add comment to ${this.taskDefinitionLabel(action.task_definition_id)}`; + default: + return this.actionTypeLabel(action.type); + } + } + + targetGradeName(targetGrade: number | undefined): string { + if (targetGrade === undefined || targetGrade === null) return ''; + + return this.targetGradeNames[targetGrade] || `${targetGrade}`; + } + + taskDefinitionLabel(taskDefinitionId: number | undefined): string { + if (taskDefinitionId === undefined || taskDefinitionId === null) { + return 'Task'; + } + + const taskDefinition = this.taskDefinitions.find((task) => task.id === taskDefinitionId); + + if (!taskDefinition) { + return `Task ${taskDefinitionId}`; + } + + return `Task ${taskDefinition.abbreviation} ${taskDefinition.name}`; + } + + taskStatusLabel(taskStatus: string): string { + return this.titleize(taskStatus); + } + + taskStatusesLabel(taskStatuses: string[] = []): string { + return taskStatuses.map((status) => this.taskStatusLabel(status)).join(', '); + } + + staffAudienceLabel(action: Partial): string { + const audiences: string[] = []; + if (action.email_tutors) audiences.push('tutors'); + if (action.email_convenors) audiences.push('convenors'); + return audiences.join(' and ') || 'staff'; + } + + insertActionVariable(rule: CommunicationRule, field: 'subject' | 'body', token: string): void { + const action = this.actionFor(rule); + const currentValue = action[field] ?? ''; + const separator = + currentValue && !currentValue.endsWith(' ') && !currentValue.endsWith('\n') ? ' ' : ''; + action[field] = `${currentValue}${separator}${token}`; + } + + renderTemplatePreview(value: string | undefined, rule: CommunicationRule): string { + if (!value) return ''; + + const escaped = this.escapeHtml(value); + const rendered = escaped.replace(/\{\{[\w.]+\}\}/g, (token) => { + const replacement = this.resolveTemplateVariable(token, rule) || token; + return `${this.escapeHtml(replacement)}`; + }); + + return rendered.replace(/\n/g, '
    '); + } + + refreshPreview(_rule: CommunicationRule): void { + const set = this.selectedSet(); + if (set) { + this.loadPreviewForSet(set); + } + } + + taskStatusPredicate(operator: string): string { + return operator === 'not_equal_to' ? 'Not In' : 'In'; + } + + tutorialLabel(tutorialId: number): string { + const tutorial = this.tutorials.find((item) => item.id === tutorialId); + return tutorial ? `${tutorial.abbreviation} ${tutorial.description}` : `Tutorial ${tutorialId}`; + } + + tutorialStreamLabel(tutorialStreamId: number): string { + const tutorialStream = this.tutorialStreams.find((item) => item.id === tutorialStreamId); + return tutorialStream + ? `${tutorialStream.abbreviation} ${tutorialStream.name}` + : `Tutorial Stream ${tutorialStreamId}`; + } + + campusLabel(campusId: number): string { + const campus = this.campuses.find((item) => item.id === campusId); + return campus ? campus.name : `Campus ${campusId}`; + } + + enrolmentPredicate(operator: string): string { + return operator === 'not_enrolled_in' ? 'Not Enrolled In' : 'Enrolled In'; + } + + dateLabel(value: string): string { + return value ? new Date(value).toLocaleString() : ''; + } + + onConditionTypeChange(rule: CommunicationRule): void { + const current = this.conditionFor(rule); + this.newConditions[rule.id] = { + type: current.type, + operator: this.operatorsFor(current.type)[0], + }; + + if (current.type === 'TaskDefinitionStatusCondition') { + this.newConditions[rule.id].task_statuses = []; + } + + if (current.type === 'TaskStatusCountCondition') { + this.newConditions[rule.id].task_statuses = []; + this.newConditions[rule.id].task_status_count = 2; + this.newConditions[rule.id].task_target_grade = 1; + } + + if (current.type === 'SpecConCondition') { + this.newConditions[rule.id].spec_con_days = 0; + } + } + + onActionTypeChange(rule: CommunicationRule): void { + const current = this.actionFor(rule); + this.newActions[rule.id] = { + type: current.type || 'EmailStudentAction', + email_tutors: false, + email_convenors: false, + }; + + if (current.type === 'TaskCommentAction') { + this.newActions[rule.id].body = ''; + this.newActions[rule.id].task_definition_id = this.taskDefinitions[0]?.id; + } + } + + private loadSets(): void { + if (!this.unit) return; + + this.loading = true; + this.setService.getForUnit(this.unit.id).subscribe({ + next: (sets) => { + this.sets = sets; + if (this.selectedSetId) { + this.expandedSetIds.add(this.selectedSetId); + } + this.rebuildTree(); + this.selectSet(); + this.loading = false; + }, + error: (error) => { + this.loading = false; + this.showError(error); + }, + }); + } + + private refreshUnitLookups(): void { + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); + this.subscriptions = []; + + if (!this.unit) return; + + this.taskDefinitions = this.unit.taskDefinitionCache.currentValues; + this.tutorials = this.unit.tutorials; + this.tutorialStreams = this.unit.tutorialStreams; + this.subscriptions.push( + this.unit.taskDefinitionCache.values.subscribe((taskDefinitions) => { + this.taskDefinitions = taskDefinitions; + }), + ); + this.subscriptions.push( + // TODO: use spinner until students are loaded + this.projectService.loadStudents(this.unit, false, true).subscribe({ + error: (error) => this.showError(error), + }), + ); + } + + private defaultRuleName(): string { + return `Rule ${this.rules.length + 1}`; + } + + private defaultSetName(): string { + return `Set ${this.sets.length + 1}`; + } + + private defaultScheduleName(set: CommunicationSet): string { + return `Schedule ${(set.schedules?.length || 0) + 1}`; + } + + private activateSet(set: CommunicationSet, selectedRuleId?: number): void { + this.rules = set.rules ?? []; + this.selectedRuleId = selectedRuleId ?? this.rules[0]?.id; + this.loadPreviewForSet(set); + } + + selectedSet(): CommunicationSet | undefined { + return this.sets.find((set) => set.id === this.selectedSetId); + } + + private blankCondition(): Partial { + return { + type: 'TargetGradeCondition', + operator: 'greater_than_or_equal_to', + }; + } + + private blankAction(): Partial { + return { + type: 'EmailStudentAction', + email_tutors: false, + email_convenors: false, + }; + } + + private blankSchedule(set: CommunicationSet): CommunicationSetSchedule { + return new CommunicationSetSchedule({ + client_key: this.newScheduleClientKey(), + communication_set_id: set.id, + name: this.defaultScheduleName(set), + active: true, + anchor_week: 1, + anchor_day: 'Monday', + recurrence: 'none', + interval: 1, + timezone: 'UTC', + hour: 8, + minute: 0, + ice_cube_schedule: { + timezone: 'UTC', + recurrence: 'none', + rules: [{type: 'one_off'}], + }, + }); + } + + private loadPreviewForSet(set: CommunicationSet): void { + if (!this.unit) { + this.setPreviewLoading = false; + return; + } + + this.setPreviewLoading = true; + this.setService.getForUnitById(this.unit.id, set.id).subscribe({ + next: (setResponse) => { + this.applySetPreviewResponse(setResponse); + this.setPreviewLoading = false; + }, + error: (error) => { + this.setPreviewLoading = false; + this.showError(error); + }, + }); + } + + private applySetPreviewResponse(setResponse: CommunicationSetPreviewResponse): void { + const rules = (setResponse.rules || []).map((rule) => new CommunicationRule(rule)); + const existingSet = this.sets.find((set) => set.id === setResponse.id); + const schedules = + setResponse.schedules !== undefined + ? (setResponse.schedules || []).map((schedule) => new CommunicationSetSchedule(schedule)) + : existingSet?.schedules || []; + const updatedSet = new CommunicationSet({ + id: setResponse.id, + unit_id: setResponse.unit_id, + name: setResponse.name, + active: setResponse.active, + schedules, + rules, + }); + const setIndex = this.sets.findIndex((set) => set.id === updatedSet.id); + if (setIndex >= 0) { + this.sets[setIndex] = updatedSet; + } + + if (this.selectedSetId === updatedSet.id) { + this.rules = rules; + if (!this.rules.some((rule) => rule.id === this.selectedRuleId)) { + this.selectedRuleId = this.rules[0]?.id; + } + } + + this.rules.forEach((rule) => { + this.previewLoading[rule.id] = true; + }); + + setResponse.previews.forEach((preview) => { + this.previewAllocations[preview.target_rule_id] = preview.allocations || []; + this.previewStudents[preview.target_rule_id] = this.studentsForPreviewRule( + preview.target_rule_id, + preview, + ); + this.previewLoaded[preview.target_rule_id] = true; + this.previewLoading[preview.target_rule_id] = false; + }); + + this.rules.forEach((rule) => { + this.previewLoading[rule.id] = false; + }); + + this.rebuildTree(); + } + + private studentsForPreviewRule( + ruleId: number, + preview: CommunicationRulePreviewResponse, + ): CommunicationRulePreviewStudent[] { + return preview.allocations.find((allocation) => allocation.rule_id === ruleId)?.students || []; + } + + private availableStudentsForRule(rule: CommunicationRule): number { + const totalStudents = this.unit?.students?.length ?? 0; + if (!this.previewLoaded[rule.id]) return totalStudents; + + const claimedByPreviousRules = this.previewAllocationsFor(rule) + .filter((allocation) => allocation.rule_id !== rule.id) + .reduce((sum, allocation) => sum + allocation.students.length, 0); + + return Math.max(0, totalStudents - claimedByPreviousRules); + } + + private sampleStudentForRule( + rule: CommunicationRule, + ): CommunicationRulePreviewStudent | undefined { + return this.studentsFor(rule)[0]; + } + + private openScheduleModal(set: CommunicationSet, schedule?: CommunicationSetSchedule): void { + const dialogRef = this.dialog.open(CommunicationScheduleModalComponent, { + width: '960px', + maxWidth: '96vw', + data: { + schedule: schedule + ? new CommunicationSetSchedule({ + ...schedule, + }) + : this.blankSchedule(set), + unit: this.unit, + } satisfies CommunicationScheduleModalData, + }); + + dialogRef.afterClosed().subscribe((result) => { + if (!result) return; + + const hydrated = new CommunicationSetSchedule({ + ...result, + client_key: schedule?.client_key || result.client_key || this.newScheduleClientKey(), + communication_set_id: set.id, + }); + + const schedules = [...(set.schedules || [])]; + const existingIndex = schedules.findIndex( + (item) => (item.id || item.client_key) === (schedule?.id || schedule?.client_key), + ); + + if (existingIndex >= 0) { + schedules[existingIndex] = hydrated; + } else { + schedules.push(hydrated); + } + + this.persistSchedules(set, schedules, 'Schedule saved'); + }); + } + + private persistSchedules( + set: CommunicationSet, + schedules: CommunicationSetSchedule[], + successMessage: string, + ): void { + this.setService + .updateForUnit(this.unit.id, set.id, { + name: set.name, + active: set.active, + schedules: schedules.map((schedule) => ({ + id: schedule.id, + name: schedule.name, + active: schedule.active, + anchor_week: schedule.anchor_week, + anchor_day: schedule.anchor_day, + hour: schedule.hour, + minute: schedule.minute, + timezone: schedule.timezone, + recurrence: schedule.recurrence, + interval: schedule.interval, + repeat_count: schedule.repeat_count, + until_at: schedule.until_at, + })), + }) + .subscribe({ + next: (updatedSet) => { + set.schedules = updatedSet.schedules || []; + const setIndex = this.sets.findIndex((item) => item.id === set.id); + if (setIndex >= 0) { + this.sets[setIndex].schedules = updatedSet.schedules || []; + } + this.alerts.success(successMessage); + }, + error: (error) => this.showError(error), + }); + } + + private showError(error): void { + this.alerts.error(error?.message || error?.error || error || 'Communication update failed'); + } + + private showExecutionProgress(job: SidekiqJob, title: string): void { + if (!job?.id) { + this.alerts.error('Failed to start communication execution', 6000); + return; + } + + this.sidekiqProgressModalService.show(title, job.id).subscribe({ + error: (error) => this.showError(error), + }); + } + + private prettyKey(key: string): string { + const labels: Record = { + operator: 'Operator', + target_grade: 'Target Grade', + task_definition_id: 'Task', + task_statuses: 'Task Statuses', + task_status_count: 'Task Status Count', + task_target_grade: 'Task Target Grade', + last_sign_in_at: 'Last Sign In', + spec_con_days: 'Special Consideration Days', + tutorial_id: 'Tutorial', + tutorial_stream_id: 'Tutorial Stream', + campus_id: 'Campus', + subject: 'Subject', + body: 'Body', + email_tutors: 'Email Tutors', + email_convenors: 'Email Convenors', + }; + + return labels[key] || key; + } + + private prettyValue(key: string, value: unknown): string { + if (key === 'operator' && typeof value === 'string') { + return this.operatorLabel(value); + } + + if ((key === 'target_grade' || key === 'task_target_grade') && typeof value === 'number') { + return this.targetGradeLabels[value] || value.toString(); + } + + if (key === 'task_statuses' && Array.isArray(value)) { + return this.taskStatusesLabel(value); + } + + if (typeof value === 'boolean') { + return value ? 'Yes' : 'No'; + } + + return `${value}`; + } + + private escapeHtml(value: string): string { + return value + .replace(/&/g, '&') + .replace(//g, '>') + .replace(/"/g, '"') + .replace(/'/g, '''); + } + + private resolveTemplateVariable(token: string, rule: CommunicationRule): string | undefined { + const student = this.sampleStudentForRule(rule); + + switch (token) { + case '{{student.first_name}}': + return student?.first_name; + case '{{student.last_name}}': + return student?.last_name; + case '{{student.preferred_name}}': + return student?.preferred_name || student?.first_name; + case '{{student.full_name}}': + return ( + student?.full_name || [student?.first_name, student?.last_name].filter(Boolean).join(' ') + ); + case '{{student.username}}': + return student?.username; + case '{{student.student_id}}': + return student?.student_id; + case '{{affected_students_count}}': + return this.studentsFor(rule).length.toString(); + case '{{unit.code}}': + return this.unit?.code; + case '{{unit.name}}': + return this.unit?.name; + case '{{rule.name}}': + return rule.name; + case '{{target_grade}}': + return student?.target_grade !== undefined && student?.target_grade !== null + ? this.targetGradeName(student.target_grade) + : undefined; + case '{{conditions_summary}}': + return this.conditionsSummary(rule); + case '{{actions_summary}}': + return this.actionsSummary(rule); + default: + return undefined; + } + } + + private hiddenKeysForRecord(record: CommunicationCondition | CommunicationAction): string[] { + const baseHiddenKeys = ['id', 'type', 'communication_rule_id', 'operator']; + + if (!('type' in record)) { + return baseHiddenKeys; + } + + switch (record.type) { + case 'ChangeTargetGradeAction': + return [...baseHiddenKeys, 'subject', 'body', 'email_tutors', 'email_convenors']; + case 'EmailStudentAction': + return [...baseHiddenKeys, 'target_grade', 'email_tutors', 'email_convenors']; + case 'EmailStaffAction': + return [...baseHiddenKeys, 'target_grade']; + default: + return baseHiddenKeys; + } + } + + conditionsSummary(rule: CommunicationRule): string { + return (rule.conditions || []) + .map((condition) => + `- ${this.conditionTypeLabel(condition.type)}: ${this.labelFor(condition)}`.trim(), + ) + .join('\n'); + } + + actionsSummary(rule: CommunicationRule): string { + return (rule.actions || []).map((action) => `- ${this.actionSummary(action)}`).join('\n'); + } + + private titleize(value: string): string { + return value + ?.split('_') + .map((word) => word.charAt(0).toUpperCase() + word.slice(1)) + .join(' '); + } + + private scheduleCadence(schedule: CommunicationSetSchedule): string { + switch (schedule.recurrence) { + case 'daily': + return `Daily every ${schedule.interval || 1} day(s)`; + case 'weekly': + return `Weekly every ${schedule.interval || 1} week(s) from ${schedule.anchor_day || 'Monday'}`; + case 'monthly': + return `Monthly every ${schedule.interval || 1} month(s) from Week ${schedule.anchor_week || 1} ${schedule.anchor_day || 'Monday'}`; + default: + return 'One-off run'; + } + } + + private scheduleEnding(schedule: CommunicationSetSchedule): string { + if (schedule.repeat_count) { + return `Stops after ${schedule.repeat_count} run(s)`; + } + + if (schedule.until_at) { + return `Stops at ${this.dateLabel(schedule.until_at)}`; + } + + return 'No expiry'; + } + + private formatTime(hour = 0, minute = 0): string { + return `${hour.toString().padStart(2, '0')}:${minute.toString().padStart(2, '0')}`; + } + + private newScheduleClientKey(): string { + return `schedule-${Date.now()}-${Math.random().toString(36).slice(2, 10)}`; + } + + private rebuildTree(): void { + const treeData = this.sets.map((set) => ({ + type: 'set' as const, + id: set.id, + label: set.name, + set, + children: (set.rules ?? []).map((rule) => ({ + type: 'rule' as const, + id: rule.id, + label: rule.name, + set, + rule, + })), + })); + + this.treeDataSource.data = treeData; + treeData.forEach((node) => { + if (this.expandedSetIds.has(node.id) || node.id === this.selectedSetId) { + this.treeControl.expand(node); + } + }); + } +} diff --git a/src/app/units/states/edit/unit-admin-state.component.html b/src/app/units/states/edit/unit-admin-state.component.html index d165bf7c0c..6a06b1e487 100644 --- a/src/app/units/states/edit/unit-admin-state.component.html +++ b/src/app/units/states/edit/unit-admin-state.component.html @@ -1,6 +1,6 @@
    Groups
    } } + @case ('communication') { + @if (unit) { +
    +
    +

    Communication System

    +

    + Create communication sets and rules to target students and automate follow-up + actions. +

    +
    + +
    + } + } }
    diff --git a/src/app/units/states/edit/unit-admin-state.component.ts b/src/app/units/states/edit/unit-admin-state.component.ts index b22376951c..57972168df 100644 --- a/src/app/units/states/edit/unit-admin-state.component.ts +++ b/src/app/units/states/edit/unit-admin-state.component.ts @@ -12,7 +12,8 @@ type UnitAdminTabKey = | 'tutorials' | 'students' | 'tasks' - | 'groups'; + | 'groups' + | 'communication'; interface UnitAdminTab { label: string; @@ -35,6 +36,7 @@ export class UnitAdminStateComponent implements OnInit, OnDestroy { {label: 'Students', routeSegment: 'students'}, {label: 'Tasks', routeSegment: 'tasks'}, {label: 'Groups', routeSegment: 'groups'}, + {label: 'Communications', routeSegment: 'communication'}, ]; public unit: Unit | null = null; From 5381b13aecd7054354d2ebfbeeb68f5990054856 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 9 Jun 2026 12:17:17 +1000 Subject: [PATCH 1089/1280] chore(release): 11.0.0-22 --- CHANGELOG.md | 7 +++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a572423099..57bb59d3ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,13 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-22](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-21...v11.0.0-22) (2026-06-09) + + +### Features + +* communications system ([#1239](https://github.com/b0ink/doubtfire-deploy/issues/1239)) ([b55bcfc](https://github.com/b0ink/doubtfire-deploy/commit/b55bcfc8f84f381beb7d62f41031db3ba6a38193)) + ## [11.0.0-21](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-20...v11.0.0-21) (2026-06-08) diff --git a/package-lock.json b/package-lock.json index 96eec16671..b9da13de65 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-21", + "version": "11.0.0-22", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-21", + "version": "11.0.0-22", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.11", diff --git a/package.json b/package.json index 92e285615b..ff4a538506 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-21", + "version": "11.0.0-22", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From a9f2ef2ffc479da570bf830c48892b822b8d9486 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 9 Jun 2026 15:12:41 +1000 Subject: [PATCH 1090/1280] chore: update package-lock --- package-lock.json | 357 +++++----------------------------------------- 1 file changed, 34 insertions(+), 323 deletions(-) diff --git a/package-lock.json b/package-lock.json index b9da13de65..7ae9c7cf28 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2872,48 +2872,6 @@ "listr2": "9.0.5" } }, - "node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.5.1.tgz", - "integrity": "sha512-tpfN4kKrrMpQ+If1l8bhmoNkECJi0iOu6AEdrTJvWVC+32sLxTARX5Rsu579mPImRP9YFWfWgeRQ5oav7zApQQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.5.1.tgz", - "integrity": "sha512-+a2tTfc3rmWhLAolFUWRgJtpSuu+Fw/yjn4rF406NMxhfjbMuiOUTDRvRlMFV+DzyjkwnokisskHbCWkS3Ly5w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@lmdb/lmdb-linux-arm": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.5.1.tgz", - "integrity": "sha512-0EgcE6reYr8InjD7V37EgXcYrloqpxVPINy3ig1MwDSbl6LF/vXTYRH9OE1Ti1D8YZnB35ZH9aTcdfSb5lql2A==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, "node_modules/@lmdb/lmdb-linux-arm64": { "version": "3.5.1", "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.1.tgz", @@ -2928,48 +2886,6 @@ "linux" ] }, - "node_modules/@lmdb/lmdb-linux-x64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.5.1.tgz", - "integrity": "sha512-SqNDY1+vpji7bh0sFH5wlWyFTOzjbDOl0/kB5RLLYDAFyd/uw3n7wyrmas3rYPpAW7z18lMOi1yKlTPv967E3g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@lmdb/lmdb-win32-arm64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.5.1.tgz", - "integrity": "sha512-50v0O1Lt37cwrmR9vWZK5hRW0Aw+KEmxJJ75fge/zIYdvNKB/0bSMSVR5Uc2OV9JhosIUyklOmrEvavwNJ8D6w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@lmdb/lmdb-win32-x64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.5.1.tgz", - "integrity": "sha512-qwosvPyl+zpUlp3gRb7UcJ3H8S28XHCzkv0Y0EgQToXjQP91ZD67EHSCDmaLjtKhe+GVIW5om1KUpzVLA0l6pg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, "node_modules/@mattlewis92/dom-autoscroller": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/@mattlewis92/dom-autoscroller/-/dom-autoscroller-2.4.2.tgz", @@ -3592,132 +3508,6 @@ "@parcel/watcher-win32-x64": "2.5.6" } }, - "node_modules/@parcel/watcher-android-arm64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", - "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-darwin-arm64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", - "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-darwin-x64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", - "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-freebsd-x64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", - "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-glibc": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", - "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-arm-musl": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", - "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/@parcel/watcher-linux-arm64-glibc": { "version": "2.5.6", "cpu": [ @@ -3758,111 +3548,6 @@ "url": "https://opencollective.com/parcel" } }, - "node_modules/@parcel/watcher-linux-x64-glibc": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", - "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-linux-x64-musl": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", - "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-arm64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", - "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-ia32": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", - "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@parcel/watcher-win32-x64": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", - "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, "node_modules/@parcel/watcher/node_modules/node-addon-api": { "version": "7.1.1", "dev": true, @@ -4161,9 +3846,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", - "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.61.1.tgz", + "integrity": "sha512-bVWIOIk6pV01p4CdUbPP7CJ/434z+OooYjDuFcR+44N35YvKUC66G8MGnvcWx5mWKW3g61J+t74l3Kj15Kwn2Q==", "cpu": [ "x64" ], @@ -4508,6 +4193,15 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, + "node_modules/@swimlane/ngx-charts/node_modules/d3-time-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", + "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-time": "1 - 2" + } + }, "node_modules/@trivago/prettier-plugin-sort-imports": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-6.0.2.tgz", @@ -6942,12 +6636,15 @@ } }, "node_modules/d3-time-format": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", - "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", - "license": "BSD-3-Clause", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", "dependencies": { - "d3-time": "1 - 2" + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" } }, "node_modules/d3-time/node_modules/d3-array": { @@ -13111,6 +12808,20 @@ "fsevents": "~2.3.2" } }, + "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", + "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", From 9d71c05e54536f4c3c4a69a3ab2a906a4b94cad6 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 9 Jun 2026 15:20:54 +1000 Subject: [PATCH 1091/1280] chore: update package-lock --- package-lock.json | 9670 ++++++++++++++++++++++++++++----------------- 1 file changed, 5955 insertions(+), 3715 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7ae9c7cf28..9e5b8063a8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -367,13 +367,13 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2102.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.9.tgz", - "integrity": "sha512-OlPEtd5pPZSFdkXEIyZ93jsfBrkvUrVPb3xs4z2WPRnBRk9jyey40eKnmql86KRHfdn4WjHpmde4NDgtDpZRxQ==", + "version": "0.2102.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.14.tgz", + "integrity": "sha512-0+vjVsCkMyJdVjz5XkPW+Bdf/9TI8V2voomx/+o0o+oOaqqiEhptQWFnaIlLr7HasjB0LxXK5P9L0oQ61vxj8Q==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.9", + "@angular-devkit/core": "21.2.14", "rxjs": "7.8.2" }, "bin": { @@ -385,10 +385,10 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/architect/node_modules/@angular-devkit/core": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.9.tgz", - "integrity": "sha512-04rdOGEzjLWFHlyAwqtuikginFeQ2jfXS5HqqKNP0VtG6Uu9NUDAEW5UDvXgqkEMfCDwGZbmg2iRHxp3AmAKVw==", + "node_modules/@angular-devkit/core": { + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.14.tgz", + "integrity": "sha512-RSOWXB9bFc2nwRWMxbIT0RbSNFUrwfBo4N5MNxbyQ69Ndc0gVm3h+3ArHv0qotH4d+pJYbm5ttXu8YqR2kc0CA==", "dev": true, "license": "MIT", "dependencies": { @@ -413,48 +413,14 @@ } } }, - "node_modules/@angular-devkit/architect/node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@angular-devkit/architect/node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@angular-devkit/schematics": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.9.tgz", - "integrity": "sha512-Gyyuq2Vet70AMkbC+e0L6rjzjZWjSOyKTlOJvd99GjjyWQf6eezjd8IcF17ppKJsML6YUagO2I6AlWROq5yJmg==", + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.14.tgz", + "integrity": "sha512-KMJlQSBEzI4+Cy1Zh72gmGQNN2I1vY+nj9CoRcZPBIi1si+0ZAc49XT85eYl+eQumNTVQviUG7LQqgLDAHml+g==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.9", + "@angular-devkit/core": "21.2.14", "jsonc-parser": "3.3.1", "magic-string": "0.30.21", "ora": "9.3.0", @@ -466,68 +432,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular-devkit/schematics/node_modules/@angular-devkit/core": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.9.tgz", - "integrity": "sha512-04rdOGEzjLWFHlyAwqtuikginFeQ2jfXS5HqqKNP0VtG6Uu9NUDAEW5UDvXgqkEMfCDwGZbmg2iRHxp3AmAKVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.18.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.4", - "rxjs": "7.8.2", - "source-map": "0.7.6" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^5.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-devkit/schematics/node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@angular-devkit/schematics/node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@angular-eslint/builder": { "version": "21.4.0", "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-21.4.0.tgz", @@ -544,68 +448,6 @@ "typescript": "*" } }, - "node_modules/@angular-eslint/builder/node_modules/@angular-devkit/core": { - "version": "21.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.14.tgz", - "integrity": "sha512-RSOWXB9bFc2nwRWMxbIT0RbSNFUrwfBo4N5MNxbyQ69Ndc0gVm3h+3ArHv0qotH4d+pJYbm5ttXu8YqR2kc0CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.18.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.4", - "rxjs": "7.8.2", - "source-map": "0.7.6" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^5.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-eslint/builder/node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@angular-eslint/builder/node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@angular-eslint/bundled-angular-compiler": { "version": "21.4.0", "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-21.4.0.tgz", @@ -669,78 +511,6 @@ "@angular/cli": ">= 21.0.0 < 22.0.0" } }, - "node_modules/@angular-eslint/schematics/node_modules/@angular-devkit/core": { - "version": "21.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.14.tgz", - "integrity": "sha512-RSOWXB9bFc2nwRWMxbIT0RbSNFUrwfBo4N5MNxbyQ69Ndc0gVm3h+3ArHv0qotH4d+pJYbm5ttXu8YqR2kc0CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.18.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.4", - "rxjs": "7.8.2", - "source-map": "0.7.6" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^5.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular-eslint/schematics/node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@angular-eslint/schematics/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, - "node_modules/@angular-eslint/schematics/node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@angular-eslint/template-parser": { "version": "21.4.0", "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-21.4.0.tgz", @@ -772,9 +542,9 @@ } }, "node_modules/@angular/animations": { - "version": "21.2.11", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.11.tgz", - "integrity": "sha512-CpyK3XxcjuYj8cl/eaKZYxrIpVOG7Ci49YSPIzyY5bzxMv7znOoRuPnEMV/EENfiQ12IraWCBh9dd7g37PBjOw==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.16.tgz", + "integrity": "sha512-YPhph/OC1A0vkT95XZW6lXMNmi5ly91JeXi+5yeG8CCxfqscVfRNPsYbRWjSueO0cQT2HJ8U1CLteQ5a1OaoHA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -783,18 +553,18 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "21.2.11" + "@angular/core": "21.2.16" } }, "node_modules/@angular/build": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.9.tgz", - "integrity": "sha512-XYP5ALB56NWvcQisznmvQdVU6WJdUCAuCAEN2eDZNVd9X1IqRNfewQfFH6FyHo7SrK4GHDReqm6xWW6rs0+weQ==", + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.14.tgz", + "integrity": "sha512-l8JB326iIwum2WmbopUUFdiuYsbHchix6MH8o6F6FA7LJr8QLTvipwwbw+Jx31/RE50WkGmzsZ1fBDw/cMbmUw==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2102.9", + "@angular-devkit/architect": "0.2102.14", "@babel/core": "7.29.0", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", @@ -837,7 +607,7 @@ "@angular/platform-browser": "^21.0.0", "@angular/platform-server": "^21.0.0", "@angular/service-worker": "^21.0.0", - "@angular/ssr": "^21.2.9", + "@angular/ssr": "^21.2.14", "karma": "^6.4.0", "less": "^4.2.0", "ng-packagr": "^21.0.0", @@ -886,251 +656,112 @@ } } }, - "node_modules/@angular/cdk": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.9.tgz", - "integrity": "sha512-0JXsr8f7xjV2815esTSq4+zGqWMa0CyNT/DV1F7lYS6qkYXcFdYUzGcd/WjNL05VKkajkSkWmTi6uyVsOpYdGA==", + "node_modules/@angular/build/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, "license": "MIT", "dependencies": { - "parse5": "^8.0.0", - "tslib": "^2.3.0" + "readdirp": "^4.0.1" }, - "peerDependencies": { - "@angular/common": "^21.0.0 || ^22.0.0", - "@angular/core": "^21.0.0 || ^22.0.0", - "@angular/platform-browser": "^21.0.0 || ^22.0.0", - "rxjs": "^6.5.3 || ^7.4.0" + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/@angular/cli": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.9.tgz", - "integrity": "sha512-KldNb7vCEVOeyEUK57dguP3dTjYeikBmAohjAouu8JLtY8OOI+tf/TA31Gco/rxZ3nGqBwkvrqpD4rcDf5AhUA==", + "node_modules/@angular/build/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, "license": "MIT", - "dependencies": { - "@angular-devkit/architect": "0.2102.9", - "@angular-devkit/core": "21.2.9", - "@angular-devkit/schematics": "21.2.9", - "@inquirer/prompts": "7.10.1", - "@listr2/prompt-adapter-inquirer": "3.0.5", - "@modelcontextprotocol/sdk": "1.26.0", - "@schematics/angular": "21.2.9", - "@yarnpkg/lockfile": "1.1.0", - "algoliasearch": "5.48.1", - "ini": "6.0.0", - "jsonc-parser": "3.3.1", - "listr2": "9.0.5", - "npm-package-arg": "13.0.2", - "pacote": "21.3.1", - "parse5-html-rewriting-stream": "8.0.0", - "semver": "7.7.4", - "yargs": "18.0.0", - "zod": "4.3.6" - }, - "bin": { - "ng": "bin/ng.js" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular/cli/node_modules/@angular-devkit/core": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.9.tgz", - "integrity": "sha512-04rdOGEzjLWFHlyAwqtuikginFeQ2jfXS5HqqKNP0VtG6Uu9NUDAEW5UDvXgqkEMfCDwGZbmg2iRHxp3AmAKVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.18.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.4", - "rxjs": "7.8.2", - "source-map": "0.7.6" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^5.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular/cli/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@angular/cli/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@angular/cli/node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@angular/cli/node_modules/cliui": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@angular/cli/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular/cli/node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 20.19.0" + "engines": { + "node": ">= 14.18.0" }, "funding": { "type": "individual", "url": "https://paulmillr.com/funding/" } }, - "node_modules/@angular/cli/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "node_modules/@angular/build/node_modules/sass": { + "version": "1.97.3", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", + "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" + "chokidar": "^4.0.0", + "immutable": "^5.0.2", + "source-map-js": ">=0.6.2 <2.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@angular/cli/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" + "bin": { + "sass": "sass.js" }, "engines": { - "node": ">=12" + "node": ">=14.0.0" }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "optionalDependencies": { + "@parcel/watcher": "^2.4.1" } }, - "node_modules/@angular/cli/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, + "node_modules/@angular/cdk": { + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.14.tgz", + "integrity": "sha512-806REq/CLf37nEhmmd8Q+ILN8z/RVG2vk2n8YZ/4TdHpcBCi5ux4AxLbpMmduLwGPOzPagJ6ggRzE5fnX0rmcQ==", "license": "MIT", "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" + "parse5": "^8.0.0", + "tslib": "^2.3.0" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "peerDependencies": { + "@angular/common": "^21.0.0 || ^22.0.0", + "@angular/core": "^21.0.0 || ^22.0.0", + "@angular/platform-browser": "^21.0.0 || ^22.0.0", + "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/cli/node_modules/yargs": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", - "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "node_modules/@angular/cli": { + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.14.tgz", + "integrity": "sha512-S8jExTjxPJILwpg2lu3DohSASVZ8DLhSNCmOe7z0qF9VskRSjC7SIQv1rq36tsJkenxuA72gjVOHZv+uSRT8HA==", "dev": true, "license": "MIT", "dependencies": { - "cliui": "^9.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "string-width": "^7.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^22.0.0" + "@angular-devkit/architect": "0.2102.14", + "@angular-devkit/core": "21.2.14", + "@angular-devkit/schematics": "21.2.14", + "@inquirer/prompts": "7.10.1", + "@listr2/prompt-adapter-inquirer": "3.0.5", + "@modelcontextprotocol/sdk": "1.26.0", + "@schematics/angular": "21.2.14", + "@yarnpkg/lockfile": "1.1.0", + "algoliasearch": "5.48.1", + "ini": "6.0.0", + "jsonc-parser": "3.3.1", + "listr2": "9.0.5", + "npm-package-arg": "13.0.2", + "pacote": "21.3.1", + "parse5-html-rewriting-stream": "8.0.0", + "semver": "7.7.4", + "yargs": "18.0.0", + "zod": "4.3.6" + }, + "bin": { + "ng": "bin/ng.js" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/@angular/cli/node_modules/yargs-parser": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", - "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" } }, "node_modules/@angular/common": { - "version": "21.2.11", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.11.tgz", - "integrity": "sha512-3Z3SABXpzM6fkX21WCRP6IwrjxNQVHM/3Fk2OXScExOAzpaOpS2bDgS4NB6rtCbmzKL/NFSp7ZPIZigfdqnWGw==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.16.tgz", + "integrity": "sha512-htHNepKzjIjkc5BQ7MKDN0bVDOfQpFr/fGUxa6irC0kFLfWt7idUTdNcxypRvjCCTuBYHkjr74fH4QKu+qvPXg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1139,14 +770,14 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "21.2.11", + "@angular/core": "21.2.16", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "21.2.11", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.11.tgz", - "integrity": "sha512-/KdE0kPQr24K/aNsdIDS2or555+8CrQxyRB5MxPKy3/8d6EvilEY/UN7pB7A5xgRQtUPMea08ZzLFJVp1qNbDA==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.16.tgz", + "integrity": "sha512-hVjp93gYgNj5aRbCQUK7L+pOfdqk96lCtmSL2hOL725Pmib9NyNIrA3ISfAQHN+Qo70763WUZahOiqBBOzfAcg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1156,9 +787,9 @@ } }, "node_modules/@angular/compiler-cli": { - "version": "21.2.11", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.11.tgz", - "integrity": "sha512-qp/LgptDYJvpEHVVdwBEtkcbybre/ftanu0qJMpH3mu5FC4HEEOChl+9m7UVrmL4jC1ZkoZcgtzsGKAQr8mw2g==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.16.tgz", + "integrity": "sha512-w2ck3o+uw29AZEGK3HvOsF/ZRiPcfoq2TaDtiNjdH+svhwawt9PfMXrDbbIKF30prWzKLpT3UsCqTz1awv7Ubw==", "dev": true, "license": "MIT", "dependencies": { @@ -1179,7 +810,7 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.11", + "@angular/compiler": "21.2.16", "typescript": ">=5.9 <6.1" }, "peerDependenciesMeta": { @@ -1188,228 +819,70 @@ } } }, - "node_modules/@angular/compiler-cli/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, + "node_modules/@angular/core": { + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.16.tgz", + "integrity": "sha512-uufKORlB0jeYdqOvjAfMYgqIqmJentOj8XvTUxsFP5k85xxzXsDarSpP199YQz6jhJJQYNOWIloDkUTQJi5rNA==", "license": "MIT", + "dependencies": { + "tslib": "^2.3.0" + }, "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "peerDependencies": { + "@angular/compiler": "21.2.16", + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.15.0 || ~0.16.0" + }, + "peerDependenciesMeta": { + "@angular/compiler": { + "optional": true + }, + "zone.js": { + "optional": true + } } }, - "node_modules/@angular/compiler-cli/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", - "dev": true, + "node_modules/@angular/forms": { + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.16.tgz", + "integrity": "sha512-2djTJmTpg/MkQ2kdCI9k0LT4RL9/Hg03fDUNN2eN5c04FIk99D3yHXUJYLwiaErLuLQNkU8HaijluKHdH93cWQ==", "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "tslib": "^2.3.0" + }, "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "peerDependencies": { + "@angular/common": "21.2.16", + "@angular/core": "21.2.16", + "@angular/platform-browser": "21.2.16", + "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@angular/compiler-cli/node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "node_modules/@angular/language-service": { + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-21.2.16.tgz", + "integrity": "sha512-LBhoBmIVopMBfFVOoc5MDD2JWO+6+fHg7kNWc2Wy+YKhSndgsWVCo4F8MIgZh6HXxofZe3pEMXO0GfDPc0Ny3g==", "dev": true, "license": "MIT", - "dependencies": { - "readdirp": "^5.0.0" - }, "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/@angular/compiler-cli/node_modules/cliui": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" - }, - "engines": { - "node": ">=20" - } - }, - "node_modules/@angular/compiler-cli/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, - "node_modules/@angular/compiler-cli/node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@angular/compiler-cli/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@angular/compiler-cli/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@angular/compiler-cli/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@angular/compiler-cli/node_modules/yargs": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", - "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^9.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "string-width": "^7.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^22.0.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/@angular/compiler-cli/node_modules/yargs-parser": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", - "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/@angular/core": { - "version": "21.2.11", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.11.tgz", - "integrity": "sha512-EULAfQ0m/I9hZJes74OFlrnfDWqlfV0esE0CkHehO5IEF9rd769+dfuGEAJAzrz+/6Q3PhS0bWDYiT68z1H8Ag==", - "license": "MIT", - "dependencies": { - "tslib": "^2.3.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - }, - "peerDependencies": { - "@angular/compiler": "21.2.11", - "rxjs": "^6.5.3 || ^7.4.0", - "zone.js": "~0.15.0 || ~0.16.0" - }, - "peerDependenciesMeta": { - "@angular/compiler": { - "optional": true - }, - "zone.js": { - "optional": true - } - } - }, - "node_modules/@angular/forms": { - "version": "21.2.11", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.11.tgz", - "integrity": "sha512-F67V612wHxPXHrbp825VirYfGPKBUM8PvL9atN2Ku1fsdGSFPU3hTxu1HU8fKYLLBpKYVVuqFqzaU/qIpTXGYA==", - "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "tslib": "^2.3.0" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - }, - "peerDependencies": { - "@angular/common": "21.2.11", - "@angular/core": "21.2.11", - "@angular/platform-browser": "21.2.11", - "rxjs": "^6.5.3 || ^7.4.0" - } - }, - "node_modules/@angular/language-service": { - "version": "21.2.11", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-21.2.11.tgz", - "integrity": "sha512-M5BVtsfgjUdR/9SkVFBQ/WoAoSSybeYOeAzuBThwmAz4CA+yvZtyuJNlaUQ2IaF7f5TCtg05Pg9YRgKOusK3HQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" - } - }, - "node_modules/@angular/material": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-21.2.9.tgz", - "integrity": "sha512-uU5Sy0rSd4Y4WjqTcrqs3MpfY/Uy5tmDPSAAvwD0y5y4QVOLoV8uhTQDI/nNg2Lh9NoJKvykZE1ITRMvjfRALQ==", - "license": "MIT", + "node_modules/@angular/material": { + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-21.2.14.tgz", + "integrity": "sha512-fMQca8VRtei93JRRG9qQ+u08DCb0nga59Esoakq5yx3+A1NfdpFeUS1tBns56U04o8KAaIAwZK3NBqXz8ZKNqg==", + "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/cdk": "21.2.9", + "@angular/cdk": "21.2.14", "@angular/common": "^21.0.0 || ^22.0.0", "@angular/core": "^21.0.0 || ^22.0.0", "@angular/forms": "^21.0.0 || ^22.0.0", @@ -1418,23 +891,23 @@ } }, "node_modules/@angular/material-date-fns-adapter": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular/material-date-fns-adapter/-/material-date-fns-adapter-21.2.9.tgz", - "integrity": "sha512-tZ48ToUMzGkrwRPsUxPElNsw4AHRtDo8wGjyihwPUAlDQRXU8Mx0oszHcceJFWlTeXSy5uK722jS4rOd+c1t0w==", + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@angular/material-date-fns-adapter/-/material-date-fns-adapter-21.2.14.tgz", + "integrity": "sha512-PvfX/Y+6ml8G+Zacgmp52nerI4fQmPtCKPDweUVA5Drm8Ygoo3zdVS9UnB+74KuH56I+AS5IZ8usJSwdV+z1UQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { "@angular/core": "^21.0.0 || ^22.0.0", - "@angular/material": "21.2.9", + "@angular/material": "21.2.14", "date-fns": ">2.20.0 <5.0" } }, "node_modules/@angular/platform-browser": { - "version": "21.2.11", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.11.tgz", - "integrity": "sha512-Uz/KwGjSEvbE8J9kNSSetzxhBWjCXv9OuxH1w2WkW6jLNU3vgvzuKX7SXDyUys6KJv5TqkClJ9BLeU11QbmJdw==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.16.tgz", + "integrity": "sha512-59ToWYDb+O3fS0+Y4ubQqV0zY6sf2esLZ19AT7JKXN7Akqbz7aQ2/3k3PKmfhwKWek5o3lkuNz8YhxKQruNh8Q==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1443,9 +916,9 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/animations": "21.2.11", - "@angular/common": "21.2.11", - "@angular/core": "21.2.11" + "@angular/animations": "21.2.16", + "@angular/common": "21.2.16", + "@angular/core": "21.2.16" }, "peerDependenciesMeta": { "@angular/animations": { @@ -1454,9 +927,9 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "21.2.11", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-21.2.11.tgz", - "integrity": "sha512-wdlYzXkc6X6f8mj2jLlaDJlRiwmurffAf37NCXMNqgTTc0j0iD/DLd3JQScMVCJ9bZ0se02EF5X3Z82W0vmmPA==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-21.2.16.tgz", + "integrity": "sha512-WtTnkJOmKiGccHRQfBdkwODAkpTB4zbPN3IKhcqCjlezKaPqZB5tjrIu72Z5pmi5VIgJz1LmfO1LSVCMC5h7dA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1465,16 +938,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.11", - "@angular/compiler": "21.2.11", - "@angular/core": "21.2.11", - "@angular/platform-browser": "21.2.11" + "@angular/common": "21.2.16", + "@angular/compiler": "21.2.16", + "@angular/core": "21.2.16", + "@angular/platform-browser": "21.2.16" } }, "node_modules/@angular/router": { - "version": "21.2.11", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.11.tgz", - "integrity": "sha512-IB7/KuRDsxAjCOxYNccq2LdCTKuu59cx5MmOhrt+TarvkNE/xdlFkP7vtrCl44DJt0q7/tveWvsn5oqTw7rN7A==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.16.tgz", + "integrity": "sha512-0+Pyh0uT4vCLabKoGCARYWlwpz4DgZI9AE01n8s9u/nKAZuEMnJtLLnaUtHEMI8nJSqpgnS/5AthuJZdDEfkYw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1483,16 +956,16 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/common": "21.2.11", - "@angular/core": "21.2.11", - "@angular/platform-browser": "21.2.11", + "@angular/common": "21.2.16", + "@angular/core": "21.2.16", + "@angular/platform-browser": "21.2.16", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "21.2.11", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-21.2.11.tgz", - "integrity": "sha512-kRYl5LxSz2mJR8LJVC6SLmww8b01j/qUq/7W/Z4UtNxjHnxUWgKDoWCCfoCiIss33MIgEGQERrWnGGOwkVlOJQ==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-21.2.16.tgz", + "integrity": "sha512-Wwdc+40T4Zk+NokLEmTN9xzEt5Fg0CtUbPgC4exHYVezfzddmq5QESqyKzDHuHOBi+P+Pm6uBCT+his/F/5xbw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1504,14 +977,14 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/core": "21.2.11", + "@angular/core": "21.2.16", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/upgrade": { - "version": "21.2.11", - "resolved": "https://registry.npmjs.org/@angular/upgrade/-/upgrade-21.2.11.tgz", - "integrity": "sha512-4FuJXAvkmP7fQVIv0cmpRZ0feo+JpH3jkXfwPNSFp4BA01Xoq89WplgYMZc40Sw82iLUqY0hiraVAWb//5S/dw==", + "version": "21.2.16", + "resolved": "https://registry.npmjs.org/@angular/upgrade/-/upgrade-21.2.16.tgz", + "integrity": "sha512-2deW5HHwZ0md4SiJPdy+mQHd7WoVzhZgjV/ruUxZBZE12YTZ0A0apl8kg70p0fxwlkXnyYMamIJmrPTPuVL/lQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -1520,18 +993,20 @@ "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.11", - "@angular/core": "21.2.11", - "@angular/platform-browser": "21.2.11", - "@angular/platform-browser-dynamic": "21.2.11" + "@angular/compiler": "21.2.16", + "@angular/core": "21.2.16", + "@angular/platform-browser": "21.2.16", + "@angular/platform-browser-dynamic": "21.2.16" } }, "node_modules/@babel/code-frame": { - "version": "7.29.0", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-validator-identifier": "^7.28.5", + "@babel/helper-validator-identifier": "^7.29.7", "js-tokens": "^4.0.0", "picocolors": "^1.1.1" }, @@ -1540,9 +1015,9 @@ } }, "node_modules/@babel/compat-data": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.0.tgz", - "integrity": "sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", "dev": true, "license": "MIT", "engines": { @@ -1598,14 +1073,14 @@ } }, "node_modules/@babel/generator": { - "version": "7.29.1", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.1.tgz", - "integrity": "sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.7.tgz", + "integrity": "sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==", "dev": true, "license": "MIT", "dependencies": { - "@babel/parser": "^7.29.0", - "@babel/types": "^7.29.0", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7", "@jridgewell/gen-mapping": "^0.3.12", "@jridgewell/trace-mapping": "^0.3.28", "jsesc": "^3.0.2" @@ -1628,14 +1103,14 @@ } }, "node_modules/@babel/helper-compilation-targets": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.28.6.tgz", - "integrity": "sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/compat-data": "^7.28.6", - "@babel/helper-validator-option": "^7.27.1", + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", "browserslist": "^4.24.0", "lru-cache": "^5.1.1", "semver": "^6.3.1" @@ -1655,9 +1130,9 @@ } }, "node_modules/@babel/helper-globals": { - "version": "7.28.0", - "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.28.0.tgz", - "integrity": "sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", "dev": true, "license": "MIT", "engines": { @@ -1665,29 +1140,29 @@ } }, "node_modules/@babel/helper-module-imports": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.28.6.tgz", - "integrity": "sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", "dev": true, "license": "MIT", "dependencies": { - "@babel/traverse": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/helper-module-transforms": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.28.6.tgz", - "integrity": "sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-module-imports": "^7.28.6", - "@babel/helper-validator-identifier": "^7.28.5", - "@babel/traverse": "^7.28.6" + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1710,9 +1185,9 @@ } }, "node_modules/@babel/helper-string-parser": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.27.1.tgz", - "integrity": "sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", "dev": true, "license": "MIT", "engines": { @@ -1720,7 +1195,9 @@ } }, "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "dev": true, "license": "MIT", "engines": { @@ -1728,9 +1205,9 @@ } }, "node_modules/@babel/helper-validator-option": { - "version": "7.27.1", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.27.1.tgz", - "integrity": "sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", "dev": true, "license": "MIT", "engines": { @@ -1738,27 +1215,27 @@ } }, "node_modules/@babel/helpers": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.2.tgz", - "integrity": "sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0" + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/parser": { - "version": "7.29.2", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.2.tgz", - "integrity": "sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.7.tgz", + "integrity": "sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/types": "^7.29.0" + "@babel/types": "^7.29.7" }, "bin": { "parser": "bin/babel-parser.js" @@ -1768,33 +1245,33 @@ } }, "node_modules/@babel/template": { - "version": "7.28.6", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", - "integrity": "sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.28.6", - "@babel/parser": "^7.28.6", - "@babel/types": "^7.28.6" + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" }, "engines": { "node": ">=6.9.0" } }, "node_modules/@babel/traverse": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.0.tgz", - "integrity": "sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.7.tgz", + "integrity": "sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==", "dev": true, "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.29.0", - "@babel/generator": "^7.29.0", - "@babel/helper-globals": "^7.28.0", - "@babel/parser": "^7.29.0", - "@babel/template": "^7.28.6", - "@babel/types": "^7.29.0", + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7", "debug": "^4.3.1" }, "engines": { @@ -1802,14 +1279,14 @@ } }, "node_modules/@babel/types": { - "version": "7.29.0", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.0.tgz", - "integrity": "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==", + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.7.tgz", + "integrity": "sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==", "dev": true, "license": "MIT", "dependencies": { - "@babel/helper-string-parser": "^7.27.1", - "@babel/helper-validator-identifier": "^7.28.5" + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" }, "engines": { "node": ">=6.9.0" @@ -1817,6 +1294,8 @@ }, "node_modules/@colors/colors": { "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, "license": "MIT", "engines": { @@ -1824,15 +1303,15 @@ } }, "node_modules/@commitlint/cli": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.5.0.tgz", - "integrity": "sha512-yNkyN/tuKTJS3wdVfsZ2tXDM4G4Gi7z+jW54Cki8N8tZqwKBltbIvUUrSbT4hz1bhW/h0CdR+5sCSpXD+wMKaQ==", + "version": "20.5.3", + "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-20.5.3.tgz", + "integrity": "sha512-OJdL0EXWD5y9LPa0nr/geOwzaS8BsdaybKkcloB0JgsguGxNv2R+hC2FTPqrAcprg35zF33KOQerY0x8W1aesA==", "dev": true, "license": "MIT", "dependencies": { "@commitlint/format": "^20.5.0", - "@commitlint/lint": "^20.5.0", - "@commitlint/load": "^20.5.0", + "@commitlint/lint": "^20.5.3", + "@commitlint/load": "^20.5.3", "@commitlint/read": "^20.5.0", "@commitlint/types": "^20.5.0", "tinyexec": "^1.0.0", @@ -1845,138 +1324,267 @@ "node": ">=v18" } }, - "node_modules/@commitlint/config-conventional": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.5.0.tgz", - "integrity": "sha512-t3Ni88rFw1XMa4nZHgOKJ8fIAT9M2j5TnKyTqJzsxea7FUetlNdYFus9dz+MhIRZmc16P0PPyEfh6X2d/qw8SA==", + "node_modules/@commitlint/cli/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", - "dependencies": { - "@commitlint/types": "^20.5.0", - "conventional-changelog-conventionalcommits": "^9.2.0" - }, "engines": { - "node": ">=v18" + "node": ">=8" } }, - "node_modules/@commitlint/config-validator": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.5.0.tgz", - "integrity": "sha512-T/Uh6iJUzyx7j35GmHWdIiGRQB+ouZDk0pwAaYq4SXgB54KZhFdJ0vYmxiW6AMYICTIWuyMxDBl1jK74oFp/Gw==", + "node_modules/@commitlint/cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.5.0", - "ajv": "^8.11.0" + "color-convert": "^2.0.1" }, "engines": { - "node": ">=v18" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@commitlint/ensure": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.5.0.tgz", - "integrity": "sha512-IpHqAUesBeW1EDDdjzJeaOxU9tnogLAyXLRBn03SHlj1SGENn2JGZqSWGkFvBJkJzfXAuCNtsoYzax+ZPS+puw==", + "node_modules/@commitlint/cli/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "@commitlint/types": "^20.5.0", - "lodash.camelcase": "^4.3.0", - "lodash.kebabcase": "^4.1.1", - "lodash.snakecase": "^4.1.1", - "lodash.startcase": "^4.4.0", - "lodash.upperfirst": "^4.3.1" + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" }, "engines": { - "node": ">=v18" + "node": ">=12" } }, - "node_modules/@commitlint/execute-rule": { - "version": "20.0.0", - "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-20.0.0.tgz", - "integrity": "sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==", + "node_modules/@commitlint/cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, "engines": { - "node": ">=v18" + "node": ">=7.0.0" } }, - "node_modules/@commitlint/format": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.5.0.tgz", - "integrity": "sha512-TI9EwFU/qZWSK7a5qyXMpKPPv3qta7FO4tKW+Wt2al7sgMbLWTsAcDpX1cU8k16TRdsiiet9aOw0zpvRXNJu7Q==", + "node_modules/@commitlint/cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@commitlint/cli/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "license": "MIT", - "dependencies": { - "@commitlint/types": "^20.5.0", - "picocolors": "^1.1.1" - }, "engines": { - "node": ">=v18" + "node": ">=8" } }, - "node_modules/@commitlint/is-ignored": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.5.0.tgz", - "integrity": "sha512-JWLarAsurHJhPozbuAH6GbP4p/hdOCoqS9zJMfqwswne+/GPs5V0+rrsfOkP68Y8PSLphwtFXV0EzJ+GTXTTGg==", + "node_modules/@commitlint/cli/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/types": "^20.5.0", - "semver": "^7.6.0" + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" }, "engines": { - "node": ">=v18" + "node": ">=8" } }, - "node_modules/@commitlint/lint": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.5.0.tgz", - "integrity": "sha512-jiM3hNUdu04jFBf1VgPdjtIPvbuVfDTBAc6L98AWcoLjF5sYqkulBHBzlVWll4rMF1T5zeQFB6r//a+s+BBKlA==", + "node_modules/@commitlint/cli/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/is-ignored": "^20.5.0", - "@commitlint/parse": "^20.5.0", - "@commitlint/rules": "^20.5.0", - "@commitlint/types": "^20.5.0" + "ansi-regex": "^5.0.1" }, "engines": { - "node": ">=v18" + "node": ">=8" } }, - "node_modules/@commitlint/load": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.5.0.tgz", - "integrity": "sha512-sLhhYTL/KxeOTZjjabKDhwidGZan84XKK1+XFkwDYL/4883kIajcz/dZFAhBJmZPtL8+nBx6bnkzA95YxPeDPw==", + "node_modules/@commitlint/cli/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/config-validator": "^20.5.0", - "@commitlint/execute-rule": "^20.0.0", - "@commitlint/resolve-extends": "^20.5.0", - "@commitlint/types": "^20.5.0", - "cosmiconfig": "^9.0.1", - "cosmiconfig-typescript-loader": "^6.1.0", - "is-plain-obj": "^4.1.0", - "lodash.mergewith": "^4.6.2", - "picocolors": "^1.1.1" + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" }, "engines": { - "node": ">=v18" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@commitlint/load/node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "node_modules/@commitlint/cli/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", "dev": true, "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@commitlint/cli/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "license": "ISC", "engines": { "node": ">=12" + } + }, + "node_modules/@commitlint/config-conventional": { + "version": "20.5.3", + "resolved": "https://registry.npmjs.org/@commitlint/config-conventional/-/config-conventional-20.5.3.tgz", + "integrity": "sha512-j34Qqeaa152chJgz2ysyk0BCpHenJn1lV0Rx0VXf8k3ccQcED+48EZrzMvo9jLmJUyBrrBwvu89I+2er4gW7QQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.5.0", + "conventional-changelog-conventionalcommits": "^9.2.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/config-validator": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/config-validator/-/config-validator-20.5.0.tgz", + "integrity": "sha512-T/Uh6iJUzyx7j35GmHWdIiGRQB+ouZDk0pwAaYq4SXgB54KZhFdJ0vYmxiW6AMYICTIWuyMxDBl1jK74oFp/Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.5.0", + "ajv": "^8.11.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/ensure": { + "version": "20.5.3", + "resolved": "https://registry.npmjs.org/@commitlint/ensure/-/ensure-20.5.3.tgz", + "integrity": "sha512-4i4AgNvH62owG9MwSiWKrle7HGNpBHHdLnWFIp5fTsHUYe5kRuh15t08L/0pdbbrRk8JKXQxxN4hZQcn+szkrw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.5.0", + "es-toolkit": "^1.46.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/execute-rule": { + "version": "20.0.0", + "resolved": "https://registry.npmjs.org/@commitlint/execute-rule/-/execute-rule-20.0.0.tgz", + "integrity": "sha512-xyCoOShoPuPL44gVa+5EdZsBVao/pNzpQhkzq3RdtlFdKZtjWcLlUFQHSWBuhk5utKYykeJPSz2i8ABHQA+ZZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/format": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/format/-/format-20.5.0.tgz", + "integrity": "sha512-TI9EwFU/qZWSK7a5qyXMpKPPv3qta7FO4tKW+Wt2al7sgMbLWTsAcDpX1cU8k16TRdsiiet9aOw0zpvRXNJu7Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.5.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/is-ignored": { + "version": "20.5.0", + "resolved": "https://registry.npmjs.org/@commitlint/is-ignored/-/is-ignored-20.5.0.tgz", + "integrity": "sha512-JWLarAsurHJhPozbuAH6GbP4p/hdOCoqS9zJMfqwswne+/GPs5V0+rrsfOkP68Y8PSLphwtFXV0EzJ+GTXTTGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/types": "^20.5.0", + "semver": "^7.6.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/lint": { + "version": "20.5.3", + "resolved": "https://registry.npmjs.org/@commitlint/lint/-/lint-20.5.3.tgz", + "integrity": "sha512-M7JbWBNr2gXKaPc4i/KipsuW1gkDHpj35KPjWtKy3Z+2AQw5wu1gBi1LIO0uoaij67CqY4K8PxPZSGens4evCw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/is-ignored": "^20.5.0", + "@commitlint/parse": "^20.5.0", + "@commitlint/rules": "^20.5.3", + "@commitlint/types": "^20.5.0" + }, + "engines": { + "node": ">=v18" + } + }, + "node_modules/@commitlint/load": { + "version": "20.5.3", + "resolved": "https://registry.npmjs.org/@commitlint/load/-/load-20.5.3.tgz", + "integrity": "sha512-1FDZWuKyu98Myb8i7Tp31jPU2rZpOwAdYRyJcy2KoGg7Xk2A+bgHN8smhMaaNSNkmE8fwt53BokywZq8Gv/5XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@commitlint/config-validator": "^20.5.0", + "@commitlint/execute-rule": "^20.0.0", + "@commitlint/resolve-extends": "^20.5.3", + "@commitlint/types": "^20.5.0", + "cosmiconfig": "^9.0.1", + "cosmiconfig-typescript-loader": "^6.1.0", + "es-toolkit": "^1.46.0", + "is-plain-obj": "^4.1.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=v18" } }, "node_modules/@commitlint/message": { @@ -2022,17 +1630,17 @@ } }, "node_modules/@commitlint/resolve-extends": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.5.0.tgz", - "integrity": "sha512-3SHPWUW2v0tyspCTcfSsYml0gses92l6TlogwzvM2cbxDgmhSRc+fldDjvGkCXJrjSM87BBaWYTPWwwyASZRrg==", + "version": "20.5.3", + "resolved": "https://registry.npmjs.org/@commitlint/resolve-extends/-/resolve-extends-20.5.3.tgz", + "integrity": "sha512-+ogW9v/u9JqpvAgTrLra/YTFo0KkjU6iNblF89pPsj4NebNc+DAWctsludwezI8YnsjBmfHpApSwcXprN/f/ew==", "dev": true, "license": "MIT", "dependencies": { "@commitlint/config-validator": "^20.5.0", "@commitlint/types": "^20.5.0", - "global-directory": "^4.0.1", + "es-toolkit": "^1.46.0", + "global-directory": "^5.0.0", "import-meta-resolve": "^4.0.0", - "lodash.mergewith": "^4.6.2", "resolve-from": "^5.0.0" }, "engines": { @@ -2040,13 +1648,13 @@ } }, "node_modules/@commitlint/rules": { - "version": "20.5.0", - "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.5.0.tgz", - "integrity": "sha512-5NdQXQEdnDPT5pK8O39ZA7HohzPRHEsDGU23cyVCNPQy4WegAbAwrQk3nIu7p2sl3dutPk8RZd91yKTrMTnRkQ==", + "version": "20.5.3", + "resolved": "https://registry.npmjs.org/@commitlint/rules/-/rules-20.5.3.tgz", + "integrity": "sha512-MPlMnb9D3wbszYMp+1hPtuhtPJndRo6I6yfkZVA4+jR8w7Kqp0u2u/Y+gzbaItx5Lltq5rw7FSZQWJMoXUC4NQ==", "dev": true, "license": "MIT", "dependencies": { - "@commitlint/ensure": "^20.5.0", + "@commitlint/ensure": "^20.5.3", "@commitlint/message": "^20.4.3", "@commitlint/to-lines": "^20.0.0", "@commitlint/types": "^20.5.0" @@ -2121,6 +1729,8 @@ }, "node_modules/@cspotcode/source-map-support": { "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", "dev": true, "license": "MIT", "dependencies": { @@ -2132,6 +1742,8 @@ }, "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", "dev": true, "license": "MIT", "dependencies": { @@ -2141,6 +1753,8 @@ }, "node_modules/@ctrl/ngx-emoji-mart": { "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@ctrl/ngx-emoji-mart/-/ngx-emoji-mart-9.3.0.tgz", + "integrity": "sha512-9uFzAvlFT21OLsTfhL3ZEO5mp51qvL1F4ErIZVBIsvAlji46u6p2KGgVA60oIheFBX4JoZI7HBDGOkGnm9dTUQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -2149,1014 +1763,2122 @@ "@angular/core": ">=15.0.0-0" } }, - "node_modules/@esbuild/linux-arm64": { + "node_modules/@emnapi/core": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.0.tgz", + "integrity": "sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.2", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.0.tgz", + "integrity": "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", + "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { "version": "0.27.3", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", - "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", + "integrity": "sha512-9fJMTNFTWZMh5qwrBItuziu834eOCUcEqymSH7pY+zoMVEZg3gcPuBNxH1EvfVYe9h0x/Ptw8KBzv7qxb7l8dg==", "cpu": [ - "arm64" + "ppc64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "aix" ], "engines": { "node": ">=18" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.9.1", + "node_modules/@esbuild/android-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.27.3.tgz", + "integrity": "sha512-i5D1hPY7GIQmXlXhs2w8AWHhenb00+GxjxRncS2ZM7YNVGNfaMxgzSGuO8o8SJzRc/oZwU2bcScvVERk03QhzA==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", - "dependencies": { - "eslint-visitor-keys": "^3.4.3" - }, + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": ">=18" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.12.2", + "node_modules/@esbuild/android-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.27.3.tgz", + "integrity": "sha512-YdghPYUmj/FX2SYKJ0OZxf+iaKgMsKHVPF1MAq/P8WirnSpCStzKJFjOjzsW0QQ7oIAiccHdcqjbHmJxRb/dmg==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=18" } }, - "node_modules/@eslint/config-array": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", - "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", - "license": "Apache-2.0", - "dependencies": { - "@eslint/object-schema": "^2.1.7", - "debug": "^4.3.1", - "minimatch": "^3.1.5" - }, + "node_modules/@esbuild/android-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.27.3.tgz", + "integrity": "sha512-IN/0BNTkHtk8lkOM8JWAYFg4ORxBkZQf9zXiEOfERX/CzxW3Vg1ewAhU7QSWQpVIzTW+b8Xy+lGzdYXV6UZObQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/config-array/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.27.3.tgz", + "integrity": "sha512-Re491k7ByTVRy0t3EKWajdLIr0gz2kKKfzafkth4Q8A5n1xTHrkqZgLLjFEHVD+AXdUGgQMq+Godfq45mGpCKg==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@eslint/config-array/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.27.3.tgz", + "integrity": "sha512-vHk/hA7/1AckjGzRqi6wbo+jaShzRowYip6rt6q7VYEDX4LEy1pZfDpdxCBnGtl+A5zq8iXDcyuxwtv3hNtHFg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "*" + "node": ">=18" } }, - "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.27.3.tgz", + "integrity": "sha512-ipTYM2fjt3kQAYOvo6vcxJx3nBYAzPjgTCk7QEgZG8AUO3ydUhvelmhrbOheMnGOlaSFUoHXB6un+A7q4ygY9w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", - "license": "Apache-2.0", - "dependencies": { - "@types/json-schema": "^7.0.15" - }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.27.3.tgz", + "integrity": "sha512-dDk0X87T7mI6U3K9VjWtHOXqwAMJBNN2r7bejDsc+j03SEjtD9HrOl8gVFByeM0aJksoUuUVU9TBaZa2rgj0oA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", - "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", + "node_modules/@esbuild/linux-arm": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.27.3.tgz", + "integrity": "sha512-s6nPv2QkSupJwLYyfS+gwdirm0ukyTFNl3KTgZEAiJDd+iHZcbTPPcWCcRYH+WlNbwChgH2QkE9NSlNrMT8Gfw==", + "cpu": [ + "arm" + ], + "dev": true, "license": "MIT", - "dependencies": { - "ajv": "^6.14.0", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.1", - "minimatch": "^3.1.5", - "strip-json-comments": "^3.1.1" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", + "node_modules/@esbuild/linux-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.27.3.tgz", + "integrity": "sha512-sZOuFz/xWnZ4KH3YfFrKCf1WyPZHakVzTiqji3WDc0BCl2kBwiJLCXpzLzUBLgmp4veFZdvN5ChW4Eq/8Fc2Fg==", + "cpu": [ + "arm64" + ], + "dev": true, "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", + "node_modules/@esbuild/linux-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.27.3.tgz", + "integrity": "sha512-yGlQYjdxtLdh0a3jHjuwOrxQjOZYD/C9PfdbgJJF3TIZWnm/tMd/RcNiLngiu4iwcBAOezdnSLAwQDPqTmtTYg==", + "cpu": [ + "ia32" + ], + "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" } }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "license": "MIT" - }, - "node_modules/@eslint/eslintrc/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.27.3.tgz", + "integrity": "sha512-WO60Sn8ly3gtzhyjATDgieJNet/KqsDlX5nRC5Y3oTFcS1l0KWba+SEa9Ja1GfDqSF1z6hif/SkpQJbL63cgOA==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "*" + "node": ">=18" } }, - "node_modules/@eslint/js": { - "version": "9.39.4", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", - "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", + "node_modules/@esbuild/linux-mips64el": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.27.3.tgz", + "integrity": "sha512-APsymYA6sGcZ4pD6k+UxbDjOFSvPWyZhjaiPyl/f79xKxwTnrn5QUnXR5prvetuaSMsb4jgeHewIDCIWljrSxw==", + "cpu": [ + "mips64el" + ], + "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" + "node": ">=18" } }, - "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", - "license": "Apache-2.0", + "node_modules/@esbuild/linux-ppc64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.27.3.tgz", + "integrity": "sha512-eizBnTeBefojtDb9nSh4vvVQ3V9Qf9Df01PfawPcRzJH4gFSgrObw+LveUyDoKU3kxi5+9RJTCWlj4FjYXVPEA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", - "license": "Apache-2.0", - "dependencies": { - "@eslint/core": "^0.17.0", - "levn": "^0.4.1" - }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.27.3.tgz", + "integrity": "sha512-3Emwh0r5wmfm3ssTWRQSyVhbOHvqegUDRd0WhmXKX2mkHJe1SFCMJhagUleMq+Uci34wLSipf8Lagt4LlpRFWQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=18" } }, - "node_modules/@gar/promise-retry": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@gar/promise-retry/-/promise-retry-1.0.3.tgz", - "integrity": "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==", + "node_modules/@esbuild/linux-s390x": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.27.3.tgz", + "integrity": "sha512-pBHUx9LzXWBc7MFIEEL0yD/ZVtNgLytvx60gES28GcWMqil8ElCYR4kvbV2BDqsHOvVDRrOxGySBM9Fcv744hw==", + "cpu": [ + "s390x" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">=18" } }, - "node_modules/@harperfast/extended-iterable": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@harperfast/extended-iterable/-/extended-iterable-1.0.3.tgz", - "integrity": "sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw==", + "node_modules/@esbuild/linux-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.27.3.tgz", + "integrity": "sha512-Czi8yzXUWIQYAtL/2y6vogER8pvcsOsk5cpwL4Gk5nJqH5UZiVByIY8Eorm5R13gq+DQKYg0+JyQoytLQas4dA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "optional": true + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } }, - "node_modules/@hono/node-server": { - "version": "1.19.14", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", - "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.27.3.tgz", + "integrity": "sha512-sDpk0RgmTCR/5HguIZa9n9u+HVKf40fbEUt+iTzSnCaGvY9kFP0YKBWZtJaraonFnqef5SlJ8/TiPAxzyS+UoA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=18.14.1" - }, - "peerDependencies": { - "hono": "^4" + "node": ">=18" } }, - "node_modules/@humanfs/core": { - "version": "0.19.2", - "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", - "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", - "license": "Apache-2.0", - "dependencies": { - "@humanfs/types": "^0.15.0" - }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.27.3.tgz", + "integrity": "sha512-P14lFKJl/DdaE00LItAukUdZO5iqNH7+PjoBm+fLQjtxfcfFE20Xf5CrLsmZdq5LFFZzb5JMZ9grUwvtVYzjiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=18.18.0" + "node": ">=18" } }, - "node_modules/@humanfs/node": { - "version": "0.16.8", - "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", - "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", - "license": "Apache-2.0", - "dependencies": { - "@humanfs/core": "^0.19.2", - "@humanfs/types": "^0.15.0", - "@humanwhocodes/retry": "^0.4.0" - }, - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanfs/types": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", - "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", - "license": "Apache-2.0", - "engines": { - "node": ">=18.18.0" - } - }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "license": "Apache-2.0", - "engines": { - "node": ">=12.22" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" - } - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", - "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", - "license": "Apache-2.0", + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.27.3.tgz", + "integrity": "sha512-AIcMP77AvirGbRl/UZFTq5hjXK+2wC7qFRGoHSDrZ5v5b8DK/GYpXW3CPRL53NkvDqb9D+alBiC/dV0Fb7eJcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=18.18" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "node": ">=18" } }, - "node_modules/@inquirer/ansi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", - "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", + "node_modules/@esbuild/openbsd-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.27.3.tgz", + "integrity": "sha512-DnW2sRrBzA+YnE70LKqnM3P+z8vehfJWHXECbwBmH/CU51z6FiqTQTHFenPlHmo3a8UgpLyH3PT+87OViOh1AQ==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], "engines": { "node": ">=18" } }, - "node_modules/@inquirer/checkbox": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", - "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.27.3.tgz", + "integrity": "sha512-NinAEgr/etERPTsZJ7aEZQvvg/A6IsZG/LgZy+81wON2huV7SrK3e63dU0XhyZP4RKGyTm7aOgmQk0bGp0fy2g==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/core": "^10.3.2", - "@inquirer/figures": "^1.0.15", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" - }, + "optional": true, + "os": [ + "openharmony" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@inquirer/confirm": { - "version": "5.1.21", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", - "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "node_modules/@esbuild/sunos-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.27.3.tgz", + "integrity": "sha512-PanZ+nEz+eWoBJ8/f8HKxTTD172SKwdXebZ0ndd953gt1HRBbhMsaNqjTyYLGLPdoWHy4zLU7bDVJztF5f3BHA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@inquirer/core": { - "version": "10.3.2", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", - "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", + "node_modules/@esbuild/win32-arm64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.27.3.tgz", + "integrity": "sha512-B2t59lWWYrbRDw/tjiWOuzSsFh1Y/E95ofKz7rIVYSQkUYBjfSgf6oeYPNWHToFRr2zx52JKApIcAS/D5TUBnA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/figures": "^1.0.15", - "@inquirer/type": "^3.0.10", - "cli-width": "^4.1.0", - "mute-stream": "^2.0.0", - "signal-exit": "^4.1.0", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.3" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@inquirer/editor": { - "version": "4.2.23", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", - "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", + "node_modules/@esbuild/win32-ia32": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.27.3.tgz", + "integrity": "sha512-QLKSFeXNS8+tHW7tZpMtjlNb7HKau0QDpwm49u0vUp9y1WOF+PEzkU84y9GqYaAVW8aH8f3GcBck26jh54cX4Q==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/external-editor": "^1.0.3", - "@inquirer/type": "^3.0.10" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@inquirer/expand": { - "version": "4.0.23", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", - "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", + "node_modules/@esbuild/win32-x64": { + "version": "0.27.3", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.27.3.tgz", + "integrity": "sha512-4uJGhsxuptu3OcpVAzli+/gWusVGwZZHTlS63hh++ehExkVT8SgiEf7/uC/PclrPPkLhZqGgCTjd0VWLo6xMqA==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", - "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } } }, - "node_modules/@inquirer/external-editor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", - "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", - "dev": true, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.9.1", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", + "integrity": "sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==", "license": "MIT", "dependencies": { - "chardet": "^2.1.1", - "iconv-lite": "^0.7.0" + "eslint-visitor-keys": "^3.4.3" }, "engines": { - "node": ">=18" + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependencies": { - "@types/node": ">=18" + "funding": { + "url": "https://opencollective.com/eslint" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" } }, - "node_modules/@inquirer/figures": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", - "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", - "dev": true, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.2", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.2.tgz", + "integrity": "sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==", "license": "MIT", "engines": { - "node": ">=18" + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" } }, - "node_modules/@inquirer/input": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", - "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", - "dev": true, - "license": "MIT", + "node_modules/@eslint/config-array": { + "version": "0.21.2", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", + "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "license": "Apache-2.0", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" + "@eslint/object-schema": "^2.1.7", + "debug": "^4.3.1", + "minimatch": "^3.1.5" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@inquirer/number": { - "version": "3.0.23", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", - "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", - "dev": true, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": "*" } }, - "node_modules/@inquirer/password": { - "version": "4.0.23", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", - "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", - "dev": true, - "license": "MIT", + "node_modules/@eslint/config-helpers": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", + "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "license": "Apache-2.0", "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" + "@eslint/core": "^0.17.0" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@inquirer/prompts": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", - "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", - "dev": true, - "license": "MIT", + "node_modules/@eslint/core": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", + "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "license": "Apache-2.0", "dependencies": { - "@inquirer/checkbox": "^4.3.2", - "@inquirer/confirm": "^5.1.21", - "@inquirer/editor": "^4.2.23", - "@inquirer/expand": "^4.0.23", - "@inquirer/input": "^4.3.1", - "@inquirer/number": "^3.0.23", - "@inquirer/password": "^4.0.23", - "@inquirer/rawlist": "^4.1.11", - "@inquirer/search": "^3.2.2", - "@inquirer/select": "^4.4.2" + "@types/json-schema": "^7.0.15" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@inquirer/rawlist": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", - "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", - "dev": true, + "node_modules/@eslint/eslintrc": { + "version": "3.3.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.5.tgz", + "integrity": "sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" + "ajv": "^6.14.0", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.1", + "minimatch": "^3.1.5", + "strip-json-comments": "^3.1.1" }, "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "funding": { + "url": "https://opencollective.com/eslint" } }, - "node_modules/@inquirer/search": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", - "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", - "dev": true, + "node_modules/@eslint/eslintrc/node_modules/ajv": { + "version": "6.15.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", + "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/figures": "^1.0.15", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" } }, - "node_modules/@inquirer/select": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", - "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", - "dev": true, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", + "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/core": "^10.3.2", - "@inquirer/figures": "^1.0.15", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" - }, - "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, - "node_modules/@inquirer/type": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", - "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", - "dev": true, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "license": "MIT", "engines": { - "node": ">=18" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">= 4" } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "dev": true, + "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "license": "MIT" + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "license": "ISC", "dependencies": { - "minipass": "^7.0.4" + "brace-expansion": "^1.1.7" }, "engines": { - "node": ">=18.0.0" + "node": "*" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", - "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", - "dev": true, + "node_modules/@eslint/js": { + "version": "9.39.4", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.4.tgz", + "integrity": "sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==", "license": "MIT", "engines": { - "node": ">=8" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "node_modules/@eslint/object-schema": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", + "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, - "license": "MIT", + "node_modules/@eslint/plugin-kit": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", + "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", + "@eslint/core": "^0.17.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@gar/promise-retry": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@gar/promise-retry/-/promise-retry-1.0.3.tgz", + "integrity": "sha512-GmzA9ckNokPypTg10pgpeHNQe7ph+iIKKmhKu3Ob9ANkswreCx7R3cKmY781K8QK3AqVL3xVh9A42JvIAbkkSA==", "dev": true, "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", + "node_modules/@harperfast/extended-iterable": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@harperfast/extended-iterable/-/extended-iterable-1.0.3.tgz", + "integrity": "sha512-sSAYhQca3rDWtQUHSAPeO7axFIUJOI6hn1gjRC5APVE1a90tuyT8f5WIgRsFhhWA7htNkju2veB9eWL6YHi/Lw==", "dev": true, - "license": "MIT" + "license": "Apache-2.0", + "optional": true }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", + "node_modules/@hono/node-server": { + "version": "1.19.14", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", + "integrity": "sha512-GwtvgtXxnWsucXvbQXkRgqksiH2Qed37H9xHZocE5sA3N8O8O8/8FA3uclQXxXVzc9XBZuEOMK7+r02FmSpHtw==", "dev": true, "license": "MIT", + "engines": { + "node": ">=18.14.1" + }, + "peerDependencies": { + "hono": "^4" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.2.tgz", + "integrity": "sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==", + "license": "Apache-2.0", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@humanfs/types": "^0.15.0" + }, + "engines": { + "node": ">=18.18.0" } }, - "node_modules/@listr2/prompt-adapter-inquirer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.5.tgz", - "integrity": "sha512-WELs+hj6xcilkloBXYf9XXK8tYEnKsgLj01Xl5ONUJpKjmT5hGVUzNUS5tooUxs7pGMrw+jFD/41WpqW4V3LDA==", - "dev": true, - "license": "MIT", + "node_modules/@humanfs/node": { + "version": "0.16.8", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.8.tgz", + "integrity": "sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==", + "license": "Apache-2.0", "dependencies": { - "@inquirer/type": "^3.0.8" + "@humanfs/core": "^0.19.2", + "@humanfs/types": "^0.15.0", + "@humanwhocodes/retry": "^0.4.0" }, "engines": { - "node": ">=20.0.0" + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/types": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@humanfs/types/-/types-0.15.0.tgz", + "integrity": "sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" }, - "peerDependencies": { - "@inquirer/prompts": ">= 3 < 8", - "listr2": "9.0.5" + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.1.tgz", - "integrity": "sha512-aoERa5B6ywXdyFeYGQ1gbQpkMkDbEo45qVoXE5QpIRavqjnyPwjOulMkmkypkmsbJ5z4Wi0TBztON8agCTG0Vg==", - "cpu": [ - "arm64" - ], + "node_modules/@humanwhocodes/retry": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.3.tgz", + "integrity": "sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@inquirer/ansi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", + "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@mattlewis92/dom-autoscroller": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@mattlewis92/dom-autoscroller/-/dom-autoscroller-2.4.2.tgz", - "integrity": "sha512-YbrUWREPGEjE/FU6foXcAT1YbVwqD/jkYnY1dFb0o4AxtP3s4xKBthlELjndZih8uwsDWgQZx1eNskRNe2BgZQ==", - "license": "MIT" + "engines": { + "node": ">=18" + } }, - "node_modules/@modelcontextprotocol/sdk": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", - "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", + "node_modules/@inquirer/checkbox": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", + "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", "dev": true, "license": "MIT", "dependencies": { - "@hono/node-server": "^1.19.9", - "ajv": "^8.17.1", - "ajv-formats": "^3.0.1", - "content-type": "^1.0.5", - "cors": "^2.8.5", - "cross-spawn": "^7.0.5", - "eventsource": "^3.0.2", - "eventsource-parser": "^3.0.0", - "express": "^5.2.1", - "express-rate-limit": "^8.2.1", - "hono": "^4.11.4", - "jose": "^6.1.3", - "json-schema-typed": "^8.0.2", - "pkce-challenge": "^5.0.0", - "raw-body": "^3.0.0", - "zod": "^3.25 || ^4.0", - "zod-to-json-schema": "^3.25.1" + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { "node": ">=18" }, "peerDependencies": { - "@cfworker/json-schema": "^4.1.1", - "zod": "^3.25 || ^4.0" + "@types/node": ">=18" }, "peerDependenciesMeta": { - "@cfworker/json-schema": { + "@types/node": { "optional": true - }, - "zod": { - "optional": false } } }, - "node_modules/@modelcontextprotocol/sdk/node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", + "node_modules/@inquirer/confirm": { + "version": "5.1.21", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", + "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", "dev": true, "license": "MIT", "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": ">= 0.10" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.3.tgz", - "integrity": "sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@napi-rs/nice": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", - "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", + "node_modules/@inquirer/core": { + "version": "10.3.2", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", + "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", "dev": true, "license": "MIT", - "optional": true, + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "cli-width": "^4.1.0", + "mute-stream": "^2.0.0", + "signal-exit": "^4.1.0", + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.3" + }, "engines": { - "node": ">= 10" + "node": ">=18" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" + "peerDependencies": { + "@types/node": ">=18" }, - "optionalDependencies": { - "@napi-rs/nice-android-arm-eabi": "1.1.1", - "@napi-rs/nice-android-arm64": "1.1.1", - "@napi-rs/nice-darwin-arm64": "1.1.1", - "@napi-rs/nice-darwin-x64": "1.1.1", - "@napi-rs/nice-freebsd-x64": "1.1.1", - "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", - "@napi-rs/nice-linux-arm64-gnu": "1.1.1", - "@napi-rs/nice-linux-arm64-musl": "1.1.1", - "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", - "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", - "@napi-rs/nice-linux-s390x-gnu": "1.1.1", - "@napi-rs/nice-linux-x64-gnu": "1.1.1", - "@napi-rs/nice-linux-x64-musl": "1.1.1", - "@napi-rs/nice-openharmony-arm64": "1.1.1", - "@napi-rs/nice-win32-arm64-msvc": "1.1.1", - "@napi-rs/nice-win32-ia32-msvc": "1.1.1", - "@napi-rs/nice-win32-x64-msvc": "1.1.1" + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@napi-rs/nice-linux-arm64-gnu": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", - "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/editor": { + "version": "4.2.23", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", + "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/external-editor": "^1.0.3", + "@inquirer/type": "^3.0.10" + }, "engines": { - "node": ">= 10" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@napi-rs/nice-linux-arm64-musl": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", - "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/expand": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", + "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@ngneat/hotkeys": { - "version": "4.1.0", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - } - }, - "node_modules/@ngstack/code-editor": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/@ngstack/code-editor/-/code-editor-9.0.0.tgz", - "integrity": "sha512-sioi0qyeo9Q8PIdhGFmUeuEx6LETqSjC/4A1Fnl9HFVYzCU7mDVdyeUITubu+4THjraH1mIAVw2t0R7rDgdHdA==", - "license": "MIT", "dependencies": { - "tslib": "^2.5.0" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" }, "peerDependencies": { - "@angular/common": ">=17.1.1", - "@angular/core": ">=17.1.1" + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "node_modules/@inquirer/external-editor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", + "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "chardet": "^2.1.1", + "iconv-lite": "^0.7.0" }, "engines": { - "node": ">= 8" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "node_modules/@inquirer/figures": { + "version": "1.0.15", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", + "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", "dev": true, "license": "MIT", "engines": { - "node": ">= 8" + "node": ">=18" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "node_modules/@inquirer/input": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", + "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", "dev": true, "license": "MIT", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": ">= 8" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@npmcli/agent": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.0.tgz", - "integrity": "sha512-kAQTcEN9E8ERLVg5AsGwLNoFb+oEG6engbqAU2P43gD4JEIkNGMHdVQ096FsOAAYpZPB0RSt0zgInKIAS1l5QA==", + "node_modules/@inquirer/number": { + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", + "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "agent-base": "^7.1.0", - "http-proxy-agent": "^7.0.0", - "https-proxy-agent": "^7.0.1", - "lru-cache": "^11.2.1", - "socks-proxy-agent": "^8.0.3" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" }, "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@npmcli/agent/node_modules/lru-cache": { - "version": "11.5.1", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", - "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "node_modules/@inquirer/password": { + "version": "4.0.23", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", + "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10" + }, "engines": { - "node": "20 || >=22" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@npmcli/fs": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-5.0.0.tgz", - "integrity": "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==", + "node_modules/@inquirer/prompts": { + "version": "7.10.1", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", + "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "semver": "^7.3.5" + "@inquirer/checkbox": "^4.3.2", + "@inquirer/confirm": "^5.1.21", + "@inquirer/editor": "^4.2.23", + "@inquirer/expand": "^4.0.23", + "@inquirer/input": "^4.3.1", + "@inquirer/number": "^3.0.23", + "@inquirer/password": "^4.0.23", + "@inquirer/rawlist": "^4.1.11", + "@inquirer/search": "^3.2.2", + "@inquirer/select": "^4.4.2" }, "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@npmcli/git": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-7.0.2.tgz", - "integrity": "sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg==", + "node_modules/@inquirer/rawlist": { + "version": "4.1.11", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", + "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "@gar/promise-retry": "^1.0.0", - "@npmcli/promise-spawn": "^9.0.0", - "ini": "^6.0.0", - "lru-cache": "^11.2.1", - "npm-pick-manifest": "^11.0.1", - "proc-log": "^6.0.0", - "semver": "^7.3.5", - "which": "^6.0.0" + "@inquirer/core": "^10.3.2", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" }, "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@npmcli/git/node_modules/isexe": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", - "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "node_modules/@inquirer/search": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", + "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", + "dependencies": { + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, "engines": { - "node": ">=20" + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", + "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^1.0.2", + "@inquirer/core": "^10.3.2", + "@inquirer/figures": "^1.0.15", + "@inquirer/type": "^3.0.10", + "yoctocolors-cjs": "^2.1.3" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "3.0.10", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", + "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@listr2/prompt-adapter-inquirer": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.5.tgz", + "integrity": "sha512-WELs+hj6xcilkloBXYf9XXK8tYEnKsgLj01Xl5ONUJpKjmT5hGVUzNUS5tooUxs7pGMrw+jFD/41WpqW4V3LDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/type": "^3.0.8" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@inquirer/prompts": ">= 3 < 8", + "listr2": "9.0.5" + } + }, + "node_modules/@lmdb/lmdb-darwin-arm64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.5.1.tgz", + "integrity": "sha512-tpfN4kKrrMpQ+If1l8bhmoNkECJi0iOu6AEdrTJvWVC+32sLxTARX5Rsu579mPImRP9YFWfWgeRQ5oav7zApQQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-darwin-x64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.5.1.tgz", + "integrity": "sha512-+a2tTfc3rmWhLAolFUWRgJtpSuu+Fw/yjn4rF406NMxhfjbMuiOUTDRvRlMFV+DzyjkwnokisskHbCWkS3Ly5w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.5.1.tgz", + "integrity": "sha512-0EgcE6reYr8InjD7V37EgXcYrloqpxVPINy3ig1MwDSbl6LF/vXTYRH9OE1Ti1D8YZnB35ZH9aTcdfSb5lql2A==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-arm64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.1.tgz", + "integrity": "sha512-aoERa5B6ywXdyFeYGQ1gbQpkMkDbEo45qVoXE5QpIRavqjnyPwjOulMkmkypkmsbJ5z4Wi0TBztON8agCTG0Vg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-linux-x64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.5.1.tgz", + "integrity": "sha512-SqNDY1+vpji7bh0sFH5wlWyFTOzjbDOl0/kB5RLLYDAFyd/uw3n7wyrmas3rYPpAW7z18lMOi1yKlTPv967E3g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@lmdb/lmdb-win32-arm64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.5.1.tgz", + "integrity": "sha512-50v0O1Lt37cwrmR9vWZK5hRW0Aw+KEmxJJ75fge/zIYdvNKB/0bSMSVR5Uc2OV9JhosIUyklOmrEvavwNJ8D6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@lmdb/lmdb-win32-x64": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.5.1.tgz", + "integrity": "sha512-qwosvPyl+zpUlp3gRb7UcJ3H8S28XHCzkv0Y0EgQToXjQP91ZD67EHSCDmaLjtKhe+GVIW5om1KUpzVLA0l6pg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", + "optional": true, + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "license": "ISC", + "optional": true + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "license": "ISC", + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "license": "ISC", + "optional": true, + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/https-proxy-agent": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", + "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", + "license": "MIT", + "optional": true, + "dependencies": { + "agent-base": "6", + "debug": "4" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "license": "MIT", + "optional": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/make-dir/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "license": "ISC", + "optional": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "license": "ISC", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "license": "MIT", + "optional": true, + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "license": "ISC", + "optional": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/nopt": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz", + "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", + "license": "ISC", + "optional": true, + "dependencies": { + "abbrev": "1" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "deprecated": "Old versions of tar are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "license": "ISC", + "optional": true, + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@mapbox/node-pre-gyp/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "license": "ISC", + "optional": true + }, + "node_modules/@mattlewis92/dom-autoscroller": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@mattlewis92/dom-autoscroller/-/dom-autoscroller-2.4.2.tgz", + "integrity": "sha512-YbrUWREPGEjE/FU6foXcAT1YbVwqD/jkYnY1dFb0o4AxtP3s4xKBthlELjndZih8uwsDWgQZx1eNskRNe2BgZQ==", + "license": "MIT" + }, + "node_modules/@modelcontextprotocol/sdk": { + "version": "1.26.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", + "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@hono/node-server": "^1.19.9", + "ajv": "^8.17.1", + "ajv-formats": "^3.0.1", + "content-type": "^1.0.5", + "cors": "^2.8.5", + "cross-spawn": "^7.0.5", + "eventsource": "^3.0.2", + "eventsource-parser": "^3.0.0", + "express": "^5.2.1", + "express-rate-limit": "^8.2.1", + "hono": "^4.11.4", + "jose": "^6.1.3", + "json-schema-typed": "^8.0.2", + "pkce-challenge": "^5.0.0", + "raw-body": "^3.0.0", + "zod": "^3.25 || ^4.0", + "zod-to-json-schema": "^3.25.1" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@cfworker/json-schema": "^4.1.1", + "zod": "^3.25 || ^4.0" + }, + "peerDependenciesMeta": { + "@cfworker/json-schema": { + "optional": true + }, + "zod": { + "optional": false + } + } + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-3.0.4.tgz", + "integrity": "sha512-LCkGo6JDfaBhgST7UpPWgNgLINpcpabaHfyz5OBx75nUYxBsaEPxjnyNjWpeb/xBup/682QnBfRBy2/LvPutZQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-darwin-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-darwin-x64/-/msgpackr-extract-darwin-x64-3.0.4.tgz", + "integrity": "sha512-zExlW9zUJKZH/tOtVMttwjKa4Xm/3KcNjnE3dPN92uCktwavMxpgCA3MoJK/DOnTWsQgo224OaST27/mPNAf+w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm/-/msgpackr-extract-linux-arm-3.0.4.tgz", + "integrity": "sha512-Tg3yX65f5GbtXLkrYEHE5oibZG9epyYWas7FogTTEJeDEF9JlXJzKgXaNhT3UXlTOeA+AfZpYZYZ0uPj7Cfquw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-arm64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-arm64/-/msgpackr-extract-linux-arm64-3.0.4.tgz", + "integrity": "sha512-dgX0P/9wGPJeHFBG+ZmhgE6bmtMt7NP5CRBGyyktpopdk/mW4POnrpQsSLtKI1dwpc+pPLuXHDh6vvskyQE/sw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-linux-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-linux-x64/-/msgpackr-extract-linux-x64-3.0.4.tgz", + "integrity": "sha512-8TNXMEjJc3QEy7R/x1INhgiU+XakDAFUzBhaz7+Rbrs8NH5UQeHQxxmzsSBJGyV6I1jW79undiQm8tOI+D+8FQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@msgpackr-extract/msgpackr-extract-win32-x64": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@msgpackr-extract/msgpackr-extract-win32-x64/-/msgpackr-extract-win32-x64-3.0.4.tgz", + "integrity": "sha512-CmCXPQrkbwExx3j946/PtHWHbYJiCRBRDl4BlkRQcJB/YOwQxJRTpoo7aTsortjgoJ1x7opzTSxn7C+ASSLVjQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@napi-rs/nice": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice/-/nice-1.1.1.tgz", + "integrity": "sha512-xJIPs+bYuc9ASBl+cvGsKbGrJmS6fAKaSZCnT0lhahT5rhA2VVy9/EcIgd2JhtEuFOJNx7UHNn/qiTPTY4nrQw==", + "dev": true, + "license": "MIT", + "optional": true, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "optionalDependencies": { + "@napi-rs/nice-android-arm-eabi": "1.1.1", + "@napi-rs/nice-android-arm64": "1.1.1", + "@napi-rs/nice-darwin-arm64": "1.1.1", + "@napi-rs/nice-darwin-x64": "1.1.1", + "@napi-rs/nice-freebsd-x64": "1.1.1", + "@napi-rs/nice-linux-arm-gnueabihf": "1.1.1", + "@napi-rs/nice-linux-arm64-gnu": "1.1.1", + "@napi-rs/nice-linux-arm64-musl": "1.1.1", + "@napi-rs/nice-linux-ppc64-gnu": "1.1.1", + "@napi-rs/nice-linux-riscv64-gnu": "1.1.1", + "@napi-rs/nice-linux-s390x-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-gnu": "1.1.1", + "@napi-rs/nice-linux-x64-musl": "1.1.1", + "@napi-rs/nice-openharmony-arm64": "1.1.1", + "@napi-rs/nice-win32-arm64-msvc": "1.1.1", + "@napi-rs/nice-win32-ia32-msvc": "1.1.1", + "@napi-rs/nice-win32-x64-msvc": "1.1.1" + } + }, + "node_modules/@napi-rs/nice-android-arm-eabi": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm-eabi/-/nice-android-arm-eabi-1.1.1.tgz", + "integrity": "sha512-kjirL3N6TnRPv5iuHw36wnucNqXAO46dzK9oPb0wj076R5Xm8PfUVA9nAFB5ZNMmfJQJVKACAPd/Z2KYMppthw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-android-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-android-arm64/-/nice-android-arm64-1.1.1.tgz", + "integrity": "sha512-blG0i7dXgbInN5urONoUCNf+DUEAavRffrO7fZSeoRMJc5qD+BJeNcpr54msPF6qfDD6kzs9AQJogZvT2KD5nw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-arm64/-/nice-darwin-arm64-1.1.1.tgz", + "integrity": "sha512-s/E7w45NaLqTGuOjC2p96pct4jRfo61xb9bU1unM/MJ/RFkKlJyJDx7OJI/O0ll/hrfpqKopuAFDV8yo0hfT7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-darwin-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-darwin-x64/-/nice-darwin-x64-1.1.1.tgz", + "integrity": "sha512-dGoEBnVpsdcC+oHHmW1LRK5eiyzLwdgNQq3BmZIav+9/5WTZwBYX7r5ZkQC07Nxd3KHOCkgbHSh4wPkH1N1LiQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-freebsd-x64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-freebsd-x64/-/nice-freebsd-x64-1.1.1.tgz", + "integrity": "sha512-kHv4kEHAylMYmlNwcQcDtXjklYp4FCf0b05E+0h6nDHsZ+F0bDe04U/tXNOqrx5CmIAth4vwfkjjUmp4c4JktQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm-gnueabihf": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm-gnueabihf/-/nice-linux-arm-gnueabihf-1.1.1.tgz", + "integrity": "sha512-E1t7K0efyKXZDoZg1LzCOLxgolxV58HCkaEkEvIYQx12ht2pa8hoBo+4OB3qh7e+QiBlp1SRf+voWUZFxyhyqg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-gnu/-/nice-linux-arm64-gnu-1.1.1.tgz", + "integrity": "sha512-CIKLA12DTIZlmTaaKhQP88R3Xao+gyJxNWEn04wZwC2wmRapNnxCUZkVwggInMJvtVElA+D4ZzOU5sX4jV+SmQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-arm64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-arm64-musl/-/nice-linux-arm64-musl-1.1.1.tgz", + "integrity": "sha512-+2Rzdb3nTIYZ0YJF43qf2twhqOCkiSrHx2Pg6DJaCPYhhaxbLcdlV8hCRMHghQ+EtZQWGNcS2xF4KxBhSGeutg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-ppc64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-ppc64-gnu/-/nice-linux-ppc64-gnu-1.1.1.tgz", + "integrity": "sha512-4FS8oc0GeHpwvv4tKciKkw3Y4jKsL7FRhaOeiPei0X9T4Jd619wHNe4xCLmN2EMgZoeGg+Q7GY7BsvwKpL22Tg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-riscv64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-riscv64-gnu/-/nice-linux-riscv64-gnu-1.1.1.tgz", + "integrity": "sha512-HU0nw9uD4FO/oGCCk409tCi5IzIZpH2agE6nN4fqpwVlCn5BOq0MS1dXGjXaG17JaAvrlpV5ZeyZwSon10XOXw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-s390x-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-s390x-gnu/-/nice-linux-s390x-gnu-1.1.1.tgz", + "integrity": "sha512-2YqKJWWl24EwrX0DzCQgPLKQBxYDdBxOHot1KWEq7aY2uYeX+Uvtv4I8xFVVygJDgf6/92h9N3Y43WPx8+PAgQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-gnu": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-gnu/-/nice-linux-x64-gnu-1.1.1.tgz", + "integrity": "sha512-/gaNz3R92t+dcrfCw/96pDopcmec7oCcAQ3l/M+Zxr82KT4DljD37CpgrnXV+pJC263JkW572pdbP3hP+KjcIg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-linux-x64-musl": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-linux-x64-musl/-/nice-linux-x64-musl-1.1.1.tgz", + "integrity": "sha512-xScCGnyj/oppsNPMnevsBe3pvNaoK7FGvMjT35riz9YdhB2WtTG47ZlbxtOLpjeO9SqqQ2J2igCmz6IJOD5JYw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-openharmony-arm64": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-openharmony-arm64/-/nice-openharmony-arm64-1.1.1.tgz", + "integrity": "sha512-6uJPRVwVCLDeoOaNyeiW0gp2kFIM4r7PL2MczdZQHkFi9gVlgm+Vn+V6nTWRcu856mJ2WjYJiumEajfSm7arPQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-arm64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-arm64-msvc/-/nice-win32-arm64-msvc-1.1.1.tgz", + "integrity": "sha512-uoTb4eAvM5B2aj/z8j+Nv8OttPf2m+HVx3UjA5jcFxASvNhQriyCQF1OB1lHL43ZhW+VwZlgvjmP5qF3+59atA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-ia32-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-ia32-msvc/-/nice-win32-ia32-msvc-1.1.1.tgz", + "integrity": "sha512-CNQqlQT9MwuCsg1Vd/oKXiuH+TcsSPJmlAFc5frFyX/KkOh0UpBLEj7aoY656d5UKZQMQFP7vJNa1DNUNORvug==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/nice-win32-x64-msvc": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@napi-rs/nice-win32-x64-msvc/-/nice-win32-x64-msvc-1.1.1.tgz", + "integrity": "sha512-vB+4G/jBQCAh0jelMTY3+kgFy00Hlx2f2/1zjMoH821IbplbWZOkLiTYXQkygNTzQJTq5cvwBDgn2ppHD+bglQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@ngneat/hotkeys": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@ngneat/hotkeys/-/hotkeys-4.1.0.tgz", + "integrity": "sha512-bqtmK0wMGQOFtNnxmklnbhVbiUoOIp5rXY4UeWGRoMgf7RGvW6dO5moZSPzenJwp8pgi2EmSyo+xpQ8R512hIw==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + } + }, + "node_modules/@ngstack/code-editor": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/@ngstack/code-editor/-/code-editor-9.0.0.tgz", + "integrity": "sha512-sioi0qyeo9Q8PIdhGFmUeuEx6LETqSjC/4A1Fnl9HFVYzCU7mDVdyeUITubu+4THjraH1mIAVw2t0R7rDgdHdA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.5.0" + }, + "peerDependencies": { + "@angular/common": ">=17.1.1", + "@angular/core": ">=17.1.1" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/agent": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-4.0.2.tgz", + "integrity": "sha512-EUEuWAxnL07Sp5/iC/1X6Xj+XThUvnbei9zfRWZdEXa7lss9RTHMhAHBeg+MZ5To9s/gGaSI+UwZTPdYMvKSeg==", + "dev": true, + "license": "ISC", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^11.2.1", + "socks-proxy-agent": "^8.0.3" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/@npmcli/fs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-5.0.0.tgz", + "integrity": "sha512-7OsC1gNORBEawOa5+j2pXN9vsicaIOH5cPXxoR6fJOmH6/EXpJB2CajXOu1fPRFun2m1lktEFX11+P89hqO/og==", + "dev": true, + "license": "ISC", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/git": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-7.0.2.tgz", + "integrity": "sha512-oeolHDjExNAJAnlYP2qzNjMX/Xi9bmu78C9dIGr4xjobrSKbuMYCph8lTzn4vnW3NjIqVmw/f8BCfouqyJXlRg==", + "dev": true, + "license": "ISC", + "dependencies": { + "@gar/promise-retry": "^1.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "ini": "^6.0.0", + "lru-cache": "^11.2.1", + "npm-pick-manifest": "^11.0.1", + "proc-log": "^6.0.0", + "semver": "^7.3.5", + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" } }, "node_modules/@npmcli/git/node_modules/lru-cache": { @@ -3166,352 +3888,757 @@ "dev": true, "license": "BlueOak-1.0.0", "engines": { - "node": "20 || >=22" + "node": "20 || >=22" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-4.0.0.tgz", + "integrity": "sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA==", + "dev": true, + "license": "ISC", + "dependencies": { + "npm-bundled": "^5.0.0", + "npm-normalize-package-bin": "^5.0.0" + }, + "bin": { + "installed-package-contents": "bin/index.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-5.0.0.tgz", + "integrity": "sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-7.0.5.tgz", + "integrity": "sha512-iVuTlG3ORq2iaVa1IWUxAO/jIp77tUKBhoMjuzYW2kL4MLN1bi/ofqkZ7D7OOwh8coAx1/S2ge0rMdGv8sLSOQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "@npmcli/git": "^7.0.0", + "glob": "^13.0.0", + "hosted-git-info": "^9.0.0", + "json-parse-even-better-errors": "^5.0.0", + "proc-log": "^6.0.0", + "semver": "^7.5.3", + "spdx-expression-parse": "^4.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/balanced-match": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@npmcli/package-json/node_modules/brace-expansion": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", + "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + } + }, + "node_modules/@npmcli/package-json/node_modules/glob": { + "version": "13.0.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", + "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "minimatch": "^10.2.2", + "minipass": "^7.1.3", + "path-scurry": "^2.0.2" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/package-json/node_modules/minimatch": { + "version": "10.2.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", + "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "brace-expansion": "^5.0.5" + }, + "engines": { + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-9.0.1.tgz", + "integrity": "sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==", + "dev": true, + "license": "ISC", + "dependencies": { + "which": "^6.0.0" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", + "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=20" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", + "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^4.0.0" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/@npmcli/redact": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-4.0.0.tgz", + "integrity": "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==", + "dev": true, + "license": "ISC", + "engines": { + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@npmcli/git/node_modules/which": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", - "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", + "node_modules/@npmcli/run-script": { + "version": "10.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-10.0.4.tgz", + "integrity": "sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg==", "dev": true, "license": "ISC", "dependencies": { - "isexe": "^4.0.0" - }, - "bin": { - "node-which": "bin/which.js" + "@npmcli/node-gyp": "^5.0.0", + "@npmcli/package-json": "^7.0.0", + "@npmcli/promise-spawn": "^9.0.0", + "node-gyp": "^12.1.0", + "proc-log": "^6.0.0" }, "engines": { "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/@npmcli/installed-package-contents": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-4.0.0.tgz", - "integrity": "sha512-yNyAdkBxB72gtZ4GrwXCM0ZUedo9nIbOMKfGjt6Cu6DXf0p8y1PViZAKDC8q8kv/fufx0WTjRBdSlyrvnP7hmA==", + "node_modules/@nx/nx-darwin-arm64": { + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-18.3.5.tgz", + "integrity": "sha512-4I5UpZ/x2WO9OQyETXKjaYhXiZKUTYcLPewruRMODWu6lgTM9hHci0SqMQB+TWe3f80K8VT8J8x3+uJjvllGlg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-darwin-x64": { + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-18.3.5.tgz", + "integrity": "sha512-Drn6jOG237AD/s6OWPt06bsMj0coGKA5Ce1y5gfLhptOGk4S4UPE/Ay5YCjq+/yhTo1gDHzCHxH0uW2X9MN9Fg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-linux-arm64-gnu": { + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-arm64-gnu/-/nx-linux-arm64-gnu-18.3.5.tgz", + "integrity": "sha512-/Xd0Q3LBgJeigJqXC/Jck/9l5b+fK+FCM0nRFMXgPXrhZPhoxWouFkoYl2F1Ofr+AQf4jup4DkVTB5r98uxSCA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-linux-x64-gnu": { + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-18.3.5.tgz", + "integrity": "sha512-vYrikG6ff4I9cvr3Ysk3y3gjQ9cDcvr3iAr+4qqcQ4qVE+OLL2++JDS6xfPvG/TbS3GTQpyy2STRBwiHgxTeJw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@nx/nx-win32-x64-msvc": { + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-18.3.5.tgz", + "integrity": "sha512-xFwKVTIXSgjdfxkpriqHv5NpmmFILTrWLEkUGSoimuRaAm1u15YWx/VmaUQ+UWuJnmgqvB/so4SMHSfNkq3ijA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@oxc-project/types": { + "version": "0.113.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.113.0.tgz", + "integrity": "sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==", "dev": true, - "license": "ISC", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" + } + }, + "node_modules/@parcel/watcher": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", + "integrity": "sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, "dependencies": { - "npm-bundled": "^5.0.0", - "npm-normalize-package-bin": "^5.0.0" + "detect-libc": "^2.0.3", + "is-glob": "^4.0.3", + "node-addon-api": "^7.0.0", + "picomatch": "^4.0.3" }, - "bin": { - "installed-package-contents": "bin/index.js" + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" }, + "optionalDependencies": { + "@parcel/watcher-android-arm64": "2.5.6", + "@parcel/watcher-darwin-arm64": "2.5.6", + "@parcel/watcher-darwin-x64": "2.5.6", + "@parcel/watcher-freebsd-x64": "2.5.6", + "@parcel/watcher-linux-arm-glibc": "2.5.6", + "@parcel/watcher-linux-arm-musl": "2.5.6", + "@parcel/watcher-linux-arm64-glibc": "2.5.6", + "@parcel/watcher-linux-arm64-musl": "2.5.6", + "@parcel/watcher-linux-x64-glibc": "2.5.6", + "@parcel/watcher-linux-x64-musl": "2.5.6", + "@parcel/watcher-win32-arm64": "2.5.6", + "@parcel/watcher-win32-ia32": "2.5.6", + "@parcel/watcher-win32-x64": "2.5.6" + } + }, + "node_modules/@parcel/watcher-android-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-android-arm64/-/watcher-android-arm64-2.5.6.tgz", + "integrity": "sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@npmcli/installed-package-contents/node_modules/npm-normalize-package-bin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", - "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", + "node_modules/@parcel/watcher-darwin-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-arm64/-/watcher-darwin-arm64-2.5.6.tgz", + "integrity": "sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@npmcli/node-gyp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-5.0.0.tgz", - "integrity": "sha512-uuG5HZFXLfyFKqg8QypsmgLQW7smiRjVc45bqD/ofZZcR/uxEjgQU8qDPv0s9TEeMUiAAU/GC5bR6++UdTirIQ==", + "node_modules/@parcel/watcher-darwin-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-darwin-x64/-/watcher-darwin-x64-2.5.6.tgz", + "integrity": "sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@npmcli/package-json": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-7.0.5.tgz", - "integrity": "sha512-iVuTlG3ORq2iaVa1IWUxAO/jIp77tUKBhoMjuzYW2kL4MLN1bi/ofqkZ7D7OOwh8coAx1/S2ge0rMdGv8sLSOQ==", + "node_modules/@parcel/watcher-freebsd-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-freebsd-x64/-/watcher-freebsd-x64-2.5.6.tgz", + "integrity": "sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/git": "^7.0.0", - "glob": "^13.0.0", - "hosted-git-info": "^9.0.0", - "json-parse-even-better-errors": "^5.0.0", - "proc-log": "^6.0.0", - "semver": "^7.5.3", - "spdx-expression-parse": "^4.0.0" + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-glibc/-/watcher-linux-arm-glibc-2.5.6.tgz", + "integrity": "sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10.0.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@parcel/watcher-linux-arm-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm-musl/-/watcher-linux-arm-musl-2.5.6.tgz", + "integrity": "sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@npmcli/package-json/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "node_modules/@parcel/watcher-linux-arm64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-glibc/-/watcher-linux-arm64-glibc-2.5.6.tgz", + "integrity": "sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "18 || 20 || >=22" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@npmcli/package-json/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", + "node_modules/@parcel/watcher-linux-arm64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", + "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "cpu": [ + "arm64" + ], "dev": true, "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "18 || 20 || >=22" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@npmcli/package-json/node_modules/glob": { - "version": "13.0.6", - "resolved": "https://registry.npmjs.org/glob/-/glob-13.0.6.tgz", - "integrity": "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==", + "node_modules/@parcel/watcher-linux-x64-glibc": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-glibc/-/watcher-linux-x64-glibc-2.5.6.tgz", + "integrity": "sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "minimatch": "^10.2.2", - "minipass": "^7.1.3", - "path-scurry": "^2.0.2" - }, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "18 || 20 || >=22" + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@npmcli/package-json/node_modules/json-parse-even-better-errors": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-5.0.0.tgz", - "integrity": "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==", + "node_modules/@parcel/watcher-linux-x64-musl": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-x64-musl/-/watcher-linux-x64-musl-2.5.6.tgz", + "integrity": "sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==", + "cpu": [ + "x64" + ], "dev": true, "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@npmcli/package-json/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", + "node_modules/@parcel/watcher-win32-arm64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-arm64/-/watcher-win32-arm64-2.5.6.tgz", + "integrity": "sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.5" - }, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "18 || 20 || >=22" + "node": ">= 10.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@npmcli/package-json/node_modules/spdx-expression-parse": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", - "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", + "node_modules/@parcel/watcher-win32-ia32": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-ia32/-/watcher-win32-ia32-2.5.6.tgz", + "integrity": "sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==", + "cpu": [ + "ia32" + ], "dev": true, "license": "MIT", - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@npmcli/promise-spawn": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-9.0.1.tgz", - "integrity": "sha512-OLUaoqBuyxeTqUvjA3FZFiXUfYC1alp3Sa99gW3EUDz3tZ3CbXDdcZ7qWKBzicrJleIgucoWamWH1saAmH/l2Q==", + "node_modules/@parcel/watcher-win32-x64": { + "version": "2.5.6", + "resolved": "https://registry.npmjs.org/@parcel/watcher-win32-x64/-/watcher-win32-x64-2.5.6.tgz", + "integrity": "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "which": "^6.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">= 10.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/@npmcli/promise-spawn/node_modules/isexe": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", - "integrity": "sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==", + "node_modules/@parcel/watcher/node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "dev": true, - "license": "BlueOak-1.0.0", + "license": "MIT", + "optional": true + }, + "node_modules/@pkgr/core": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", + "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=20" + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/pkgr" } }, - "node_modules/@npmcli/promise-spawn/node_modules/which": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", - "integrity": "sha512-oGLe46MIrCRqX7ytPUf66EAYvdeMIZYn3WaocqqKZAxrBpkqHfL/qvTyJ/bTk5+AqHCjXmrv3CEWgy368zhRUg==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-vRq9f4NzvbdZavhQbjkJBx7rRebDKYR9zHfO/Wg486+I7bSecdUapzCm5cyXoK+LHokTxgSq7A5baAXUZkIz0w==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^4.0.0" - }, - "bin": { - "node-which": "bin/which.js" - }, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@npmcli/redact": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@npmcli/redact/-/redact-4.0.0.tgz", - "integrity": "sha512-gOBg5YHMfZy+TfHArfVogwgfBeQnKbbGo3pSUyK/gSI0AVu+pEiDVcKlQb0D8Mg1LNRZILZ6XG8I5dJ4KuAd9Q==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-kFgEvkWLqt3YCgKB5re9RlIrx9bRsvyVUnaTakEpOPuLGzLpLapYxE9BufJNvPg8GjT6mB1alN4yN1NjzoeM8Q==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@npmcli/run-script": { - "version": "10.0.4", - "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-10.0.4.tgz", - "integrity": "sha512-mGUWr1uMnf0le2TwfOZY4SFxZGXGfm4Jtay/nwAa2FLNAKXUoUwaGwBMNH36UHPtinWfTSJ3nqFQr0091CxVGg==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.4.tgz", + "integrity": "sha512-JXmaOJGsL/+rsmMfutcDjxWM2fTaVgCHGoXS7nE8Z3c9NAYjGqHvXrAhMUZvMpHS/k7Mg+X7n/MVKb7NYWKKww==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", - "dependencies": { - "@npmcli/node-gyp": "^5.0.0", - "@npmcli/package-json": "^7.0.0", - "@npmcli/promise-spawn": "^9.0.0", - "node-gyp": "^12.1.0", - "proc-log": "^6.0.0" - }, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@nx/nx-darwin-arm64": { - "version": "18.3.5", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-arm64/-/nx-darwin-arm64-18.3.5.tgz", - "integrity": "sha512-4I5UpZ/x2WO9OQyETXKjaYhXiZKUTYcLPewruRMODWu6lgTM9hHci0SqMQB+TWe3f80K8VT8J8x3+uJjvllGlg==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.4.tgz", + "integrity": "sha512-ep3Catd6sPnHTM0P4hNEvIv5arnDvk01PfyJIJ+J3wVCG1eEaPo09tvFqdtcaTrkwQy0VWR24uz+cb4IsK53Qw==", "cpu": [ - "arm64" + "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" + "freebsd" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@nx/nx-darwin-x64": { - "version": "18.3.5", - "resolved": "https://registry.npmjs.org/@nx/nx-darwin-x64/-/nx-darwin-x64-18.3.5.tgz", - "integrity": "sha512-Drn6jOG237AD/s6OWPt06bsMj0coGKA5Ce1y5gfLhptOGk4S4UPE/Ay5YCjq+/yhTo1gDHzCHxH0uW2X9MN9Fg==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.4.tgz", + "integrity": "sha512-LwA5ayKIpnsgXJEwWc3h8wPiS33NMIHd9BhsV92T8VetVAbGe2qXlJwNVDGHN5cOQ22R9uYvbrQir2AB+ntT2w==", "cpu": [ - "x64" + "arm" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" + "linux" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@nx/nx-linux-arm64-gnu": { - "version": "18.3.5", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.4.tgz", + "integrity": "sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@nx/nx-linux-x64-gnu": { - "version": "18.3.5", - "resolved": "https://registry.npmjs.org/@nx/nx-linux-x64-gnu/-/nx-linux-x64-gnu-18.3.5.tgz", - "integrity": "sha512-vYrikG6ff4I9cvr3Ysk3y3gjQ9cDcvr3iAr+4qqcQ4qVE+OLL2++JDS6xfPvG/TbS3GTQpyy2STRBwiHgxTeJw==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.4.tgz", + "integrity": "sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==", "cpu": [ - "x64" + "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 10" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@nx/nx-win32-x64-msvc": { - "version": "18.3.5", - "resolved": "https://registry.npmjs.org/@nx/nx-win32-x64-msvc/-/nx-win32-x64-msvc-18.3.5.tgz", - "integrity": "sha512-xFwKVTIXSgjdfxkpriqHv5NpmmFILTrWLEkUGSoimuRaAm1u15YWx/VmaUQ+UWuJnmgqvB/so4SMHSfNkq3ijA==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.4.tgz", + "integrity": "sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": ">= 10" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.113.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.113.0.tgz", - "integrity": "sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, - "node_modules/@parcel/watcher": { - "version": "2.5.6", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "optional": true, - "dependencies": { - "detect-libc": "^2.0.3", - "is-glob": "^4.0.3", - "node-addon-api": "^7.0.0", - "picomatch": "^4.0.3" - }, - "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - }, - "optionalDependencies": { - "@parcel/watcher-android-arm64": "2.5.6", - "@parcel/watcher-darwin-arm64": "2.5.6", - "@parcel/watcher-darwin-x64": "2.5.6", - "@parcel/watcher-freebsd-x64": "2.5.6", - "@parcel/watcher-linux-arm-glibc": "2.5.6", - "@parcel/watcher-linux-arm-musl": "2.5.6", - "@parcel/watcher-linux-arm64-glibc": "2.5.6", - "@parcel/watcher-linux-arm64-musl": "2.5.6", - "@parcel/watcher-linux-x64-glibc": "2.5.6", - "@parcel/watcher-linux-x64-musl": "2.5.6", - "@parcel/watcher-win32-arm64": "2.5.6", - "@parcel/watcher-win32-ia32": "2.5.6", - "@parcel/watcher-win32-x64": "2.5.6" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@parcel/watcher-linux-arm64-glibc": { - "version": "2.5.6", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.4.tgz", + "integrity": "sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", @@ -3520,17 +4647,13 @@ "linux" ], "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@parcel/watcher-linux-arm64-musl": { - "version": "2.5.6", - "resolved": "https://registry.npmjs.org/@parcel/watcher-linux-arm64-musl/-/watcher-linux-arm64-musl-2.5.6.tgz", - "integrity": "sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.4.tgz", + "integrity": "sha512-6lcI79+X8klGiGd8yHuTgQRjuuJYNggmEml+RsyN596P23l/zf9FVmJ7K0KVKkFAeYEdg0iMUKyIxiV5vebDNQ==", "cpu": [ "arm64" ], @@ -3538,39 +4661,33 @@ "license": "MIT", "optional": true, "os": [ - "linux" + "openharmony" ], "engines": { - "node": ">= 10.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@parcel/watcher/node_modules/node-addon-api": { - "version": "7.1.1", - "dev": true, - "license": "MIT", - "optional": true - }, - "node_modules/@pkgr/core": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.3.6.tgz", - "integrity": "sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==", + "node_modules/@rolldown/binding-wasm32-wasi": { + "version": "1.0.0-rc.4", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.4.tgz", + "integrity": "sha512-wz7ohsKCAIWy91blZ/1FlpPdqrsm1xpcEOQVveWoL6+aSPKL4VUcoYmmzuLTssyZxRpEwzuIxL/GDsvpjaBtOw==", + "cpu": [ + "wasm32" + ], "dev": true, "license": "MIT", - "engines": { - "node": "^14.18.0 || >=16.0.0" + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" }, - "funding": { - "url": "https://opencollective.com/pkgr" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { + "node_modules/@rolldown/binding-win32-arm64-msvc": { "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.4.tgz", - "integrity": "sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.4.tgz", + "integrity": "sha512-cfiMrfuWCIgsFmcVG0IPuO6qTRHvF7NuG3wngX1RZzc6dU8FuBFb+J3MIR5WrdTNozlumfgL4cvz+R4ozBCvsQ==", "cpu": [ "arm64" ], @@ -3578,24 +4695,24 @@ "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ], "engines": { "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@rolldown/binding-linux-arm64-musl": { + "node_modules/@rolldown/binding-win32-x64-msvc": { "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.4.tgz", - "integrity": "sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.4.tgz", + "integrity": "sha512-p6UeR9y7ht82AH57qwGuFYn69S6CZ7LLKdCKy/8T3zS9VTrJei2/CGsTUV45Da4Z9Rbhc7G4gyWQ/Ioamqn09g==", "cpu": [ - "arm64" + "x64" ], "dev": true, "license": "MIT", "optional": true, "os": [ - "linux" + "win32" ], "engines": { "node": "^20.19.0 || >=22.12.0" @@ -3609,9 +4726,9 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz", - "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.1.tgz", + "integrity": "sha512-JnBB8MdXj45cajvTuO5FmPlvFVJRQgvrz1uSEl3NwqFnReAPGwb8EanbGi4z2nRaqLzjJSv5/JmycoTKlRZxHA==", "cpu": [ "arm" ], @@ -3623,9 +4740,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz", - "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.61.1.tgz", + "integrity": "sha512-Jx2g7iSjw4AOT0HDPHM9RV3GNjRXwybWtSFZiZAYUTjUwjVrYIwq3kBf+LnhqJlzXFAqTAh2F7IGI+O568exPw==", "cpu": [ "arm64" ], @@ -3637,9 +4754,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz", - "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.61.1.tgz", + "integrity": "sha512-0F1L/Z3Eqv8mT2n3dCpeO8GcTvHvVqkP5/t6DMsn0KzhYVcg+s7Ncl5DS8qjKYEeio6Az0Gt6nyBORay5qIlCA==", "cpu": [ "arm64" ], @@ -3651,9 +4768,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz", - "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.61.1.tgz", + "integrity": "sha512-qLttcH871ujY4YcVfUSShhOw+CsoTatYz8gRbHO7Bb92QH059/P0y5do1KMs41fY0BpD2x4AJH/gID0zFiqVKQ==", "cpu": [ "x64" ], @@ -3665,9 +4782,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz", - "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.61.1.tgz", + "integrity": "sha512-fUI4RapGE0Oh3mb8mgfvC1O2nU1RpDZUKnDQm3xB1Ipg7C2wTs5Kstz7G2uWK99a8S2yTMq8/P4uycwNa0nJyw==", "cpu": [ "arm64" ], @@ -3679,9 +4796,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz", - "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.61.1.tgz", + "integrity": "sha512-H5YrdvJaDtI/U9/emrD4b++xkvp3y/JvOe4rizHbxvkyMfRS/CiRYdji+Pl8D0brEaNFWUh1drQxgAGIl6Xudw==", "cpu": [ "x64" ], @@ -3693,9 +4810,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz", - "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.61.1.tgz", + "integrity": "sha512-Q8CBCCQtDFrYtXoeUXSrnFXKOnyUhx6bz+SkL6A0E7V8kAiCJ5pamq1WtbfpVGhR5TSpXY6ak3avmDc5fHTyJA==", "cpu": [ "arm" ], @@ -3707,9 +4824,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz", - "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.61.1.tgz", + "integrity": "sha512-nwnhk1581l0FBVellGcVCAT0Oi06onEA3WB53sf01VO3I0UPBkMH9sXONYME2K0ovXcNayJfNtHfm6mpJElatQ==", "cpu": [ "arm" ], @@ -3721,9 +4838,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz", - "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.61.1.tgz", + "integrity": "sha512-x5Xr49hwt3hdW75UOZm3395YwwzPyauktslv29KpWL/T+vVAzoT3azLcTWv0eMciBNrx+DYjH4paehHoLpPvpg==", "cpu": [ "arm64" ], @@ -3734,9 +4851,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz", - "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.61.1.tgz", + "integrity": "sha512-unMS3H73DpaoPyyEVPjGKleM/s0mkmsauTENpw4INQY8y4+IuLNjkueQ5QCtC0D3N38Y38yhAU8OoZ20S2Tm6w==", "cpu": [ "arm64" ], @@ -3748,9 +4865,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz", - "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.61.1.tgz", + "integrity": "sha512-zNZzGRnAhwjFEYmvphJRV5XaQGjs62cCmeYYHUT//NbvEnHauw+I85nGG+SiVg5ld4GX8D1IbKIX+ozITQnhMQ==", "cpu": [ "loong64" ], @@ -3762,9 +4879,9 @@ ] }, "node_modules/@rollup/rollup-linux-loong64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz", - "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.61.1.tgz", + "integrity": "sha512-LdpWGL8X209B2SIvWjqlc8VZgM6PKfontSerGepuldQmHYrAOtnMCXeJkxXGbC+PPZVOuu5czJo7fNV6aeW8rQ==", "cpu": [ "loong64" ], @@ -3776,9 +4893,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz", - "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.61.1.tgz", + "integrity": "sha512-EC5kTtNaNGOmbMGqar8dvJy6y/hg99GAwjfBz++pxZhQATXGcRjd6c5en5wcbru0vkRmiMGsQKdMJOOf6sza4g==", "cpu": [ "ppc64" ], @@ -3790,9 +4907,9 @@ ] }, "node_modules/@rollup/rollup-linux-ppc64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz", - "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.61.1.tgz", + "integrity": "sha512-8hiwp6D4acEcNK78I4rP0/XtS1sknWIAMJBPdR4l6zUtyTm5KiTDr5bXmWt4foY7nAN7AThDHgkLIEZOWKbzWw==", "cpu": [ "ppc64" ], @@ -3804,9 +4921,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz", - "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.61.1.tgz", + "integrity": "sha512-10dh/h/BqA7DuMPWSxkR8uks18FRwnwOEqr5zOTEl+NOwP/OMzKX8OFR/Of9xxDA7D5qef1Nzar5WDD2kCCr1g==", "cpu": [ "riscv64" ], @@ -3818,9 +4935,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz", - "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.61.1.tgz", + "integrity": "sha512-YKJ5lg35DP17gcAOggnihe+APw9HLyj1Xn7gsmGumBJAUDa6NGXNixJzmkWLhcK9TOuuyQjdamzvJefkO7qHZQ==", "cpu": [ "riscv64" ], @@ -3832,9 +4949,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz", - "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.61.1.tgz", + "integrity": "sha512-Mlil5G2Jj6a7B3LWGctg+XPL9vdXYuzCtNXfxOQ0nPjc2m6ueUktocPGH9bnAM0bNRKb/bAWTujUU7IJQdQA+g==", "cpu": [ "s390x" ], @@ -3859,9 +4976,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz", - "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.61.1.tgz", + "integrity": "sha512-qy5pBvZbqNFheBz61R1rzsezjm0J7O2oNGoWtGoY89SZYLUfxAJTBAqDChqAIdB4rCiIbi9nF7yZ83GnNiLwSw==", "cpu": [ "x64" ], @@ -3873,9 +4990,9 @@ ] }, "node_modules/@rollup/rollup-openbsd-x64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz", - "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.61.1.tgz", + "integrity": "sha512-E83TXjI4zm0+5f2qO+UOudaCYIhYwpJ5jq6YCZNIZ+6CbfhKrkAGezeiASBL9ElxAxFsRS9ZhESv8mfnj6TKeg==", "cpu": [ "x64" ], @@ -3887,9 +5004,9 @@ ] }, "node_modules/@rollup/rollup-openharmony-arm64": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz", - "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.61.1.tgz", + "integrity": "sha512-fbWnKqVkjrJN38vNe3ahkbk6iejS/3b0Nt7EEtPpE6RBacZcGXNKbzfHN3GUUlXOPghUg0j6XUGrtjX9z1sIvA==", "cpu": [ "arm64" ], @@ -3901,9 +5018,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz", - "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.61.1.tgz", + "integrity": "sha512-ArMl38iVAbk0New1ogihQNY6iphLi4ZaRsa037gUzv5yeKPY8TD3Dmy4x2RNC1VztU/uqm+G+/RwFrSka3Oy2g==", "cpu": [ "arm64" ], @@ -3915,9 +5032,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz", - "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.61.1.tgz", + "integrity": "sha512-0mYtjHS9ucAbcATycCNK9IGBk/cCe/ma7EmSLGZdsxnOA8cjRIyU04wDpVAD9NiOfLUR9KTxdiO53uOkherqjQ==", "cpu": [ "ia32" ], @@ -3929,9 +5046,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz", - "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.61.1.tgz", + "integrity": "sha512-gK1iCEPfpoSG9wfBihXxvBMi8ZfcWffYkEsC/Eih+iFENTaewvNcrEQ69lIOWYO5pePHKLHHO7nq5AILGO/HQQ==", "cpu": [ "x64" ], @@ -3943,9 +5060,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz", - "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.1.tgz", + "integrity": "sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==", "cpu": [ "x64" ], @@ -3958,18 +5075,20 @@ }, "node_modules/@scarf/scarf": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", + "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", "hasInstallScript": true, "license": "Apache-2.0" }, "node_modules/@schematics/angular": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.9.tgz", - "integrity": "sha512-1renEbBZz9Yw3A0GUOJ6x6E1jd2Vu/fX5tEGiFNbIoWaNwa71SlFTvKKqaYxiYQkrpc7oexVJ2ymuvOfgTbI1w==", + "version": "21.2.14", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.14.tgz", + "integrity": "sha512-rIEdtNTdCCTwuo7B4tMoq5qmbLXdBgmW6Ays1hyno//4OE+HFtvlWZd+hl6KceEyN00IcZ2HRaPnfd71E1JnoA==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.9", - "@angular-devkit/schematics": "21.2.9", + "@angular-devkit/core": "21.2.14", + "@angular-devkit/schematics": "21.2.14", "jsonc-parser": "3.3.1" }, "engines": { @@ -3978,68 +5097,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@schematics/angular/node_modules/@angular-devkit/core": { - "version": "21.2.9", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.9.tgz", - "integrity": "sha512-04rdOGEzjLWFHlyAwqtuikginFeQ2jfXS5HqqKNP0VtG6Uu9NUDAEW5UDvXgqkEMfCDwGZbmg2iRHxp3AmAKVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.18.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.4", - "rxjs": "7.8.2", - "source-map": "0.7.6" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^5.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@schematics/angular/node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/@schematics/angular/node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/@sigstore/bundle": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz", @@ -4054,9 +5111,9 @@ } }, "node_modules/@sigstore/core": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.2.0.tgz", - "integrity": "sha512-kxHrDQ9YgfrWUSXU0cjsQGv8JykOFZQ9ErNKbFPWzk3Hgpwu8x2hHrQ9IdA8yl+j9RTLTC3sAF3Tdq1IQCP4oA==", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-3.2.1.tgz", + "integrity": "sha512-qRsxPnCrbC/puegGxKuynfnxgLiHqWStrSjxkoB4YKqq3Z3s4cyZyj42ZdWFAEblNP65C+rBH8EuREHIXoi83g==", "dev": true, "license": "Apache-2.0", "engines": { @@ -4106,14 +5163,14 @@ } }, "node_modules/@sigstore/verify": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-3.1.0.tgz", - "integrity": "sha512-mNe0Iigql08YupSOGv197YdHpPPr+EzDZmfCgMc7RPNaZTw5aLN01nBl6CHJOh3BGtnMIj83EeN4butBchc8Ag==", + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-3.1.1.tgz", + "integrity": "sha512-qv7+G3J2cc6wwFj3yKvXOamzqhMwSk1ogPGmhpS8iXllcPrJaIIBA+4HbttlHVu1pqWTdmaCH/WE7UOC51kdoA==", "dev": true, "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.1.0", + "@sigstore/core": "^3.2.1", "@sigstore/protobuf-specs": "^0.5.0" }, "engines": { @@ -4151,6 +5208,8 @@ }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "dev": true, "license": "MIT" }, @@ -4193,15 +5252,6 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, - "node_modules/@swimlane/ngx-charts/node_modules/d3-time-format": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", - "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-time": "1 - 2" - } - }, "node_modules/@trivago/prettier-plugin-sort-imports": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-6.0.2.tgz", @@ -4245,21 +5295,29 @@ }, "node_modules/@tsconfig/node10": { "version": "1.0.12", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.12.tgz", + "integrity": "sha512-UCYBaeFvM11aU2y3YPZ//O5Rhj+xKyzy7mvcIoAjASbigy8mHMryP5cK7dgjlz2hWxh1g5pLw084E0a/wlUSFQ==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node12": { "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node14": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", "dev": true, "license": "MIT" }, "node_modules/@tsconfig/node16": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", "dev": true, "license": "MIT" }, @@ -4326,8 +5384,21 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@tybys/wasm-util": { + "version": "0.10.2", + "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", + "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@types/angular": { "version": "1.5.11", + "resolved": "https://registry.npmjs.org/@types/angular/-/angular-1.5.11.tgz", + "integrity": "sha512-Nth2ys1RPMZfOQIs8yveTGBa/5dJ4PhSznm87dinYtQBKFzg7CBO4YqNWGuPibSkQ/uBbcYlnbBFHH7EdeMI3Q==", "dev": true, "license": "MIT", "dependencies": { @@ -4336,11 +5407,15 @@ }, "node_modules/@types/canvas-confetti": { "version": "1.9.0", + "resolved": "https://registry.npmjs.org/@types/canvas-confetti/-/canvas-confetti-1.9.0.tgz", + "integrity": "sha512-aBGj/dULrimR1XDZLtG9JwxX1b4HPRF6CX9Yfwh3NvstZEm1ZL7RBnel4keCPSqs1ANRu1u2Aoz9R+VmtjYuTg==", "dev": true, "license": "MIT" }, "node_modules/@types/cors": { "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", "dev": true, "license": "MIT", "dependencies": { @@ -4349,6 +5424,8 @@ }, "node_modules/@types/d3": { "version": "3.5.53", + "resolved": "https://registry.npmjs.org/@types/d3/-/d3-3.5.53.tgz", + "integrity": "sha512-8yKQA9cAS6+wGsJpBysmnhlaaxlN42Qizqkw+h2nILSlS+MAG2z4JdO6p+PJrJ+ACvimkmLJL281h157e52psQ==", "dev": true, "license": "MIT" }, @@ -4360,13 +5437,15 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", - "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", "license": "MIT" }, "node_modules/@types/file-saver": { "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/file-saver/-/file-saver-2.0.7.tgz", + "integrity": "sha512-dNKVfHd/jk0SkR/exKGj2ggkB45MAkzvWCaqLUUgkyjITkGNzH8H+yUwr+BLJUBjZOe9w8X3wgmXhZDRg1ED6A==", "dev": true, "license": "MIT" }, @@ -4379,6 +5458,8 @@ }, "node_modules/@types/jasminewd2": { "version": "2.0.13", + "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.13.tgz", + "integrity": "sha512-aJ3wj8tXMpBrzQ5ghIaqMisD8C3FIrcO6sDKHqFbuqAsI7yOxj0fA7MrRCPLZHIVUjERIwsMmGn/vB0UQ9u0Hg==", "dev": true, "license": "MIT", "dependencies": { @@ -4387,6 +5468,8 @@ }, "node_modules/@types/jquery": { "version": "1.10.45", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-1.10.45.tgz", + "integrity": "sha512-JvoVtPbu1wrcOldn5gvuyJqr7DLX6I657N68Fqj5S7AUutdYZqabQjfP7dY6Gee7/Afo1uajwcORVlQfnsjkLQ==", "dev": true, "license": "MIT" }, @@ -4397,12 +5480,16 @@ "license": "MIT" }, "node_modules/@types/lodash": { - "version": "4.17.23", + "version": "4.17.24", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.24.tgz", + "integrity": "sha512-gIW7lQLZbue7lRSWEFql49QJJWThrTFFeIMJdp3eH4tKoxm1OvEPg02rm4wCCSHS0cL3/Fizimb35b7k8atwsQ==", "dev": true, "license": "MIT" }, "node_modules/@types/node": { - "version": "20.19.33", + "version": "20.19.42", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.19.42.tgz", + "integrity": "sha512-5L7SUaFC1RyDraj2yRhyBzHTobyXHmohD100CChNtyPyleoq37Mqab5Gn8XEKI04dfN/oqPdpHk38MgcQWHbZg==", "dev": true, "license": "MIT", "dependencies": { @@ -4411,11 +5498,15 @@ }, "node_modules/@types/q": { "version": "0.0.32", + "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", + "integrity": "sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==", "dev": true, "license": "MIT" }, "node_modules/@types/selenium-webdriver": { "version": "3.0.26", + "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz", + "integrity": "sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==", "dev": true, "license": "MIT" }, @@ -4437,17 +5528,16 @@ } }, "node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.60.1.tgz", - "integrity": "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg==", - "dev": true, + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.61.0.tgz", + "integrity": "sha512-bFNvl9ZczlVb+wR2Akszf3gHfKVj/8WanXaGJ3UstTA7brNKg0cNdk6X1Psu5V7MZ2oQtzZKOEzIUehaoxbDGw==", "license": "MIT", "dependencies": { "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/type-utils": "8.60.1", - "@typescript-eslint/utils": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", + "@typescript-eslint/scope-manager": "8.61.0", + "@typescript-eslint/type-utils": "8.61.0", + "@typescript-eslint/utils": "8.61.0", + "@typescript-eslint/visitor-keys": "8.61.0", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" @@ -4460,32 +5550,21 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "@typescript-eslint/parser": "^8.60.1", + "@typescript-eslint/parser": "^8.61.0", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/@typescript-eslint/parser": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.60.1.tgz", - "integrity": "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA==", - "dev": true, + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.61.0.tgz", + "integrity": "sha512-5B7PfA2e1NQGCnDHd/0lW7W3gvp3d59Ryw54FYO8Uswxo9f6ikw3AZV+Xj/TvpImmpsiYyUqAfhC6kJID1jF6w==", "license": "MIT", "dependencies": { - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", + "@typescript-eslint/scope-manager": "8.61.0", + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/typescript-estree": "8.61.0", + "@typescript-eslint/visitor-keys": "8.61.0", "debug": "^4.4.3" }, "engines": { @@ -4501,13 +5580,13 @@ } }, "node_modules/@typescript-eslint/project-service": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.57.0.tgz", - "integrity": "sha512-pR+dK0BlxCLxtWfaKQWtYr7MhKmzqZxuii+ZjuFlZlIGRZm22HnXFqa2eY+90MUz8/i80YJmzFGDUsi8dMOV5w==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.61.0.tgz", + "integrity": "sha512-DV42F7MLJO6Rax7SK1yg43tcnEfGUrurSpSxKuVX+a3RCTzBlH3fuxprrOJXKCJGAaw82xXocikJ0uQaqwXgGA==", "license": "MIT", "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.57.0", - "@typescript-eslint/types": "^8.57.0", + "@typescript-eslint/tsconfig-utils": "^8.61.0", + "@typescript-eslint/types": "^8.61.0", "debug": "^4.4.3" }, "engines": { @@ -4518,18 +5597,17 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/scope-manager": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.60.1.tgz", - "integrity": "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w==", - "dev": true, + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.61.0.tgz", + "integrity": "sha512-IWdXFHFSb6mlC3HPc7QsLDm5zYEbUla6trDEHf32D3/dnuUyXd87plScSNXSbm0/RxMvObpI17sv/EDTGrGZkA==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1" + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/visitor-keys": "8.61.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4540,9 +5618,9 @@ } }, "node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.57.0.tgz", - "integrity": "sha512-LtXRihc5ytjJIQEH+xqjB0+YgsV4/tW35XKX3GTZHpWtcC8SPkT/d4tqdf1cKtesryHm2bgp6l555NYcT2NLvA==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.61.0.tgz", + "integrity": "sha512-O5Amvdv9ztMpxpf+vmFULGG78IE6Qwdr3bCGvqwG4nwc9H2qXkOYJJnRbRHyMkQTjv1d03olqwwwzHLMqpFePQ==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4552,19 +5630,18 @@ "url": "https://opencollective.com/typescript-eslint" }, "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/@typescript-eslint/type-utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.60.1.tgz", - "integrity": "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A==", - "dev": true, + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.61.0.tgz", + "integrity": "sha512-TuBiQYIkd97yBfInHCTKVYMbX4kvEmpOEuixIuzCU9p8BGT1SfyyO0d0IfDMbPIHcjn/hWnusUX5e8v5Xg+X8A==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1", - "@typescript-eslint/utils": "8.60.1", + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/typescript-estree": "8.61.0", + "@typescript-eslint/utils": "8.61.0", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, @@ -4581,9 +5658,9 @@ } }, "node_modules/@typescript-eslint/types": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.60.1.tgz", - "integrity": "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w==", + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.61.0.tgz", + "integrity": "sha512-9QTQpZ5Iin4CdIodfbDQFSeiSJKidgYJYug1P9CC2xWgUTvlmixViqDZNciMjwLBZyJnG4tGmPl97rVAFb1AJg==", "license": "MIT", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4594,16 +5671,15 @@ } }, "node_modules/@typescript-eslint/typescript-estree": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.60.1.tgz", - "integrity": "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew==", - "dev": true, + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.61.0.tgz", + "integrity": "sha512-42zatd5qSvvcV1JdDBCLxYRznvP4eIHpPoZXdkPFnAmanA4FuZ5dibSnCBggY8hQnqajPpoGjXFdZ7fIJKQnlA==", "license": "MIT", "dependencies": { - "@typescript-eslint/project-service": "8.60.1", - "@typescript-eslint/tsconfig-utils": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/visitor-keys": "8.60.1", + "@typescript-eslint/project-service": "8.61.0", + "@typescript-eslint/tsconfig-utils": "8.61.0", + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/visitor-keys": "8.61.0", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", @@ -4621,50 +5697,10 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/project-service": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/project-service/-/project-service-8.60.1.tgz", - "integrity": "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/tsconfig-utils": "^8.60.1", - "@typescript-eslint/types": "^8.60.1", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/@typescript-eslint/tsconfig-utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.60.1.tgz", - "integrity": "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.1.0" - } - }, "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, "license": "MIT", "engines": { "node": "18 || 20 || >=22" @@ -4674,7 +5710,6 @@ "version": "5.0.6", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "dev": true, "license": "MIT", "dependencies": { "balanced-match": "^4.0.2" @@ -4687,7 +5722,6 @@ "version": "10.2.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "dev": true, "license": "BlueOak-1.0.0", "dependencies": { "brace-expansion": "^5.0.5" @@ -4700,16 +5734,15 @@ } }, "node_modules/@typescript-eslint/utils": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.60.1.tgz", - "integrity": "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg==", - "dev": true, + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.61.0.tgz", + "integrity": "sha512-3bzFt7ImFMW/jVYwJamDoe/dMOdFLSC6pom6rRjdh4SZJEYupyMzem8e7vKZLclLfpHjlwSAXOUxtKxGXUiLqA==", "license": "MIT", "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.60.1", - "@typescript-eslint/types": "8.60.1", - "@typescript-eslint/typescript-estree": "8.60.1" + "@typescript-eslint/scope-manager": "8.61.0", + "@typescript-eslint/types": "8.61.0", + "@typescript-eslint/typescript-estree": "8.61.0" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -4724,13 +5757,12 @@ } }, "node_modules/@typescript-eslint/visitor-keys": { - "version": "8.60.1", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.60.1.tgz", - "integrity": "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag==", - "dev": true, + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.61.0.tgz", + "integrity": "sha512-QVLZu3ZPQEE+HICQyAMZ2yLQhxf0meY/wx6Hx14YcTNj13JB3qHlX3lJ02L3fLGHgERRH71kvYDwiXIguT3AjQ==", "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.60.1", + "@typescript-eslint/types": "8.61.0", "eslint-visitor-keys": "^5.0.0" }, "engines": { @@ -4745,7 +5777,6 @@ "version": "5.0.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", - "dev": true, "license": "Apache-2.0", "engines": { "node": "^20.19.0 || ^22.13.0 || >=24" @@ -4769,6 +5800,8 @@ }, "node_modules/@worktile/gantt": { "version": "18.0.5", + "resolved": "https://registry.npmjs.org/@worktile/gantt/-/gantt-18.0.5.tgz", + "integrity": "sha512-LCcWaFBmeg5u9cVDEmREHdR+qJJHE3Ld4VxdoJpTXfhDkx2f19tp0wMR9MkwOLRwwTCx/5gGJ1kTbz4P0Zfc1Q==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -4788,22 +5821,26 @@ "dev": true, "license": "BSD-2-Clause" }, - "node_modules/accepts": { - "version": "1.3.8", + "node_modules/abbrev": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz", + "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==", "dev": true, - "license": "MIT", - "dependencies": { - "mime-types": "~2.1.34", - "negotiator": "0.6.3" - }, + "license": "ISC", "engines": { - "node": ">= 0.6" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/accepts/node_modules/negotiator": { - "version": "0.6.3", + "node_modules/accepts": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", + "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", "dev": true, "license": "MIT", + "dependencies": { + "mime-types": "^3.0.0", + "negotiator": "^1.0.0" + }, "engines": { "node": ">= 0.6" } @@ -4830,7 +5867,9 @@ } }, "node_modules/acorn-walk": { - "version": "8.3.4", + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", "dev": true, "license": "MIT", "dependencies": { @@ -4841,7 +5880,9 @@ } }, "node_modules/adm-zip": { - "version": "0.5.16", + "version": "0.5.17", + "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.17.tgz", + "integrity": "sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ==", "dev": true, "license": "MIT", "engines": { @@ -4928,6 +5969,8 @@ }, "node_modules/angular-calendar": { "version": "0.31.1", + "resolved": "https://registry.npmjs.org/angular-calendar/-/angular-calendar-0.31.1.tgz", + "integrity": "sha512-pjSIpoAaUzS/gx+14eOr4hPZhlQ8HxpiZypCSGqJNptq5PD+vOdVQ3h/Aaqnk86GraVcAQPXqfu64MtdKwTVNw==", "license": "MIT", "dependencies": { "@scarf/scarf": "^1.1.1", @@ -4988,70 +6031,10 @@ "typescript-eslint": "^8.0.0" } }, - "node_modules/angular-eslint/node_modules/@angular-devkit/core": { - "version": "21.2.14", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.14.tgz", - "integrity": "sha512-RSOWXB9bFc2nwRWMxbIT0RbSNFUrwfBo4N5MNxbyQ69Ndc0gVm3h+3ArHv0qotH4d+pJYbm5ttXu8YqR2kc0CA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.18.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.4", - "rxjs": "7.8.2", - "source-map": "0.7.6" - }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^5.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/angular-eslint/node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "readdirp": "^5.0.0" - }, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/angular-eslint/node_modules/readdirp": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", - "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "engines": { - "node": ">= 20.19.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/angular-markdown-filter": { "version": "1.3.2", + "resolved": "https://registry.npmjs.org/angular-markdown-filter/-/angular-markdown-filter-1.3.2.tgz", + "integrity": "sha512-2dr3IB/d9dyLTH36nE61Qkxm078sOpHvpd4Q863eXEgrwsre8YySxWsgaq1qooY3P7C7wQ1LhFGvh5rAA25wnA==", "license": "MIT", "dependencies": { "showdown": "^1.2.3" @@ -5070,6 +6053,8 @@ }, "node_modules/angular-nvd3": { "version": "1.0.9", + "resolved": "https://registry.npmjs.org/angular-nvd3/-/angular-nvd3-1.0.9.tgz", + "integrity": "sha512-FcGYVXeNejlDj+Yr6g3ydRT+kuLAzKY/KMuc4eiLJbSvRcSqfLJtrFZi6wFXGhW3OlbLHvCjAeFzDvTac3gNTQ==", "license": "MIT", "dependencies": { "angular": "^1.x", @@ -5106,23 +6091,28 @@ } }, "node_modules/ansi-regex": { - "version": "5.0.1", + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, "node_modules/ansi-styles": { - "version": "4.3.0", + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", "license": "MIT", "dependencies": { - "color-convert": "^2.0.1" + "color-convert": "^1.9.0" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=4" } }, "node_modules/any-promise": { @@ -5134,6 +6124,8 @@ }, "node_modules/anymatch": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "license": "ISC", "dependencies": { @@ -5157,6 +6149,43 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/aproba": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-2.1.0.tgz", + "integrity": "sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==", + "license": "ISC", + "optional": true + }, + "node_modules/are-we-there-yet": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", + "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "delegates": "^1.0.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/are-we-there-yet/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "license": "MIT", + "optional": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/arg": { "version": "5.0.2", "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", @@ -5187,8 +6216,33 @@ "dev": true, "license": "MIT" }, + "node_modules/array-union": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", + "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-uniq": "^1.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/array-uniq": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", + "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", "dev": true, "license": "MIT", "engines": { @@ -5197,6 +6251,8 @@ }, "node_modules/asn1": { "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5205,6 +6261,8 @@ }, "node_modules/assert-plus": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", "dev": true, "license": "MIT", "engines": { @@ -5213,11 +6271,15 @@ }, "node_modules/asynckit": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "dev": true, "license": "MIT" }, "node_modules/autoprefixer": { "version": "6.7.7", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", + "integrity": "sha512-WKExI/eSGgGAkWAO+wMVdFObZV7hQen54UpD1kCCTN3tvlL3W1jL4+lPP/M7MwoP7Q4RHzKtO3JQ4HxYEcd+xQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5231,6 +6293,8 @@ }, "node_modules/autoprefixer/node_modules/ansi-regex": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "license": "MIT", "engines": { @@ -5239,6 +6303,8 @@ }, "node_modules/autoprefixer/node_modules/ansi-styles": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "license": "MIT", "engines": { @@ -5247,6 +6313,9 @@ }, "node_modules/autoprefixer/node_modules/browserslist": { "version": "1.7.7", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-1.7.7.tgz", + "integrity": "sha512-qHJblDE2bXVRYzuDetv/wAeHOJyO97+9wxC1cdCtyzgNuSozOyRCiiLaCR1f71AN66lQdVVBipWm63V+a7bPOw==", + "deprecated": "Browserslist 2 could fail on reading Browserslist >3.0 config used in other tools.", "dev": true, "license": "MIT", "dependencies": { @@ -5259,6 +6328,8 @@ }, "node_modules/autoprefixer/node_modules/chalk": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "license": "MIT", "dependencies": { @@ -5274,30 +6345,18 @@ }, "node_modules/autoprefixer/node_modules/chalk/node_modules/supports-color": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" } }, - "node_modules/autoprefixer/node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/autoprefixer/node_modules/has-flag": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/autoprefixer/node_modules/postcss": { "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "license": "MIT", "dependencies": { @@ -5312,6 +6371,8 @@ }, "node_modules/autoprefixer/node_modules/source-map": { "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -5320,6 +6381,8 @@ }, "node_modules/autoprefixer/node_modules/strip-ansi": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "license": "MIT", "dependencies": { @@ -5329,19 +6392,10 @@ "node": ">=0.10.0" } }, - "node_modules/autoprefixer/node_modules/supports-color": { - "version": "3.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^1.0.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/aws-sign2": { "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", "dev": true, "license": "Apache-2.0", "engines": { @@ -5350,6 +6404,8 @@ }, "node_modules/aws4": { "version": "1.13.2", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", + "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", "dev": true, "license": "MIT" }, @@ -5365,10 +6421,14 @@ }, "node_modules/balanced-match": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", "license": "MIT" }, "node_modules/base64-arraybuffer": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz", + "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==", "license": "MIT", "engines": { "node": ">= 0.6.0" @@ -5376,6 +6436,8 @@ }, "node_modules/base64id": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", "dev": true, "license": "MIT", "engines": { @@ -5383,9 +6445,9 @@ } }, "node_modules/baseline-browser-mapping": { - "version": "2.10.33", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.33.tgz", - "integrity": "sha512-bA6+tcSLpz2tIEdDXZPpPTIuxBcC4+w6SieaYyfigIa4h8GlFxbA17v22Vx3JUtuZQj9SgOsnbK+aTBzyDyEuw==", + "version": "2.10.34", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.34.tgz", + "integrity": "sha512-IMDedajPifLnHNY0X9n8hKxRTQ6/eTHwr5bDo04WnuqxyKw6LYtQywCuuqPZwhl3aBXMvQpJov42GLCwRRdQzw==", "dev": true, "license": "Apache-2.0", "bin": { @@ -5397,6 +6459,8 @@ }, "node_modules/bcrypt-pbkdf": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -5426,6 +6490,8 @@ }, "node_modules/binary-extensions": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", + "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "license": "MIT", "engines": { @@ -5437,6 +6503,8 @@ }, "node_modules/blocking-proxy": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", + "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", "dev": true, "license": "MIT", "dependencies": { @@ -5450,63 +6518,28 @@ } }, "node_modules/body-parser": { - "version": "1.20.5", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", - "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "content-type": "~1.0.5", - "debug": "2.6.9", - "depd": "2.0.0", - "destroy": "~1.2.0", - "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", - "on-finished": "~2.4.1", - "qs": "~6.15.1", - "raw-body": "~2.5.3", - "type-is": "~1.6.18", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.8", - "npm": "1.2.8000 || >= 1.4.16" - } - }, - "node_modules/body-parser/node_modules/debug": { - "version": "2.6.9", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "2.0.0" - } - }, - "node_modules/body-parser/node_modules/iconv-lite": { - "version": "0.4.24", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/body-parser/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, - "node_modules/body-parser/node_modules/on-finished": { - "version": "2.4.1", + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", + "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", "dev": true, "license": "MIT", "dependencies": { - "ee-first": "1.1.1" + "bytes": "^3.1.2", + "content-type": "^1.0.5", + "debug": "^4.4.3", + "http-errors": "^2.0.0", + "iconv-lite": "^0.7.0", + "on-finished": "^2.4.1", + "qs": "^6.14.1", + "raw-body": "^3.0.1", + "type-is": "^2.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/boolbase": { @@ -5528,6 +6561,8 @@ }, "node_modules/braces": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", "dev": true, "license": "MIT", "dependencies": { @@ -5573,6 +6608,8 @@ }, "node_modules/browserstack": { "version": "1.6.1", + "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", + "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", "dev": true, "license": "MIT", "dependencies": { @@ -5581,6 +6618,8 @@ }, "node_modules/browserstack/node_modules/agent-base": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, "license": "MIT", "dependencies": { @@ -5592,6 +6631,8 @@ }, "node_modules/browserstack/node_modules/debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5600,6 +6641,8 @@ }, "node_modules/browserstack/node_modules/https-proxy-agent": { "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, "license": "MIT", "dependencies": { @@ -5619,6 +6662,8 @@ }, "node_modules/bytes": { "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", "dev": true, "license": "MIT", "engines": { @@ -5716,10 +6761,14 @@ }, "node_modules/calendar-utils": { "version": "0.10.4", + "resolved": "https://registry.npmjs.org/calendar-utils/-/calendar-utils-0.10.4.tgz", + "integrity": "sha512-gBK4xCJ42yjaUKwuUha6cZOfxAmGzvSgbdAaX3xLRioeKbYoOK1x1qeD6dch72rsMZlTgATPbBBx42bnkStqgQ==", "license": "MIT" }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, "license": "MIT", "dependencies": { @@ -5732,6 +6781,8 @@ }, "node_modules/call-bound": { "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", "dev": true, "license": "MIT", "dependencies": { @@ -5747,6 +6798,8 @@ }, "node_modules/callsites": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", "license": "MIT", "engines": { "node": ">=6" @@ -5754,6 +6807,8 @@ }, "node_modules/camelcase": { "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", "license": "MIT", "engines": { "node": ">=6" @@ -5770,14 +6825,16 @@ } }, "node_modules/caniuse-db": { - "version": "1.0.30001769", + "version": "1.0.30001797", + "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001797.tgz", + "integrity": "sha512-wV1BrKS/ZUWGpO22bqFgYx0d51CVR5lgWNdvtF1Aib78DNXVyeIZUG2mMTr9Vuul2Qab/YNs94S3rRmeE9cQ8g==", "dev": true, "license": "CC-BY-4.0" }, "node_modules/caniuse-lite": { - "version": "1.0.30001793", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001793.tgz", - "integrity": "sha512-iwSsYWaCOoh26cV8NwNRViHlrfUvYsHDfRVcbtmw0Kg6PJIZZXwMkj1442FYLBGkeUf1juAsU3DTfxW579mrPA==", + "version": "1.0.30001797", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001797.tgz", + "integrity": "sha512-l8xKG+gwAIExZGl9FrF7KUwuOmk6wbEPC9Xoy/RtnWv1XG0Q4LFlagaLpUv3Kiza3W/wm27zy0yWJEieYKAP6w==", "dev": true, "funding": [ { @@ -5797,11 +6854,31 @@ }, "node_modules/canonical-path": { "version": "0.0.2", + "resolved": "https://registry.npmjs.org/canonical-path/-/canonical-path-0.0.2.tgz", + "integrity": "sha512-y8EIEvL+IW81S4hRQWCRFtly+g1cc1G+wxHpjhYR9jI2+JJjWiaKnkH8mmvNHOMOAd9fzgARDO3AEzjuR51qaA==", "dev": true, "license": "MIT" }, + "node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/canvas-confetti": { "version": "1.9.4", + "resolved": "https://registry.npmjs.org/canvas-confetti/-/canvas-confetti-1.9.4.tgz", + "integrity": "sha512-yxQbJkAVrFXWNbTUjPqjF7G+g6pDotOUHGbkZq2NELZUMDpiJ85rIEazVb8GTaAptNW2miJAXbs1BtioA251Pw==", "license": "ISC", "funding": { "type": "donate", @@ -5810,21 +6887,47 @@ }, "node_modules/caseless": { "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", "dev": true, "license": "Apache-2.0" }, "node_modules/chalk": { - "version": "4.1.2", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" }, "engines": { - "node": ">=10" + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^3.0.0" }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "engines": { + "node": ">=4" } }, "node_modules/chardet": { @@ -5835,26 +6938,19 @@ "license": "MIT" }, "node_modules/chokidar": { - "version": "3.6.0", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", "dev": true, "license": "MIT", "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" + "readdirp": "^5.0.0" }, "engines": { - "node": ">= 8.10.0" + "node": ">= 20.19.0" }, "funding": { "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" } }, "node_modules/chownr": { @@ -5913,105 +7009,112 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" + "node": ">= 12" } }, - "node_modules/cli-truncate/node_modules/string-width": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", - "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", "dev": true, - "license": "MIT", + "license": "ISC", "dependencies": { - "get-east-asian-width": "^1.5.0", - "strip-ansi": "^7.1.2" + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" }, "engines": { "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/cli-truncate/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "node_modules/cliui/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, "engines": { "node": ">=12" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "node_modules/cliui/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "dev": true, - "license": "ISC", - "engines": { - "node": ">= 12" - } + "license": "MIT" }, - "node_modules/cliui": { - "version": "8.0.1", + "node_modules/cliui/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=12" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/cliui/node_modules/wrap-ansi": { - "version": "7.0.0", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" }, "engines": { - "node": ">=10" + "node": ">=18" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/color-convert": { - "version": "2.0.1", + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", "license": "MIT", "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" + "color-name": "1.1.3" } }, "node_modules/color-name": { - "version": "1.1.4", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", "license": "MIT" }, + "node_modules/color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "license": "ISC", + "optional": true, + "bin": { + "color-support": "bin.js" + } + }, "node_modules/colorette": { "version": "2.0.20", "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", @@ -6019,8 +7122,20 @@ "dev": true, "license": "MIT" }, + "node_modules/colors": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", + "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, "node_modules/combined-stream": { "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", "dev": true, "license": "MIT", "dependencies": { @@ -6032,6 +7147,8 @@ }, "node_modules/commander": { "version": "2.6.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", + "integrity": "sha512-PhbTMT+ilDXZKqH8xbvuUY2ZEQNef0Q7DKxgoEKb4ccytsdvVVJmYqR0sGbi96nxU6oGrwEIQnclpK2NBZuQlg==", "dev": true, "license": "MIT", "engines": { @@ -6051,10 +7168,14 @@ }, "node_modules/concat-map": { "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", "license": "MIT" }, "node_modules/concurrently": { "version": "3.6.1", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-3.6.1.tgz", + "integrity": "sha512-/+ugz+gwFSEfTGUxn0KHkY+19XPRTXR8+7oUK/HxgiN1n7FjeJmkrbSiXAJfyQ0zORgJYPaenmymwon51YXH9Q==", "dev": true, "license": "MIT", "dependencies": { @@ -6076,127 +7197,111 @@ "node": ">=4.0.0" } }, - "node_modules/concurrently/node_modules/ansi-styles": { - "version": "3.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/concurrently/node_modules/chalk": { - "version": "2.4.2", + "node_modules/concurrently/node_modules/date-fns": { + "version": "1.30.1", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-1.30.1.tgz", + "integrity": "sha512-hBSVCvSmWC+QypYObzwGOd9wqdDpOt+0wl0KbU+R+uuZBS1jN8VsD1ss3irQDknRj5NvxiTF6oj/nDRnN/UQNw==", "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - }, - "engines": { - "node": ">=4" - } + "license": "MIT" }, - "node_modules/concurrently/node_modules/chalk/node_modules/has-flag": { - "version": "3.0.0", + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } + "license": "MIT" }, - "node_modules/concurrently/node_modules/chalk/node_modules/supports-color": { - "version": "5.5.0", + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^3.0.0" + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" }, "engines": { - "node": ">=4" + "node": ">= 0.10.0" } }, - "node_modules/concurrently/node_modules/color-convert": { - "version": "1.9.3", + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/concurrently/node_modules/color-name": { - "version": "1.1.3", - "dev": true, - "license": "MIT" - }, - "node_modules/concurrently/node_modules/date-fns": { - "version": "1.30.1", - "dev": true, - "license": "MIT" - }, - "node_modules/concurrently/node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" + "ms": "2.0.0" } }, - "node_modules/concurrently/node_modules/has-flag": { - "version": "1.0.0", + "node_modules/connect/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.8" } }, - "node_modules/concurrently/node_modules/supports-color": { - "version": "3.2.3", + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^1.0.0" + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" }, "engines": { - "node": ">=0.8.0" + "node": ">= 0.8" } }, - "node_modules/confbox": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", - "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, "license": "MIT" }, - "node_modules/connect": { - "version": "3.7.0", + "node_modules/connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, "license": "MIT", "dependencies": { - "debug": "2.6.9", - "finalhandler": "1.1.2", - "parseurl": "~1.3.3", - "utils-merge": "1.0.1" + "ee-first": "1.1.1" }, "engines": { - "node": ">= 0.10.0" + "node": ">= 0.8" } }, - "node_modules/connect/node_modules/debug": { - "version": "2.6.9", + "node_modules/connect/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, "license": "MIT", - "dependencies": { - "ms": "2.0.0" + "engines": { + "node": ">= 0.6" } }, - "node_modules/connect/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" + "node_modules/console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", + "license": "ISC", + "optional": true }, "node_modules/content-disposition": { "version": "1.1.0", @@ -6214,6 +7319,8 @@ }, "node_modules/content-type": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", "dev": true, "license": "MIT", "engines": { @@ -6272,6 +7379,8 @@ }, "node_modules/cookie": { "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "dev": true, "license": "MIT", "engines": { @@ -6289,7 +7398,9 @@ } }, "node_modules/core-js": { - "version": "3.48.0", + "version": "3.49.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.49.0.tgz", + "integrity": "sha512-es1U2+YTtzpwkxVLwAFdSpaIMyQaq0PBgm3YD1W3Qpsn1NAmO3KSgZfu+oGSWVu6NvLHoHCV/aYcsE5wiB7ALg==", "hasInstallScript": true, "license": "MIT", "funding": { @@ -6298,11 +7409,15 @@ } }, "node_modules/core-util-is": { - "version": "1.0.2", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", "license": "MIT" }, "node_modules/cors": { "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", "dev": true, "license": "MIT", "dependencies": { @@ -6318,9 +7433,9 @@ } }, "node_modules/cosmiconfig": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.1.tgz", - "integrity": "sha512-hr4ihw+DBqcvrsEDioRO31Z17x71pUYoNe/4h6Z0wB72p7MU7/9gH8Q3s12NFhHPfYBBOV3qyfUxmr/Yn3shnQ==", + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz", + "integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==", "dev": true, "license": "MIT", "dependencies": { @@ -6362,23 +7477,17 @@ "typescript": ">=5" } }, - "node_modules/cosmiconfig-typescript-loader/node_modules/jiti": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", - "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "lib/jiti-cli.mjs" - } - }, "node_modules/create-require": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", "dev": true, "license": "MIT" }, "node_modules/cross-spawn": { "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -6391,6 +7500,8 @@ }, "node_modules/css-line-break": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz", + "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==", "license": "MIT", "dependencies": { "utrie": "^1.0.2" @@ -6441,11 +7552,15 @@ }, "node_modules/custom-event": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", "dev": true, "license": "MIT" }, "node_modules/d3": { "version": "3.5.17", + "resolved": "https://registry.npmjs.org/d3/-/d3-3.5.17.tgz", + "integrity": "sha512-yFk/2idb8OHPKkbAL8QaOaqENNoMhIaSHZerk3oQsECwkObkCpJyjYwCe+OHiq6UEdhe1m8ZGARRRO3ljFjlKg==", "license": "BSD-3-Clause" }, "node_modules/d3-array": { @@ -6589,6 +7704,12 @@ "d3-path": "1" } }, + "node_modules/d3-sankey/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, "node_modules/d3-scale": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", @@ -6627,27 +7748,27 @@ } }, "node_modules/d3-time": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", - "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", - "license": "BSD-3-Clause", - "dependencies": { - "d3-array": "2" - } - }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", "license": "ISC", "dependencies": { - "d3-time": "1 - 3" + "d3-array": "2 - 3" }, "engines": { "node": ">=12" } }, - "node_modules/d3-time/node_modules/d3-array": { + "node_modules/d3-time-format": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-3.0.0.tgz", + "integrity": "sha512-UXJh6EKsHBTjopVqZBhFysQcoXSv/5yLONZvkQ5Kk3qbwiUYkdX17Xa1PT6U1ZWXGGfB1ey5L8dKMlFq2DO0Ag==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-time": "1 - 2" + } + }, + "node_modules/d3-time-format/node_modules/d3-array": { "version": "2.12.1", "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-2.12.1.tgz", "integrity": "sha512-B0ErZK/66mHtEsR1TkPEEkwdy+WDesimkM5gpZr5Dsg54BiTA5RXtYW5qTLIAcekaS9xfZrzBLF/OAkB3Qn1YQ==", @@ -6656,6 +7777,21 @@ "internmap": "^1.0.0" } }, + "node_modules/d3-time-format/node_modules/d3-time": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-2.1.1.tgz", + "integrity": "sha512-/eIQe/eR4kCQwq7yxi7z4c6qEXf2IYGcjoWB5OOQy4Tq9Uv39/947qlDcN2TLkiTzQWzvnsuYPB9TrWaNfipKQ==", + "license": "BSD-3-Clause", + "dependencies": { + "d3-array": "2" + } + }, + "node_modules/d3-time-format/node_modules/internmap": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", + "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", + "license": "ISC" + }, "node_modules/d3-timer": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/d3-timer/-/d3-timer-3.0.1.tgz", @@ -6686,6 +7822,8 @@ }, "node_modules/dashdash": { "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", "dev": true, "license": "MIT", "dependencies": { @@ -6697,6 +7835,8 @@ }, "node_modules/date-fns": { "version": "3.6.0", + "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-3.6.0.tgz", + "integrity": "sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==", "license": "MIT", "funding": { "type": "github", @@ -6705,6 +7845,8 @@ }, "node_modules/date-format": { "version": "4.0.14", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.14.tgz", + "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", "dev": true, "license": "MIT", "engines": { @@ -6713,6 +7855,8 @@ }, "node_modules/debug": { "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", "license": "MIT", "dependencies": { "ms": "^2.1.3" @@ -6728,17 +7872,36 @@ }, "node_modules/decamelize": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "license": "MIT", + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/deep-is": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "license": "MIT" }, "node_modules/del": { "version": "2.2.2", + "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", + "integrity": "sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6754,43 +7917,10 @@ "node": ">=0.10.0" } }, - "node_modules/del/node_modules/array-union": { - "version": "1.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "array-uniq": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/arrify": { - "version": "1.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/globby": { - "version": "5.0.0", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/del/node_modules/pify": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", "dev": true, "license": "MIT", "engines": { @@ -6799,6 +7929,9 @@ }, "node_modules/del/node_modules/rimraf": { "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -6810,14 +7943,25 @@ }, "node_modules/delayed-stream": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", "dev": true, "license": "MIT", "engines": { "node": ">=0.4.0" } }, + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", + "optional": true + }, "node_modules/depd": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, "license": "MIT", "engines": { @@ -6826,6 +7970,8 @@ }, "node_modules/destroy": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, "license": "MIT", "engines": { @@ -6835,7 +7981,8 @@ }, "node_modules/detect-libc": { "version": "2.1.2", - "dev": true, + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "license": "Apache-2.0", "optional": true, "engines": { @@ -6844,6 +7991,8 @@ }, "node_modules/di": { "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "dev": true, "license": "MIT" }, @@ -6854,8 +8003,20 @@ "dev": true, "license": "Apache-2.0" }, + "node_modules/diff": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", + "integrity": "sha512-X07nttJQkwkfKfvTPG/KSnE2OMdcUCao6+eXF3wmnIQRn2aPAHH3VxDbDOdegkd6JbPsXqShpvEOHfAT+nCNwQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/dijkstrajs": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", "license": "MIT" }, "node_modules/dlv": { @@ -6867,6 +8028,8 @@ }, "node_modules/dom-serialize": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -6959,6 +8122,8 @@ }, "node_modules/dunder-proto": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", "dev": true, "license": "MIT", "dependencies": { @@ -6972,6 +8137,8 @@ }, "node_modules/ecc-jsbn": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", "dev": true, "license": "MIT", "dependencies": { @@ -6981,22 +8148,28 @@ }, "node_modules/ee-first": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==", "dev": true, "license": "MIT" }, "node_modules/electron-to-chromium": { - "version": "1.5.368", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.368.tgz", - "integrity": "sha512-7RckJJK4uESJF9PxvfMWd3TGqIiieUTG4HxnKaKuIpGbcr+r2ZEB3g2gAhCP3Fqm42vJSzLfgab9eva/C4/XVw==", + "version": "1.5.369", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.369.tgz", + "integrity": "sha512-XM22K9FNaaCOvMMrBn1caIc8v0g6+pKt660ZbfQqUZvfil0hEzr8ZoiY7VcSLGM3L/x3rz5PqZrk+bKOOmVM9w==", "dev": true, "license": "ISC" }, "node_modules/emoji-regex": { "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "license": "MIT" }, "node_modules/encodeurl": { - "version": "1.0.2", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "dev": true, "license": "MIT", "engines": { @@ -7027,12 +8200,61 @@ }, "node_modules/engine.io-parser": { "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "dev": true, "license": "MIT", "engines": { "node": ">=10.0.0" } }, + "node_modules/engine.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/enhanced-resolve": { "version": "5.23.0", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.23.0.tgz", @@ -7049,6 +8271,8 @@ }, "node_modules/ent": { "version": "2.2.2", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.2.tgz", + "integrity": "sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==", "dev": true, "license": "MIT", "dependencies": { @@ -7076,6 +8300,8 @@ }, "node_modules/env-paths": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", "dev": true, "license": "MIT", "engines": { @@ -7104,6 +8330,8 @@ }, "node_modules/error-ex": { "version": "1.3.4", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", + "integrity": "sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7112,6 +8340,8 @@ }, "node_modules/es-define-property": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, "license": "MIT", "engines": { @@ -7120,6 +8350,8 @@ }, "node_modules/es-errors": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", "dev": true, "license": "MIT", "engines": { @@ -7127,7 +8359,9 @@ } }, "node_modules/es-object-atoms": { - "version": "1.1.1", + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", "dev": true, "license": "MIT", "dependencies": { @@ -7137,8 +8371,21 @@ "node": ">= 0.4" } }, + "node_modules/es-toolkit": { + "version": "1.47.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.47.0.tgz", + "integrity": "sha512-n1GuoD0WEQZMBk5tttoZSqwgyLx01oqa5XsBmCHwPyNe1S9jPBEmtR2pSgp2kJuWE3ciFZ6yRHmY4pM4C3OOkw==", + "dev": true, + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks" + ] + }, "node_modules/es5-shim": { "version": "4.6.7", + "resolved": "https://registry.npmjs.org/es5-shim/-/es5-shim-4.6.7.tgz", + "integrity": "sha512-jg21/dmlrNQI7JyyA2w7n+yifSxBng0ZralnSfVZjoCawgNTCnS+yBCyVM9DL5itm7SUnDGgv7hcq2XCZX4iRQ==", "license": "MIT", "engines": { "node": ">=0.4.0" @@ -7146,11 +8393,15 @@ }, "node_modules/es6-promise": { "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", "dev": true, "license": "MIT" }, "node_modules/es6-promisify": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", "dev": true, "license": "MIT", "dependencies": { @@ -7201,6 +8452,8 @@ }, "node_modules/escalade": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { @@ -7209,17 +8462,19 @@ }, "node_modules/escape-html": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==", "dev": true, "license": "MIT" }, "node_modules/escape-string-regexp": { - "version": "4.0.0", + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, "license": "MIT", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=0.8.0" } }, "node_modules/eslint": { @@ -7368,6 +8623,8 @@ }, "node_modules/eslint-visitor-keys": { "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", "license": "Apache-2.0", "engines": { "node": "^12.22.0 || ^14.17.0 || >=16.0.0" @@ -7392,6 +8649,21 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/eslint/node_modules/brace-expansion": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", @@ -7402,6 +8674,52 @@ "concat-map": "0.0.1" } }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/eslint/node_modules/eslint-scope": { "version": "8.4.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", @@ -7430,18 +8748,28 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/eslint/node_modules/glob-parent": { - "version": "6.0.2", - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.3" - }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "license": "MIT", "engines": { - "node": ">=10.13.0" + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "license": "MIT", + "engines": { + "node": ">= 4" } }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "license": "MIT" }, "node_modules/eslint/node_modules/minimatch": { @@ -7453,7 +8781,19 @@ "brace-expansion": "^1.1.7" }, "engines": { - "node": "*" + "node": "*" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" } }, "node_modules/espree": { @@ -7487,6 +8827,8 @@ }, "node_modules/esquery": { "version": "1.7.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.7.0.tgz", + "integrity": "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==", "license": "BSD-3-Clause", "dependencies": { "estraverse": "^5.1.0" @@ -7497,6 +8839,8 @@ }, "node_modules/esrecurse": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", "license": "BSD-2-Clause", "dependencies": { "estraverse": "^5.2.0" @@ -7507,6 +8851,8 @@ }, "node_modules/estraverse": { "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", "license": "BSD-2-Clause", "engines": { "node": ">=4.0" @@ -7523,6 +8869,8 @@ }, "node_modules/etag": { "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", "dev": true, "license": "MIT", "engines": { @@ -7531,6 +8879,8 @@ }, "node_modules/eventemitter3": { "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true, "license": "MIT" }, @@ -7548,9 +8898,9 @@ } }, "node_modules/eventsource-parser": { - "version": "3.0.8", - "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.0.8.tgz", - "integrity": "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eventsource-parser/-/eventsource-parser-3.1.0.tgz", + "integrity": "sha512-kJezFj9YFAMLeORyi7aCLxLbD5/qWMQnoMVlVPyHIll7lgRJCc3JVln9Vgl9nwQi0YkMnhdGTMNn7CkRRAptMg==", "dev": true, "license": "MIT", "engines": { @@ -7559,6 +8909,8 @@ }, "node_modules/exit": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", "dev": true, "engines": { "node": ">= 0.8.0" @@ -7634,243 +8986,6 @@ "express": ">= 4.11" } }, - "node_modules/express/node_modules/accepts": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", - "integrity": "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-types": "^3.0.0", - "negotiator": "^1.0.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/body-parser": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "^3.1.2", - "content-type": "^1.0.5", - "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", - "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/encodeurl": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", - "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/finalhandler": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", - "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.0", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "on-finished": "^2.4.1", - "parseurl": "^1.3.3", - "statuses": "^2.0.1" - }, - "engines": { - "node": ">= 18.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/fresh": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", - "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/mime-db": { - "version": "1.54.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", - "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/express/node_modules/mime-types": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", - "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "^1.54.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/on-finished": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", - "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ee-first": "1.1.1" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/raw-body": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", - "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", - "dev": true, - "license": "MIT", - "dependencies": { - "bytes": "~3.1.2", - "http-errors": "~2.0.1", - "iconv-lite": "~0.7.0", - "unpipe": "~1.0.0" - }, - "engines": { - "node": ">= 0.10" - } - }, - "node_modules/express/node_modules/send": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", - "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.4.3", - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "etag": "^1.8.1", - "fresh": "^2.0.0", - "http-errors": "^2.0.1", - "mime-types": "^3.0.2", - "ms": "^2.1.3", - "on-finished": "^2.4.1", - "range-parser": "^1.2.1", - "statuses": "^2.0.2" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/serve-static": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", - "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "encodeurl": "^2.0.0", - "escape-html": "^1.0.3", - "parseurl": "^1.3.3", - "send": "^1.2.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/statuses": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", - "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/express/node_modules/type-is": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", - "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", - "dev": true, - "license": "MIT", - "dependencies": { - "content-type": "^2.0.0", - "media-typer": "^1.1.0", - "mime-types": "^3.0.0" - }, - "engines": { - "node": ">= 18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, - "node_modules/express/node_modules/type-is/node_modules/content-type": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", - "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" - } - }, "node_modules/exsolve": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.0.8.tgz", @@ -7880,11 +8995,15 @@ }, "node_modules/extend": { "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true, "license": "MIT" }, "node_modules/extsprintf": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", "dev": true, "engines": [ "node >=0.6.0" @@ -7893,6 +9012,8 @@ }, "node_modules/fast-deep-equal": { "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "license": "MIT" }, "node_modules/fast-diff": { @@ -7919,12 +9040,29 @@ "node": ">=8.6.0" } }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", "license": "MIT" }, "node_modules/fast-levenshtein": { "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "license": "MIT" }, "node_modules/fast-uri": { @@ -7956,6 +9094,8 @@ }, "node_modules/fdir": { "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "license": "MIT", "engines": { "node": ">=12.0.0" @@ -7983,51 +9123,49 @@ }, "node_modules/file-saver": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz", + "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA==", "license": "MIT" }, "node_modules/fill-range": { "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", "dev": true, - "license": "MIT", - "dependencies": { - "to-regex-range": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/finalhandler": { - "version": "1.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "2.6.9", - "encodeurl": "~1.0.2", - "escape-html": "~1.0.3", - "on-finished": "~2.3.0", - "parseurl": "~1.3.3", - "statuses": "~1.5.0", - "unpipe": "~1.0.0" + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" }, "engines": { - "node": ">= 0.8" + "node": ">=8" } }, - "node_modules/finalhandler/node_modules/debug": { - "version": "2.6.9", + "node_modules/finalhandler": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-2.1.1.tgz", + "integrity": "sha512-S8KoZgRZN+a5rNwqTxlZZePjT/4cnm0ROV70LedRHZ0p8u9fRID0hJUZQpkKLzro8LfmC8sx23bY6tVNxv8pQA==", "dev": true, "license": "MIT", "dependencies": { - "ms": "2.0.0" + "debug": "^4.4.0", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "on-finished": "^2.4.1", + "parseurl": "^1.3.3", + "statuses": "^2.0.1" + }, + "engines": { + "node": ">= 18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/finalhandler/node_modules/ms": { - "version": "2.0.0", - "dev": true, - "license": "MIT" - }, "node_modules/find-up": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", "license": "MIT", "dependencies": { "locate-path": "^6.0.0", @@ -8082,6 +9220,8 @@ }, "node_modules/font-awesome": { "version": "4.7.0", + "resolved": "https://registry.npmjs.org/font-awesome/-/font-awesome-4.7.0.tgz", + "integrity": "sha512-U6kGnykA/6bFmg1M/oT9EkFeIYv7JlX3bozwQJWiiLz6L0w3F5vBVPxHlwyX/vtNq1ckcpRKOB9f2Qal/VtFpg==", "license": "(OFL-1.1 AND MIT)", "engines": { "node": ">=0.10.3" @@ -8089,6 +9229,8 @@ }, "node_modules/forever-agent": { "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", "dev": true, "license": "Apache-2.0", "engines": { @@ -8097,6 +9239,8 @@ }, "node_modules/form-data": { "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8108,6 +9252,29 @@ "node": ">= 0.12" } }, + "node_modules/form-data/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/form-data/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -8118,6 +9285,31 @@ "node": ">= 0.6" } }, + "node_modules/fresh": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-2.0.0.tgz", + "integrity": "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, "node_modules/fs-minipass": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", @@ -8133,7 +9325,9 @@ }, "node_modules/fs.realpath": { "version": "1.0.0", - "dev": true, + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "devOptional": true, "license": "ISC" }, "node_modules/fsevents": { @@ -8153,12 +9347,91 @@ }, "node_modules/function-bind": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gauge": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-3.0.2.tgz", + "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "aproba": "^1.0.3 || ^2.0.0", + "color-support": "^1.1.2", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.1", + "object-assign": "^4.1.1", + "signal-exit": "^3.0.0", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wide-align": "^1.1.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/gauge/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC", + "optional": true + }, + "node_modules/gauge/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/gauge/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", @@ -8171,15 +9444,17 @@ }, "node_modules/get-caller-file": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", "license": "ISC", "engines": { "node": "6.* || 8.* || >= 10.*" } }, "node_modules/get-east-asian-width": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", - "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz", + "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==", "dev": true, "license": "MIT", "engines": { @@ -8191,6 +9466,8 @@ }, "node_modules/get-intrinsic": { "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8214,6 +9491,8 @@ }, "node_modules/get-proto": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", "dev": true, "license": "MIT", "dependencies": { @@ -8226,6 +9505,8 @@ }, "node_modules/getpass": { "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", "dev": true, "license": "MIT", "dependencies": { @@ -8254,7 +9535,7 @@ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "fs.realpath": "^1.0.0", @@ -8272,14 +9553,15 @@ } }, "node_modules/glob-parent": { - "version": "5.1.2", - "dev": true, + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", "license": "ISC", "dependencies": { - "is-glob": "^4.0.1" + "is-glob": "^4.0.3" }, "engines": { - "node": ">= 6" + "node": ">=10.13.0" } }, "node_modules/glob-to-regexp": { @@ -8293,7 +9575,7 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", - "dev": true, + "devOptional": true, "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", @@ -8304,7 +9586,7 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, + "devOptional": true, "license": "ISC", "dependencies": { "brace-expansion": "^1.1.7" @@ -8314,31 +9596,21 @@ } }, "node_modules/global-directory": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", - "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-5.0.0.tgz", + "integrity": "sha512-1pgFdhK3J2LeM+dVf2Pd424yHx2ou338lC0ErNP2hPx4j8eW1Sp0XqSjNxtk6Tc4Kr5wlWtSvz8cn2yb7/SG/w==", "dev": true, "license": "MIT", "dependencies": { - "ini": "4.1.1" + "ini": "6.0.0" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/global-directory/node_modules/ini": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", - "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } - }, "node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -8351,8 +9623,38 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globby": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", + "integrity": "sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^1.0.1", + "arrify": "^1.0.0", + "glob": "^7.0.3", + "object-assign": "^4.0.1", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/globby/node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/gopd": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, "license": "MIT", "engines": { @@ -8364,11 +9666,15 @@ }, "node_modules/graceful-fs": { "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true, "license": "ISC" }, "node_modules/har-schema": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", "dev": true, "license": "ISC", "engines": { @@ -8377,6 +9683,9 @@ }, "node_modules/har-validator": { "version": "5.1.5", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", + "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", + "deprecated": "this library is no longer supported", "dev": true, "license": "MIT", "dependencies": { @@ -8406,11 +9715,15 @@ }, "node_modules/har-validator/node_modules/json-schema-traverse": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true, "license": "MIT" }, "node_modules/has-ansi": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==", "dev": true, "license": "MIT", "dependencies": { @@ -8422,6 +9735,8 @@ }, "node_modules/has-ansi/node_modules/ansi-regex": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "license": "MIT", "engines": { @@ -8429,14 +9744,19 @@ } }, "node_modules/has-flag": { - "version": "4.0.0", + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-1.0.0.tgz", + "integrity": "sha512-DyYHfIYwAJmjAjSSPKANxI8bFY9YtFrgkAfinBojQ8YJTOuOuav64tMUJv584SES4xl74PmuaevIyaLESHdTAA==", + "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=0.10.0" } }, "node_modules/has-symbols": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, "license": "MIT", "engines": { @@ -8448,6 +9768,8 @@ }, "node_modules/has-tostringtag": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", "dependencies": { @@ -8460,8 +9782,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==", + "license": "ISC", + "optional": true + }, "node_modules/hasown": { - "version": "2.0.2", + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", "dev": true, "license": "MIT", "dependencies": { @@ -8472,9 +9803,9 @@ } }, "node_modules/hono": { - "version": "4.12.23", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.23.tgz", - "integrity": "sha512-eIaZ9qDgu7XV0pxOCrg7/WhnQ6Ivm22UcxhXx/A3dcbqbbYgBEkc6e/J/s7j2tS96zoB0S9VBdLwQNCWwUo4LA==", + "version": "4.12.25", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.25.tgz", + "integrity": "sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ==", "dev": true, "license": "MIT", "engines": { @@ -8506,11 +9837,15 @@ }, "node_modules/html-escaper": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", "dev": true, "license": "MIT" }, "node_modules/html2canvas": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz", + "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==", "license": "MIT", "dependencies": { "css-line-break": "^2.1.0", @@ -8522,6 +9857,8 @@ }, "node_modules/html5-qrcode": { "version": "2.3.8", + "resolved": "https://registry.npmjs.org/html5-qrcode/-/html5-qrcode-2.3.8.tgz", + "integrity": "sha512-jsr4vafJhwoLVEDW3n1KvPnCCXWaQfRng0/EEYk1vNcQGcG/htAdhJX0be8YyqMoSz7+hZvOZSTAepsabiuhiQ==", "license": "Apache-2.0" }, "node_modules/htmlparser2": { @@ -8566,6 +9903,8 @@ }, "node_modules/http-errors": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", + "integrity": "sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8583,16 +9922,10 @@ "url": "https://opencollective.com/express" } }, - "node_modules/http-errors/node_modules/statuses": { - "version": "2.0.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" - } - }, "node_modules/http-proxy": { "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8620,6 +9953,8 @@ }, "node_modules/http-signature": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8648,6 +9983,8 @@ }, "node_modules/husky": { "version": "8.0.3", + "resolved": "https://registry.npmjs.org/husky/-/husky-8.0.3.tgz", + "integrity": "sha512-+dQSyqPh4x1hlO1swXBiNb2HzTDN1I2IGLQx1GrBuiqFJfoMrnZWwVmatvSiO+Iz8fBUnf+lekwNo4c2LlXItg==", "dev": true, "license": "MIT", "bin": { @@ -8678,9 +10015,9 @@ } }, "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "version": "7.0.5", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", + "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", "license": "MIT", "engines": { "node": ">= 4" @@ -8740,6 +10077,8 @@ }, "node_modules/immediate": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/immediate/-/immediate-3.0.6.tgz", + "integrity": "sha512-XXOFtyqDjNDAQxVfYxuF7g9Il/IbWmmlQg2MYKOH8ExIT1qg6xc4zyS3HaEEATgs1btfzxq15ciUiY7gjSXRGQ==", "license": "MIT" }, "node_modules/immutable": { @@ -8751,6 +10090,8 @@ }, "node_modules/import-fresh": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -8765,6 +10106,8 @@ }, "node_modules/import-fresh/node_modules/resolve-from": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", "license": "MIT", "engines": { "node": ">=4" @@ -8783,6 +10126,8 @@ }, "node_modules/imurmurhash": { "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", "license": "MIT", "engines": { "node": ">=0.8.19" @@ -8790,7 +10135,10 @@ }, "node_modules/inflight": { "version": "1.0.6", - "dev": true, + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "devOptional": true, "license": "ISC", "dependencies": { "once": "^1.3.0", @@ -8799,6 +10147,8 @@ }, "node_modules/inherits": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, "node_modules/ini": { @@ -8812,13 +10162,18 @@ } }, "node_modules/internmap": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-1.0.1.tgz", - "integrity": "sha512-lDB5YccMydFBtasVtxnZ3MRBHuaoE8GKsppq+EchKL2U4nK/DmEpPHNH8MZe5HkMtpSiTSOZwfN0tzYjO/lJEw==", - "license": "ISC" + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, "node_modules/ip": { "version": "1.1.9", + "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", + "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", "dev": true, "license": "MIT" }, @@ -8844,11 +10199,15 @@ }, "node_modules/is-arrayish": { "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", "dev": true, "license": "MIT" }, "node_modules/is-binary-path": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "license": "MIT", "dependencies": { @@ -8859,11 +10218,13 @@ } }, "node_modules/is-core-module": { - "version": "2.16.1", + "version": "2.16.2", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.2.tgz", + "integrity": "sha512-evOr8xfXKxE6qSR0hSXL2r3sd7ALj8+7jQEUvPYcm5sgZFdJ+AYzT6yNmJenvIYQBgIGwfwz08sL8zoL7yq2BA==", "dev": true, "license": "MIT", "dependencies": { - "hasown": "^2.0.2" + "hasown": "^2.0.3" }, "engines": { "node": ">= 0.4" @@ -8874,20 +10235,33 @@ }, "node_modules/is-extglob": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "license": "MIT", "engines": { "node": ">=0.10.0" } }, "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", + "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", + "dev": true, "license": "MIT", + "dependencies": { + "get-east-asian-width": "^1.3.1" + }, "engines": { - "node": ">=8" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/is-glob": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "license": "MIT", "dependencies": { "is-extglob": "^2.1.1" @@ -8911,6 +10285,8 @@ }, "node_modules/is-number": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "dev": true, "license": "MIT", "engines": { @@ -8929,6 +10305,8 @@ }, "node_modules/is-path-cwd": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", + "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==", "dev": true, "license": "MIT", "engines": { @@ -8937,6 +10315,8 @@ }, "node_modules/is-path-in-cwd": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", + "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8946,8 +10326,10 @@ "node": ">=0.10.0" } }, - "node_modules/is-path-in-cwd/node_modules/is-path-inside": { + "node_modules/is-path-inside": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", + "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==", "dev": true, "license": "MIT", "dependencies": { @@ -8957,8 +10339,30 @@ "node": ">=0.10.0" } }, + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-promise": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", + "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", + "dev": true, + "license": "MIT" + }, "node_modules/is-regex": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, "license": "MIT", "dependencies": { @@ -8976,6 +10380,8 @@ }, "node_modules/is-typedarray": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", "dev": true, "license": "MIT" }, @@ -9000,6 +10406,8 @@ }, "node_modules/isbinaryfile": { "version": "4.0.10", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.10.tgz", + "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, "license": "MIT", "engines": { @@ -9011,15 +10419,21 @@ }, "node_modules/isexe": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, "node_modules/isstream": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", "dev": true, "license": "MIT" }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -9045,6 +10459,8 @@ }, "node_modules/istanbul-lib-report": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -9056,8 +10472,33 @@ "node": ">=10" } }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/istanbul-lib-source-maps": { "version": "3.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", + "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -9073,6 +10514,8 @@ }, "node_modules/istanbul-lib-source-maps/node_modules/istanbul-lib-coverage": { "version": "2.0.5", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", + "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -9081,6 +10524,8 @@ }, "node_modules/istanbul-lib-source-maps/node_modules/make-dir": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", "dev": true, "license": "MIT", "dependencies": { @@ -9093,6 +10538,8 @@ }, "node_modules/istanbul-lib-source-maps/node_modules/pify": { "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", "dev": true, "license": "MIT", "engines": { @@ -9101,6 +10548,9 @@ }, "node_modules/istanbul-lib-source-maps/node_modules/rimraf": { "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -9112,6 +10562,8 @@ }, "node_modules/istanbul-lib-source-maps/node_modules/semver": { "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "license": "ISC", "bin": { @@ -9120,6 +10572,8 @@ }, "node_modules/istanbul-lib-source-maps/node_modules/source-map": { "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -9128,6 +10582,8 @@ }, "node_modules/istanbul-reports": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -9140,6 +10596,8 @@ }, "node_modules/jasmine": { "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", + "integrity": "sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==", "dev": true, "license": "MIT", "dependencies": { @@ -9153,32 +10611,32 @@ }, "node_modules/jasmine-core": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.1.1.tgz", + "integrity": "sha512-lmUfT5XcK9KKvt3lLYzn93hc4MGzlUBowExFVgzbSW0ZCrdeyS574dfsyfRhxbg81Wj4gk+RxUiTnj7KBfDA1g==", "dev": true, "license": "MIT" }, "node_modules/jasmine-spec-reporter": { "version": "5.0.2", + "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-5.0.2.tgz", + "integrity": "sha512-6gP1LbVgJ+d7PKksQBc2H0oDGNRQI3gKUsWlswKaQ2fif9X5gzhQcgM5+kiJGCQVurOG09jqNhk7payggyp5+g==", "dev": true, "license": "Apache-2.0", "dependencies": { "colors": "1.4.0" } }, - "node_modules/jasmine-spec-reporter/node_modules/colors": { - "version": "1.4.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.1.90" - } - }, "node_modules/jasmine/node_modules/jasmine-core": { "version": "2.8.0", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", + "integrity": "sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==", "dev": true, "license": "MIT" }, "node_modules/jasminewd2": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", + "integrity": "sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg==", "dev": true, "license": "MIT", "engines": { @@ -9193,9 +10651,9 @@ "license": "MIT" }, "node_modules/jiti": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", - "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", + "integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==", "devOptional": true, "license": "MIT", "bin": { @@ -9220,11 +10678,15 @@ }, "node_modules/js-base64": { "version": "2.6.4", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.6.4.tgz", + "integrity": "sha512-pZe//GGmwJndub7ZghVHz7vjb2LgC1m8B07Au3eYqeqv9emhESByMXxaEgkUkEqJe87oBbSniGYoQNIBklc7IQ==", "dev": true, "license": "BSD-3-Clause" }, "node_modules/js-tokens": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", "dev": true, "license": "MIT" }, @@ -9252,6 +10714,8 @@ }, "node_modules/jsbn": { "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", "dev": true, "license": "MIT" }, @@ -9276,26 +10740,32 @@ }, "node_modules/json-parse-better-errors": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", "dev": true, "license": "MIT" }, "node_modules/json-parse-even-better-errors": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz", - "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-5.0.0.tgz", + "integrity": "sha512-ZF1nxZ28VhQouRWhUcVlUIN3qwSgPuswK05s/HIaoetAoE/9tngVmCHjSxmSQPav1nd+lPtTL0YZ/2AFdR/iYQ==", "dev": true, "license": "MIT", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/json-schema": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", "dev": true, "license": "(AFL-2.1 OR BSD-3-Clause)" }, "node_modules/json-schema-traverse": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "dev": true, "license": "MIT" }, @@ -9308,15 +10778,21 @@ }, "node_modules/json-stable-stringify-without-jsonify": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "license": "MIT" }, "node_modules/json-stringify-safe": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", "dev": true, "license": "ISC" }, "node_modules/json5": { "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "license": "MIT", "bin": { @@ -9333,6 +10809,16 @@ "dev": true, "license": "MIT" }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/jsonparse": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", @@ -9345,6 +10831,8 @@ }, "node_modules/jsprim": { "version": "1.4.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", + "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", "dev": true, "license": "MIT", "dependencies": { @@ -9359,6 +10847,8 @@ }, "node_modules/jszip": { "version": "3.10.1", + "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", + "integrity": "sha512-xXDvecyTpGLrqFrvkrUSoxxfJI5AH7U8zxxtVclpsUtMCq4JQ290LY8AW5c7Ggnr/Y/oK+bQMbqK2qmtk3pN4g==", "license": "(MIT OR GPL-3.0-or-later)", "dependencies": { "lie": "~3.3.0", @@ -9367,28 +10857,10 @@ "setimmediate": "^1.0.5" } }, - "node_modules/jszip/node_modules/readable-stream": { - "version": "2.3.8", - "license": "MIT", - "dependencies": { - "core-util-is": "~1.0.0", - "inherits": "~2.0.3", - "isarray": "~1.0.0", - "process-nextick-args": "~2.0.0", - "safe-buffer": "~5.1.1", - "string_decoder": "~1.1.1", - "util-deprecate": "~1.0.1" - } - }, - "node_modules/jszip/node_modules/string_decoder": { - "version": "1.1.1", - "license": "MIT", - "dependencies": { - "safe-buffer": "~5.1.0" - } - }, "node_modules/karma": { "version": "6.4.4", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.4.4.tgz", + "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, "license": "MIT", "dependencies": { @@ -9426,6 +10898,8 @@ }, "node_modules/karma-chrome-launcher": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", + "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", "dev": true, "license": "MIT", "dependencies": { @@ -9434,6 +10908,8 @@ }, "node_modules/karma-chrome-launcher/node_modules/which": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", "dev": true, "license": "ISC", "dependencies": { @@ -9445,6 +10921,8 @@ }, "node_modules/karma-coverage-istanbul-reporter": { "version": "3.0.3", + "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", + "integrity": "sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw==", "dev": true, "license": "MIT", "dependencies": { @@ -9484,6 +10962,8 @@ }, "node_modules/karma-jasmine": { "version": "4.0.2", + "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-4.0.2.tgz", + "integrity": "sha512-ggi84RMNQffSDmWSyyt4zxzh2CQGwsxvYYsprgyR1j8ikzIduEdOlcLvXjZGwXG/0j41KUXOWsUCBfbEHPWP9g==", "dev": true, "license": "MIT", "dependencies": { @@ -9498,6 +10978,8 @@ }, "node_modules/karma-jasmine-html-reporter": { "version": "1.7.0", + "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz", + "integrity": "sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -9508,9 +10990,62 @@ }, "node_modules/karma-jasmine/node_modules/jasmine-core": { "version": "3.99.1", + "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.99.1.tgz", + "integrity": "sha512-Hu1dmuoGcZ7AfyynN3LsfruwMbxMALMka+YtZeGoLuDEySVmVAPaonkNoBRIw/ectu8b9tVQCJNgp4a4knp+tg==", "dev": true, "license": "MIT" }, + "node_modules/karma/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/karma/node_modules/body-parser": { + "version": "1.20.5", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.5.tgz", + "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "~1.2.0", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "on-finished": "~2.4.1", + "qs": "~6.15.1", + "raw-body": "~2.5.3", + "type-is": "~1.6.18", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/karma/node_modules/brace-expansion": { "version": "1.1.15", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", @@ -9522,8 +11057,35 @@ "concat-map": "0.0.1" } }, + "node_modules/karma/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, "node_modules/karma/node_modules/cliui": { "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "license": "ISC", "dependencies": { @@ -9532,6 +11094,105 @@ "wrap-ansi": "^7.0.0" } }, + "node_modules/karma/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/karma/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/karma/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/karma/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/karma/node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/karma/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/karma/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/karma/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/karma/node_modules/minimatch": { "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", @@ -9545,16 +11206,111 @@ "node": "*" } }, + "node_modules/karma/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "dev": true, + "license": "MIT" + }, + "node_modules/karma/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/karma/node_modules/raw-body": { + "version": "2.5.3", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.3.tgz", + "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bytes": "~3.1.2", + "http-errors": "~2.0.1", + "iconv-lite": "~0.4.24", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/karma/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/karma/node_modules/source-map": { "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", "engines": { - "node": ">=0.10.0" + "node": ">=0.10.0" + } + }, + "node_modules/karma/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/karma/node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" } }, "node_modules/karma/node_modules/wrap-ansi": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", "dependencies": { @@ -9571,6 +11327,8 @@ }, "node_modules/karma/node_modules/yargs": { "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "license": "MIT", "dependencies": { @@ -9586,6 +11344,16 @@ "node": ">=10" } }, + "node_modules/karma/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -9597,6 +11365,8 @@ }, "node_modules/levn": { "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1", @@ -9608,6 +11378,8 @@ }, "node_modules/lie": { "version": "3.3.0", + "resolved": "https://registry.npmjs.org/lie/-/lie-3.3.0.tgz", + "integrity": "sha512-UaiMJzeWRlEujzAuw5LokY1L5ecNQYZKfmyZ9L7wDHb/p5etKaxXhohBcrw0EYby+G/NA52vRSN4N39dxHAIwQ==", "license": "MIT", "dependencies": { "immediate": "~3.0.5" @@ -9628,6 +11400,8 @@ }, "node_modules/lines-and-columns": { "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", "dev": true, "license": "MIT" }, @@ -9649,19 +11423,6 @@ "node": ">=20.0.0" } }, - "node_modules/listr2/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/listr2/node_modules/ansi-styles": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", @@ -9707,22 +11468,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/listr2/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/listr2/node_modules/wrap-ansi": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", @@ -9772,6 +11517,8 @@ }, "node_modules/load-json-file": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", + "integrity": "sha512-Kx8hMakjX03tiGTLAIdJ+lL0htKnXjEZN6hk/tozf/WOuYGdZBJrZ+rCJRbVCugsjB3jMLn9746NsQIf5VjBMw==", "dev": true, "license": "MIT", "dependencies": { @@ -9786,6 +11533,8 @@ }, "node_modules/load-json-file/node_modules/parse-json": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", + "integrity": "sha512-aOIos8bujGN93/8Ox/jPLh7RwVnPEysynVFE+fQZyg6jKELEHwzgKdLRFHUgXJL6kylijVSBC4BvN9OmsB48Rw==", "dev": true, "license": "MIT", "dependencies": { @@ -9816,6 +11565,8 @@ }, "node_modules/locate-path": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", "license": "MIT", "dependencies": { "p-locate": "^5.0.0" @@ -9840,50 +11591,10 @@ "dev": true, "license": "MIT" }, - "node_modules/lodash.camelcase": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", - "integrity": "sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.kebabcase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", - "integrity": "sha512-N8XRTIMMqqDgSy4VLKPnJ/+hpGZN+PHQiJnSenYqPaVV/NCqEogTnAdZLQiGKhxX+JCs8waWq2t1XHWKOmlY8g==", - "dev": true, - "license": "MIT" - }, "node_modules/lodash.merge": { "version": "4.6.2", - "license": "MIT" - }, - "node_modules/lodash.mergewith": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.mergewith/-/lodash.mergewith-4.6.2.tgz", - "integrity": "sha512-GK3g5RPZWTRSeLSpgP8Xhra+pnjBC56q9FZYe1d5RN3TJ35dbkGy3YqBSMbyCrlbi+CM9Z3Jk5yTL7RCsqboyQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.snakecase": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", - "integrity": "sha512-QZ1d4xoBHYUeuouhEq3lk3Uq7ldgyFXGBhg04+oRLnIz8o9T65Eh+8YdroUwn846zchkA9yDsDl5CVVaV2nqYw==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.startcase": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/lodash.startcase/-/lodash.startcase-4.4.0.tgz", - "integrity": "sha512-+WKqsK294HMSc2jEbNgpHpd0JfIBhp7rEV4aqXWqFr6AlXov+SlcgB1Fv01y2kGe3Gc8nMW7VA0SrGuSkRfIEg==", - "dev": true, - "license": "MIT" - }, - "node_modules/lodash.upperfirst": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", - "integrity": "sha512-sReKOYJIJf74dhJONhU4e0/shzi1trVbSWDOhKYE5XV2O+H7Sb2Dihwuc7xWxVl+DgFPyTqIN3zMfT9cq5iWDg==", - "dev": true, + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "license": "MIT" }, "node_modules/log-symbols": { @@ -9923,19 +11634,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/log-update/node_modules/ansi-styles": { "version": "6.2.3", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", @@ -9956,22 +11654,6 @@ "dev": true, "license": "MIT" }, - "node_modules/log-update/node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/log-update/node_modules/slice-ansi": { "version": "7.1.2", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-7.1.2.tgz", @@ -10007,22 +11689,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/log-update/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/log-update/node_modules/wrap-ansi": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", @@ -10043,6 +11709,8 @@ }, "node_modules/log4js": { "version": "6.9.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.9.1.tgz", + "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -10058,6 +11726,8 @@ }, "node_modules/lottie-web": { "version": "5.13.0", + "resolved": "https://registry.npmjs.org/lottie-web/-/lottie-web-5.13.0.tgz", + "integrity": "sha512-+gfBXl6sxXMPe8tKQm7qzLnUy5DUPJPKIyRHwtpCpyUEYjHYRJC/5gjUvdkuO2c3JllrPtHXH5UJJK8LRYl5yQ==", "license": "MIT" }, "node_modules/lru-cache": { @@ -10082,6 +11752,8 @@ }, "node_modules/make-dir": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", "dev": true, "license": "MIT", "dependencies": { @@ -10096,13 +11768,15 @@ }, "node_modules/make-error": { "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", "dev": true, "license": "ISC" }, "node_modules/make-fetch-happen": { - "version": "15.0.5", - "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.5.tgz", - "integrity": "sha512-uCbIa8jWWmQZt4dSnEStkVC6gdakiinAm4PiGsywIkguF0eWMdcjDz0ECYhUolFU3pFLOev9VNPCEygydXnddg==", + "version": "15.0.6", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-15.0.6.tgz", + "integrity": "sha512-Je0fLJ0F5atA7F+eIlLzk+Wkcl57JDf4kf+EW8xiP5E31xOQxkIxTbgf1Oi1Lw9tRI9UEMRdI5Vz2xTzoNU1Jw==", "dev": true, "license": "ISC", "dependencies": { @@ -10137,6 +11811,8 @@ }, "node_modules/math-intrinsics": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", "dev": true, "license": "MIT", "engines": { @@ -10144,15 +11820,19 @@ } }, "node_modules/media-typer": { - "version": "0.3.0", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/memorystream": { "version": "0.3.1", + "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", + "integrity": "sha512-S3UwM3yj5mtUSEfP41UZmt/0SCoVYUcU1rkXv+BQ5Ig8ndL4sPoJNBUJERafdPb5jjHJGuMgytgKvKIf58XNBw==", "dev": true, "engines": { "node": ">= 0.10.0" @@ -10223,6 +11903,8 @@ }, "node_modules/mime": { "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.6.0.tgz", + "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true, "license": "MIT", "bin": { @@ -10233,7 +11915,9 @@ } }, "node_modules/mime-db": { - "version": "1.52.0", + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", "dev": true, "license": "MIT", "engines": { @@ -10241,14 +11925,20 @@ } }, "node_modules/mime-types": { - "version": "2.1.35", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-3.0.2.tgz", + "integrity": "sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==", "dev": true, "license": "MIT", "dependencies": { - "mime-db": "1.52.0" + "mime-db": "^1.54.0" }, "engines": { - "node": ">= 0.6" + "node": ">=18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, "node_modules/mimic-function": { @@ -10264,6 +11954,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/minimatch": { "version": "9.0.9", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.9.tgz", @@ -10282,6 +11985,8 @@ }, "node_modules/minimist": { "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", "dev": true, "license": "MIT", "funding": { @@ -10423,6 +12128,8 @@ }, "node_modules/mkdirp": { "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", "dependencies": { @@ -10466,6 +12173,8 @@ }, "node_modules/moment": { "version": "2.30.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", + "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==", "license": "MIT", "engines": { "node": "*" @@ -10505,12 +12214,14 @@ }, "node_modules/ms": { "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", "license": "MIT" }, "node_modules/msgpackr": { - "version": "1.11.10", - "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.11.10.tgz", - "integrity": "sha512-iCZNq+HszvF+fC3anCm4nBmWEnbeIAfpDs6IStAEKhQ2YSgkjzVG2FF9XJqwwQh5bH3N9OUTUt4QwVN6MLMLtA==", + "version": "1.12.1", + "resolved": "https://registry.npmjs.org/msgpackr/-/msgpackr-1.12.1.tgz", + "integrity": "sha512-4EUH9tQHnMmEgzW/MdAP0KIfa1T9AF+htl0ffe2n5vb2EKn9y2co8ccpgWko6S52Jy1PQZKwRnx5/KkYjtd9MQ==", "dev": true, "license": "MIT", "optional": true, @@ -10519,9 +12230,9 @@ } }, "node_modules/msgpackr-extract": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.3.tgz", - "integrity": "sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==", + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/msgpackr-extract/-/msgpackr-extract-3.0.4.tgz", + "integrity": "sha512-4kmO/MdyUIkLIvTPr8VHLil4AtoKIoniWPIEk5+CDy0xnWC84azhSFmuJ7PxZdsYtiP5kEeQsORAVIeMgxT+Hw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -10533,12 +12244,12 @@ "download-msgpackr-prebuilds": "bin/download-prebuilds.js" }, "optionalDependencies": { - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.3", - "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.3" + "@msgpackr-extract/msgpackr-extract-darwin-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-darwin-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-arm64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-linux-x64": "3.0.4", + "@msgpackr-extract/msgpackr-extract-win32-x64": "3.0.4" } }, "node_modules/mute-stream": { @@ -10563,6 +12274,13 @@ "thenify-all": "^1.0.0" } }, + "node_modules/nan": { + "version": "2.27.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.27.0.tgz", + "integrity": "sha512-hC+0LidcL3XE4rp1C4H54KujgXKzbfyTngZTwBByQxsOxCEKZT0MPQ4hOKUH2jU1OYstqdDH4onyHPDzcV0XdQ==", + "license": "MIT", + "optional": true + }, "node_modules/nanoid": { "version": "3.3.12", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", @@ -10584,6 +12302,8 @@ }, "node_modules/natural-compare": { "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", "license": "MIT" }, "node_modules/negotiator": { @@ -10612,6 +12332,8 @@ }, "node_modules/ng-flex-layout": { "version": "17.3.7-beta.1", + "resolved": "https://registry.npmjs.org/ng-flex-layout/-/ng-flex-layout-17.3.7-beta.1.tgz", + "integrity": "sha512-MTjlQUldB/hEsn0DY/RoY2SKBQoyaKltlOOFjCjH2OfcYA3COHhkJS3PZe9NAjR7TBDb9Ve989m18bSucRzACQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -10648,6 +12370,8 @@ }, "node_modules/ngx-lottie": { "version": "11.0.2", + "resolved": "https://registry.npmjs.org/ngx-lottie/-/ngx-lottie-11.0.2.tgz", + "integrity": "sha512-sQhCTxfrzWpjN2HVFCSyAQYQg8ZjZVtO1xIhOkrJNHY3/TR/zZkVrhakWcaM5bVxyA7gfUnK3ox+iK59Yd8Bsw==", "license": "MIT", "dependencies": { "@scarf/scarf": "^1.1.1", @@ -10693,10 +12417,31 @@ "license": "MIT", "optional": true }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "optional": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, "node_modules/node-gyp": { - "version": "12.3.0", - "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.3.0.tgz", - "integrity": "sha512-QNcUWM+HgJplcPzBvFBZ9VXacyGZ4+VTOb80PwWR+TlVzoHbRKULNEzpRsnaoxG3Wzr7Qh7BYxGDU3CbKib2Yg==", + "version": "12.4.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.4.0.tgz", + "integrity": "sha512-OMcPNvqTCFUnNaBlmdgq+lfNqY7gTiSmNRDjY3uAXRyudeKZEZxu3CLtjMQrx4zZxCX2b/mpNqTtwuCJgXhHkw==", "dev": true, "license": "MIT", "dependencies": { @@ -10734,16 +12479,6 @@ "node-gyp-build-optional-packages-test": "build-test.js" } }, - "node_modules/node-gyp/node_modules/abbrev": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-4.0.0.tgz", - "integrity": "sha512-a1wflyaL0tHtJSmLSOVybYhy22vRih4eduhhrkcjgrWGnRfrZtovJ2FRjxuTtkkj47O/baf0R86QU5OuYpz8fA==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/node-gyp/node_modules/isexe": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-4.0.0.tgz", @@ -10754,22 +12489,6 @@ "node": ">=20" } }, - "node_modules/node-gyp/node_modules/nopt": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz", - "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==", - "dev": true, - "license": "ISC", - "dependencies": { - "abbrev": "^4.0.0" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/node-gyp/node_modules/undici": { "version": "6.26.0", "resolved": "https://registry.npmjs.org/undici/-/undici-6.26.0.tgz", @@ -10806,8 +12525,56 @@ "node": ">=18" } }, + "node_modules/nopt": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-9.0.0.tgz", + "integrity": "sha512-Zhq3a+yFKrYwSBluL4H9XP3m3y5uvQkB/09CwDruCiRmR/UJYnn9W4R48ry0uGC70aeTPKLynBtscP9efFFcPw==", + "dev": true, + "license": "ISC", + "dependencies": { + "abbrev": "^4.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^20.17.0 || >=22.9.0" + } + }, + "node_modules/normalize-package-data": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", + "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "hosted-git-info": "^2.1.4", + "resolve": "^1.10.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "node_modules/normalize-package-data/node_modules/hosted-git-info": { + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.9.tgz", + "integrity": "sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==", + "dev": true, + "license": "ISC" + }, + "node_modules/normalize-package-data/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, "node_modules/normalize-path": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", "engines": { @@ -10816,6 +12583,8 @@ }, "node_modules/normalize-range": { "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", "dev": true, "license": "MIT", "engines": { @@ -10835,16 +12604,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm-bundled/node_modules/npm-normalize-package-bin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", - "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/npm-install-checks": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-8.0.0.tgz", @@ -10859,13 +12618,13 @@ } }, "node_modules/npm-normalize-package-bin": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", - "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", + "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", "dev": true, "license": "ISC", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/npm-package-arg": { @@ -10914,16 +12673,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/npm-pick-manifest/node_modules/npm-normalize-package-bin": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-5.0.0.tgz", - "integrity": "sha512-CJi3OS4JLsNMmr2u07OJlhcrPxCeOeP/4xq67aWNai6TNWWbTrlNDgl8NcFKVlcBKp18GPj+EzbNIgrBfZhsag==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, "node_modules/npm-registry-fetch": { "version": "19.1.1", "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-19.1.1.tgz", @@ -10946,6 +12695,8 @@ }, "node_modules/npm-run-all2": { "version": "7.0.2", + "resolved": "https://registry.npmjs.org/npm-run-all2/-/npm-run-all2-7.0.2.tgz", + "integrity": "sha512-7tXR+r9hzRNOPNTvXegM+QzCuMjzUIIq66VDunL6j60O4RrExx32XUhlrS7UK4VcdGw5/Wxzb3kfNcFix9JKDA==", "dev": true, "license": "MIT", "dependencies": { @@ -10971,6 +12722,8 @@ }, "node_modules/npm-run-all2/node_modules/ansi-styles": { "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", "dev": true, "license": "MIT", "engines": { @@ -10982,6 +12735,8 @@ }, "node_modules/npm-run-all2/node_modules/isexe": { "version": "3.1.5", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.5.tgz", + "integrity": "sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -10990,6 +12745,8 @@ }, "node_modules/npm-run-all2/node_modules/which": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-5.0.0.tgz", + "integrity": "sha512-JEdGzHwwkrbWoGOlIHqQ5gtprKGOenpDHpxE9zVR1bWbOtYRyPPHMe9FaP6x61CmNaTThSkb0DAJte5jD+DmzQ==", "dev": true, "license": "ISC", "dependencies": { @@ -11002,6 +12759,20 @@ "node": "^18.17.0 || >=20.5.0" } }, + "node_modules/npmlog": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-5.0.1.tgz", + "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", + "deprecated": "This package is no longer supported.", + "license": "ISC", + "optional": true, + "dependencies": { + "are-we-there-yet": "^2.0.0", + "console-control-strings": "^1.1.0", + "gauge": "^3.0.0", + "set-blocking": "^2.0.0" + } + }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", @@ -11017,11 +12788,15 @@ }, "node_modules/num2fraction": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha512-Y1wZESM7VUThYY+4W+X4ySH2maqcA+p7UR+w8VWNWVAd6lwuXXWz/w/Cz43J/dI2I+PS6wD5N+bJUF+gjWvIqg==", "dev": true, "license": "MIT" }, "node_modules/nvd3": { "version": "1.8.6", + "resolved": "https://registry.npmjs.org/nvd3/-/nvd3-1.8.6.tgz", + "integrity": "sha512-YGQ9hAQHuQCF0JmYkT2GhNMHb5pA+vDfQj6C2GdpQPzdRPj/srPG3mh/3fZzUFt+at1NusLk/RqICUWkxm4viQ==", "license": "Apache-2.0", "peerDependencies": { "d3": "^3.4.4" @@ -11029,6 +12804,8 @@ }, "node_modules/oauth-sign": { "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "dev": true, "license": "Apache-2.0", "engines": { @@ -11037,7 +12814,9 @@ }, "node_modules/object-assign": { "version": "4.1.1", - "dev": true, + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11055,6 +12834,8 @@ }, "node_modules/object-inspect": { "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, "license": "MIT", "engines": { @@ -11065,7 +12846,9 @@ } }, "node_modules/on-finished": { - "version": "2.3.0", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", "dev": true, "license": "MIT", "dependencies": { @@ -11077,7 +12860,9 @@ }, "node_modules/once": { "version": "1.4.0", - "dev": true, + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "devOptional": true, "license": "ISC", "dependencies": { "wrappy": "1" @@ -11101,6 +12886,8 @@ }, "node_modules/optionator": { "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", "license": "MIT", "dependencies": { "deep-is": "^0.1.3", @@ -11137,19 +12924,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/ora/node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, "node_modules/ora/node_modules/chalk": { "version": "5.6.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", @@ -11163,39 +12937,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/ora/node_modules/string-width": { - "version": "8.2.1", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", - "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.5.0", - "strip-ansi": "^7.1.2" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ora/node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.2.2" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, "node_modules/ordered-binary": { "version": "1.6.1", "resolved": "https://registry.npmjs.org/ordered-binary/-/ordered-binary-1.6.1.tgz", @@ -11206,6 +12947,8 @@ }, "node_modules/os-tmpdir": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", "dev": true, "license": "MIT", "engines": { @@ -11214,6 +12957,8 @@ }, "node_modules/p-limit": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", "license": "MIT", "dependencies": { "yocto-queue": "^0.1.0" @@ -11227,6 +12972,8 @@ }, "node_modules/p-locate": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", "license": "MIT", "dependencies": { "p-limit": "^3.0.2" @@ -11253,6 +13000,8 @@ }, "node_modules/p-try": { "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", "license": "MIT", "engines": { "node": ">=6" @@ -11292,10 +13041,14 @@ }, "node_modules/pako": { "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", "license": "(MIT AND Zlib)" }, "node_modules/parent-module": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -11316,6 +13069,8 @@ }, "node_modules/parse-json": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", "dev": true, "license": "MIT", "dependencies": { @@ -11333,6 +13088,8 @@ }, "node_modules/parse-json/node_modules/json-parse-even-better-errors": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", "dev": true, "license": "MIT" }, @@ -11410,6 +13167,8 @@ }, "node_modules/parseurl": { "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", "dev": true, "license": "MIT", "engines": { @@ -11418,6 +13177,8 @@ }, "node_modules/path-exists": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", "license": "MIT", "engines": { "node": ">=8" @@ -11425,7 +13186,9 @@ }, "node_modules/path-is-absolute": { "version": "1.0.1", - "dev": true, + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "devOptional": true, "license": "MIT", "engines": { "node": ">=0.10.0" @@ -11433,11 +13196,15 @@ }, "node_modules/path-is-inside": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", + "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", "dev": true, "license": "(WTFPL OR MIT)" }, "node_modules/path-key": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", "license": "MIT", "engines": { "node": ">=8" @@ -11445,6 +13212,8 @@ }, "node_modules/path-parse": { "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", "dev": true, "license": "MIT" }, @@ -11486,6 +13255,19 @@ "url": "https://opencollective.com/express" } }, + "node_modules/path-type": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", + "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", + "dev": true, + "license": "MIT", + "dependencies": { + "pify": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/path2d-polyfill": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", @@ -11518,11 +13300,15 @@ }, "node_modules/performance-now": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", "dev": true, "license": "MIT" }, "node_modules/picocolors": { "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, "license": "ISC" }, @@ -11539,7 +13325,9 @@ } }, "node_modules/pidtree": { - "version": "0.6.0", + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.1.tgz", + "integrity": "sha512-e0F9AOF1JMrCfBsyJOwU9lNvQ0WtXTq0j/4jk0BQ5JSI9VAybPXmDpPRw/2FQ3e5d3ZFN1mLh7jW99m/jjaptw==", "dev": true, "license": "MIT", "bin": { @@ -11551,6 +13339,8 @@ }, "node_modules/pify": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", "dev": true, "license": "MIT", "engines": { @@ -11559,6 +13349,8 @@ }, "node_modules/pinkie": { "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", "dev": true, "license": "MIT", "engines": { @@ -11567,6 +13359,8 @@ }, "node_modules/pinkie-promise": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", "dev": true, "license": "MIT", "dependencies": { @@ -11623,6 +13417,8 @@ }, "node_modules/pngjs": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", "license": "MIT", "engines": { "node": ">=10.13.0" @@ -11630,6 +13426,8 @@ }, "node_modules/positioning": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/positioning/-/positioning-2.0.1.tgz", + "integrity": "sha512-DsAgM42kV/ObuwlRpAzDTjH9E8fGKkMDJHWFX+kfNXSxh7UCCQxEmdjv/Ws5Ft1XDnt3JT8fIDYeKNSE2TbttA==", "license": "MIT" }, "node_modules/postcss": { @@ -11817,6 +13615,8 @@ }, "node_modules/postcss-scss": { "version": "0.1.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-0.1.9.tgz", + "integrity": "sha512-FkLd8Pxci394edesXqewjAd6eMnYGUPK5bgkYbYHX7YPeJDcuaKMuHnXsd0i3tnXJOLTuX+L+m3edda1IKMrbQ==", "dev": true, "license": "MIT", "dependencies": { @@ -11825,6 +13625,8 @@ }, "node_modules/postcss-scss/node_modules/ansi-regex": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "license": "MIT", "engines": { @@ -11833,6 +13635,8 @@ }, "node_modules/postcss-scss/node_modules/ansi-styles": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "license": "MIT", "engines": { @@ -11841,6 +13645,8 @@ }, "node_modules/postcss-scss/node_modules/chalk": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "license": "MIT", "dependencies": { @@ -11856,30 +13662,18 @@ }, "node_modules/postcss-scss/node_modules/chalk/node_modules/supports-color": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" } }, - "node_modules/postcss-scss/node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/postcss-scss/node_modules/has-flag": { - "version": "1.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/postcss-scss/node_modules/postcss": { "version": "5.2.18", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", + "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", "dev": true, "license": "MIT", "dependencies": { @@ -11894,6 +13688,8 @@ }, "node_modules/postcss-scss/node_modules/source-map": { "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -11902,6 +13698,8 @@ }, "node_modules/postcss-scss/node_modules/strip-ansi": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "license": "MIT", "dependencies": { @@ -11911,17 +13709,6 @@ "node": ">=0.10.0" } }, - "node_modules/postcss-scss/node_modules/supports-color": { - "version": "3.2.3", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^1.0.0" - }, - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/postcss-selector-parser": { "version": "6.1.2", "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", @@ -11938,11 +13725,15 @@ }, "node_modules/postcss-value-parser": { "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", "dev": true, "license": "MIT" }, "node_modules/prelude-ls": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", "license": "MIT", "engines": { "node": ">= 0.8.0" @@ -11989,6 +13780,8 @@ }, "node_modules/process-nextick-args": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT" }, "node_modules/promise-retry": { @@ -12007,6 +13800,9 @@ }, "node_modules/protractor": { "version": "7.0.0", + "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", + "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", + "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", "dev": true, "license": "MIT", "dependencies": { @@ -12036,6 +13832,8 @@ }, "node_modules/protractor/node_modules/ansi-regex": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "license": "MIT", "engines": { @@ -12044,6 +13842,8 @@ }, "node_modules/protractor/node_modules/ansi-styles": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "license": "MIT", "engines": { @@ -12052,6 +13852,8 @@ }, "node_modules/protractor/node_modules/chalk": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "license": "MIT", "dependencies": { @@ -12067,6 +13869,8 @@ }, "node_modules/protractor/node_modules/cliui": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "dev": true, "license": "ISC", "dependencies": { @@ -12077,6 +13881,8 @@ }, "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", "engines": { @@ -12085,6 +13891,8 @@ }, "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", "dependencies": { @@ -12094,16 +13902,10 @@ "node": ">=8" } }, - "node_modules/protractor/node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/protractor/node_modules/find-up": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "dev": true, "license": "MIT", "dependencies": { @@ -12114,8 +13916,20 @@ "node": ">=8" } }, + "node_modules/protractor/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/protractor/node_modules/locate-path": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "dev": true, "license": "MIT", "dependencies": { @@ -12127,6 +13941,8 @@ }, "node_modules/protractor/node_modules/p-limit": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "dev": true, "license": "MIT", "dependencies": { @@ -12141,6 +13957,8 @@ }, "node_modules/protractor/node_modules/p-locate": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "dev": true, "license": "MIT", "dependencies": { @@ -12152,6 +13970,8 @@ }, "node_modules/protractor/node_modules/source-map": { "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -12160,14 +13980,56 @@ }, "node_modules/protractor/node_modules/source-map-support": { "version": "0.4.18", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", + "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", "dev": true, "license": "MIT", "dependencies": { "source-map": "^0.5.6" } }, + "node_modules/protractor/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/string-width/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/protractor/node_modules/string-width/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/protractor/node_modules/strip-ansi": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "license": "MIT", "dependencies": { @@ -12179,6 +14041,8 @@ }, "node_modules/protractor/node_modules/supports-color": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "license": "MIT", "engines": { @@ -12187,11 +14051,15 @@ }, "node_modules/protractor/node_modules/y18n": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "dev": true, "license": "ISC" }, "node_modules/protractor/node_modules/yargs": { "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "dev": true, "license": "MIT", "dependencies": { @@ -12213,6 +14081,8 @@ }, "node_modules/protractor/node_modules/yargs-parser": { "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "dev": true, "license": "ISC", "dependencies": { @@ -12239,6 +14109,8 @@ }, "node_modules/psl": { "version": "1.15.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", + "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", "dev": true, "license": "MIT", "dependencies": { @@ -12250,6 +14122,8 @@ }, "node_modules/psl/node_modules/punycode": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", "engines": { @@ -12258,6 +14132,8 @@ }, "node_modules/punycode": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "dev": true, "license": "MIT" }, @@ -12275,6 +14151,8 @@ }, "node_modules/qjobs": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true, "license": "MIT", "engines": { @@ -12283,6 +14161,8 @@ }, "node_modules/qrcode": { "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", "license": "MIT", "dependencies": { "dijkstrajs": "^1.0.1", @@ -12296,8 +14176,19 @@ "node": ">=10.13.0" } }, + "node_modules/qrcode/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/qrcode/node_modules/cliui": { "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", "license": "ISC", "dependencies": { "string-width": "^4.2.0", @@ -12307,6 +14198,8 @@ }, "node_modules/qrcode/node_modules/find-up": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", "license": "MIT", "dependencies": { "locate-path": "^5.0.0", @@ -12316,8 +14209,19 @@ "node": ">=8" } }, + "node_modules/qrcode/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/qrcode/node_modules/locate-path": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", "license": "MIT", "dependencies": { "p-locate": "^4.1.0" @@ -12328,6 +14232,8 @@ }, "node_modules/qrcode/node_modules/p-limit": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -12341,6 +14247,8 @@ }, "node_modules/qrcode/node_modules/p-locate": { "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", "license": "MIT", "dependencies": { "p-limit": "^2.2.0" @@ -12349,12 +14257,42 @@ "node": ">=8" } }, + "node_modules/qrcode/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/qrcode/node_modules/y18n": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "license": "ISC" }, "node_modules/qrcode/node_modules/yargs": { "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", "license": "MIT", "dependencies": { "cliui": "^6.0.0", @@ -12375,6 +14313,8 @@ }, "node_modules/qrcode/node_modules/yargs-parser": { "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", "license": "ISC", "dependencies": { "camelcase": "^5.0.0", @@ -12440,6 +14380,8 @@ }, "node_modules/range-parser": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", "dev": true, "license": "MIT", "engines": { @@ -12447,28 +14389,19 @@ } }, "node_modules/raw-body": { - "version": "2.5.3", + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-3.0.2.tgz", + "integrity": "sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==", "dev": true, "license": "MIT", "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", - "iconv-lite": "~0.4.24", + "iconv-lite": "~0.7.0", "unpipe": "~1.0.0" }, "engines": { - "node": ">= 0.8" - } - }, - "node_modules/raw-body/node_modules/iconv-lite": { - "version": "0.4.24", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" + "node": ">= 0.10" } }, "node_modules/read-cache": { @@ -12493,6 +14426,8 @@ }, "node_modules/read-package-json-fast": { "version": "4.0.0", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz", + "integrity": "sha512-qpt8EwugBWDw2cgE2W+/3oxC+KTez2uSVR8JU9Q36TXPAGCaozfQUs59v4j4GFpWTaw0i6hAZSvOmu1J0uOEUg==", "dev": true, "license": "ISC", "dependencies": { @@ -12503,76 +14438,68 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/read-pkg": { - "version": "3.0.0", + "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-4.0.0.tgz", + "integrity": "sha512-lR4MXjGNgkJc7tkQ97kb2nuEMnNCyU//XYVH0MKTGcXEiSudQ5MKGKen3C5QubYy0vmq+JGitUg92uuywGEwIA==", "dev": true, "license": "MIT", - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - }, "engines": { - "node": ">=4" + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/read-pkg/node_modules/hosted-git-info": { - "version": "2.8.9", - "dev": true, - "license": "ISC" - }, - "node_modules/read-pkg/node_modules/normalize-package-data": { - "version": "2.5.0", + "node_modules/read-package-json-fast/node_modules/npm-normalize-package-bin": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-4.0.0.tgz", + "integrity": "sha512-TZKxPvItzai9kN9H/TkmCtx/ZN/hvr3vUycjlfmH0ootY9yFBzNOpiXAdIn1Iteqsvk4lQn6B5PTrt+n6h8k/w==", "dev": true, - "license": "BSD-2-Clause", - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" + "license": "ISC", + "engines": { + "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/read-pkg/node_modules/path-type": { + "node_modules/read-pkg": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", + "integrity": "sha512-BLq/cCO9two+lBgiTYNqD6GdtK8s4NpaWrl6/rCO9w0TUS8oJl7cmToOZfRYllKTISY6nt1U7jQ53brmKqY6BA==", "dev": true, "license": "MIT", "dependencies": { - "pify": "^3.0.0" + "load-json-file": "^4.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^3.0.0" }, "engines": { "node": ">=4" } }, - "node_modules/read-pkg/node_modules/semver": { - "version": "5.7.2", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/readdirp": { - "version": "3.6.0", - "dev": true, + "node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", "license": "MIT", "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" } }, - "node_modules/readdirp/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "node_modules/readdirp": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.0.0.tgz", + "integrity": "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">= 20.19.0" }, "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, "node_modules/reflect-metadata": { @@ -12584,6 +14511,9 @@ }, "node_modules/request": { "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -12609,7 +14539,30 @@ "uuid": "^3.3.2" }, "engines": { - "node": ">= 6" + "node": ">= 6" + } + }, + "node_modules/request/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/request/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" } }, "node_modules/request/node_modules/qs": { @@ -12624,6 +14577,8 @@ }, "node_modules/require-directory": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -12631,6 +14586,8 @@ }, "node_modules/require-from-string": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "dev": true, "license": "MIT", "engines": { @@ -12639,21 +14596,26 @@ }, "node_modules/require-main-filename": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", "license": "ISC" }, "node_modules/requires-port": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true, "license": "MIT" }, "node_modules/resolve": { - "version": "1.22.10", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz", - "integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==", + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", "dev": true, "license": "MIT", "dependencies": { - "is-core-module": "^2.16.0", + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", "path-parse": "^1.0.7", "supports-preserve-symlinks-flag": "^1.0.0" }, @@ -12669,6 +14631,8 @@ }, "node_modules/resolve-from": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", "dev": true, "license": "MIT", "engines": { @@ -12715,11 +14679,16 @@ }, "node_modules/rfdc": { "version": "1.4.1", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.4.1.tgz", + "integrity": "sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==", "license": "MIT" }, "node_modules/rimraf": { "version": "3.0.2", - "dev": true, + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", + "devOptional": true, "license": "ISC", "dependencies": { "glob": "^7.1.3" @@ -12764,13 +14733,13 @@ } }, "node_modules/rollup": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz", - "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==", + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.1.tgz", + "integrity": "sha512-I4KW6iuRpuu2uHBLraZ1wNZe0DP7lnRha+VJ9tNaYVaVgKhW0aI3h4RYnoRPeql0flHm/Co55b7snEDcOfOJrA==", "dev": true, "license": "MIT", "dependencies": { - "@types/estree": "1.0.8" + "@types/estree": "1.0.9" }, "bin": { "rollup": "dist/bin/rollup" @@ -12780,48 +14749,34 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.60.2", - "@rollup/rollup-android-arm64": "4.60.2", - "@rollup/rollup-darwin-arm64": "4.60.2", - "@rollup/rollup-darwin-x64": "4.60.2", - "@rollup/rollup-freebsd-arm64": "4.60.2", - "@rollup/rollup-freebsd-x64": "4.60.2", - "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", - "@rollup/rollup-linux-arm-musleabihf": "4.60.2", - "@rollup/rollup-linux-arm64-gnu": "4.60.2", - "@rollup/rollup-linux-arm64-musl": "4.60.2", - "@rollup/rollup-linux-loong64-gnu": "4.60.2", - "@rollup/rollup-linux-loong64-musl": "4.60.2", - "@rollup/rollup-linux-ppc64-gnu": "4.60.2", - "@rollup/rollup-linux-ppc64-musl": "4.60.2", - "@rollup/rollup-linux-riscv64-gnu": "4.60.2", - "@rollup/rollup-linux-riscv64-musl": "4.60.2", - "@rollup/rollup-linux-s390x-gnu": "4.60.2", - "@rollup/rollup-linux-x64-gnu": "4.60.2", - "@rollup/rollup-linux-x64-musl": "4.60.2", - "@rollup/rollup-openbsd-x64": "4.60.2", - "@rollup/rollup-openharmony-arm64": "4.60.2", - "@rollup/rollup-win32-arm64-msvc": "4.60.2", - "@rollup/rollup-win32-ia32-msvc": "4.60.2", - "@rollup/rollup-win32-x64-gnu": "4.60.2", - "@rollup/rollup-win32-x64-msvc": "4.60.2", + "@rollup/rollup-android-arm-eabi": "4.61.1", + "@rollup/rollup-android-arm64": "4.61.1", + "@rollup/rollup-darwin-arm64": "4.61.1", + "@rollup/rollup-darwin-x64": "4.61.1", + "@rollup/rollup-freebsd-arm64": "4.61.1", + "@rollup/rollup-freebsd-x64": "4.61.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.61.1", + "@rollup/rollup-linux-arm-musleabihf": "4.61.1", + "@rollup/rollup-linux-arm64-gnu": "4.61.1", + "@rollup/rollup-linux-arm64-musl": "4.61.1", + "@rollup/rollup-linux-loong64-gnu": "4.61.1", + "@rollup/rollup-linux-loong64-musl": "4.61.1", + "@rollup/rollup-linux-ppc64-gnu": "4.61.1", + "@rollup/rollup-linux-ppc64-musl": "4.61.1", + "@rollup/rollup-linux-riscv64-gnu": "4.61.1", + "@rollup/rollup-linux-riscv64-musl": "4.61.1", + "@rollup/rollup-linux-s390x-gnu": "4.61.1", + "@rollup/rollup-linux-x64-gnu": "4.61.1", + "@rollup/rollup-linux-x64-musl": "4.61.1", + "@rollup/rollup-openbsd-x64": "4.61.1", + "@rollup/rollup-openharmony-arm64": "4.61.1", + "@rollup/rollup-win32-arm64-msvc": "4.61.1", + "@rollup/rollup-win32-ia32-msvc": "4.61.1", + "@rollup/rollup-win32-x64-gnu": "4.61.1", + "@rollup/rollup-win32-x64-msvc": "4.61.1", "fsevents": "~2.3.2" } }, - "node_modules/rollup/node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.60.2", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", - "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, "node_modules/router": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/router/-/router-2.2.0.tgz", @@ -12839,13 +14794,6 @@ "node": ">= 18" } }, - "node_modules/router/node_modules/is-promise": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", - "integrity": "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==", - "dev": true, - "license": "MIT" - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -12872,6 +14820,8 @@ }, "node_modules/rx": { "version": "2.3.24", + "resolved": "https://registry.npmjs.org/rx/-/rx-2.3.24.tgz", + "integrity": "sha512-Ue4ZB7Dzbn2I9sIj8ws536nOP2S53uypyCkCz9q0vlYD5Kn6/pu4dE+wt2ZfFzd9m73hiYKnnCb1OyKqc+MRkg==", "dev": true }, "node_modules/rxjs": { @@ -12885,10 +14835,14 @@ }, "node_modules/safe-buffer": { "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "license": "MIT" }, "node_modules/safe-regex-test": { "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, "license": "MIT", "dependencies": { @@ -12905,56 +14859,36 @@ }, "node_modules/safer-buffer": { "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", "dev": true, "license": "MIT" }, "node_modules/sass": { - "version": "1.97.3", + "version": "1.100.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.100.0.tgz", + "integrity": "sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==", "dev": true, "license": "MIT", "dependencies": { - "chokidar": "^4.0.0", - "immutable": "^5.0.2", + "chokidar": "^5.0.0", + "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { "sass": "sass.js" }, "engines": { - "node": ">=14.0.0" + "node": ">=20.19.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" } }, - "node_modules/sass/node_modules/chokidar": { - "version": "4.0.3", - "dev": true, - "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, - "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - } - }, - "node_modules/sass/node_modules/readdirp": { - "version": "4.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/saucelabs": { "version": "1.5.0", + "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", + "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", "dev": true, "dependencies": { "https-proxy-agent": "^2.2.1" @@ -12965,6 +14899,8 @@ }, "node_modules/saucelabs/node_modules/agent-base": { "version": "4.3.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", + "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", "dev": true, "license": "MIT", "dependencies": { @@ -12976,6 +14912,8 @@ }, "node_modules/saucelabs/node_modules/debug": { "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", "dev": true, "license": "MIT", "dependencies": { @@ -12984,6 +14922,8 @@ }, "node_modules/saucelabs/node_modules/https-proxy-agent": { "version": "2.2.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", + "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", "dev": true, "license": "MIT", "dependencies": { @@ -12995,7 +14935,9 @@ } }, "node_modules/sax": { - "version": "1.4.4", + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", + "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", "dev": true, "license": "BlueOak-1.0.0", "engines": { @@ -13004,6 +14946,8 @@ }, "node_modules/selenium-webdriver": { "version": "3.6.0", + "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", + "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -13018,6 +14962,9 @@ }, "node_modules/selenium-webdriver/node_modules/rimraf": { "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -13029,6 +14976,8 @@ }, "node_modules/selenium-webdriver/node_modules/tmp": { "version": "0.0.30", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", + "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", "dev": true, "license": "MIT", "dependencies": { @@ -13050,21 +14999,76 @@ "node": ">=10" } }, + "node_modules/send": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/send/-/send-1.2.1.tgz", + "integrity": "sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.4.3", + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "etag": "^1.8.1", + "fresh": "^2.0.0", + "http-errors": "^2.0.1", + "mime-types": "^3.0.2", + "ms": "^2.1.3", + "on-finished": "^2.4.1", + "range-parser": "^1.2.1", + "statuses": "^2.0.2" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/serve-static": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", + "integrity": "sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==", + "dev": true, + "license": "MIT", + "dependencies": { + "encodeurl": "^2.0.0", + "escape-html": "^1.0.3", + "parseurl": "^1.3.3", + "send": "^1.2.0" + }, + "engines": { + "node": ">= 18" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, "node_modules/set-blocking": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", "license": "ISC" }, "node_modules/setimmediate": { "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", "license": "MIT" }, "node_modules/setprototypeof": { "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==", "dev": true, "license": "ISC" }, "node_modules/shebang-command": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -13075,13 +15079,17 @@ }, "node_modules/shebang-regex": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", "engines": { "node": ">=8" } }, "node_modules/shell-quote": { - "version": "1.8.3", + "version": "1.8.4", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.4.tgz", + "integrity": "sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==", "dev": true, "license": "MIT", "engines": { @@ -13093,6 +15101,8 @@ }, "node_modules/showdown": { "version": "1.9.1", + "resolved": "https://registry.npmjs.org/showdown/-/showdown-1.9.1.tgz", + "integrity": "sha512-9cGuS382HcvExtf5AHk7Cb4pAeQQ+h0eTr33V1mu+crYWV4KvWAw6el92bDrqGEk5d46Ai/fhbEUwqJ/mTCNEA==", "license": "BSD-3-Clause", "dependencies": { "yargs": "^14.2" @@ -13103,23 +15113,17 @@ }, "node_modules/showdown/node_modules/ansi-regex": { "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/showdown/node_modules/ansi-styles": { - "version": "3.2.1", - "license": "MIT", - "dependencies": { - "color-convert": "^1.9.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/showdown/node_modules/cliui": { "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", "license": "ISC", "dependencies": { "string-width": "^3.1.0", @@ -13127,23 +15131,16 @@ "wrap-ansi": "^5.1.0" } }, - "node_modules/showdown/node_modules/color-convert": { - "version": "1.9.3", - "license": "MIT", - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/showdown/node_modules/color-name": { - "version": "1.1.3", - "license": "MIT" - }, "node_modules/showdown/node_modules/emoji-regex": { "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", "license": "MIT" }, "node_modules/showdown/node_modules/find-up": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", "license": "MIT", "dependencies": { "locate-path": "^3.0.0" @@ -13154,6 +15151,8 @@ }, "node_modules/showdown/node_modules/is-fullwidth-code-point": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", "license": "MIT", "engines": { "node": ">=4" @@ -13161,6 +15160,8 @@ }, "node_modules/showdown/node_modules/locate-path": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", "license": "MIT", "dependencies": { "p-locate": "^3.0.0", @@ -13172,6 +15173,8 @@ }, "node_modules/showdown/node_modules/p-limit": { "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", "license": "MIT", "dependencies": { "p-try": "^2.0.0" @@ -13185,6 +15188,8 @@ }, "node_modules/showdown/node_modules/p-locate": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", "license": "MIT", "dependencies": { "p-limit": "^2.0.0" @@ -13195,6 +15200,8 @@ }, "node_modules/showdown/node_modules/path-exists": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", "license": "MIT", "engines": { "node": ">=4" @@ -13202,6 +15209,8 @@ }, "node_modules/showdown/node_modules/string-width": { "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", "license": "MIT", "dependencies": { "emoji-regex": "^7.0.1", @@ -13214,6 +15223,8 @@ }, "node_modules/showdown/node_modules/strip-ansi": { "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", "license": "MIT", "dependencies": { "ansi-regex": "^4.1.0" @@ -13224,6 +15235,8 @@ }, "node_modules/showdown/node_modules/wrap-ansi": { "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", "license": "MIT", "dependencies": { "ansi-styles": "^3.2.0", @@ -13236,10 +15249,14 @@ }, "node_modules/showdown/node_modules/y18n": { "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", "license": "ISC" }, "node_modules/showdown/node_modules/yargs": { "version": "14.2.3", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-14.2.3.tgz", + "integrity": "sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg==", "license": "MIT", "dependencies": { "cliui": "^5.0.0", @@ -13257,6 +15274,8 @@ }, "node_modules/showdown/node_modules/yargs-parser": { "version": "15.0.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-15.0.3.tgz", + "integrity": "sha512-/MVEVjTXy/cGAjdtQf8dW3V9b97bPN7rNn8ETj6BmAQL7ibC7O1Q9SPJbGjgh3SlwoBNXMzj/ZGIj8mBgl12YA==", "license": "ISC", "dependencies": { "camelcase": "^5.0.0", @@ -13264,13 +15283,15 @@ } }, "node_modules/side-channel": { - "version": "1.1.0", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3", - "side-channel-list": "^1.0.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" }, @@ -13282,12 +15303,14 @@ } }, "node_modules/side-channel-list": { - "version": "1.0.0", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "object-inspect": "^1.13.3" + "object-inspect": "^1.13.4" }, "engines": { "node": ">= 0.4" @@ -13298,6 +15321,8 @@ }, "node_modules/side-channel-map": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", "dev": true, "license": "MIT", "dependencies": { @@ -13315,6 +15340,8 @@ }, "node_modules/side-channel-weakmap": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", "dev": true, "license": "MIT", "dependencies": { @@ -13345,23 +15372,56 @@ } }, "node_modules/sigstore": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-4.1.0.tgz", - "integrity": "sha512-/fUgUhYghuLzVT/gaJoeVehLCgZiUxPCPMcyVNY0lIf/cTCz58K/WTI7PefDarXxp9nUKpEwg1yyz3eSBMTtgA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-4.1.1.tgz", + "integrity": "sha512-endqECJkfhozrXMK5ngu/UAA0xVcVEFdnHJCElGaExypjW+HK5i6zu3NteLoaX/iFbRUbC3+DjttQs0GARr+5w==", "dev": true, "license": "Apache-2.0", "dependencies": { "@sigstore/bundle": "^4.0.0", - "@sigstore/core": "^3.1.0", + "@sigstore/core": "^3.2.1", "@sigstore/protobuf-specs": "^0.5.0", - "@sigstore/sign": "^4.1.0", - "@sigstore/tuf": "^4.0.1", - "@sigstore/verify": "^3.1.0" + "@sigstore/sign": "^4.1.1", + "@sigstore/tuf": "^4.0.2", + "@sigstore/verify": "^3.1.1" }, "engines": { "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true + }, + "node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, "node_modules/slice-ansi": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-8.0.0.tgz", @@ -13392,22 +15452,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/slice-ansi/node_modules/is-fullwidth-code-point": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-5.1.0.tgz", - "integrity": "sha512-5XHYaSyiqADb4RnZ1Bdad6cPp8Toise4TzEjcOYDHZkTCbKgiUl7WTUCpNWHuxmDt91wnsZBc9xinNzopv3JMQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-east-asian-width": "^1.3.1" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/smart-buffer": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", @@ -13421,6 +15465,8 @@ }, "node_modules/socket.io": { "version": "4.8.3", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.3.tgz", + "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==", "dev": true, "license": "MIT", "dependencies": { @@ -13461,10 +15507,57 @@ "node": ">=10.0.0" } }, + "node_modules/socket.io/node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/socket.io/node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, "node_modules/socks": { - "version": "2.8.8", - "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.8.tgz", - "integrity": "sha512-NlGELfPrgX2f1TAAcz0WawlLn+0r3FyhhCRpFFK2CemXenPYvzMWWZINv3eDNo9ucdwme7oCHRY0Jnbs4aIkog==", + "version": "2.8.9", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.9.tgz", + "integrity": "sha512-LJhUYUvItdQ0LkJTmPeaEObWXAqFyfmP85x0tch/ez9cahmhlBBLbIqDFnvBnUJGagb0JbIQrkBs1wJ+yRYpEw==", "dev": true, "license": "MIT", "dependencies": { @@ -13503,6 +15596,8 @@ }, "node_modules/source-map-js": { "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", "dev": true, "license": "BSD-3-Clause", "engines": { @@ -13532,10 +15627,14 @@ }, "node_modules/spawn-command": { "version": "0.0.2", + "resolved": "https://registry.npmjs.org/spawn-command/-/spawn-command-0.0.2.tgz", + "integrity": "sha512-zC8zGoGkmc8J9ndvml8Xksr1Amk9qBujgbF0JAIWO7kXr43w0h/0GJNM/Vustixu+YE8N/MTrQ7N31FvHUACxQ==", "dev": true }, "node_modules/spdx-correct": { "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -13543,13 +15642,28 @@ "spdx-license-ids": "^3.0.0" } }, + "node_modules/spdx-correct/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/spdx-exceptions": { "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==", "dev": true, "license": "CC-BY-3.0" }, "node_modules/spdx-expression-parse": { - "version": "3.0.1", + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-4.0.0.tgz", + "integrity": "sha512-Clya5JIij/7C6bRR22+tnGXbc4VKlibKSVj2iHvVeX5iMW7s1SIQlqu699JkODJJIhh/pUu8L0/VLh8xflD+LQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13558,12 +15672,16 @@ } }, "node_modules/spdx-license-ids": { - "version": "3.0.22", + "version": "3.0.23", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.23.tgz", + "integrity": "sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==", "dev": true, "license": "CC0-1.0" }, "node_modules/sshpk": { "version": "1.18.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", + "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13600,11 +15718,13 @@ } }, "node_modules/statuses": { - "version": "1.5.0", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", + "integrity": "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==", "dev": true, "license": "MIT", "engines": { - "node": ">= 0.6" + "node": ">= 0.8" } }, "node_modules/stdin-discarder": { @@ -13617,75 +15737,70 @@ "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/streamroller": { - "version": "3.1.5", - "dev": true, - "license": "MIT", - "dependencies": { - "date-format": "^4.0.14", - "debug": "^4.3.4", - "fs-extra": "^8.1.0" - }, - "engines": { - "node": ">=8.0" - } - }, - "node_modules/streamroller/node_modules/fs-extra": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "node_modules/streamroller/node_modules/jsonfile": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/streamroller/node_modules/universalify": { - "version": "0.1.2", + "node_modules/streamroller": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.1.5.tgz", + "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", "dev": true, "license": "MIT", + "dependencies": { + "date-format": "^4.0.14", + "debug": "^4.3.4", + "fs-extra": "^8.1.0" + }, "engines": { - "node": ">= 4.0.0" + "node": ">=8.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" } }, "node_modules/string-width": { - "version": "4.2.3", + "version": "8.2.1", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.1.tgz", + "integrity": "sha512-IIaP0g3iy9Cyy18w3M9YcaDudujEAVHKt3a3QJg1+sr/oX96TbaGUubG0hJyCjCBThFH+tFpcIyoUHUn1ogaLA==", + "dev": true, "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "get-east-asian-width": "^1.5.0", + "strip-ansi": "^7.1.2" }, "engines": { - "node": ">=8" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/strip-ansi": { - "version": "6.0.1", + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" + "ansi-regex": "^6.2.2" }, "engines": { - "node": ">=8" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, "node_modules/strip-bom": { "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", "dev": true, "license": "MIT", "engines": { @@ -13694,6 +15809,8 @@ }, "node_modules/strip-json-comments": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "license": "MIT", "engines": { "node": ">=8" @@ -13736,17 +15853,22 @@ } }, "node_modules/supports-color": { - "version": "7.2.0", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", + "integrity": "sha512-Jds2VIYDrlp5ui7t8abHN2bjAu4LV/q4N2KivFPpGH0lrka0BMq/33AmECUXlKPcHigkNaqfXRENFju+rlcy+A==", + "dev": true, "license": "MIT", "dependencies": { - "has-flag": "^4.0.0" + "has-flag": "^1.0.0" }, "engines": { - "node": ">=8" + "node": ">=0.8.0" } }, "node_modules/supports-preserve-symlinks-flag": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "dev": true, "license": "MIT", "engines": { @@ -13828,17 +15950,42 @@ "node": ">=14.0.0" } }, - "node_modules/tailwindcss/node_modules/glob-parent": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", - "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "node_modules/tailwindcss/node_modules/chokidar": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", + "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "license": "ISC", "dependencies": { - "is-glob": "^4.0.3" + "is-glob": "^4.0.1" }, "engines": { - "node": ">=10.13.0" + "node": ">= 6" } }, "node_modules/tailwindcss/node_modules/jiti": { @@ -13851,6 +15998,32 @@ "jiti": "bin/jiti.js" } }, + "node_modules/tailwindcss/node_modules/picomatch": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", + "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/tailwindcss/node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, "node_modules/tapable": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", @@ -13866,9 +16039,9 @@ } }, "node_modules/tar": { - "version": "7.5.13", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.13.tgz", - "integrity": "sha512-tOG/7GyXpFevhXVh8jOPJrmtRpOTsYqUIkVdVooZYJS/z8WhfQUX8RJILmeuJNinGAMSu1veBr4asSHFt5/hng==", + "version": "7.5.16", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.16.tgz", + "integrity": "sha512-56adEpPMouktRlBLXiaYFFzZ/3+JXa8P9n7WbR+ibIjtviN55mEaOkiysCnPnWm+7kkui1Dn8J9l+g6zV8731w==", "dev": true, "license": "BlueOak-1.0.0", "dependencies": { @@ -13894,6 +16067,8 @@ }, "node_modules/text-segmentation": { "version": "1.0.3", + "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz", + "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==", "license": "MIT", "dependencies": { "utrie": "^1.0.2" @@ -13923,9 +16098,9 @@ } }, "node_modules/tinyexec": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.1.1.tgz", - "integrity": "sha512-VKS/ZaQhhkKFMANmAOhhXVoIfBXblQxGX1myCQ2faQrfmobMftXeJPcZGp0gS07ocvGJWDLZGyOZDadDBqYIJg==", + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", + "integrity": "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg==", "dev": true, "license": "MIT", "engines": { @@ -13934,6 +16109,8 @@ }, "node_modules/tinyglobby": { "version": "0.2.15", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", + "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -13958,6 +16135,8 @@ }, "node_modules/to-regex-range": { "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13969,6 +16148,8 @@ }, "node_modules/toidentifier": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", "dev": true, "license": "MIT", "engines": { @@ -13977,6 +16158,8 @@ }, "node_modules/tough-cookie": { "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", "dev": true, "license": "BSD-3-Clause", "dependencies": { @@ -13989,14 +16172,25 @@ }, "node_modules/tough-cookie/node_modules/punycode": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT", + "optional": true + }, "node_modules/tree-kill": { "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", "dev": true, "license": "MIT", "bin": { @@ -14024,6 +16218,8 @@ }, "node_modules/ts-md5": { "version": "1.3.1", + "resolved": "https://registry.npmjs.org/ts-md5/-/ts-md5-1.3.1.tgz", + "integrity": "sha512-DiwiXfwvcTeZ5wCE0z+2A9EseZsztaiZtGrtSaY5JOD7ekPnR/GoIVD5gXZAlK9Na9Kvpo9Waz5rW64WKAWApg==", "license": "MIT", "engines": { "node": ">=12" @@ -14031,6 +16227,8 @@ }, "node_modules/ts-node": { "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14073,19 +16271,15 @@ }, "node_modules/ts-node/node_modules/arg": { "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", "dev": true, "license": "MIT" }, - "node_modules/ts-node/node_modules/diff": { - "version": "4.0.4", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, "node_modules/tslib": { "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", "license": "0BSD" }, "node_modules/tuf-js": { @@ -14105,6 +16299,8 @@ }, "node_modules/tunnel-agent": { "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -14116,11 +16312,15 @@ }, "node_modules/tweetnacl": { "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", "dev": true, "license": "Unlicense" }, "node_modules/type-check": { "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", "license": "MIT", "dependencies": { "prelude-ls": "^1.2.1" @@ -14130,285 +16330,78 @@ } }, "node_modules/type-is": { - "version": "1.6.18", - "dev": true, - "license": "MIT", - "dependencies": { - "media-typer": "0.3.0", - "mime-types": "~2.1.24" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=14.17" - } - }, - "node_modules/typescript-eslint": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.57.0.tgz", - "integrity": "sha512-W8GcigEMEeB07xEZol8oJ26rigm3+bfPHxHvwbYUlu1fUDsGuQ7Hiskx5xGW/xM4USc9Ephe3jtv7ZYPQntHeA==", - "license": "MIT", - "dependencies": { - "@typescript-eslint/eslint-plugin": "8.57.0", - "@typescript-eslint/parser": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0", - "@typescript-eslint/utils": "8.57.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/eslint-plugin": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.57.0.tgz", - "integrity": "sha512-qeu4rTHR3/IaFORbD16gmjq9+rEs9fGKdX0kF6BKSfi+gCuG3RCKLlSBYzn/bGsY9Tj7KE/DAQStbp8AHJGHEQ==", - "license": "MIT", - "dependencies": { - "@eslint-community/regexpp": "^4.12.2", - "@typescript-eslint/scope-manager": "8.57.0", - "@typescript-eslint/type-utils": "8.57.0", - "@typescript-eslint/utils": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0", - "ignore": "^7.0.5", - "natural-compare": "^1.4.0", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "@typescript-eslint/parser": "^8.57.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/parser": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.57.0.tgz", - "integrity": "sha512-XZzOmihLIr8AD1b9hL9ccNMzEMWt/dE2u7NyTY9jJG6YNiNthaD5XtUHVF2uCXZ15ng+z2hT3MVuxnUYhq6k1g==", - "license": "MIT", - "dependencies": { - "@typescript-eslint/scope-manager": "8.57.0", - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0", - "debug": "^4.4.3" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/scope-manager": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.57.0.tgz", - "integrity": "sha512-nvExQqAHF01lUM66MskSaZulpPL5pgy5hI5RfrxviLgzZVffB5yYzw27uK/ft8QnKXI2X0LBrHJFr1TaZtAibw==", - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/type-utils": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.57.0.tgz", - "integrity": "sha512-yjgh7gmDcJ1+TcEg8x3uWQmn8ifvSupnPfjP21twPKrDP/pTHlEQgmKcitzF/rzPSmv7QjJ90vRpN4U+zoUjwQ==", - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0", - "@typescript-eslint/utils": "8.57.0", - "debug": "^4.4.3", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/types": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.57.0.tgz", - "integrity": "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg==", - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/typescript-estree": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.57.0.tgz", - "integrity": "sha512-m7faHcyVg0BT3VdYTlX8GdJEM7COexXxS6KqGopxdtkQRvBanK377QDHr4W/vIPAR+ah9+B/RclSW5ldVniO1Q==", - "license": "MIT", - "dependencies": { - "@typescript-eslint/project-service": "8.57.0", - "@typescript-eslint/tsconfig-utils": "8.57.0", - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/visitor-keys": "8.57.0", - "debug": "^4.4.3", - "minimatch": "^10.2.2", - "semver": "^7.7.3", - "tinyglobby": "^0.2.15", - "ts-api-utils": "^2.4.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/utils": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.57.0.tgz", - "integrity": "sha512-5iIHvpD3CZe06riAsbNxxreP+MuYgVUsV0n4bwLH//VJmgtt54sQeY2GszntJ4BjYCpMzrfVh2SBnUQTtys2lQ==", - "license": "MIT", - "dependencies": { - "@eslint-community/eslint-utils": "^4.9.1", - "@typescript-eslint/scope-manager": "8.57.0", - "@typescript-eslint/types": "8.57.0", - "@typescript-eslint/typescript-estree": "8.57.0" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" - }, - "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "typescript": ">=4.8.4 <6.0.0" - } - }, - "node_modules/typescript-eslint/node_modules/@typescript-eslint/visitor-keys": { - "version": "8.57.0", - "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.57.0.tgz", - "integrity": "sha512-zm6xx8UT/Xy2oSr2ZXD0pZo7Jx2XsCoID2IUh9YSTFRu7z+WdwYTRk6LhUftm1crwqbuoF6I8zAFeCMw0YjwDg==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-2.1.0.tgz", + "integrity": "sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==", + "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/types": "8.57.0", - "eslint-visitor-keys": "^5.0.0" + "content-type": "^2.0.0", + "media-typer": "^1.1.0", + "mime-types": "^3.0.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">= 18" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/typescript-eslint" + "url": "https://opencollective.com/express" } }, - "node_modules/typescript-eslint/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "node_modules/type-is/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, "license": "MIT", "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/typescript-eslint/node_modules/brace-expansion": { - "version": "5.0.6", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.6.tgz", - "integrity": "sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" + "node": ">=18" }, - "engines": { - "node": "18 || 20 || >=22" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/typescript-eslint/node_modules/eslint-visitor-keys": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", - "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", "license": "Apache-2.0", - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=24" + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/typescript-eslint/node_modules/ignore": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", - "integrity": "sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==", - "license": "MIT", "engines": { - "node": ">= 4" + "node": ">=14.17" } }, - "node_modules/typescript-eslint/node_modules/minimatch": { - "version": "10.2.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz", - "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==", - "license": "BlueOak-1.0.0", + "node_modules/typescript-eslint": { + "version": "8.61.0", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.61.0.tgz", + "integrity": "sha512-8y31Rd0eGTrDKqhy6vT0HtzhN+YLjQizwX3aA3hPXP/ynSfnrBXcQY5IzsP9/DM7+klX4IUncZZjkchP0z+rUw==", + "license": "MIT", "dependencies": { - "brace-expansion": "^5.0.5" + "@typescript-eslint/eslint-plugin": "8.61.0", + "@typescript-eslint/parser": "8.61.0", + "@typescript-eslint/typescript-estree": "8.61.0", + "@typescript-eslint/utils": "8.61.0" }, "engines": { - "node": "18 || 20 || >=22" + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "typescript": ">=4.8.4 <6.1.0" } }, "node_modules/ua-parser-js": { "version": "0.7.41", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.41.tgz", + "integrity": "sha512-O3oYyCMPYgNNHuO7Jjk3uacJWZF8loBgwrfd/5LE/HyZ3lUIOdniQ7DNXJcIgZbwioZxk0fLfI4EVnetdiX5jg==", "dev": true, "funding": [ { @@ -14448,6 +16441,8 @@ }, "node_modules/underscore.string": { "version": "2.3.3", + "resolved": "https://registry.npmjs.org/underscore.string/-/underscore.string-2.3.3.tgz", + "integrity": "sha512-hbD5MibthuDAu4yA5wxes5bzFgqd3PpBJuClbRxaNddxfdsz+qf+1kHwrGQFrmchmDHb9iNU+6EHDn8uj0xDJg==", "engines": { "node": "*" } @@ -14464,11 +16459,25 @@ }, "node_modules/undici-types": { "version": "6.21.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz", + "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==", "dev": true, "license": "MIT" }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", "dev": true, "license": "MIT", "engines": { @@ -14477,6 +16486,8 @@ }, "node_modules/update-browserslist-db": { "version": "1.2.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz", + "integrity": "sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==", "dev": true, "funding": [ { @@ -14506,6 +16517,8 @@ }, "node_modules/uri-js": { "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", "license": "BSD-2-Clause", "dependencies": { "punycode": "^2.1.0" @@ -14513,6 +16526,8 @@ }, "node_modules/uri-js/node_modules/punycode": { "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", "license": "MIT", "engines": { "node": ">=6" @@ -14520,10 +16535,14 @@ }, "node_modules/util-deprecate": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, "node_modules/utils-merge": { "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, "license": "MIT", "engines": { @@ -14532,6 +16551,8 @@ }, "node_modules/utrie": { "version": "1.0.2", + "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz", + "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==", "license": "MIT", "dependencies": { "base64-arraybuffer": "^1.0.2" @@ -14539,6 +16560,9 @@ }, "node_modules/uuid": { "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", "dev": true, "license": "MIT", "bin": { @@ -14547,11 +16571,15 @@ }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", "dev": true, "license": "MIT" }, "node_modules/validate-npm-package-license": { "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -14559,6 +16587,17 @@ "spdx-expression-parse": "^3.0.0" } }, + "node_modules/validate-npm-package-license/node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, "node_modules/validate-npm-package-name": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", @@ -14571,6 +16610,8 @@ }, "node_modules/vary": { "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", "dev": true, "license": "MIT", "engines": { @@ -14579,6 +16620,8 @@ }, "node_modules/verror": { "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", "dev": true, "engines": [ "node >=0.6.0" @@ -14590,6 +16633,13 @@ "extsprintf": "^1.2.0" } }, + "node_modules/verror/node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", + "dev": true, + "license": "MIT" + }, "node_modules/vite": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", @@ -14667,6 +16717,8 @@ }, "node_modules/void-elements": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true, "license": "MIT", "engines": { @@ -14697,6 +16749,8 @@ }, "node_modules/webdriver-js-extender": { "version": "2.1.0", + "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", + "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14709,6 +16763,8 @@ }, "node_modules/webdriver-manager": { "version": "12.1.9", + "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz", + "integrity": "sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==", "dev": true, "license": "MIT", "dependencies": { @@ -14733,6 +16789,8 @@ }, "node_modules/webdriver-manager/node_modules/ansi-regex": { "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", "dev": true, "license": "MIT", "engines": { @@ -14741,6 +16799,8 @@ }, "node_modules/webdriver-manager/node_modules/ansi-styles": { "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", "dev": true, "license": "MIT", "engines": { @@ -14749,6 +16809,8 @@ }, "node_modules/webdriver-manager/node_modules/chalk": { "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", "dev": true, "license": "MIT", "dependencies": { @@ -14762,21 +16824,18 @@ "node": ">=0.10.0" } }, - "node_modules/webdriver-manager/node_modules/escape-string-regexp": { - "version": "1.0.5", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, "node_modules/webdriver-manager/node_modules/ini": { "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", "dev": true, "license": "ISC" }, "node_modules/webdriver-manager/node_modules/rimraf": { "version": "2.7.1", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", + "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", + "deprecated": "Rimraf versions prior to v4 are no longer supported", "dev": true, "license": "ISC", "dependencies": { @@ -14788,6 +16847,8 @@ }, "node_modules/webdriver-manager/node_modules/semver": { "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", "dev": true, "license": "ISC", "bin": { @@ -14796,6 +16857,8 @@ }, "node_modules/webdriver-manager/node_modules/strip-ansi": { "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", "dev": true, "license": "MIT", "dependencies": { @@ -14807,14 +16870,36 @@ }, "node_modules/webdriver-manager/node_modules/supports-color": { "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", "dev": true, "license": "MIT", "engines": { "node": ">=0.8.0" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause", + "optional": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -14828,10 +16913,72 @@ }, "node_modules/which-module": { "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "license": "ISC" }, + "node_modules/wide-align": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", + "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", + "license": "ISC", + "optional": true, + "dependencies": { + "string-width": "^1.0.2 || 2 || 3 || 4" + } + }, + "node_modules/wide-align/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "optional": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wide-align/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "optional": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/word-wrap": { "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", "license": "MIT", "engines": { "node": ">=0.10.0" @@ -14839,6 +16986,8 @@ }, "node_modules/wrap-ansi": { "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", "license": "MIT", "dependencies": { "ansi-styles": "^4.0.0", @@ -14849,9 +16998,88 @@ "node": ">=8" } }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "license": "MIT" + }, + "node_modules/wrap-ansi/node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wrappy": { "version": "1.0.2", - "dev": true, + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "devOptional": true, "license": "ISC" }, "node_modules/ws": { @@ -14878,6 +17106,8 @@ }, "node_modules/xml2js": { "version": "0.4.23", + "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", + "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", "dev": true, "license": "MIT", "dependencies": { @@ -14890,6 +17120,8 @@ }, "node_modules/xmlbuilder": { "version": "11.0.1", + "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", + "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", "dev": true, "license": "MIT", "engines": { @@ -14898,6 +17130,8 @@ }, "node_modules/y18n": { "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", "dev": true, "license": "ISC", "engines": { @@ -14911,59 +17145,63 @@ "dev": true, "license": "ISC" }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "dev": true, - "license": "ISC", - "optional": true, - "peer": true, - "bin": { - "yaml": "bin.mjs" - }, - "engines": { - "node": ">= 14.6" - }, - "funding": { - "url": "https://github.com/sponsors/eemeli" - } - }, "node_modules/yargs": { - "version": "17.7.2", + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "dev": true, "license": "MIT", "dependencies": { - "cliui": "^8.0.1", + "cliui": "^9.0.1", "escalade": "^3.1.1", "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", + "string-width": "^7.2.0", "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" + "yargs-parser": "^22.0.0" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, "node_modules/yargs-parser": { - "version": "20.2.9", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "dev": true, "license": "ISC", "engines": { - "node": ">=10" + "node": "^20.19.0 || ^22.12.0 || >=23" } }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "21.1.1", + "node_modules/yargs/node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", "dev": true, - "license": "ISC", + "license": "MIT" + }, + "node_modules/yargs/node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" + }, "engines": { - "node": ">=12" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/yn": { "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "dev": true, "license": "MIT", "engines": { @@ -14972,6 +17210,8 @@ }, "node_modules/yocto-queue": { "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", "license": "MIT", "engines": { "node": ">=10" From 0348f06a615887dbf6d2f6d534cb37e99e9f3769 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 10 Jun 2026 10:28:46 +1000 Subject: [PATCH 1092/1280] chore: ignore formatting commit in git blame --- .git-blame-ignore-revs | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 .git-blame-ignore-revs diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs new file mode 100644 index 0000000000..8af4e23280 --- /dev/null +++ b/.git-blame-ignore-revs @@ -0,0 +1,2 @@ +# 8 June 2026: Repository-wide formatting and lint configuration +26b4962794d16e90587fb179aab966b39459050c From ba7910a59460a4d4139273b272e99625e5efc518 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 10 Jun 2026 10:54:21 +1000 Subject: [PATCH 1093/1280] fix: avoid loading rendering all students at the same time --- .../units/states/students-list/students-list.component.ts | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/app/units/states/students-list/students-list.component.ts b/src/app/units/states/students-list/students-list.component.ts index 2876bae073..a0a4de5b8f 100644 --- a/src/app/units/states/students-list/students-list.component.ts +++ b/src/app/units/states/students-list/students-list.component.ts @@ -83,6 +83,7 @@ export class StudentsListComponent implements OnInit, AfterViewInit, OnDestroy { ngAfterViewInit(): void { this.dataSource.paginator = this.paginator; + this.updateDataSource(); } ngOnDestroy(): void { @@ -157,6 +158,10 @@ export class StudentsListComponent implements OnInit, AfterViewInit, OnDestroy { } private updateDataSource(resetPagination: boolean = false): void { + if (!this.paginator) { + return; + } + const students = this.filteredProjects(); this.dataSource.data = students; From df6a6ecc73d01dd2ef449270bc7c6de446d93884 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 10 Jun 2026 11:08:04 +1000 Subject: [PATCH 1094/1280] fix: apply status color --- .../tasks/project-tasks-list/project-tasks-list.component.html | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/app/tasks/project-tasks-list/project-tasks-list.component.html b/src/app/tasks/project-tasks-list/project-tasks-list.component.html index 28db724d6d..243bba9805 100644 --- a/src/app/tasks/project-tasks-list/project-tasks-list.component.html +++ b/src/app/tasks/project-tasks-list/project-tasks-list.component.html @@ -19,6 +19,9 @@
    {{ grouping.name }}
    (click)="selectChip(task)" class="task-status chip truncate text-center" [ngClass]="newTaskService.statusClass(task.status)" + [style.--mat-chip-elevated-container-color]=" + newTaskService.statusColors.get(task.status) + " > @if (task.similarityFlag) { From 21d3e9510825c155f595a5c069ff450b895bd780 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 10 Jun 2026 11:29:48 +1000 Subject: [PATCH 1095/1280] refactor: add skeleton ui to students and portfolios route --- .../portfolios-list.component.html | 85 ++++++++++++++++++- .../portfolios-list.component.ts | 12 ++- .../portfolios/portfolios.component.html | 4 +- .../states/portfolios/portfolios.component.ts | 7 +- .../students-list.component.html | 54 +++++++++++- .../students-list/students-list.component.ts | 14 ++- 6 files changed, 158 insertions(+), 18 deletions(-) diff --git a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html index 23e3f17566..ea67268a4d 100644 --- a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html +++ b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html @@ -5,12 +5,19 @@

    Mark portfolios

    Filter - + Mark portfolios hideSingleSelectionIndicator [(ngModel)]="tutorialFilter" (change)="onTutorialFilterChange($event)" + [disabled]="loading" > Mark portfolios hideSingleSelectionIndicator [(ngModel)]="gradeFilter" (change)="onGradeFilterChange($event)" + [disabled]="loading" > Mark portfolios
    - @@ -81,6 +90,7 @@

    Mark portfolios

    matTooltip="Downloading all portfolios may take a long time" matTooltipShowDelay="500" matTooltipPosition="above" + [disabled]="loading" > downloadDownload Portfolios @@ -89,12 +99,73 @@

    Mark portfolios

    @if (hasD2lMapping()) { - }
    + @if (loading) { +
    +
    +
    + @for ( + width of [ + '110px', + '170px', + '150px', + '130px', + '80px', + '110px', + '180px', + '400px', + '80px', + '50px', + ]; + track $index + ) { + + } +
    + + @for (row of [0, 1, 2, 3, 4, 5, 6, 7]; track row) { +
    + @for ( + width of [ + '110px', + '170px', + '150px', + '130px', + '80px', + '110px', + '180px', + '400px', + '80px', + '50px', + ]; + track $index + ) { + + } +
    + } +
    +
    + } + Mark portfolios matSortDisableClear class="f-table selectable" (matSortChange)="sortTableData($event)" + [hidden]="loading" > @@ -216,5 +288,10 @@

    Mark portfolios

    Student
    - +
    diff --git a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts index 9047047eda..3f3c314edb 100644 --- a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts +++ b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts @@ -13,8 +13,9 @@ import { Component, EventEmitter, Input, - OnInit, + OnChanges, Output, + SimpleChanges, ViewChild, } from '@angular/core'; import {MatButtonToggleChange} from '@angular/material/button-toggle'; @@ -29,8 +30,9 @@ import {D2lTransferModal} from '../../d2l-transfer-modal/d2l-transfer.component' styleUrl: './portfolios-list.component.scss', standalone: false, }) -export class PortfoliosListComponent implements OnInit, AfterViewInit { +export class PortfoliosListComponent implements OnChanges, AfterViewInit { @Input() unit: Unit; + @Input() loading = true; @Output() public studentSelected: EventEmitter = new EventEmitter(); @@ -62,8 +64,10 @@ export class PortfoliosListComponent implements OnInit, AfterViewInit { this.dataSource.sort = this.sort; } - ngOnInit(): void { - this.updateDataSource(); + ngOnChanges(changes: SimpleChanges): void { + if (!this.loading && this.unit && (changes.loading || changes.unit)) { + this.updateDataSource(); + } } openProject(event: Event, project: Project) { diff --git a/src/app/units/states/portfolios/portfolios.component.html b/src/app/units/states/portfolios/portfolios.component.html index a4a05762a3..9ab91ac774 100644 --- a/src/app/units/states/portfolios/portfolios.component.html +++ b/src/app/units/states/portfolios/portfolios.component.html @@ -5,6 +5,7 @@

    Student Portfolios

    @@ -38,8 +39,5 @@

    Student Portfolios

    } - } @else { - -
    Loading unit...
    }
    diff --git a/src/app/units/states/portfolios/portfolios.component.ts b/src/app/units/states/portfolios/portfolios.component.ts index 398463d779..a8aeda7118 100644 --- a/src/app/units/states/portfolios/portfolios.component.ts +++ b/src/app/units/states/portfolios/portfolios.component.ts @@ -19,6 +19,7 @@ export class PortfoliosComponent implements OnInit { // Exposed to child components public unit: Unit = null; public selectedProject: Project; + public loadingStudents = true; @ViewChild('tabs') tabs!: MatTabGroup; @@ -48,10 +49,12 @@ export class PortfoliosComponent implements OnInit { this.unit$ = this.unit$ ?? of(this.route.parent.snapshot.data.unit); this.unit$?.pipe(first()).subscribe({ next: (unit) => { + this.unit = unit; + this.unit.loadD2lMapping().subscribe(); + this.projectService.loadStudents(unit, false).subscribe({ next: () => { - this.unit = unit; - this.unit.loadD2lMapping().subscribe(); + this.loadingStudents = false; }, error: (error) => { this.alertService.error(`Failed to load unit: ${error}`, 6000); diff --git a/src/app/units/states/students-list/students-list.component.html b/src/app/units/states/students-list/students-list.component.html index 70d1d02aa5..89cd97d026 100644 --- a/src/app/units/states/students-list/students-list.component.html +++ b/src/app/units/states/students-list/students-list.component.html @@ -12,6 +12,7 @@

    Students

    [(ngModel)]="searchText" (ngModelChange)="onSearchChange()" [matAutocomplete]="studentSearch" + [disabled]="loadingStudents" /> @for (suggestion of filteredSuggestions; track suggestion) { @@ -26,13 +27,53 @@

    Students

    [ngModel]="staffFilter" class="w-full max-w-lg" (ngModelChange)="setStaffFilter($event)" + [disabled]="loadingStudents" > All Tutorials My Tutorials
    -
    + @if (loadingStudents) { +
    +
    + @for (width of ['4%', '10%', '16%', '28%', '8%', '8%', '8%', '10%', '10%']; track $index) { + + } +
    + + @for (row of [0, 1, 2, 3, 4, 5, 6, 7]; track row) { +
    + + + + + @for (column of [0, 1, 2, 3, 4]; track column) { + + } +
    + } +
    + } + +
    Students
    - - @@ -168,6 +215,7 @@

    Students

    diff --git a/src/app/units/states/students-list/students-list.component.ts b/src/app/units/states/students-list/students-list.component.ts index a0a4de5b8f..5b1a7cff5c 100644 --- a/src/app/units/states/students-list/students-list.component.ts +++ b/src/app/units/states/students-list/students-list.component.ts @@ -1,4 +1,4 @@ -import {Observable, Subscription, first, of} from 'rxjs'; +import {Observable, Subscription, finalize, first, of} from 'rxjs'; import { Project, ProjectService, @@ -42,6 +42,7 @@ export class StudentsListComponent implements OnInit, AfterViewInit, OnDestroy { searchText = ''; staffFilter: 'all' | 'mine' = 'all'; filteredSuggestions: string[] = []; + loadingStudents = true; unit: Unit; private subscriptions: Subscription[] = []; @@ -61,6 +62,7 @@ export class StudentsListComponent implements OnInit, AfterViewInit, OnDestroy { this.subscriptions.push( this.unit$?.pipe(first()).subscribe((unit) => { if (!unit) { + this.loadingStudents = false; return; } @@ -76,7 +78,15 @@ export class StudentsListComponent implements OnInit, AfterViewInit, OnDestroy { this.updateSuggestions(); this.updateDataSource(); - this.projectService.loadStudents(this.unit).pipe(first()).subscribe(); + this.projectService + .loadStudents(this.unit) + .pipe( + first(), + finalize(() => { + this.loadingStudents = false; + }), + ) + .subscribe(); }), ); } From c812b8c117c9f45c2874301df835a8ecfc3177ba Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 10 Jun 2026 14:38:01 +1000 Subject: [PATCH 1096/1280] chore: default tooltip position to above elements --- src/app/doubtfire-angular.module.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 4fefb44031..482788d626 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -77,6 +77,7 @@ import {MatTableModule} from '@angular/material/table'; import {MatTabsModule} from '@angular/material/tabs'; import {MatToolbarModule} from '@angular/material/toolbar'; import {MatTooltipModule} from '@angular/material/tooltip'; +import {MAT_TOOLTIP_DEFAULT_OPTIONS, MatTooltipDefaultOptions} from '@angular/material/tooltip'; import {MatTreeModule} from '@angular/material/tree'; import {BrowserModule, DomSanitizer, Title} from '@angular/platform-browser'; import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; @@ -407,6 +408,13 @@ const GANTT_CHART_CONFIG = { }, }; +const DEFAULT_TOOLTIP_OPTIONS: MatTooltipDefaultOptions = { + showDelay: 0, + hideDelay: 0, + touchendHideDelay: 1500, + position: 'above', +}; + @NgModule({ // Components we declare declarations: [ @@ -716,6 +724,10 @@ const GANTT_CHART_CONFIG = { CommunicationSetService, CsvResultModalService, CsvUploadModalService, + { + provide: MAT_TOOLTIP_DEFAULT_OPTIONS, + useValue: DEFAULT_TOOLTIP_OPTIONS, + }, ], imports: [ FlexLayoutModule, From be0fcbaee9c7be5ed399b5c88cdfb7b4618abc83 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 10 Jun 2026 15:23:41 +1000 Subject: [PATCH 1097/1280] chore: improve task list padding --- .../directives/unit-task-list/unit-task-list.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html index 3c473a0d1d..f237e2f7c6 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html @@ -1,4 +1,4 @@ -
    +
    From 2f327f1b8cb098767571b491599780412317e6cc Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 10 Jun 2026 16:31:38 +1000 Subject: [PATCH 1098/1280] chore: add subtitle --- .../directives/staff-notes-view/staff-notes-view.component.html | 1 + 1 file changed, 1 insertion(+) diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html index 92a3039c43..5b52d8d214 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.html @@ -3,6 +3,7 @@ comment

    Staff Notes for {{ project?.student?.name }}

    +

    Use these notes for private staff discussions about the student. Students cannot view them.

    From 7ebe61bc555f8e45b3cc5b82ef00ff57bd8a7fe3 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 10 Jun 2026 16:43:41 +1000 Subject: [PATCH 1099/1280] refactor: disable feedback submissions after deadline --- .../submission-type-modal.component.html | 26 +++++++++++++++---- .../submission-type-modal.component.ts | 13 +++++++++- 2 files changed, 33 insertions(+), 6 deletions(-) diff --git a/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.html b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.html index bb5d44c08a..42044d1858 100644 --- a/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.html +++ b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.html @@ -4,16 +4,19 @@

    Select submission type

    This task won't be marked as complete by your tutor. It will be assessed as part of your final portfolio.

    -

    - You can submit it for feedback before the deadline, but you'll need to resubmit it later for - portfolio assessment. -

    + @if (!isPastFeedbackDeadline) { +

    + You can submit it for feedback before the deadline, but you'll need to resubmit it later for + portfolio assessment. +

    + }
    - @if (selectedTransition === 'ready_for_feedback') { + @if (isPastFeedbackDeadline) { + + } @else if (selectedTransition === 'ready_for_feedback') {

    You've made progress on this task and would like feedback, clarification, or to discuss questions with your tutor. diff --git a/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.ts b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.ts index 5b3621d837..a1bb60da68 100644 --- a/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.ts +++ b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.ts @@ -16,12 +16,20 @@ export interface SubmissionTypeModalData { export class SubmissionTypeModalComponent { selectedTransition: 'ready_for_feedback' | 'assess_in_portfolio' = null; + public get isPastFeedbackDeadline(): boolean { + return Date.now() > this.data.task.localDeadlineDate().getTime(); + } + constructor( @Inject(MAT_DIALOG_DATA) public data: SubmissionTypeModalData, private dialogRef: MatDialogRef, ) {} public selectRff() { + if (this.isPastFeedbackDeadline) { + return; + } + this.selectedTransition = 'ready_for_feedback'; } @@ -30,7 +38,10 @@ export class SubmissionTypeModalComponent { } public submit() { - if (this.selectedTransition === null) { + if ( + this.selectedTransition === null || + (this.selectedTransition === 'ready_for_feedback' && this.isPastFeedbackDeadline) + ) { return; } From ac015c5d7c50de7d60e7c081c6bbfbab7e327c2f Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 10 Jun 2026 16:50:54 +1000 Subject: [PATCH 1100/1280] refactor: rename tutor notes to moderation notes --- src/app/common/header/header.component.html | 2 +- .../header/task-dropdown/task-dropdown.component.html | 3 ++- .../tutor-notes-view/tutor-notes-view.component.html | 2 +- .../directives/task-dashboard/task-dashboard.component.html | 4 ++-- .../unit-staff-editor/unit-staff-editor.component.html | 6 +++++- .../inbox-dashboard/inbox-dashboard.component.html | 2 +- .../inbox/directives/moderation/moderation.component.ts | 2 +- 7 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/app/common/header/header.component.html b/src/app/common/header/header.component.html index 715d74c1bf..549c5189db 100644 --- a/src/app/common/header/header.component.html +++ b/src/app/common/header/header.component.html @@ -46,7 +46,7 @@ } @if (currentUnit && currentUnitRole && currentUnitRole.tutorNoteCount > 0) { - diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.html index 456422ea90..7cfe442732 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.html @@ -1,7 +1,7 @@

    comment -

    Tutor Notes for {{ unitRole?.user?.name }}

    +

    Moderation Notes for {{ unitRole?.user?.name }}

    @if (task) {

    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html index c980e95db5..de593aa7b3 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html @@ -33,7 +33,7 @@ - Staff Notes + Student Notes @if (task.project.staffNoteCount) { @if (canAccessTutorNotes) { - + } } diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html index 34ebd4db13..d01957ae86 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html @@ -106,7 +106,11 @@

    Unit Staff

    + + + + + @@ -82,6 +92,12 @@
    Actions
    - -
    - -
    + +
    + + +
    + @if (task.numNewComments > 0) { + + {{ task.numNewComments }} + + } + @if (task.similaritiesDetected) { + + + visibility + + + } +
    + +
    + @if (task.hasGrade()) { + + {{ task.gradeDesc() }} + + } + @if (task.hasQualityPoints()) { + + {{ task.qualityPts }} + + {{ task.definition.maxQualityPts }} + + } + @if (task.isDueSoon() && !task.inFinalState()) { + + + schedule + + + } + @if (task.betweenDueDateAndDeadlineDate() && !task.isPastDeadline() && !task.inFinalState()) { + + + schedule + + + } + @if (task.isPastDeadline() && !task.inFinalState()) { + + + schedule + + ! + + }
    +
    + +
    + @if (!isCollapsed) { +
    +
    + +
    + +
    +
    +
    + } -
    @for (taskDef of filteredTaskDefinitions; track taskDef) { @@ -33,137 +117,78 @@ }" > @if (taskDef) { -
    -
    -
    -
    -
    {{ taskDef.name }}
    + @if (isCollapsed) { +
    + + {{ taskDef.abbreviation }} + + @if (taskListItem(taskDef); as task) { + + } +
    + } @else { +
    +
    +
    +
    +
    {{ taskDef.name }}
    -
    - @if (taskDef.isGroupTask()) { - groups - } @else { - person - } +
    + @if (taskDef.isGroupTask()) { + groups + } @else { + person + } -
    - {{ taskDef.abbreviation }} - - - {{ gradeNames[taskDef.targetGrade] }} Task -
    - @if (taskListItem(taskDef); as task) { - - @if (!task.isBeforeStartDate() && !task.inSubmittedState()) { - - hourglass_bottomhourglass_top + {{ task.timeToStart() }} + + } --> + @if (!task.isBeforeStartDate() && !task.inSubmittedState()) { + - {{ task.timeToDue() }} - + + hourglass_bottom + + {{ task.timeToDue() }} + + } } - } +
    + @if (taskListItem(taskDef); as task) { + + }
    - @if (taskListItem(taskDef); as task) { -
    - - -
    - @if (task.numNewComments > 0) { - - {{ task.numNewComments }} - - } - @if (task.similaritiesDetected) { - - visibility - - } -
    - -
    - @if (task.hasGrade()) { - - {{ task.gradeDesc() }} - - } - @if (task.hasQualityPoints()) { - - {{ task.qualityPts }} - - {{ - task.definition.maxQualityPts - }} - - } - @if (task.isDueSoon() && !task.inFinalState()) { - - schedule - - } - @if ( - task.betweenDueDateAndDeadlineDate() && - !task.isPastDeadline() && - !task.inFinalState() - ) { - - schedule - - } - @if (task.isPastDeadline() && !task.inFinalState()) { - - schedule - ! - - } -
    -
    - } -
    + } } } @empty { @@ -176,7 +201,27 @@ [disableRipple]="true" [ngClass]="project.portfolioTaskStatusClass()" > - + @if (isCollapsed) { + + + history_edu + +
    + +
    +
    + } @else { + + } } diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss index 652d53cb6f..6838d99b48 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.scss @@ -10,6 +10,18 @@ $my-palette: mat.m2-define-palette($md-formatif); padding-right: 8px; } +:host(.collapsed) { + padding-right: 0; + + .mat-mdc-list-item { + overflow: visible; + } + + ::ng-deep .mdc-list-item__content { + overflow: visible; + } +} + ::ng-deep .cdk-virtual-scroll-content-wrapper { width: 100%; } diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts index 588bdbc475..f4e4c4e4d1 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts @@ -1,5 +1,5 @@ import {Location} from '@angular/common'; -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import {Component, HostBinding, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {BehaviorSubject} from 'rxjs'; import {Project, Task, TaskDefinition} from 'src/app/api/models/doubtfire-model'; @@ -17,6 +17,12 @@ export class FUnitTaskListComponent implements OnChanges, OnInit { @Input() project: Project; @Input() taskDefinitions: TaskDefinition[]; @Input() tasks: Task[]; + @Input() isCollapsed = false; + + @HostBinding('class.collapsed') + public get collapsedHostClass(): boolean { + return this.isCollapsed; + } // What is the selected task definition @Input() selectedTaskDefinition$: BehaviorSubject; From 42fd95d73da8c466a5e304fe2653f4f0ea67a604 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 16 Jun 2026 12:51:16 +1000 Subject: [PATCH 1110/1280] refactor: add project dashboard in portfolios progress view --- ...portfolios-project-progress.component.html | 109 ++++++++++-------- .../portfolios-project-progress.component.ts | 92 ++++++++++++++- 2 files changed, 148 insertions(+), 53 deletions(-) diff --git a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html index cdbdb593de..250032c055 100644 --- a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html +++ b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html @@ -1,58 +1,65 @@

    Review progress of {{ project.student.name }}

    Review the students progress through the unit's tasks.

    -
    -
    - - - Target Grade - - -
    -
    - - @for (grade of gradeValues; track grade) { - - - - } - -
    - {{ gradeWord(project.targetGrade) ?? 'N/A' }} + + + +
    diff --git a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts index eadf0c3f47..8ffa907fa2 100644 --- a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts +++ b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts @@ -1,4 +1,5 @@ -import {Component, Input} from '@angular/core'; +import {Component, ElementRef, HostListener, Input, OnChanges} from '@angular/core'; +import {BehaviorSubject} from 'rxjs'; import {Project} from 'src/app/api/models/project'; import {Unit} from 'src/app/api/models/unit'; import {ProjectService} from 'src/app/api/services/project.service'; @@ -12,22 +13,64 @@ import {GradeService} from 'src/app/common/services/grade.service'; styleUrl: './portfolios-project-progress.component.scss', standalone: false, }) -export class PortfoliosProjectProgressComponent { +export class PortfoliosProjectProgressComponent implements OnChanges { @Input() project: Project; @Input() unit: Unit; + public project$: BehaviorSubject = new BehaviorSubject(null); + public taskStats: {numberOfTasksCompleted: number; numberOfTasksRemaining: number} = { numberOfTasksCompleted: 0, numberOfTasksRemaining: 0, }; constructor( + private elementRef: ElementRef, private gradeService: GradeService, private projectService: ProjectService, private alertService: AlertService, private taskService: TaskService, ) {} + @HostListener('wheel', ['$event']) + public prioritisePageScroll(event: WheelEvent): void { + if (event.deltaY === 0 || !(event.target instanceof HTMLElement)) { + return; + } + + const projectDashboard = event.target.closest('f-project-dashboard'); + if (!projectDashboard || !this.elementRef.nativeElement.contains(projectDashboard)) { + return; + } + + if (event.target.closest('f-unit-task-list')) { + return; + } + + const innerScrollContainer = this.findInnerScrollContainer(event.target, projectDashboard); + if ( + event.deltaY < 0 && + innerScrollContainer && + this.canScroll(innerScrollContainer, event.deltaY) + ) { + return; + } + + const scrollContainer = this.findOuterScrollContainer(projectDashboard); + if (!scrollContainer || !this.canScroll(scrollContainer, event.deltaY)) { + return; + } + + event.preventDefault(); + scrollContainer.scrollBy({top: event.deltaY}); + } + + ngOnChanges(): void { + if (this.project) { + this.project$.next(this.project); + } + } + public get gradeValues() { return this.gradeService.gradeValues; } @@ -80,4 +123,49 @@ export class PortfoliosProjectProgressComponent { }, }); } + + private findInnerScrollContainer(target: HTMLElement, root: Element): HTMLElement | null { + let element: HTMLElement | null = target; + + while (element && element !== root) { + if (this.isScrollable(element)) { + return element; + } + + element = element.parentElement; + } + + return null; + } + + private findOuterScrollContainer(projectDashboard: Element): HTMLElement { + let parent = projectDashboard.parentElement; + + while (parent) { + if (this.isScrollable(parent)) { + return parent; + } + + parent = parent.parentElement; + } + + return document.scrollingElement as HTMLElement; + } + + private isScrollable(element: HTMLElement): boolean { + if (element.scrollHeight <= element.clientHeight) { + return false; + } + + const overflowY = getComputedStyle(element).overflowY; + return overflowY === 'auto' || overflowY === 'scroll' || overflowY === 'overlay'; + } + + private canScroll(element: HTMLElement, deltaY: number): boolean { + if (deltaY > 0) { + return element.scrollTop + element.clientHeight < element.scrollHeight; + } + + return element.scrollTop > 0; + } } From f8d514261c7eca5465ac3af95da33b95a39d3f23 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:20:44 +1000 Subject: [PATCH 1111/1280] fix: use either portfolio available field --- .../directives/portfolios-list/portfolios-list.component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts index 8eaeeb4de1..36b7a1dc0b 100644 --- a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts +++ b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts @@ -120,7 +120,9 @@ export class PortfoliosListComponent implements OnChanges, AfterViewInit { const currentUser = this.userService.currentUser; const students = this.unit.students - .filter((p) => (this.portfolioFilter === 'submitted_only' ? p.hasPortfolio : true)) + .filter((p) => + this.portfolioFilter === 'submitted_only' ? p.hasPortfolio || p.portfolioAvailable : true, + ) .filter((p) => (this.tutorialFilter === 'mine' ? p.hasTutor(currentUser) : true)) .filter((p) => (this.gradeFilter !== null ? p.submittedGrade === this.gradeFilter : true)); From 39a62f1b722dc525af928fb01b854ab4854673e5 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 16 Jun 2026 16:21:52 +1000 Subject: [PATCH 1112/1280] refactor: add routing system to portfolios navigation --- src/app/app.routes.ts | 15 ++ .../project-dashboard.component.html | 1 + .../project-dashboard.component.ts | 1 + .../portfolios-list.component.html | 2 +- ...portfolios-project-progress.component.html | 1 + .../portfolios-project-progress.component.ts | 2 + .../portfolios/portfolios.component.html | 79 ++++---- .../states/portfolios/portfolios.component.ts | 173 ++++++++++++++---- .../unit-task-list.component.ts | 7 + 9 files changed, 214 insertions(+), 67 deletions(-) diff --git a/src/app/app.routes.ts b/src/app/app.routes.ts index 6122dd6101..e96ce8ce6c 100644 --- a/src/app/app.routes.ts +++ b/src/app/app.routes.ts @@ -117,6 +117,21 @@ export const routes: Routes = [ component: PortfoliosComponent, data: {task: 'Student Portfolios'}, }, + { + path: 'students/portfolios/:projectId', + component: PortfoliosComponent, + data: {task: 'Student Portfolios'}, + }, + { + path: 'students/portfolios/:projectId/:tab', + component: PortfoliosComponent, + data: {task: 'Student Portfolios'}, + }, + { + path: 'students/portfolios/:projectId/:tab/:taskAbbreviation', + component: PortfoliosComponent, + data: {task: 'Student Portfolios'}, + }, {path: 'students', component: StudentsListComponent, data: {task: 'Student List'}}, { path: 'admin', diff --git a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html index f275aad740..a54a599425 100644 --- a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html +++ b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html @@ -51,6 +51,7 @@ [tasks]="project.tasks" [selectedTaskDefinition$]="selectedTaskDefinition$" [isCollapsed]="taskListCollapsed" + [selectionUrlBase]="taskSelectionUrlBase" > } @else {
    diff --git a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.ts b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.ts index 83ca228bcc..189b177e34 100644 --- a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.ts +++ b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.ts @@ -28,6 +28,7 @@ import {GlobalStateService, ViewType} from '../../index/global-state.service'; export class ProjectDashboardComponent implements OnInit { @Input() public project$: Observable; @Input() public defaultTaskListCollapsed = false; + @Input() public taskSelectionUrlBase: unknown[] | null = null; /** * The currently selected task definition - selected in the unit task list. diff --git a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html index ea67268a4d..cce514ee07 100644 --- a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html +++ b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html @@ -1,4 +1,4 @@ -
    +

    Mark portfolios

    Assess student portfolios

    diff --git a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html index 250032c055..acc95740ce 100644 --- a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html +++ b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html @@ -56,6 +56,7 @@

    Review progress of {{ project.student.name }}

    class="block min-h-fit min-w-0" [project$]="project$" [defaultTaskListCollapsed]="true" + [taskSelectionUrlBase]="taskSelectionUrlBase" > - - - @if (selectedProject) { - + @case ('progress') { + @if (selectedProject) { + + } } - - - @if (selectedProject) { - + @case ('staff-notes') { + @if (selectedProject) { + + } } - - - @if (selectedProject) { - + @case ('portfolio') { + @if (selectedProject) { + + } } - - + @case ('assessment') { + @if (selectedProject) { + + } + } + } +
    }
    diff --git a/src/app/units/states/portfolios/portfolios.component.ts b/src/app/units/states/portfolios/portfolios.component.ts index 4811403780..7144b754d5 100644 --- a/src/app/units/states/portfolios/portfolios.component.ts +++ b/src/app/units/states/portfolios/portfolios.component.ts @@ -1,27 +1,45 @@ -import {Component, Input, OnInit, ViewChild} from '@angular/core'; -import {MatTabGroup} from '@angular/material/tabs'; +import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {MatTabChangeEvent} from '@angular/material/tabs'; import {ActivatedRoute, Router} from '@angular/router'; -import {Observable, first, of} from 'rxjs'; +import {BehaviorSubject, Observable, Subscription, first, of} from 'rxjs'; import {Project} from 'src/app/api/models/project'; import {Unit} from 'src/app/api/models/unit'; import {ProjectService} from 'src/app/api/services/project.service'; import {AlertService} from 'src/app/common/services/alert.service'; +type PortfolioTabKey = 'select' | 'progress' | 'staff-notes' | 'portfolio' | 'assessment'; + +interface PortfolioTab { + label: string; + routeSegment: PortfolioTabKey; + requiresProject: boolean; +} + @Component({ selector: 'f-portfolios', templateUrl: './portfolios.component.html', styleUrl: './portfolios.component.scss', standalone: false, }) -export class PortfoliosComponent implements OnInit { +export class PortfoliosComponent implements OnInit, OnDestroy { @Input() unit$: Observable; - // Exposed to child components + public readonly tabs: PortfolioTab[] = [ + {label: 'Select Student', routeSegment: 'select', requiresProject: false}, + {label: 'View Progress', routeSegment: 'progress', requiresProject: true}, + {label: 'View Staff Notes', routeSegment: 'staff-notes', requiresProject: true}, + {label: 'View Portfolio', routeSegment: 'portfolio', requiresProject: true}, + {label: 'Assess Portfolio', routeSegment: 'assessment', requiresProject: true}, + ]; + public unit: Unit = null; - public selectedProject: Project; + public selectedProject: Project | null = null; + public selectedProject$: BehaviorSubject = new BehaviorSubject(null); public loadingStudents = true; + public currentTab: PortfolioTab = this.tabs[0]; - @ViewChild('tabs') tabs!: MatTabGroup; + private subscriptions: Subscription[] = []; + private selectedProjectId: number | null = null; constructor( private projectService: ProjectService, @@ -30,42 +48,133 @@ export class PortfoliosComponent implements OnInit { private alertService: AlertService, ) {} - studentSelected(project: Project) { - this.selectedProject = null; + public ngOnInit(): void { + this.unit$ = this.unit$ ?? of(this.route.parent.snapshot.data.unit); + this.subscriptions.push( + this.unit$.pipe(first()).subscribe({ + next: (unit) => { + this.unit = unit; + this.unit.loadD2lMapping().subscribe(); + this.loadStudents(); + this.subscriptions.push( + this.route.paramMap.subscribe((params) => { + this.updateCurrentTabFromState(params.get('tab'), params.get('projectId')); + }), + ); + }, + error: (error) => { + this.alertService.error(`Failed to load unit: ${error}`, 6000); + this.router.navigateByUrl('/home'); + }, + }), + ); + } + + public ngOnDestroy(): void { + this.subscriptions.forEach((subscription) => subscription.unsubscribe()); + } + + public get currentIndex(): number { + const index = this.tabs.findIndex((tab) => tab.routeSegment === this.currentTab.routeSegment); + return index >= 0 ? index : 0; + } + + public get progressTaskSelectionUrlBase(): unknown[] | null { + if (!this.unit || !this.selectedProject) { + return null; + } - this.projectService.loadProject(project, this.unit).subscribe({ + return ['/units', this.unit.id, 'students', 'portfolios', this.selectedProject.id, 'progress']; + } + + public studentSelected(project: Project): void { + this.navigateToProject(project.id, 'progress'); + } + + public onTabChange(event: MatTabChangeEvent): void { + const nextTab = this.tabs[event.index] ?? this.tabs[0]; + this.currentTab = nextTab; + + if (nextTab.routeSegment === 'select' || !this.selectedProject) { + this.router.navigate(['/units', this.unit.id, 'students', 'portfolios'], {replaceUrl: true}); + return; + } + + this.navigateToProject(this.selectedProject.id, nextTab.routeSegment); + } + + private loadStudents(): void { + this.projectService.loadStudents(this.unit, false).subscribe({ + next: () => { + this.loadingStudents = false; + }, + error: (error) => { + this.alertService.error(`Failed to load unit: ${error}`, 6000); + this.router.navigateByUrl('/home'); + }, + }); + } + + private updateCurrentTabFromState( + tabParam?: string | null, + projectIdParam?: string | null, + ): void { + const projectId = projectIdParam ? Number(projectIdParam) : null; + const requestedTab = this.tabFromRoute(tabParam, !!projectId); + + this.currentTab = requestedTab; + + if (!projectId) { + this.selectedProjectId = null; + this.selectedProject = null; + this.selectedProject$.next(null); + return; + } + + if (this.selectedProject?.id === projectId) { + return; + } + + this.loadProject(projectId); + } + + private tabFromRoute(tabParam: string | null, hasProject: boolean): PortfolioTab { + if (!hasProject) { + return this.tabs[0]; + } + + const routeTab = this.tabs.find( + (tab) => tab.routeSegment === tabParam && tab.routeSegment !== 'select', + ); + + return routeTab ?? this.tabs.find((tab) => tab.routeSegment === 'progress') ?? this.tabs[0]; + } + + private loadProject(projectId: number): void { + this.selectedProjectId = projectId; + + this.projectService.loadProject(projectId, this.unit).subscribe({ next: (project) => { + if (this.selectedProjectId !== project.id) { + return; + } + this.selectedProject = project; - this.tabs.selectedIndex = 1; + this.selectedProject$.next(project); }, error: (error) => { + this.selectedProjectId = null; + this.selectedProject = null; + this.selectedProject$.next(null); this.alertService.error(`Failed to load project: ${error}`, 6000); console.error(error); }, }); } - ngOnInit(): void { - this.unit$ = this.unit$ ?? of(this.route.parent.snapshot.data.unit); - this.unit$?.pipe(first()).subscribe({ - next: (unit) => { - this.unit = unit; - this.unit.loadD2lMapping().subscribe(); - - this.projectService.loadStudents(unit, false).subscribe({ - next: () => { - this.loadingStudents = false; - }, - error: (error) => { - this.alertService.error(`Failed to load unit: ${error}`, 6000); - this.router.navigateByUrl('/home'); - }, - }); - }, - error: (error) => { - this.alertService.error(`Failed to load unit: ${error}`, 6000); - this.router.navigateByUrl('/home'); - }, + private navigateToProject(projectId: number, tab: PortfolioTabKey): void { + this.router.navigate(['/units', this.unit.id, 'students', 'portfolios', projectId, tab], { + replaceUrl: true, }); } } diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts index f4e4c4e4d1..044f6a0b6b 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts @@ -18,6 +18,7 @@ export class FUnitTaskListComponent implements OnChanges, OnInit { @Input() taskDefinitions: TaskDefinition[]; @Input() tasks: Task[]; @Input() isCollapsed = false; + @Input() selectionUrlBase: unknown[] | null = null; @HostBinding('class.collapsed') public get collapsedHostClass(): boolean { @@ -155,6 +156,12 @@ export class FUnitTaskListComponent implements OnChanges, OnInit { } private buildSelectionUrlTree(taskDef: TaskDefinition | null) { + if (this.selectionUrlBase) { + return this.angularRouter.createUrlTree( + taskDef ? [...this.selectionUrlBase, taskDef.abbreviation] : this.selectionUrlBase, + ); + } + const unitId = this.route.parent?.snapshot.paramMap.get('unitId'); if (this.route.parent?.snapshot.data.unit && unitId) { return this.angularRouter.createUrlTree( From 0a9e7e4e807858686b7d66596e32aec0141b9ad3 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Tue, 16 Jun 2026 17:03:36 +1000 Subject: [PATCH 1113/1280] refactor: move charts to mat cards --- .../progress-dashboard.component.html | 60 ++++++++----------- 1 file changed, 26 insertions(+), 34 deletions(-) diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html index 93df2d92d1..02ac242529 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html @@ -56,50 +56,42 @@

    - -
    -
    -
    -

    Progress Burndown

    -

    - The burndown chart shows how much work remains for you to achieve your target grade. -

    -
    -
    -
    + + + Progress Burndown + + The burndown chart shows how much work remains for you to achieve your target grade. + + + -
    -
    - Aim to keep your - Complete - line close to or ahead of the - Target - line to keep on track. -
    -
    - - -
    -
    -
    -

    Task Statuses

    -

    - Breakdown summary of each of your task statuses. -

    +
    + Aim to keep your + Complete + line close to or ahead of the + Target + line to keep on track.
    -
    -
    + + + + + + Task Statuses + Breakdown summary of each of your task statuses + + -
    -
    + +
    From 4ff55627566f9004872c915658bd91bc348dd8e8 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Tue, 16 Jun 2026 17:32:06 +1000 Subject: [PATCH 1114/1280] feat: check access token expiry locally before attempting request (#1270) --- src/app/api/models/user/user.ts | 1 + .../api/services/authentication.service.ts | 2 + .../common/services/http-error.interceptor.ts | 50 ++++++++++++------- 3 files changed, 34 insertions(+), 19 deletions(-) diff --git a/src/app/api/models/user/user.ts b/src/app/api/models/user/user.ts index f020d22d54..df4d7c5846 100644 --- a/src/app/api/models/user/user.ts +++ b/src/app/api/models/user/user.ts @@ -21,6 +21,7 @@ export class User extends Entity { public receiveFeedbackNotifications: boolean; public hasRunFirstTimeSetup: boolean; public authenticationToken: string; + public authenticationTokenExpiry: string; public pronouns: string | null; public acceptedTiiEula: boolean; diff --git a/src/app/api/services/authentication.service.ts b/src/app/api/services/authentication.service.ts index b99fa5c05b..1f4ed2b7ff 100644 --- a/src/app/api/services/authentication.service.ts +++ b/src/app/api/services/authentication.service.ts @@ -14,6 +14,7 @@ import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global interface AuthResponse { user: object; auth_token: string; + auth_token_expiry: string; lti_token?: string; } @@ -175,6 +176,7 @@ export class AuthenticationService { // Set the user's authentication token for access to api. user.authenticationToken = response['auth_token']; + user.authenticationTokenExpiry = response['auth_token_expiry']; // Record the current user this.userService.currentUser = user; diff --git a/src/app/common/services/http-error.interceptor.ts b/src/app/common/services/http-error.interceptor.ts index 3de001b7ed..1e0264220e 100644 --- a/src/app/common/services/http-error.interceptor.ts +++ b/src/app/common/services/http-error.interceptor.ts @@ -37,27 +37,19 @@ export class HttpErrorInterceptor implements HttpInterceptor { } intercept(request: HttpRequest, next: HttpHandler): Observable> { - // const retryTimes: number = 3; - // const delayDuration: number = 100; + const request$ = this.isAccessTokenExpired(request) + ? throwError(() => new HttpErrorResponse({status: 419})) + : next.handle(request); - // TODO: Check for access token / refresh token expiration before trying the initial request - // .. This way we can avoid spamming console with 409 errors - - return next.handle(request).pipe( - // retryWhen(errors => errors - // .pipe( - // concatMap((error, count) => { - // if (count < retryTimes && (error.status === 400 || error.status === 0)) { - // return of(error.status); - // } - // return throwError(error); - // }), - // delay(delayDuration) - // ) - // ), + return request$.pipe( catchError((error: HttpErrorResponse) => { if (this.isAuthError(error)) { + if (this.isAccessTokenRequest(request)) { + return throwError(() => this.extractErrorMessage(error)); + } + if (!this.refreshTokenInProgress) { + console.log('Refreshing access token'); this.refreshTokenInProgress = true; this.refreshTokenSubject.next(null); return this.attemptRefresh$().pipe( @@ -70,6 +62,9 @@ export class HttpErrorInterceptor implements HttpInterceptor { if (this.isAuthError(err)) { this.authenticationService.timeoutAuthentication(); } + if (!(err instanceof HttpErrorResponse)) { + return throwError(() => err); + } return throwError(() => this.extractErrorMessage(err)); }), finalize(() => (this.refreshTokenInProgress = false)), @@ -78,8 +73,9 @@ export class HttpErrorInterceptor implements HttpInterceptor { return this.refreshTokenSubject.pipe( filter((result) => result !== null), take(1), - switchMap((_res) => { - return next.handle(this.injectToken(request)); + switchMap(() => next.handle(this.injectToken(request))), + catchError((err: HttpErrorResponse) => { + return throwError(() => this.extractErrorMessage(err)); }), ); } @@ -94,6 +90,22 @@ export class HttpErrorInterceptor implements HttpInterceptor { return error.status === 419 || (error.status === 403 && this.userService.isAnonymousUser()); } + private isAccessTokenExpired(request: HttpRequest) { + const user = this.userService.currentUser; + const expiry = Date.parse(user.authenticationTokenExpiry); + + return ( + !this.isAccessTokenRequest(request) && + !!user.authenticationToken && + !Number.isNaN(expiry) && + expiry <= Date.now() + ); + } + + private isAccessTokenRequest(request: HttpRequest) { + return request.url.endsWith('/auth/access-token'); + } + private extractErrorMessage(error: HttpErrorResponse) { let errorMessage: string; let logMessage: string = ''; From 5c95b4718e0ee01bf4db1e7e645c3f2f953d62ef Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 17 Jun 2026 10:28:32 +1000 Subject: [PATCH 1115/1280] refactor: prevent camera running in background (#1210) * refactor: prevent camera running in background * refactor: improve ui scaling of tutor mobile view * chore: improve ui * fix: ensure scanner works after route loads * chore: improve ui * refactor: hide qr scanner in header if already in tutor discussion route * fix: ensure scanner works after route loads --- src/app/common/header/header.component.html | 2 +- src/app/common/header/header.component.ts | 4 + .../tutor-discussion.component.html | 6 +- .../tutor-discussion.component.ts | 169 ++++++++++++++---- 4 files changed, 142 insertions(+), 39 deletions(-) diff --git a/src/app/common/header/header.component.html b/src/app/common/header/header.component.html index 549c5189db..4f479836ec 100644 --- a/src/app/common/header/header.component.html +++ b/src/app/common/header/header.component.html @@ -52,7 +52,7 @@ > } - @if (currentUnit) { + @if (currentUnit && !isTutorDiscussionRoute) { diff --git a/src/app/common/header/header.component.ts b/src/app/common/header/header.component.ts index db60bca5b4..68ebc4dd99 100644 --- a/src/app/common/header/header.component.ts +++ b/src/app/common/header/header.component.ts @@ -182,6 +182,10 @@ export class HeaderComponent implements OnInit, OnDestroy { } } + public get isTutorDiscussionRoute(): boolean { + return this.router.url.split('?')[0].endsWith('/discussion'); + } + showSidekiqJob() { this.sidekiqJobsModalService.show(); } diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html index 2512e09030..843c67695b 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html @@ -48,7 +48,7 @@ }
    -
    +
    @if (project && project?.student) {
    @@ -66,8 +66,8 @@
    Click the QR code to open the scanner..
    } -
    diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts index 39ceefd689..99ca6117dd 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts @@ -1,5 +1,14 @@ import {Html5QrcodeScanner, Html5QrcodeScannerState} from 'html5-qrcode'; -import {AfterViewInit, Component, Input, ViewChild, ViewEncapsulation} from '@angular/core'; +import {DOCUMENT} from '@angular/common'; +import { + AfterViewInit, + Component, + Inject, + Input, + OnDestroy, + ViewChild, + ViewEncapsulation, +} from '@angular/core'; import {MatSelectionList} from '@angular/material/list'; import {MatTabChangeEvent} from '@angular/material/tabs'; import {ActivatedRoute, Router} from '@angular/router'; @@ -34,8 +43,10 @@ enum TutorDiscussionTabView { encapsulation: ViewEncapsulation.None, standalone: false, }) -export class TutorDiscussionComponent implements AfterViewInit { +export class TutorDiscussionComponent implements AfterViewInit, OnDestroy { private readonly discussedInClassNotePrefix = `I'm manually marking this discussed in class because...`; + private readonly mobileDiscussionViewportContent = + 'width=device-width, initial-scale=0.8, maximum-scale=5'; @Input() unitId: number; @Input() username: string; @@ -55,7 +66,9 @@ export class TutorDiscussionComponent implements AfterViewInit { public scanningQr: boolean = false; public loadingStudentData: boolean = false; - private html5QrcodeScanner: Html5QrcodeScanner; + private html5QrcodeScanner?: Html5QrcodeScanner; + private originalViewportContent: string | null = null; + private mobileDiscussionZoomApplied = false; private _unitId: number; private _username: string; @@ -64,6 +77,7 @@ export class TutorDiscussionComponent implements AfterViewInit { public footerTabView: TutorDiscussionTabView = TutorDiscussionTabView.SHOW_COMMENTS; constructor( + @Inject(DOCUMENT) private document: Document, private unitService: UnitService, private authService: AuthenticationService, private userService: UserService, @@ -78,6 +92,11 @@ export class TutorDiscussionComponent implements AfterViewInit { private taskService: TaskService, ) {} + public ngOnDestroy(): void { + this.stopQrScanner(); + this.restoreViewportZoom(); + } + public currentUserTutorsInStream(tutorialStream: TutorialStream): boolean { const user = this.userService.currentUser; const tutorials = this.unit.tutorials.filter( @@ -142,7 +161,7 @@ export class TutorDiscussionComponent implements AfterViewInit { this._username = this.username; this.getStudentTasks(); } else { - this.scanQrCode(); + setTimeout(() => this.scanQrCode()); } } else { this.getUnit().then((u) => { @@ -183,6 +202,7 @@ export class TutorDiscussionComponent implements AfterViewInit { public closeQrReader(): void { if (!this.project) { // Exiting the route entirely + this.stopQrScanner(); if (this.unitId) { this.router.navigate(['/units', this.unitId, 'tasks', 'inbox']); } else { @@ -191,11 +211,12 @@ export class TutorDiscussionComponent implements AfterViewInit { } else { // Close the camera view this.scanningQr = false; + this.stopQrScanner(); } } private changeProject() { - this.html5QrcodeScanner.pause(true); + this.html5QrcodeScanner?.pause(true); this.loadingStudentData = true; setTimeout(() => { try { @@ -205,14 +226,112 @@ export class TutorDiscussionComponent implements AfterViewInit { this.loadingStudentData = false; setTimeout(() => { - this.html5QrcodeScanner.resume(); + this.html5QrcodeScanner?.resume(); }, 2000); } }); } + private applyMobileDiscussionZoom(): void { + if (!window.matchMedia('(max-width: 768px)').matches) { + return; + } + + const viewport = this.document.querySelector('meta[name="viewport"]'); + if (!viewport) { + return; + } + + this.originalViewportContent ??= viewport.getAttribute('content'); + viewport.setAttribute('content', this.mobileDiscussionViewportContent); + this.mobileDiscussionZoomApplied = true; + } + + private restoreViewportZoom(): void { + if (!this.mobileDiscussionZoomApplied) { + return; + } + + const viewport = this.document.querySelector('meta[name="viewport"]'); + if (viewport && this.originalViewportContent) { + viewport.setAttribute('content', this.originalViewportContent); + } + + this.mobileDiscussionZoomApplied = false; + } + hideQrScannerBloat: boolean = true; + private async stopQrScanner(): Promise { + if (!this.html5QrcodeScanner) { + return; + } + + try { + await this.html5QrcodeScanner.clear(); + } catch (_e) { + // The scanner may already be stopped by its own controls. + } finally { + this.html5QrcodeScanner = undefined; + } + } + + private async getCameraPermissionState(): Promise { + if (!navigator.permissions?.query) { + return null; + } + + try { + const permissionStatus = await navigator.permissions.query({ + name: 'camera' as PermissionName, + }); + return permissionStatus.state; + } catch (_e) { + return null; + } + } + + private async prepareQrScannerCamera(): Promise { + const cachedScannerData = localStorage.getItem('HTML5_QRCODE_DATA'); + const cameraPermissionState = await this.getCameraPermissionState(); + if (cachedScannerData) { + try { + const html5QrcodeData = JSON.parse(cachedScannerData); + if (html5QrcodeData?.hasPermission && cameraPermissionState === 'granted') { + this.hideQrScannerBloat = html5QrcodeData.lastUsedCameraId ? true : false; + return; + } + } catch (_e) { + localStorage.removeItem('HTML5_QRCODE_DATA'); + } + } + + // Trigger video permissions once so device labels are available for back camera selection. + // Stopping these tracks releases the camera; the browser keeps the permission grant. + const stream = await navigator.mediaDevices.getUserMedia({video: true}); + + try { + const devices = await navigator.mediaDevices.enumerateDevices(); + + // Find the deviceId of the back camera + const backCameras = devices.filter( + (d) => d.kind === 'videoinput' && d.label.toLowerCase().includes('back camera'), + ); + + const html5QrcodeData = { + hasPermission: true, + lastUsedCameraId: backCameras[0]?.deviceId ?? null, + }; + localStorage.setItem('HTML5_QRCODE_DATA', JSON.stringify(html5QrcodeData)); + + // Hide most of the UI if we found and set the back camera + // Otherwise, we need to reveal the UI so that the user can select which camera to use + this.hideQrScannerBloat = html5QrcodeData.lastUsedCameraId ? true : false; + } finally { + stream.getTracks().forEach((track) => track.stop()); + } + } + public scanQrCode() { if (this.attendance && !this.selectedTaskDefinition) { this.alertService.error('You must select a task first', 3000); @@ -222,39 +341,13 @@ export class TutorDiscussionComponent implements AfterViewInit { this.scanningQr = true; this.loadingStudentData = false; - if ( - this.html5QrcodeScanner && - this.html5QrcodeScanner.getState() === Html5QrcodeScannerState.PAUSED - ) { + if (this.html5QrcodeScanner?.getState() === Html5QrcodeScannerState.PAUSED) { this.html5QrcodeScanner.resume(); } else { - this.html5QrcodeScanner?.clear(); - - // Trigger video permissions - // If we call getUserMedia when html5QrcodeScanner is already active, the scanner will break on iOS - navigator.mediaDevices - .getUserMedia({video: true}) + this.stopQrScanner() + .then(() => this.prepareQrScannerCamera()) .then(() => { - return navigator.mediaDevices.enumerateDevices(); - }) - .then((devices) => { - // Find the deviceId of the back camera - const backCameras = devices.filter( - (d) => d.kind === 'videoinput' && d.label.toLowerCase().includes('back camera'), - ); - - const html5QrcodeData = { - hasPermission: true, - lastUsedCameraId: backCameras[0]?.deviceId ?? null, - }; - localStorage.setItem('HTML5_QRCODE_DATA', JSON.stringify(html5QrcodeData)); - - // Hide most of the UI if we found and set the back camera - // Otherwise, we need to reveal the UI so that the user can select which camera to use - this.hideQrScannerBloat = html5QrcodeData.lastUsedCameraId ? true : false; - setTimeout(() => { - // Only init the scanner once and let it run in the background this.html5QrcodeScanner = new Html5QrcodeScanner( 'qr-reader', // id of the div in the html {fps: 10, qrbox: 250}, @@ -270,6 +363,10 @@ export class TutorDiscussionComponent implements AfterViewInit { }, ); }); + }) + .catch((_e) => { + this.scanningQr = false; + this.alertService.error('Camera permission is required to scan QR codes', 3000); }); } } @@ -534,6 +631,8 @@ export class TutorDiscussionComponent implements AfterViewInit { this.project = project; this.scanningQr = false; this.loadingStudentData = false; + this.stopQrScanner(); + this.applyMobileDiscussionZoom(); }) .catch((e) => { console.error(e); From 4cdae07eb5bef0f9866927892e92b6b80dde0c74 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 17 Jun 2026 11:36:05 +1000 Subject: [PATCH 1116/1280] feat: submission history (#1269) * feat: submission history * refactor: improve tab order * refactor: merge history components * chore: format * fix: add task status fallbacks * fix: manually add back code block styling --- src/app/api/models/doubtfire-model.ts | 2 + .../models/overseer/overseer-assessment.ts | 4 +- src/app/api/models/submission-history.ts | 34 ++ src/app/api/models/task-definition.ts | 1 + src/app/api/models/task-status.ts | 2 +- .../services/overseer-assessment.service.ts | 1 + .../services/submission-history.service.ts | 44 +++ .../api/services/task-definition.service.ts | 3 + .../status-icon/status-icon.component.html | 8 +- .../status-icon/status-icon.component.ts | 27 +- src/app/doubtfire-angular.module.ts | 4 +- .../submission-files-modal.component.ts | 8 +- .../task-overseer-report.component.html | 353 ++++++++++-------- .../task-overseer-report.component.ts | 129 ++++--- .../task-dashboard.component.html | 10 +- .../task-dashboard.component.ts | 71 +--- .../states/dashboard/selected-task.service.ts | 8 +- .../task-submission-history.component.html | 43 --- .../task-submission-history.component.scss | 188 ---------- .../task-submission-history.component.ts | 110 ------ .../task-definition-upload.component.html | 16 + .../task-definition-upload.component.ts | 17 +- 22 files changed, 432 insertions(+), 651 deletions(-) create mode 100644 src/app/api/models/submission-history.ts create mode 100644 src/app/api/services/submission-history.service.ts delete mode 100644 src/app/tasks/task-submission-history/task-submission-history.component.html delete mode 100644 src/app/tasks/task-submission-history/task-submission-history.component.scss delete mode 100644 src/app/tasks/task-submission-history/task-submission-history.component.ts diff --git a/src/app/api/models/doubtfire-model.ts b/src/app/api/models/doubtfire-model.ts index 9ee73db62a..4c04633b82 100644 --- a/src/app/api/models/doubtfire-model.ts +++ b/src/app/api/models/doubtfire-model.ts @@ -18,6 +18,7 @@ export * from './unit'; export * from './project'; export * from './task'; export * from './task-definition'; +export * from './submission-history'; export * from './learning-outcome'; export * from './tutorial-enrolment'; export * from './unit-role'; @@ -53,6 +54,7 @@ export * from '../services/task.service'; export * from '../services/tutorial.service'; export * from '../services/tutorial-stream.service'; export * from '../services/overseer-assessment.service'; +export * from '../services/submission-history.service'; export * from '../services/campus.service'; export * from '../services/user.service'; export * from '../services/unit-role.service'; diff --git a/src/app/api/models/overseer/overseer-assessment.ts b/src/app/api/models/overseer/overseer-assessment.ts index f658c57986..20e5d959d3 100644 --- a/src/app/api/models/overseer/overseer-assessment.ts +++ b/src/app/api/models/overseer/overseer-assessment.ts @@ -2,9 +2,10 @@ import {Entity, EntityCache, EntityMapping} from 'ngx-entity-service'; import {AppInjector} from 'src/app/app-injector'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {Task} from '../doubtfire-model'; +import {SubmissionArchive} from '../submission-history'; import {OverseerStepResult} from './overseer-step-result'; -export class OverseerAssessment extends Entity { +export class OverseerAssessment extends Entity implements SubmissionArchive { id: number; // overseerStepId: number; timestamp: Date; @@ -16,6 +17,7 @@ export class OverseerAssessment extends Entity { createdAt?: Date; updatedAt?: Date; taskId?: number; + submissionHistoryId?: number; totalSteps: number; passedSteps: number; diff --git a/src/app/api/models/submission-history.ts b/src/app/api/models/submission-history.ts new file mode 100644 index 0000000000..d65888b64a --- /dev/null +++ b/src/app/api/models/submission-history.ts @@ -0,0 +1,34 @@ +import {Entity} from 'ngx-entity-service'; +import {AppInjector} from 'src/app/app-injector'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Task} from './task'; + +export interface SubmissionArchive { + id: number; + task?: Task; + timestamp: Date; + timestampString: string; + hasSubmissionFiles?: boolean; + submissionFilesUrl(): string; +} + +export class SubmissionHistory extends Entity implements SubmissionArchive { + id: number; + task?: Task; + taskId?: number; + timestamp: Date; + timestampString: string; + createdAt?: Date; + hasSubmissionFiles?: boolean; + overseerAssessmentId?: number; + + constructor(task?: Task) { + super(); + this.task = task; + } + + public submissionFilesUrl(): string { + const constants = AppInjector.get(DoubtfireConstants); + return `${constants.API_URL}/projects/${this.task.project.id}/task_def_id/${this.task.definition.id}/submission_histories/${this.id}/files`; + } +} diff --git a/src/app/api/models/task-definition.ts b/src/app/api/models/task-definition.ts index d884b4b78f..e128d60cfc 100644 --- a/src/app/api/models/task-definition.ts +++ b/src/app/api/models/task-definition.ts @@ -17,6 +17,7 @@ export interface UploadRequirement { type: string; tiiCheck?: boolean; tiiPct?: number; + submissionHistory?: boolean; } export interface SimilarityCheck { diff --git a/src/app/api/models/task-status.ts b/src/app/api/models/task-status.ts index d2894a4478..a452b22d5c 100644 --- a/src/app/api/models/task-status.ts +++ b/src/app/api/models/task-status.ts @@ -482,6 +482,6 @@ export class TaskStatus { } public static statusClass(status: TaskStatusEnum | undefined): string { - return status?.replace(new RegExp('_', 'g'), '-'); + return status?.replace(new RegExp('_', 'g'), '-') ?? 'not-started'; } } diff --git a/src/app/api/services/overseer-assessment.service.ts b/src/app/api/services/overseer-assessment.service.ts index 1200c13a35..c206952ec5 100644 --- a/src/app/api/services/overseer-assessment.service.ts +++ b/src/app/api/services/overseer-assessment.service.ts @@ -24,6 +24,7 @@ export class OverseerAssessmentService extends EntityService 'id', 'submissionTimestamp', 'taskId', + 'submissionHistoryId', 'createdAt', 'updatedAt', ['taskStatus', 'result_task_status'], diff --git a/src/app/api/services/submission-history.service.ts b/src/app/api/services/submission-history.service.ts new file mode 100644 index 0000000000..e65d1053ce --- /dev/null +++ b/src/app/api/services/submission-history.service.ts @@ -0,0 +1,44 @@ +import {EntityService} from 'ngx-entity-service'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {Observable} from 'rxjs'; +import {SubmissionHistory} from 'src/app/api/models/submission-history'; +import {Task} from 'src/app/api/models/task'; +import API_URL from 'src/app/config/constants/apiUrl'; + +@Injectable() +export class SubmissionHistoryService extends EntityService { + protected readonly endpointFormat = + 'projects/:project_id:/task_def_id/:td_id:/submission_histories/:id:'; + + constructor(httpClient: HttpClient) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'taskId', + 'createdAt', + 'hasSubmissionFiles', + 'overseerAssessmentId', + { + keys: ['timestamp', 'submission_timestamp'], + toEntityFn: (data) => new Date(Number(data['submission_timestamp']) * 1000), + }, + ['timestampString', 'submission_timestamp'], + ); + } + + public createInstanceFrom(_json: object, task?: Task): SubmissionHistory { + return new SubmissionHistory(task); + } + + public queryForTask(task: Task): Observable { + return this.query( + { + project_id: task.project.id, + td_id: task.definition.id, + }, + {constructorParams: task}, + ); + } +} diff --git a/src/app/api/services/task-definition.service.ts b/src/app/api/services/task-definition.service.ts index 5bb0e6baca..578b0838e6 100644 --- a/src/app/api/services/task-definition.service.ts +++ b/src/app/api/services/task-definition.service.ts @@ -66,6 +66,7 @@ export class TaskDefinitionService extends CachedEntityService { type: upreq.type, tii_check: upreq.tiiCheck, tii_pct: upreq.tiiPct, + submission_history: upreq.submissionHistory, }; }), ); @@ -78,6 +79,7 @@ export class TaskDefinitionService extends CachedEntityService { type: string; tii_check: boolean; tii_pct: number; + submission_history: boolean; }[] )?.map((upreq) => { return { @@ -86,6 +88,7 @@ export class TaskDefinitionService extends CachedEntityService { type: upreq.type, tiiCheck: upreq.tii_check, tiiPct: upreq.tii_pct, + submissionHistory: upreq.submission_history, }; }); }, diff --git a/src/app/common/status-icon/status-icon.component.html b/src/app/common/status-icon/status-icon.component.html index 0165a2d2a4..45bd7cbd89 100644 --- a/src/app/common/status-icon/status-icon.component.html +++ b/src/app/common/status-icon/status-icon.component.html @@ -1,6 +1,6 @@
    {{ statusIcon(status) }}{{ statusIcon }}
    diff --git a/src/app/common/status-icon/status-icon.component.ts b/src/app/common/status-icon/status-icon.component.ts index e2794943bf..56e2cf060a 100644 --- a/src/app/common/status-icon/status-icon.component.ts +++ b/src/app/common/status-icon/status-icon.component.ts @@ -8,20 +8,31 @@ import {TaskStatus, TaskStatusEnum} from 'src/app/api/models/task-status'; standalone: false, }) export class StatusIconComponent implements OnInit { - @Input() status: TaskStatusEnum = 'not_started'; + @Input() status?: TaskStatusEnum = 'not_started'; @Input() showTooltip: boolean; @Input() compact = false; - statusIcon: (status: TaskStatusEnum) => string; - statusLabel: (status: TaskStatusEnum) => string; - statusClass: (status: TaskStatusEnum) => string; - ngOnInit(): void { if (this.showTooltip == null) { this.showTooltip = true; } - this.statusIcon = (status: TaskStatusEnum) => TaskStatus.STATUS_MATERIAL_ICONS.get(status); - this.statusLabel = (status: TaskStatusEnum) => TaskStatus.STATUS_LABELS.get(status); - this.statusClass = (status: TaskStatusEnum) => TaskStatus.statusClass(status); + } + + get statusIcon(): string { + return TaskStatus.STATUS_MATERIAL_ICONS.get(this.resolvedStatus) ?? 'pause'; + } + + get statusLabel(): string { + return TaskStatus.STATUS_LABELS.get(this.resolvedStatus) ?? 'Not Started'; + } + + get statusClass(): string { + return TaskStatus.statusClass(this.resolvedStatus); + } + + get resolvedStatus(): TaskStatusEnum { + return this.status && TaskStatus.STATUS_KEYS.includes(this.status) + ? this.status + : 'not_started'; } } diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index ca76573084..518f8f3eb5 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -122,6 +122,7 @@ import { OverseerAssessmentService, OverseerImageService, ProjectService, + SubmissionHistoryService, TaskCommentService, TaskService, TaskSimilarityService, @@ -303,7 +304,6 @@ import {ScormCommentComponent} from './tasks/task-comments-viewer/scorm-comment/ import {ScormExtensionCommentComponent} from './tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component'; import {TaskAssessmentCommentComponent} from './tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component'; import {TaskCommentsViewerComponent} from './tasks/task-comments-viewer/task-comments-viewer.component'; -import {TaskSubmissionHistoryComponent} from './tasks/task-submission-history/task-submission-history.component'; import {UnitStudentEnrolmentModalComponent} from './units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component'; import {AnalyticsTutorTimesComponent} from './units/states/analytics/directives/analytics-tutor-times.component'; import {UnitAnalyticsComponent} from './units/states/analytics/unit-analytics-route.component'; @@ -497,7 +497,6 @@ const DEFAULT_TOOLTIP_OPTIONS: MatTooltipDefaultOptions = { StatusIconComponent, TaskAssessmentCommentComponent, TaskAssessmentModalComponent, - TaskSubmissionHistoryComponent, GradeIconComponent, HeaderComponent, UnitDropdownComponent, @@ -666,6 +665,7 @@ const DEFAULT_TOOLTIP_OPTIONS: MatTooltipDefaultOptions = { ActivityTypeService, OverseerImageService, OverseerAssessmentService, + SubmissionHistoryService, EmojiService, FileDownloaderService, CheckForUpdateService, diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts index 00a8e1588d..47d19f2a7e 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts @@ -2,7 +2,7 @@ import * as monaco from 'monaco-editor'; import {HttpResponse} from '@angular/common/http'; import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; -import {OverseerAssessment} from 'src/app/api/models/doubtfire-model'; +import {SubmissionArchive} from 'src/app/api/models/submission-history'; import { ArchiveFileEntry, isArchiveCodeOrTextFile, @@ -13,10 +13,10 @@ import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloa import {AlertService} from 'src/app/common/services/alert.service'; export interface SubmissionFilesModalData { - assessment: OverseerAssessment; + assessment: SubmissionArchive; assessmentNumber?: number; assessmentIsMostRecent?: boolean; - comparedWith?: OverseerAssessment; + comparedWith?: SubmissionArchive; comparedWithNumber?: number; comparedWithIsMostRecent?: boolean; } @@ -151,7 +151,7 @@ export class SubmissionFilesModalComponent implements OnInit, OnDestroy { } } - private downloadSubmissionArchive(assessment: OverseerAssessment): Promise { + private downloadSubmissionArchive(assessment: SubmissionArchive): Promise { return new Promise((resolve, reject) => { this.fileDownloader.downloadBlob( assessment.submissionFilesUrl(), diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html index 668fb5daaf..4d8eaaad19 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.html @@ -1,55 +1,79 @@
    - +
    - - @for (oa of overseerAssessments; track oa; let idx = $index) { - - - - - Submission {{ overseerAssessments.length - idx }}: {{ oa.timestamp | humanizedDate }} - @if (idx === 0) { - (Most recent) - } - @if (isComparisonSource(oa)) { - (Selected for comparison) - } - - @if (oa.reportReady) { +@if (loading) { +
    + +
    +} @else { + + @for (history of histories; track history.id; let idx = $index) { + + + + @if (assessmentFor(history); as oa) { + + } +
    +
    + Submission {{ histories.length - idx }} + @if (idx === 0) { + (Most recent) + } + @if (isComparisonSource(history)) { + (Selected for comparison) + } +
    +
    + {{ history.timestamp | date: 'dd/MM/yyyy HH:mm' }} +
    +
    +
    +
    - {{ oa.passedSteps }} / {{ oa.totalSteps }} - @if (oa.passedSteps === oa.totalSteps) { - done - } @else { - cancel + @if (assessmentFor(history); as oa) { + @if (oa.reportReady) { + Click to view Overseer report + {{ oa.passedSteps }} / {{ oa.totalSteps }} + @if (oa.passedSteps === oa.totalSteps) { + done + } @else { + cancel + } + } @else { + + Tests In Progress + + + } } - @if (oa.hasSubmissionFiles && currentUnitRole) { + + @if (history.hasSubmissionFiles && currentUnitRole) { -
    - - @if (hasComparisonSourceFor(oa)) { - - } @else if (isComparisonSource(oa)) { + } @else if (isComparisonSource(history)) {
    - } @else { -
    - Tests In Progress - -
    - } -
    +
    - - @for (result of oa.stepResultsCache.values | async; track result.id; let idx = $index) { - - - - Step {{ idx + 1 }}: {{ result.overseerStep?.displayName }} - @if (result.pass) { - done - } @else { - cancel - } - + @if (assessmentFor(history); as oa) { + + @for (result of oa.stepResultsCache.values | async; track result.id; let idx = $index) { + + + + Step {{ idx + 1 }}: {{ result.overseerStep?.displayName }} + @if (result.pass) { + done + } @else { + cancel + } + - - + + - @if (!result.pass) { -

    - {{ result.feedbackMessage }} -

    - } + @if (!result.pass) { +

    + {{ result.feedbackMessage }} +

    + } - @if ( - result.expectedOutput && - result.expectedOutput !== result.stdout && - (result.overseerStep?.stepType === 'output_diff' || !result.overseerStep) - ) { -
    - + @if ( + result.expectedOutput && + result.expectedOutput !== result.stdout && + (result.overseerStep?.stepType === 'output_diff' || !result.overseerStep) + ) { +
    + - - + + - -
    - @if (viewOutput === 'diff' || viewOutput === 'split_diff') { - @if (result.expectedOutput !== result.stdout) { - + +
    + @if (viewOutput === 'diff' || viewOutput === 'split_diff') { + @if (result.expectedOutput !== result.stdout) { + + } + } @else if (viewOutput === 'your_output') { + + } @else if (viewOutput === 'expected_output') { + + } + } @else if (result.stdout) { +
    {{result.stdout}}
    + } @else if (result.pass) { +
    + SUCCESS +
    +
    + (No Output) +
    } - } @else if (viewOutput === 'your_output') { - - } @else if (viewOutput === 'expected_output') { - - } - } @else if (result.stdout) { -
    {{result.stdout}}
    - } @else if (result.pass) { -
    SUCCESS
    -
    - (No Output) -
    +
    } -
    - } - @if (loadingAssessments.has(oa.id)) { -
    - -
    - } @else { - @for (skipped of oa.stepsSkipped; track skipped.id; let idx = $index) { - - - - - - Step {{ oa.stepResultsCache.currentValues.length + idx + 1 }}: - {{ skipped?.displayName ?? '-' }} - (Skipped) - + @if (loadingAssessments.has(oa.id)) { +
    + +
    + } @else { + @for (skipped of oa.stepsSkipped; track skipped.id; let idx = $index) { + + + + + + Step {{ oa.stepResultsCache.currentValues.length + idx + 1 }}: + {{ skipped?.displayName ?? '-' }} + (Skipped) + - pause - - - } + pause +
    +
    + } + } +
    } -
    - - } @empty { -
    - subtitles_off -
    No submission reports for this task.
    -
    - } - + + } @empty { +
    + subtitles_off +
    No retained submissions for this task.
    +
    + } + +} diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts index c017ed3fe2..d9868ab3ef 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts @@ -1,12 +1,14 @@ import {Component, Input, OnInit} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; import {MatMenuTrigger} from '@angular/material/menu'; +import {forkJoin} from 'rxjs'; import {OverseerAssessment, UnitRole, UserService} from 'src/app/api/models/doubtfire-model'; +import {SubmissionHistory} from 'src/app/api/models/submission-history'; import {Task} from 'src/app/api/models/task'; import {OverseerAssessmentService} from 'src/app/api/services/overseer-assessment.service'; import {OverseerStepResultService} from 'src/app/api/services/overseer-step-result.service'; +import {SubmissionHistoryService} from 'src/app/api/services/submission-history.service'; import {AlertService} from 'src/app/common/services/alert.service'; -import {TaskSubmissionService} from 'src/app/common/services/task-submission.service'; import {SubmissionFilesModalComponent} from './submission-files-modal/submission-files-modal.component'; @Component({ @@ -18,11 +20,14 @@ import {SubmissionFilesModalComponent} from './submission-files-modal/submission export class TaskOverseerReportComponent implements OnInit { @Input() task: Task; @Input() loadOverseerAssessmentId?: number; - public comparisonSourceAssessmentId: number | null = null; + public histories: SubmissionHistory[] = []; + public overseerAssessments: OverseerAssessment[] = []; + public comparisonSourceHistoryId: number | null = null; + public loading = false; constructor( private alerts: AlertService, - private submissions: TaskSubmissionService, + private submissionHistoryService: SubmissionHistoryService, private overseerAssessmentService: OverseerAssessmentService, private overseerStepResultsService: OverseerStepResultService, private dialog: MatDialog, @@ -98,38 +103,38 @@ export class TaskOverseerReportComponent implements OnInit { this.viewOutput = 'expected_output'; } - public overseerAssessments: OverseerAssessment[] = []; - - public get comparisonSourceAssessment(): OverseerAssessment | null { - if (!this.comparisonSourceAssessmentId) { + public get comparisonSourceHistory(): SubmissionHistory | null { + if (!this.comparisonSourceHistoryId) { return null; } - return ( - this.overseerAssessments.find( - (assessment) => assessment.id === this.comparisonSourceAssessmentId, - ) ?? null - ); + return this.histories.find((history) => history.id === this.comparisonSourceHistoryId) ?? null; } ngOnInit(): void { - this.loadAssessments(); + this.loadHistory(); } - loadAssessments(isRefresh: boolean = false) { + loadHistory(isRefresh: boolean = false) { if (isRefresh) { this.loadOverseerAssessmentId = null; } - this.overseerAssessmentService.queryForTask(this.task).subscribe({ - next: (assessments) => { + this.loading = true; + + forkJoin({ + histories: this.submissionHistoryService.queryForTask(this.task), + assessments: this.overseerAssessmentService.queryForTask(this.task), + }).subscribe({ + next: ({histories, assessments}) => { + this.histories = histories; this.overseerAssessments = assessments; + if ( - this.comparisonSourceAssessmentId && - !this.overseerAssessments.some( - (assessment) => assessment.id === this.comparisonSourceAssessmentId, - ) + this.comparisonSourceHistoryId && + !this.histories.some((history) => history.id === this.comparisonSourceHistoryId) ) { - this.comparisonSourceAssessmentId = null; + this.comparisonSourceHistoryId = null; } + for (const oa of this.overseerAssessments) { for (const result of oa.stepResultsCache.currentValues) { result.overseerStep = this.task.definition.overseerStepsCache.currentValues.find( @@ -137,26 +142,39 @@ export class TaskOverseerReportComponent implements OnInit { ); } } + this.loading = false; }, error: (error) => { - this.alerts.error(`Failed to load overseer reports: ${error}`, 6000); + this.loading = false; + this.alerts.error(`Failed to load submission history: ${error}`, 6000); }, }); } loadingAssessments: Set = new Set(); - onAssessmentOpen(overseerAssesment: OverseerAssessment) { - if (this.loadOverseerAssessmentId === overseerAssesment.id) { + assessmentFor(history: SubmissionHistory): OverseerAssessment | undefined { + return this.overseerAssessments.find( + (assessment) => assessment.submissionHistoryId === history.id, + ); + } + + onHistoryOpen(history: SubmissionHistory) { + const overseerAssessment = this.assessmentFor(history); + if (!overseerAssessment) { + return; + } + + if (this.loadOverseerAssessmentId === overseerAssessment.id) { setTimeout(() => { - const el = document.getElementById(`oa-panel-${overseerAssesment.id}`); + const el = document.getElementById(`history-panel-${history.id}`); el?.scrollIntoView({behavior: 'smooth', block: 'start'}); }, 250); } - this.loadingAssessments.add(overseerAssesment.id); + this.loadingAssessments.add(overseerAssessment.id); - this.overseerStepResultsService.getOverseerStepResults(overseerAssesment).subscribe({ + this.overseerStepResultsService.getOverseerStepResults(overseerAssessment).subscribe({ next: () => { for (const oa of this.overseerAssessments) { for (const result of oa.stepResultsCache.currentValues) { @@ -165,11 +183,11 @@ export class TaskOverseerReportComponent implements OnInit { ); } } - this.loadingAssessments.delete(overseerAssesment.id); + this.loadingAssessments.delete(overseerAssessment.id); }, error: (error) => { console.error(error); - this.loadingAssessments.delete(overseerAssesment.id); + this.loadingAssessments.delete(overseerAssessment.id); }, }); } @@ -178,66 +196,55 @@ export class TaskOverseerReportComponent implements OnInit { event.stopPropagation(); } - isComparisonSource(assessment: OverseerAssessment): boolean { - return this.comparisonSourceAssessmentId === assessment.id; + isComparisonSource(history: SubmissionHistory): boolean { + return this.comparisonSourceHistoryId === history.id; } - hasComparisonSourceFor(assessment: OverseerAssessment): boolean { - return ( - this.comparisonSourceAssessmentId !== null && - this.comparisonSourceAssessmentId !== assessment.id - ); + hasComparisonSourceFor(history: SubmissionHistory): boolean { + return this.comparisonSourceHistoryId !== null && this.comparisonSourceHistoryId !== history.id; } - selectComparisonSource( - assessment: OverseerAssessment, - event?: Event, - menuTrigger?: MatMenuTrigger, - ) { + selectComparisonSource(history: SubmissionHistory, event?: Event, menuTrigger?: MatMenuTrigger) { event?.stopPropagation(); - this.comparisonSourceAssessmentId = assessment.id; + this.comparisonSourceHistoryId = history.id; menuTrigger?.closeMenu(); - this.alerts.message(`Selected submission ${assessment.timestampString} for comparison.`, 3500); + this.alerts.message(`Selected submission ${history.timestampString} for comparison.`, 3500); } clearComparisonSource(event?: Event) { event?.stopPropagation(); - this.comparisonSourceAssessmentId = null; + this.comparisonSourceHistoryId = null; } - compareWithSelected(assessment: OverseerAssessment, event?: Event) { + compareWithSelected(history: SubmissionHistory, event?: Event) { event?.stopPropagation(); - const selected = this.comparisonSourceAssessment; - if (!selected || selected.id === assessment.id) { + const selected = this.comparisonSourceHistory; + if (!selected || selected.id === history.id) { return; } - this.openSubmissionFilesDialog(assessment, selected); + this.openSubmissionFilesDialog(history, selected); } - viewSubmissionFiles(assessment: OverseerAssessment, event?: Event) { + viewSubmissionFiles(history: SubmissionHistory, event?: Event) { event?.stopPropagation(); - this.openSubmissionFilesDialog(assessment); + this.openSubmissionFilesDialog(history); } - private openSubmissionFilesDialog( - assessment: OverseerAssessment, - comparedWith?: OverseerAssessment, - ) { - const assessmentIndex = this.overseerAssessments.findIndex((item) => item.id === assessment.id); + private openSubmissionFilesDialog(history: SubmissionHistory, comparedWith?: SubmissionHistory) { + const historyIndex = this.histories.findIndex((item) => item.id === history.id); const comparedWithIndex = comparedWith - ? this.overseerAssessments.findIndex((item) => item.id === comparedWith.id) + ? this.histories.findIndex((item) => item.id === comparedWith.id) : -1; this.dialog.open(SubmissionFilesModalComponent, { data: { - assessment, - assessmentNumber: - assessmentIndex >= 0 ? this.overseerAssessments.length - assessmentIndex : undefined, - assessmentIsMostRecent: assessmentIndex === 0, + assessment: history, + assessmentNumber: historyIndex >= 0 ? this.histories.length - historyIndex : undefined, + assessmentIsMostRecent: historyIndex === 0, comparedWith, comparedWithNumber: - comparedWithIndex >= 0 ? this.overseerAssessments.length - comparedWithIndex : undefined, + comparedWithIndex >= 0 ? this.histories.length - comparedWithIndex : undefined, comparedWithIsMostRecent: comparedWithIndex === 0, }, maxWidth: '95vw', diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html index de593aa7b3..e4ad3411dd 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html @@ -19,6 +19,7 @@ @if (canAccessStaffViews) { + @@ -29,7 +30,6 @@ - @@ -69,12 +69,6 @@ folder_zip Download submitted files - @if (overseerEnabled) { - - }
    @@ -150,7 +144,7 @@
    } } - @case (DashboardViews.overseer) { + @case (DashboardViews.submission_history) { @if (canAccessStaffViews) {
    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.ts index 70f8e8febf..7aecf1173d 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.ts @@ -6,8 +6,6 @@ import {Task} from 'src/app/api/models/task'; import {TaskService} from 'src/app/api/services/task.service'; import {UserService} from 'src/app/api/services/user.service'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; -import {TaskAssessmentModalService} from 'src/app/common/modals/task-assessment-modal/task-assessment-modal.service'; -import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {SelectedTaskService} from '../../selected-task.service'; import {DashboardViews} from '../../selected-task.service'; @@ -36,41 +34,28 @@ export class TaskDashboardComponent implements OnInit, OnChanges { taskSheetPdfUrl?: string; taskSubmissionPdfUrl?: string; }; - public overseerEnabledObs = this.doubtfire.IsOverseerEnabled; public currentView: DashboardViews; - - public currentIndex; + public currentIndex = 0; + + private readonly tabViews: DashboardViews[] = [ + DashboardViews.details, + DashboardViews.task, + DashboardViews.submission, + DashboardViews.submission_history, + DashboardViews.similarity, + DashboardViews.staff_notes, + DashboardViews.tutor_notes, + ]; onTabChange(event: MatTabChangeEvent) { - switch (event.index) { - case 0: - this.setSelectedDashboardView(DashboardViews.details); - break; - case 1: - this.setSelectedDashboardView(DashboardViews.task); - break; - case 2: - this.setSelectedDashboardView(DashboardViews.submission); - break; - case 3: - this.setSelectedDashboardView(DashboardViews.similarity); - break; - case 4: - this.setSelectedDashboardView(DashboardViews.overseer); - break; - case 5: - this.setSelectedDashboardView(DashboardViews.staff_notes); - break; - case 6: - this.setSelectedDashboardView(DashboardViews.tutor_notes); - break; + const view = this.tabViews[event.index]; + if (view !== undefined) { + this.setSelectedDashboardView(view); } } constructor( - private doubtfire: DoubtfireConstants, private taskService: TaskService, - private taskAssessmentModal: TaskAssessmentModalService, private fileDownloader: FileDownloaderService, private route: ActivatedRoute, private userService: UserService, @@ -116,28 +101,14 @@ export class TaskDashboardComponent implements OnInit, OnChanges { } private tabIndexForView(view: DashboardViews): number { - switch (view) { - case DashboardViews.task: - return 1; - case DashboardViews.submission: - return 2; - case DashboardViews.similarity: - return this.canAccessStaffViews ? 3 : 0; - case DashboardViews.overseer: - return this.canAccessStaffViews ? 4 : 0; - case DashboardViews.staff_notes: - return this.canAccessStaffViews ? 5 : 0; - case DashboardViews.tutor_notes: - return this.canAccessTutorNotes ? 6 : 0; - default: - return 0; - } + const index = this.tabViews.indexOf(view); + return index >= 0 ? index : 0; } private canAccessDashboardView(view: DashboardViews): boolean { switch (view) { case DashboardViews.similarity: - case DashboardViews.overseer: + case DashboardViews.submission_history: case DashboardViews.staff_notes: case DashboardViews.discussion_prompts: return this.canAccessStaffViews; @@ -148,10 +119,6 @@ export class TaskDashboardComponent implements OnInit, OnChanges { } } - public get overseerEnabled() { - return this.doubtfire.IsOverseerEnabled.value && this.task?.overseerEnabled; - } - public get canAccessStaffViews(): boolean { return this.tutor || !!this.currentUnitRole; } @@ -184,10 +151,6 @@ export class TaskDashboardComponent implements OnInit, OnChanges { ); } - showSubmissionHistoryModal() { - this.taskAssessmentModal.show(this.task); - } - downloadSubmission() { this.fileDownloader.downloadFile(this.urls.taskSubmissionPdfAttachmentUrl, 'submission.pdf'); } diff --git a/src/app/projects/states/dashboard/selected-task.service.ts b/src/app/projects/states/dashboard/selected-task.service.ts index e130494610..5d770fd253 100644 --- a/src/app/projects/states/dashboard/selected-task.service.ts +++ b/src/app/projects/states/dashboard/selected-task.service.ts @@ -12,7 +12,7 @@ export enum DashboardViews { staff_notes, tutor_notes, discussion_prompts, - overseer, + submission_history, } @Injectable({ @@ -84,7 +84,11 @@ export class SelectedTaskService { } public showOverseerReports() { - this.currentView$.next(DashboardViews.overseer); + this.currentView$.next(DashboardViews.submission_history); + } + + public showSubmissionHistory() { + this.currentView$.next(DashboardViews.submission_history); } public showDiscussionPrompts() { diff --git a/src/app/tasks/task-submission-history/task-submission-history.component.html b/src/app/tasks/task-submission-history/task-submission-history.component.html deleted file mode 100644 index 4bf56849ca..0000000000 --- a/src/app/tasks/task-submission-history/task-submission-history.component.html +++ /dev/null @@ -1,43 +0,0 @@ -
    -
    -
    -
    Submissions
    - - @for (tab of tabs; track tab) { - -
    -
    - {{ tab.timestamp | humanizedDate }} -
    - @if (tab.status === 'pre_queued') { - schedule - } @else { - - } -
    -
    - } -
    -
    -
    - - @for (selTab of selectedTab.content; track selTab) { - -
    {{ selTab.result }} 
    - -
    - } -
    -
    -
    -
    diff --git a/src/app/tasks/task-submission-history/task-submission-history.component.scss b/src/app/tasks/task-submission-history/task-submission-history.component.scss deleted file mode 100644 index b6884f11bf..0000000000 --- a/src/app/tasks/task-submission-history/task-submission-history.component.scss +++ /dev/null @@ -1,188 +0,0 @@ -@use 'sass:color'; - -// @import "src/styles/mixins/flex-center"; -//== Media queries breakpoints -// -//## Define the breakpoints at which your layout will change, adapting to different screen sizes. - -// Extra small screen / phone -//** Deprecated `$screen-xs` as of v3.0.1 -// $screen-xs: 480px !default; -// //** Deprecated `$screen-xs-min` as of v3.2.0 -// $screen-xs-min: $screen-xs !default; -// //** Deprecated `$screen-phone` as of v3.0.1 -// $screen-phone: $screen-xs-min !default; - -// // Small screen / tablet -// //** Deprecated `$screen-sm` as of v3.0.1 -// $screen-sm: 768px !default; -// $screen-sm-min: $screen-sm !default; -// //** Deprecated `$screen-tablet` as of v3.0.1 -// $screen-tablet: $screen-sm-min !default; - -// // Medium screen / desktop -// //** Deprecated `$screen-md` as of v3.0.1 -// $screen-md: 992px !default; -// $screen-md-min: $screen-md !default; -// //** Deprecated `$screen-desktop` as of v3.0.1 -// $screen-desktop: $screen-md-min !default; - -// // Large screen / wide desktop -// //** Deprecated `$screen-lg` as of v3.0.1 -// $screen-lg: 1200px !default; -// $screen-lg-min: $screen-lg !default; -// //** Deprecated `$screen-lg-desktop` as of v3.0.1 -// $screen-lg-desktop: $screen-lg-min !default; - -// // So media queries don't overlap when required, provide a maximum -// $screen-xs-max: ($screen-sm-min - 1) !default; -// $screen-sm-max: ($screen-md-min - 1) !default; -// $screen-md-max: ($screen-lg-min - 1) !default; - -.submission-wrap { - height: 100%; - display: flex; -} - -.submission-main { - flex: 1; - display: flex; - width: 100%; -} - -@media (max-width: 992px) { - .submission-main { - flex-direction: column; - } -} - -.submission-sidenav, -.submisson-result { - overflow-y: scroll; - padding: 1em 1em 0 1em; -} - -/*TODO(mdc-migration): The following rule targets internal classes of list that may no longer apply for the MDC version.*/ -/*TODO(mdc-migration): The following rule targets internal classes of list that may no longer apply for the MDC version.*/ -mat-list.list-group { - overflow-y: scroll; -} - -.terminal-output { - padding: 10px; - margin: 1em 0 0 0; - // margin-bottom: 0; -} - -.submission-sidenav { - flex: 1; - width: 100%; - padding: 0; - display: inline-block; - line-height: 1; -} - -.submission-sidenav.panel.panel-primary { - margin-bottom: 0; -} - -@media (max-width: 992px) { - .submission-sidenav.panel.panel-primary { - margin-bottom: 2em; - } -} - -.submission-sidenav .panel-heading { - line-height: 2; -} - -.submisson-result { - flex: 3; - height: 100%; - padding-top: 0; - - padding-right: 0; -} -@media (max-width: 992px) { - .submisson-result { - padding-left: 0; - } -} - -.panel-heading.panel-title.submission-heading { - position: sticky; - top: 0; - z-index: 2; -} - -pre { - white-space: pre-wrap; -} - -/*TODO(mdc-migration): The following rule targets internal classes of list that may no longer apply for the MDC version.*/ -/*TODO(mdc-migration): The following rule targets internal classes of list that may no longer apply for the MDC version.*/ -mat-list, -mat-nav-list { - padding-top: 0; - border-bottom-width: 1px; - padding-bottom: 1px; -} - -/*TODO(mdc-migration): The following rule targets internal classes of tabs that may no longer apply for the MDC version.*/ -/*TODO(mdc-migration): The following rule targets internal classes of tabs that may no longer apply for the MDC version.*/ -mat-tab-header.mat-mdc-tab-header { - margin-bottom: 5px; - position: sticky; - top: 0; - z-index: 2; - background: white; -} - -/*TODO(mdc-migration): The following rule targets internal classes of tabs that may no longer apply for the MDC version.*/ -/*TODO(mdc-migration): The following rule targets internal classes of tabs that may no longer apply for the MDC version.*/ -mat-tab-body.mat-mdc-tab-body.mat-tab-body-active { - z-index: 1; -} - -.submission-heading { - border-radius: 0; - background-color: #337ab7; - color: white; -} - -@mixin custom-box-shadow($color) { - box-shadow: -15px 0 $color inset; -} - -/*TODO(mdc-migration): The following rule targets internal classes of list that may no longer apply for the MDC version.*/ -/*TODO(mdc-migration): The following rule targets internal classes of list that may no longer apply for the MDC version.*/ -mat-list-item { - border-bottom-width: 1px !important; - border-color: #f5f5f5; - transition: all 200ms ease-out; - transition-property: box-shadow, padding-right; - display: flex; - &:hover, - &:focus { - cursor: pointer; - text-decoration: none; - background-color: #f5f5f5; - @include custom-box-shadow(color.adjust(#0079d8, $lightness: 15%)); - } - &.selected { - background-color: rgb(231, 231, 231); - @include custom-box-shadow(#0079d8); - } -} - -.panel > .list-group:last-child .list-group-item:last-child, -.panel > .panel-collapse > .list-group:last-child .list-group-item:last-child { - border-color: #f5f5f5; - border-style: solid; - border-radius: 0; -} - -.panel .panel-heading { - margin-bottom: 0; - padding: 6px 15px; -} diff --git a/src/app/tasks/task-submission-history/task-submission-history.component.ts b/src/app/tasks/task-submission-history/task-submission-history.component.ts deleted file mode 100644 index 9f98d50832..0000000000 --- a/src/app/tasks/task-submission-history/task-submission-history.component.ts +++ /dev/null @@ -1,110 +0,0 @@ -import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; -import {Subject} from 'rxjs'; -import {OverseerAssessmentService, Task} from 'src/app/api/models/doubtfire-model'; -import {OverseerAssessment} from 'src/app/api/models/doubtfire-model'; -import {AlertService} from 'src/app/common/services/alert.service'; -import {TaskSubmissionService} from 'src/app/common/services/task-submission.service'; - -@Component({ - selector: 'f-task-submission-history', - templateUrl: './task-submission-history.component.html', - styleUrls: ['./task-submission-history.component.scss'], - standalone: false, -}) -export class TaskSubmissionHistoryComponent implements OnInit { - @Input() task: Task; - @Output() hasNoData: EventEmitter = new EventEmitter(); - tabs: OverseerAssessment[]; - // timestamps: string[]; - selectedTab: OverseerAssessment = new OverseerAssessment(); - @Input() refreshTrigger: Subject; - - constructor( - private alerts: AlertService, - private submissions: TaskSubmissionService, - private overseerAssessmentService: OverseerAssessmentService, - ) {} - - ngOnInit() { - this.fillTabs(); - - this.refreshTrigger.subscribe(() => { - this.fillTabs(); - }); - } - - private handleError(error: Error) { - this.alerts.error('Error: ' + error, 6000); - } - - fillTabs(): void { - // this.submissions.getLatestSubmissionsTimestamps(this.task); - // let transformedData = this.overseerAssessmentService.queryForTask(this.task).pipe( - // map(data => { - // return data.map((ts: any) => { - // let result = new SubmissionTab(); - // timestamp: new Date(ts.submission_timestamp * 1000), - // content: '', - // timestampString: ts.submission_timestamp, - // taskStatus: ts.result_task_status, - // submissionStatus: ts.status, - // createdAt: ts.created_at, - // updatedAt: ts.updated_at, - // taskId: ts.task_id}; - // }); - // }) - // ); - - this.overseerAssessmentService.queryForTask(this.task).subscribe( - (tabs) => { - if (tabs.length === 0) { - this.tabs = [new OverseerAssessment()]; - this.selectedTab.content = [ - {label: 'No Data', result: 'There are no submissions for this task at the moment.'}, - ]; - } else { - this.tabs = tabs; - } - // if (this.selectedTab.timestampString) { - // this.openSubmission(tabs.filter(x => x.timestampString === this.selectedTab.timestampString)[0]); - // } else { - // this.openSubmission(tabs[0]); - // } - }, - (error) => { - this.handleError(error); - }, - ); - } - - triggerOverseer(tab: OverseerAssessment) { - this.overseerAssessmentService.triggerOverseer(tab).subscribe( - (_response: OverseerAssessment) => { - this.alerts.success('Overseer assessment will be run again.', 2000); - }, - (_response: Error) => { - this.alerts.error('Error requesting overseer assessment.', 6000); - }, - ); - } - - openSubmission(tab: OverseerAssessment) { - this.selectedTab = tab; - // this.selectedTab.timestamp = tab.timestamp; - // this.selectedTab.timestampString = tab.timestampString; - // this.selectedTab.taskStatus = tab.taskStatus; - // this.selectedTab.submissionStatus = tab.submissionStatus; - - this.submissions.getSubmissionByTimestamp(this.task, tab.timestampString).subscribe( - (sub) => { - this.selectedTab.content = sub; - this.hasNoData.emit(false); - }, - (error) => { - // TODO: make error handling more readable... - this.selectedTab.content = [{label: 'Error', result: error?.error?.error}]; - this.hasNoData.emit(true); - }, - ); - } -} diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html index 8b28d600bf..0649d98406 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html @@ -22,6 +22,16 @@
    Submission History + + Check Similarity
    +@if (missingOverseerSubmissionHistory) { +
    + Overseer requires at least one upload requirement to be retained in submission history. +
    +} + @if (taskDefinition.needsJplag) {
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts index 69c8e51fb2..3cbb9a03ed 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts @@ -14,7 +14,14 @@ export class TaskDefinitionUploadComponent { @Input() public taskDefinition: TaskDefinition; @ViewChild('upreqTable', {static: true}) table: MatTable; - public columns: string[] = ['file-name', 'file-type', 'tii-check', 'flag-pct', 'row-actions']; + public columns: string[] = [ + 'file-name', + 'file-type', + 'submission-history', + 'tii-check', + 'flag-pct', + 'row-actions', + ]; constructor(private constants: DoubtfireConstants) {} @@ -30,6 +37,7 @@ export class TaskDefinitionUploadComponent { name: '', tiiCheck: false, tiiPct: 30, + submissionHistory: false, }); this.table.renderRows(); } @@ -38,6 +46,13 @@ export class TaskDefinitionUploadComponent { return this.constants.IsTiiEnabled.value; } + public get missingOverseerSubmissionHistory(): boolean { + return ( + this.taskDefinition.assessmentEnabled && + !this.taskDefinition.uploadRequirements.some((requirement) => requirement.submissionHistory) + ); + } + public removeUpReq(upreq: UploadRequirement) { this.taskDefinition.uploadRequirements = this.taskDefinition.uploadRequirements.filter( (anUpReq) => anUpReq.key != upreq.key, From 1ffc7ad7b9dc18f22be32bf6313bfde97957dd2f Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Wed, 17 Jun 2026 12:11:59 +1000 Subject: [PATCH 1117/1280] refactor: sort attributes (#1280) --- eslint.config.js | 14 +++ .../edit-profile/edit-profile.component.html | 2 +- .../activity-type-list.component.html | 50 ++++---- .../campus-list/campus-list.component.html | 88 +++++++------- .../overseer-image-list.component.html | 68 +++++------ ...eate-new-unit-modal-content.component.html | 18 +-- .../new-teaching-period-dialog.component.html | 38 +++--- .../teaching-period-list.component.html | 44 +++---- .../teaching-period-unit-import.dialog.html | 36 +++--- .../admin/states/units/units.component.html | 44 +++---- .../admin/states/users/users.component.html | 50 ++++---- .../tii-action-log.component.html | 44 +++---- .../archive-viewer.component.html | 24 ++-- .../audio-player/audio-player.component.html | 4 +- .../audio-comment-recorder.html | 24 ++-- .../microphone-tester-component.html | 14 +-- .../edit-profile-form.component.html | 78 ++++++------ .../feedback-template-editor.component.html | 70 +++++------ .../common/file-drop/file-drop.component.html | 14 +-- .../file-uploader.component.html | 14 +-- .../file-viewer/file-viewer.component.html | 12 +- src/app/common/footer/footer.component.html | 76 ++++++------ .../grade-icon/grade-icon.component.html | 4 +- src/app/common/header/header.component.html | 38 +++--- .../task-dropdown.component.html | 38 +++--- .../unit-dropdown.component.html | 30 ++--- .../hero-sidebar/hero-sidebar.component.html | 4 +- .../learning-outcome-editor.component.html | 52 ++++---- .../nested-csv-download-modal.component.html | 4 +- .../calendar-modal.component.html | 28 ++--- .../comments-modal.component.html | 2 +- .../confirmation-modal.component.html | 4 +- .../csv-result-modal.component.html | 24 ++-- .../csv-upload-modal.component.html | 4 +- .../task-date-slider.component.html | 6 +- ...ussed-in-class-reason-modal.component.html | 6 +- .../extension-modal.component.html | 22 ++-- .../modals/qr-modal/qr-modal.component.html | 2 +- .../scorm-extension-modal.component.html | 16 +-- .../sidekiq-jobs-modal.component.html | 4 +- .../sidekiq-progress-modal.component.html | 2 +- .../spec-con-modal.component.html | 10 +- .../task-assessment-modal.component.html | 8 +- .../obect-select/object-select.component.html | 4 +- .../pdf-viewer-panel.component.html | 4 +- .../pdf-viewer/pdf-viewer.component.html | 30 ++--- .../project-progress-gauge.component.html | 18 +-- src/app/common/services/alert.component.html | 2 +- .../status-icon/status-icon.component.html | 6 +- .../submission-files-download.component.html | 8 +- .../common/unit-code/unit-code.component.html | 2 +- .../user-badge/user-badge.component.html | 18 +-- .../common/user-icon/user-icon.component.html | 2 +- .../unauthorised/unauthorised.component.html | 2 +- .../unavailable-card.component.html | 2 +- .../accept-eula/accept-eula.component.html | 4 +- ...ember-contribution-assigner.component.html | 26 ++-- .../group-member-list.component.html | 22 ++-- .../group-selector.component.html | 40 +++---- .../group-set-manager.component.html | 24 ++-- .../group-set-selector.component.html | 2 +- src/app/home/states/home/home.component.html | 34 +++--- .../lti-dashboard.component.html | 39 +++--- .../lti-unit-link.component.html | 11 +- .../project-progress-dashboard.component.html | 8 +- .../progress-dashboard.component.html | 12 +- .../task-planner-card.component.html | 2 +- .../task-list-item.component.html | 8 +- .../task-assessment-card.component.html | 8 +- .../task-description-card.component.html | 6 +- .../submission-files-modal.component.html | 22 ++-- .../task-prerequisites-card.component.html | 2 +- .../task-scorm-card.component.html | 10 +- .../task-similarity-view.component.html | 18 +-- .../task-status-card.component.html | 14 +-- .../task-submission-card.component.html | 10 +- .../task-dashboard.component.html | 12 +- .../project-dashboard.component.html | 20 ++-- .../discussion-prompts.component.html | 2 +- .../project-groups-state.component.html | 2 +- .../project-groups.component.html | 2 +- .../jplag/jplag-report-viewer.component.html | 6 +- .../states/plan/project-plan.component.html | 2 +- ...planner-prerequisites-modal.component.html | 20 ++-- .../task-planner/task-planner.component.html | 44 +++---- ...tfolio-add-extra-files-step.component.html | 10 +- ...portfolio-grade-select-step.component.html | 8 +- ...earning-summary-report-step.component.html | 8 +- .../portfolio-review-step.component.html | 8 +- .../portfolio-welcome-step.component.html | 2 +- .../portfolio/portfolio-state.component.html | 16 +-- .../staff-notes/staff-notes.component.html | 22 ++-- .../tutor-discussion.component.html | 51 ++++---- .../tutor-notes/tutor-notes.component.html | 28 ++--- .../states/tutorials/tutorials.component.html | 42 +++---- .../states/sign-in/sign-in.component.html | 8 +- .../feedback-appeal-modal.component.html | 8 +- .../grade-task-modal.component.html | 18 +-- .../submission-type-modal.component.html | 10 +- .../upload-submission-modal.component.html | 36 +++--- .../project-tasks-list.component.html | 4 +- ...achment-confirmation-dialog.component.html | 6 +- .../discussion-prompt-composer-dialog.html | 10 +- .../discussion-prompt-composer.component.html | 20 ++-- .../task-comment-composer.component.html | 102 ++++++++-------- .../task-feedback-templates.component.html | 28 ++--- .../comment-bubble-action.component.html | 20 ++-- .../extension-comment.component.html | 6 +- .../intelligent-discussion-dialog.html | 38 +++--- ...telligent-discussion-player.component.html | 10 +- ...lligent-discussion-recorder.component.html | 2 +- .../pdf-image-comment.component.html | 2 +- .../scorm-comment.component.html | 10 +- .../scorm-extension-comment.component.html | 4 +- .../task-assessment-comment.component.html | 6 +- .../task-comments-viewer.component.html | 70 +++++------ ...nit-student-enrolment-modal.component.html | 4 +- .../analytics-tutor-times.component.html | 24 ++-- .../unit-analytics-route.component.html | 2 +- .../communication-actions.component.html | 26 ++-- ...ommunication-schedule-modal.component.html | 16 +-- .../communication-schedules.component.html | 2 +- .../communication-conditions.component.html | 30 ++--- .../unit-communications-editor.component.html | 90 +++++++------- .../d2l-unit-details-form.component.html | 14 +-- .../unit-details-editor.component.html | 18 +-- .../unit-group-set-editor.component.html | 58 ++++----- .../bulk-import-staff-modal.component.html | 10 +- .../unit-staff-editor.component.html | 76 ++++++------ .../student-campus-select.component.html | 2 +- .../student-tutorial-select.component.html | 2 +- .../unit-students-editor.component.html | 48 ++++---- .../task-definition-dates.component.html | 8 +- ...finition-discussion-prompts.component.html | 24 ++-- .../task-definition-editor.component.html | 36 +++--- .../task-definition-general.component.html | 10 +- .../task-definition-options.component.html | 4 +- ...verseer-script-editor-modal.component.html | 2 +- .../task-definition-overseer.component.html | 64 +++++----- ...sk-definition-prerequisites.component.html | 34 +++--- .../task-definition-resources.component.html | 18 +-- .../task-definition-scorm.component.html | 18 +-- .../task-definition-upload.component.html | 46 +++---- .../task-definition-who.component.html | 4 +- .../unit-task-editor.component.html | 48 ++++---- .../unit-tutorials-list.component.html | 112 +++++++++--------- .../unit-tutorials-manager.component.html | 4 +- .../edit/unit-admin-state.component.html | 4 +- .../unit-groups/unit-groups.component.html | 2 +- .../d2l-transfer.component.html | 12 +- .../portfolios-assessment.component.html | 8 +- .../portfolios-list.component.html | 96 +++++++-------- ...portfolios-project-progress.component.html | 2 +- .../download-staff-notes.component.html | 2 +- .../portfolios/portfolios.component.html | 8 +- .../upload-grades.component.html | 2 +- .../states/rollover/rollover.component.html | 6 +- .../students-list.component.html | 78 ++++++------ .../inbox-dashboard.component.html | 6 +- .../confirm-moderation-modal.component.html | 4 +- .../moderation/moderation.component.html | 36 +++--- ...ch-feedback-workflow-dialog.component.html | 2 +- .../staff-task-list.component.html | 77 ++++++------ .../task-claim/task-claim.component.html | 6 +- .../states/tasks/inbox/inbox.component.html | 46 +++---- .../unit-task-inbox-state.component.html | 8 +- .../task-details-view.component.html | 4 +- .../unit-task-list.component.html | 14 +-- .../task-viewer-state.component.html | 18 +-- .../progress-burndown-chart.component.html | 12 +- .../task-status-pie-chart.component.html | 6 +- .../task-visualisation.component.html | 2 +- src/app/welcome/welcome.component.html | 8 +- src/index.html | 16 +-- 174 files changed, 1812 insertions(+), 1804 deletions(-) diff --git a/eslint.config.js b/eslint.config.js index 6267e075a4..f724f8a890 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -102,6 +102,20 @@ module.exports = tseslint.config( // and inline templates as long as we have the `processor` set on our TypeScript config above) files: ['**/*.html'], rules: { + '@angular-eslint/template/attributes-order': [ + 'error', + { + alphabetical: true, + order: [ + 'STRUCTURAL_DIRECTIVE', + 'TEMPLATE_REFERENCE', + 'ATTRIBUTE_BINDING', + 'INPUT_BINDING', + 'TWO_WAY_BINDING', + 'OUTPUT_BINDING', + ], + }, + ], '@angular-eslint/template/prefer-control-flow': 'error', // TODO: remove below eslint rule ignores to improve accessibility '@angular-eslint/template/label-has-associated-control': 'off', diff --git a/src/app/account/edit-profile/edit-profile.component.html b/src/app/account/edit-profile/edit-profile.component.html index a7b9c7b6e9..43c2d6788c 100644 --- a/src/app/account/edit-profile/edit-profile.component.html +++ b/src/app/account/edit-profile/edit-profile.component.html @@ -1,6 +1,6 @@
    -
    +
    @if (!loading) { } diff --git a/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.html b/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.html index 1827e2e139..9322c53928 100644 --- a/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.html +++ b/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.html @@ -6,64 +6,64 @@

    Activities

    - - - + - - - - + - - - + - - - - + + +
    Name + + Name @if (!editing(activityType)) {
    {{ activityType.name }}
    } @else { - + }
    + - + Abbreviation + + Abbreviation @if (!editing(activityType)) {
    {{ activityType.abbreviation }}
    } @else { - + }
    + - + + @if (!editing(activityType)) {
    @@ -71,21 +71,21 @@

    Activities

    } @else {
    - @@ -93,7 +93,7 @@

    Activities

    }
    +
    diff --git a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html index 5045f1adcf..4985f3bb05 100644 --- a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html +++ b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.html @@ -7,58 +7,58 @@

    Campuses

    - - - + - - - - + - - - - + - - + - - - - + - - - + - - - - + + +
    Name + + Name @if (!editing(campus)) {
    {{ campus.name }}
    } @else { - + }
    + - + Abbreviation + + Abbreviation @if (!editing(campus)) {
    {{ campus.abbreviation }}
    } @else { - + }
    + - + Default Sync Mode + + Default Sync Mode @if (!editing(campus)) {
    {{ campus.mode | titlecase }} @@ -66,7 +66,7 @@

    Campuses

    } @else { Default Sync Mode - + @for (mode of syncModes; track mode) { {{ mode | titlecase }} @@ -76,10 +76,10 @@

    Campuses

    }
    + Default Sync Mode - + @for (mode of syncModes; track mode) { {{ mode | titlecase }} @@ -91,9 +91,9 @@

    Campuses

    - -
    Timezone + + Timezone @if (!editing(campus)) {
    {{ campus.timezone }} @@ -102,46 +102,46 @@

    Campuses

    Timezone - + }
    + Timezone - + Active + + Active @if (!editing(campus)) {
    - +
    } @else { - + }
    + + @if (!editing(campus)) {
    - @@ -149,22 +149,22 @@

    Campuses

    } @else {
    - @@ -172,7 +172,7 @@

    Campuses

    }
    +
    diff --git a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html index 62667efd70..50283a5848 100644 --- a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html +++ b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.html @@ -17,86 +17,86 @@

    - - - + - - - - + - - - + - + - - + - + - - + - + - - + - - - - + + +
    Name + + Name @if (!editing(overseerImage)) {
    {{ overseerImage.name }}
    } @else { - + }
    + - + Tag + + Tag @if (!editing(overseerImage)) {
    {{ overseerImage.tag }}
    } @else { - + }
    + - + + @if (!editing(overseerImage)) {
    -
    }
    Last Pulled + Last Pulled @if (!editing(overseerImage)) {
    {{ overseerImage.lastPulledDate | humanizedDate }}
    }
    Status + Status @if (!editing(overseerImage)) {
    }
    + @if (!editing(overseerImage)) {
    @@ -159,20 +159,20 @@

    } @else {
    - - -
    }

    +
    diff --git a/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal-content.component.html b/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal-content.component.html index dc3993eba3..466d9ab2e3 100644 --- a/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal-content.component.html +++ b/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal-content.component.html @@ -1,29 +1,29 @@

    Create Unit

    Unit Code - + Unit Name - + Teaching Period Custom teaching period @for (tp of teachingPeriods; track tp; let i = $index) { @@ -40,11 +40,11 @@

    Create Unit

    - + DD/MM/YYYY - DD/MM/YYYY @@ -53,7 +53,7 @@

    Create Unit

    } - +
    diff --git a/src/app/admin/states/teaching-periods/teaching-period-list/new-teaching-period-dialog.component.html b/src/app/admin/states/teaching-periods/teaching-period-list/new-teaching-period-dialog.component.html index b8ae10c207..3fc90d09f4 100644 --- a/src/app/admin/states/teaching-periods/teaching-period-list/new-teaching-period-dialog.component.html +++ b/src/app/admin/states/teaching-periods/teaching-period-list/new-teaching-period-dialog.component.html @@ -1,9 +1,9 @@ -
    +
    - + @@ -12,8 +12,8 @@ -->
    - - +
    @@ -24,21 +24,21 @@ Teaching Period Name Teaching Period Year @@ -47,17 +47,17 @@ @@ -69,10 +69,10 @@ Active Until DD/MM/YYYY @@ -106,10 +106,10 @@

    Teaching Breaks for {{ newOrSelectedTeachingPeriod.name }}

    Break Start Date MM/DD/YYYY @@ -120,18 +120,18 @@

    Teaching Breaks for {{ newOrSelectedTeachingPeriod.name }}

    Number of weeks
    - - + - - + + - - + + - - + + - - + + - - + - - - + +
    Active - + Active + Name{{ element.name }}Name{{ element.name }} Start Date{{ element.startDate | date }}Start Date{{ element.startDate | date }} End date{{ element.endDate | date }}End date{{ element.endDate | date }} Active until{{ element.activeUntil | date }}Active until{{ element.activeUntil | date }} Actions + Actions
    - @@ -63,7 +63,7 @@

    Teaching periods

    +
    diff --git a/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.html b/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.html index 0860ef83b0..275098a43d 100644 --- a/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.html +++ b/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.html @@ -2,8 +2,8 @@

    Import Units Into {{ data.teachingPeriod.name }}

    - - + - + - + - + - + - - + - - + +
    Unit Code + Unit Code Import Units Into {{ data.teachingPeriod.name }} - Source Unit + Source Unit Import Units Into {{ data.teachingPeriod.name }} - Unit Name + Unit Name @if (unitToImport.sourceUnit) { {{ unitToImport.sourceUnit.name }} } @if (!unitToImport.sourceUnit) { @@ -41,12 +41,12 @@

    Import Units Into {{ data.teachingPeriod.name }}

    -
    Main Convenor + Main Convenor Import Units Into {{ data.teachingPeriod.name }} - Status + Status {{ statusForUnit(unitToImport) }} +
    -
    +
    Unit Code(s) - + - +
    diff --git a/src/app/admin/states/units/units.component.html b/src/app/admin/states/units/units.component.html index 769db63c2d..d334c47c1c 100644 --- a/src/app/admin/states/units/units.component.html +++ b/src/app/admin/states/units/units.component.html @@ -15,66 +15,66 @@

    {{ title }}

    - - + - - + + - - - + - - + + - - + + - - + - + @if (mode === 'tutor') { } @if (mode === 'admin') { } @if (mode === 'student') { } @@ -123,7 +123,7 @@

    {{ title }}

    @if (mode === 'admin') { - diff --git a/src/app/admin/states/users/users.component.html b/src/app/admin/states/users/users.component.html index d301a4b144..fb093e9401 100644 --- a/src/app/admin/states/users/users.component.html +++ b/src/app/admin/states/users/users.component.html @@ -1,6 +1,6 @@
    -
    +

    {{ externalName }} Users

    Users Administration View

    @@ -9,9 +9,9 @@

    Users Administration View

    @@ -20,76 +20,76 @@

    Users Administration View

    Unit Code + Unit Code Name{{ element.name }}Name{{ element.name }} Unit Role + {{ element.unit_role }} Teaching Period + Teaching Period {{ element.teaching_period }} Start Date{{ element.start_date | date: 'EEE d MMM y' }}Start Date{{ element.start_date | date: 'EEE d MMM y' }} End Date{{ element.end_date | date: 'EEE d MMM y' }}End Date{{ element.end_date | date: 'EEE d MMM y' }} Active + Active @if (element.teachingPeriod) { @if (element.teachingPeriod.active && element.active) { @@ -96,25 +96,25 @@

    {{ title }}

    - - + - - + + - - + + - - + + - - + - - + + - - + +
    - + + First Name{{ user.firstName }}First Name{{ user.firstName }} Last Name{{ user.lastName }}Last Name{{ user.lastName }} Username{{ user.username }}Username{{ user.username }} Email + Email {{ user.email }} System Role{{ user.systemRole }}System Role{{ user.systemRole }}
    - + - + Bulk users operations
    diff --git a/src/app/admin/tii-action-log/tii-action-log.component.html b/src/app/admin/tii-action-log/tii-action-log.component.html index 9d1e9d85d3..4590ee9977 100644 --- a/src/app/admin/tii-action-log/tii-action-log.component.html +++ b/src/app/admin/tii-action-log/tii-action-log.component.html @@ -6,9 +6,9 @@

    Turnitin Actions

    @@ -17,58 +17,58 @@

    Turnitin Actions

    - - + - - + - - + - - + - - + - - + - - + - - + + - +
    Action Type + Action Type {{ action.description }} Last Run + Last Run {{ action.lastRun ? (action.lastRun | date: 'd LLL y') : '' }} Retries + Retries {{ action.retries }} Retry? + Retry? {{ action.retry }} Error Code + Error Code {{ action.errorCode }} Complete? + Complete? {{ action.complete }} Error Message + Error Message {{ action.errorMessage }} + @if (!(action.complete || action.retry)) { - } @@ -77,13 +77,13 @@

    Turnitin Actions

    -
    diff --git a/src/app/common/archive-viewer/archive-viewer.component.html b/src/app/common/archive-viewer/archive-viewer.component.html index 5368148a38..2b081b24ec 100644 --- a/src/app/common/archive-viewer/archive-viewer.component.html +++ b/src/app/common/archive-viewer/archive-viewer.component.html @@ -23,11 +23,11 @@ @if (!readOnly && saveEndpoint) {
    @@ -131,7 +131,7 @@ insert_drive_file

    This file type cannot be previewed.

    - @@ -143,7 +143,7 @@ } - + @for (node of nodes; track trackTreeNode($index, node)) { @if (node.isDirectory) {
    } @else { diff --git a/src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.html b/src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.html index 1638aeb89d..7e2f11bdd9 100644 --- a/src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.html +++ b/src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.html @@ -6,48 +6,48 @@
    diff --git a/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester-component.html b/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester-component.html index aca754db86..70df258499 100644 --- a/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester-component.html +++ b/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester-component.html @@ -6,14 +6,14 @@

    Step 1. Record some audio!

    - @@ -25,21 +25,21 @@

    Step 1. Record some audio!

    -
    +

    Step 2. Stop the recording, and playback the audio to make sure it's audible:

    -
    +

    Step 3. Check the "Ready to go" cehckbox below if you're all set!

    diff --git a/src/app/common/edit-profile-form/edit-profile-form.component.html b/src/app/common/edit-profile-form/edit-profile-form.component.html index f314ea254c..a51b79fee2 100644 --- a/src/app/common/edit-profile-form/edit-profile-form.component.html +++ b/src/app/common/edit-profile-form/edit-profile-form.component.html @@ -1,9 +1,9 @@
    @@ -11,7 +11,7 @@
    -
    @@ -21,7 +21,7 @@

    {{ user?.firstName }}

    -
    +
    - + Username - +
    -
    - +
    + First Name - +
    - + Second Name - +
    -
    +
    - + Preferred Name - +
    - + Custom Pronouns @if (user.systemRole === 'Student') { Student ID - + } Email - + @if (canSeeSystemRole) { - + System Role Administrator Convenor @@ -112,55 +112,55 @@

    {{ user?.firstName }}

    } -
    +
    Receive notifications for new messages
    Receive notifications when your portfolio is ready
    Receive notifications when new tasks are available
    -
    - + Send anonymous research statistics
    @if (tiiEnabled) { -
    +
    Accepted TurnItIn EULA
    } -
    +
    } @if (mode === 'edit') { diff --git a/src/app/common/feedback-template-editor/feedback-template-editor.component.html b/src/app/common/feedback-template-editor/feedback-template-editor.component.html index 1def23d307..c8fe0c13a1 100644 --- a/src/app/common/feedback-template-editor/feedback-template-editor.component.html +++ b/src/app/common/feedback-template-editor/feedback-template-editor.component.html @@ -7,17 +7,17 @@

    Edit Feedback Templates for Outcom #templateTable class="f-table selectable flex-grow" mat-table - [dataSource]="templateSource" matSort + [dataSource]="templateSource" (matSortChange)="sortTemplateData($event)" > -

    @if (feedbackTemplate.type === 'group') { folder @@ -28,60 +28,60 @@

    Edit Feedback Templates for Outcom

    ParentParent {{ getParentChipText(feedbackTemplate.parentChipId) }} Chip TextChip Text {{ feedbackTemplate.chipText }} DescriptionDescription {{ feedbackTemplate.description }} Comment TextComment Text {{ feedbackTemplate.commentText }} Summary TextSummary Text {{ feedbackTemplate.type === 'group' ? '' : feedbackTemplate.summaryText }} Task StatusTask Status @if (feedbackTemplate.taskStatus) { @@ -95,26 +95,26 @@

    Edit Feedback Templates for Outcom

    @if (feedbackTemplateHasChanges(feedbackTemplate)) { }
    @@ -133,7 +133,7 @@

    Edit Feedback Templates for Outcom
    - +
    Edit Feedback Templates for Outcom } -
    @@ -190,11 +190,11 @@

    Edit Template

    Chip Text @@ -202,11 +202,11 @@

    Edit Template

    Description
    @@ -216,10 +216,10 @@

    Edit Template

    Comment Text @@ -229,10 +229,10 @@

    Edit Template

    Summary Text @@ -253,8 +253,8 @@

    Edit Template

    @@ -24,11 +24,11 @@
    Select {{ upload.display.name }}
    } @if (asButton) { - + }
    } @@ -151,7 +151,7 @@
    Upload Summary

    Error Message: {{ uploadingInfo.error }}

    - diff --git a/src/app/common/file-viewer/file-viewer.component.html b/src/app/common/file-viewer/file-viewer.component.html index 537049c15b..88ad9162d4 100644 --- a/src/app/common/file-viewer/file-viewer.component.html +++ b/src/app/common/file-viewer/file-viewer.component.html @@ -7,21 +7,21 @@ > } } @if (fileType === 'html') {
    - +
    }
    diff --git a/src/app/common/footer/footer.component.html b/src/app/common/footer/footer.component.html index 8e470d155d..03f306d20b 100644 --- a/src/app/common/footer/footer.component.html +++ b/src/app/common/footer/footer.component.html @@ -15,12 +15,12 @@ @if (selectedTask?.definition?.assessInPortfolioOnly) { -->
    @if (!selectedTask?.hasPdf && selectedTask?.status === 'ready_for_feedback') { } } @if (currentUnit && currentUnitRole && currentUnitRole.tutorNoteCount > 0) { - @@ -60,10 +60,10 @@ @if (currentUser.role === 'Admin' || currentUser.role === 'Convenor') { diff --git a/src/app/common/header/task-dropdown/task-dropdown.component.html b/src/app/common/header/task-dropdown/task-dropdown.component.html index 05d42af095..5f7e239d25 100644 --- a/src/app/common/header/task-dropdown/task-dropdown.component.html +++ b/src/app/common/header/task-dropdown/task-dropdown.component.html @@ -44,7 +44,7 @@ } @if (currentActivity) { chevron_right - @if (currentProject !== null && currentView === 'PROJECT') { - - - - - } @if (unitRole && currentView === 'UNIT') { - - @if (isMentor || unitRole.role === 'Convenor') { - } @if (canMarkOverflowTask) { - } - - - - - - - - @if ( unitRole.role === 'Convenor' || unitRole.role === 'Admin' || unitRole.role === 'Auditor' ) { - diff --git a/src/app/common/header/unit-dropdown/unit-dropdown.component.html b/src/app/common/header/unit-dropdown/unit-dropdown.component.html index 7c0afe82e5..3bf5b0c19f 100644 --- a/src/app/common/header/unit-dropdown/unit-dropdown.component.html +++ b/src/app/common/header/unit-dropdown/unit-dropdown.component.html @@ -1,19 +1,19 @@
    @if (unit) { {{ menuState.menuOpen ? 'arrow_drop_up' : 'arrow_drop_down' }} } @if (!unit) { - } diff --git a/src/app/common/hero-sidebar/hero-sidebar.component.html b/src/app/common/hero-sidebar/hero-sidebar.component.html index 12145dfff4..09a24f8278 100644 --- a/src/app/common/hero-sidebar/hero-sidebar.component.html +++ b/src/app/common/hero-sidebar/hero-sidebar.component.html @@ -2,10 +2,10 @@
    Homepage Logo

    {{ externalName.value }}

    diff --git a/src/app/common/learning-outcome-editor/learning-outcome-editor.component.html b/src/app/common/learning-outcome-editor/learning-outcome-editor.component.html index 34110a1323..c8c668aabe 100644 --- a/src/app/common/learning-outcome-editor/learning-outcome-editor.component.html +++ b/src/app/common/learning-outcome-editor/learning-outcome-editor.component.html @@ -3,45 +3,45 @@ #outcomeTable class="f-table selectable flex-grow" mat-table - [dataSource]="outcomeSource" matSort + [dataSource]="outcomeSource" (matSortChange)="sortOutcomeData($event)" > - Abbreviation + Abbreviation {{ learningOutcome.abbreviation }} - Short Description + Short Description {{ learningOutcome.shortDescription }} - Full Outcome Description + Full Outcome Description {{ learningOutcome.fullOutcomeDescription }} - Connected Learning Outcomes + Connected Learning Outcomes @for (outcome of getLinkedOutcomes(learningOutcome); track outcome.abbreviation) { @@ -52,26 +52,26 @@ - + @if (learningOutcomeHasChanges(learningOutcome)) { } - + @if (selectedOutcome) { @@ -126,10 +126,10 @@

    Edit Outcome

    Abbreviation @@ -137,8 +137,8 @@

    Edit Outcome

    Short Description @@ -148,8 +148,8 @@

    Edit Outcome

    Full Outcome Description @@ -169,15 +169,15 @@

    Edit Outcome

    } @for (outcome of filteredOutcomes(); track outcome) { @@ -191,7 +191,7 @@

    Edit Outcome

    -
    diff --git a/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.html b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.html index d236474d37..9ce06782e4 100644 --- a/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.html +++ b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.html @@ -8,7 +8,7 @@

    Download the {{ data.type }} CSV

    -
    +
    - +
    diff --git a/src/app/common/modals/calendar-modal/calendar-modal.component.html b/src/app/common/modals/calendar-modal/calendar-modal.component.html index 3af81bbb87..d7fe452d00 100644 --- a/src/app/common/modals/calendar-modal/calendar-modal.component.html +++ b/src/app/common/modals/calendar-modal/calendar-modal.component.html @@ -4,14 +4,14 @@

    Web calendar

    @@ -50,7 +50,7 @@

    Web calendar

    URL to subscribe to your web calendar from your iCalendar client.

    -
    +
    @@ -79,7 +79,7 @@

    Web calendar

    Options

    -
    +
    Included units in my calendar: @@ -89,8 +89,8 @@

    Options

    @for (project of includedProjects; track project) { {{ project.unit.code }} @@ -114,9 +114,9 @@

    Options

    Remind me @@ -124,15 +124,15 @@

    Options

    Time Unit - + Weeks Days Hours @@ -151,11 +151,11 @@

    Options

    newReminderUnit !== webcal.reminder.unit)) ) { +
    diff --git a/src/app/common/modals/comments-modal/comments-modal.component.html b/src/app/common/modals/comments-modal/comments-modal.component.html index c4e73f0de0..86be41b59f 100644 --- a/src/app/common/modals/comments-modal/comments-modal.component.html +++ b/src/app/common/modals/comments-modal/comments-modal.component.html @@ -1,9 +1,9 @@
    @if (taskComment.commentType === 'image') { Image attachment } @else if (taskComment.commentType === 'pdf') { diff --git a/src/app/common/modals/confirmation-modal/confirmation-modal.component.html b/src/app/common/modals/confirmation-modal/confirmation-modal.component.html index 4232cf08ee..894582f3c8 100644 --- a/src/app/common/modals/confirmation-modal/confirmation-modal.component.html +++ b/src/app/common/modals/confirmation-modal/confirmation-modal.component.html @@ -12,9 +12,9 @@

    {{ message }} - - +

    diff --git a/src/app/common/modals/csv-result-modal/csv-result-modal.component.html b/src/app/common/modals/csv-result-modal/csv-result-modal.component.html index a08ab98d77..6c963b1cc6 100644 --- a/src/app/common/modals/csv-result-modal/csv-result-modal.component.html +++ b/src/app/common/modals/csv-result-modal/csv-result-modal.component.html @@ -2,13 +2,12 @@

    {{ data.title }}

    @for (selection of csvResponseSelections; track selection.key) { {{ selection.label }} ({{ itemData(selection.key).length }}) @@ -33,10 +33,10 @@

    {{ data.title }}

    No data to show

    } @else {
    - +
    - - + - + - + - - + +
    Message + Message
    {{ displayMessage(row.item) }}
    @@ -45,8 +45,8 @@

    {{ data.title }}

    @for (columnId of dynamicColumnIds; track columnId) { -
    {{ headerForColumn(columnId) }} + {{ headerForColumn(columnId) }}
    {{ rowValueForColumn(row.rowObject, columnId) }}
    @@ -55,16 +55,16 @@

    {{ data.title }}

    } -
    Other + Other
    {{ row.otherData || '-' }}
    } @@ -81,5 +81,5 @@

    {{ data.title }}

    } - + diff --git a/src/app/common/modals/csv-upload-modal/csv-upload-modal.component.html b/src/app/common/modals/csv-upload-modal/csv-upload-modal.component.html index b4ccd4a6e2..11b7db0a4d 100644 --- a/src/app/common/modals/csv-upload-modal/csv-upload-modal.component.html +++ b/src/app/common/modals/csv-upload-modal/csv-upload-modal.component.html @@ -5,10 +5,10 @@

    {{ data.title }}

    {{ data.message }}

    } - +
    - + diff --git a/src/app/common/modals/date-change-modal/task-date-slider.component.html b/src/app/common/modals/date-change-modal/task-date-slider.component.html index 5cd73218b1..3471580e68 100644 --- a/src/app/common/modals/date-change-modal/task-date-slider.component.html +++ b/src/app/common/modals/date-change-modal/task-date-slider.component.html @@ -8,12 +8,12 @@ } @else { } - + @@ -21,8 +21,8 @@ @if (task.unit.allowFlexibleDates) { diff --git a/src/app/common/modals/discussed-in-class-reason-modal/discussed-in-class-reason-modal.component.html b/src/app/common/modals/discussed-in-class-reason-modal/discussed-in-class-reason-modal.component.html index dea3973f11..5eb196bf48 100644 --- a/src/app/common/modals/discussed-in-class-reason-modal/discussed-in-class-reason-modal.component.html +++ b/src/app/common/modals/discussed-in-class-reason-modal/discussed-in-class-reason-modal.component.html @@ -11,10 +11,10 @@

    {{ data.title }}

    Reason @if (reasonBody.length > 0 && !hasReasonBody) { Please enter at least {{ minimumReasonLength }} characters. @@ -27,7 +27,7 @@

    {{ data.title }}

    - diff --git a/src/app/common/modals/extension-modal/extension-modal.component.html b/src/app/common/modals/extension-modal/extension-modal.component.html index 50d7666b53..30beb590e5 100644 --- a/src/app/common/modals/extension-modal/extension-modal.component.html +++ b/src/app/common/modals/extension-modal/extension-modal.component.html @@ -5,14 +5,14 @@

    Extension request

    request shortly.

    - + Reason {{ extensionData.controls.extensionReason.value.length }} / {{ reasonMaxLength }}Extension request Choose a date @@ -44,13 +44,13 @@

    Extension request

    - +
    - + - + +
    diff --git a/src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.component.html b/src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.component.html index 5fb4608cbe..af7491923d 100644 --- a/src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.component.html +++ b/src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.component.html @@ -31,7 +31,7 @@

    @if (job?.status !== 'working' && job?.result) { - + }

    diff --git a/src/app/common/modals/spec-con-modal/spec-con-modal.component.html b/src/app/common/modals/spec-con-modal/spec-con-modal.component.html index 7bb56e4b07..182c88c0f6 100644 --- a/src/app/common/modals/spec-con-modal/spec-con-modal.component.html +++ b/src/app/common/modals/spec-con-modal/spec-con-modal.component.html @@ -6,18 +6,18 @@

    Grant Extension / Special Consideration

    Number of days - +
    - + } - +
    diff --git a/src/app/common/obect-select/object-select.component.html b/src/app/common/obect-select/object-select.component.html index 376fa15760..a94a68f337 100644 --- a/src/app/common/obect-select/object-select.component.html +++ b/src/app/common/obect-select/object-select.component.html @@ -3,10 +3,10 @@ {{ label }} } @if (placeholder) { diff --git a/src/app/common/pdf-viewer-panel/pdf-viewer-panel.component.html b/src/app/common/pdf-viewer-panel/pdf-viewer-panel.component.html index fa076921b2..2e65ecfe24 100644 --- a/src/app/common/pdf-viewer-panel/pdf-viewer-panel.component.html +++ b/src/app/common/pdf-viewer-panel/pdf-viewer-panel.component.html @@ -11,11 +11,11 @@
    @if (resourcesUrl) { - + download Resources } -
    diff --git a/src/app/common/pdf-viewer/pdf-viewer.component.html b/src/app/common/pdf-viewer/pdf-viewer.component.html index 1319e1642d..6cd74b6e19 100644 --- a/src/app/common/pdf-viewer/pdf-viewer.component.html +++ b/src/app/common/pdf-viewer/pdf-viewer.component.html @@ -1,45 +1,45 @@
    - -
    - + search @@ -51,21 +51,21 @@ @if (pdfBlobUrl) { @if (useNativePdfViewer) { @if (pdfBlobUrl) { - PDF Preview + PDF Preview } } @else { } } @else { - + }
    diff --git a/src/app/common/project-progress/project-progress-gauge.component.html b/src/app/common/project-progress/project-progress-gauge.component.html index 4ccf5a81a5..c1a7ba8dca 100644 --- a/src/app/common/project-progress/project-progress-gauge.component.html +++ b/src/app/common/project-progress/project-progress-gauge.component.html @@ -1,17 +1,17 @@ diff --git a/src/app/common/services/alert.component.html b/src/app/common/services/alert.component.html index e84b05de0c..e565e82c95 100644 --- a/src/app/common/services/alert.component.html +++ b/src/app/common/services/alert.component.html @@ -4,7 +4,7 @@ {{ data?.message }} - + diff --git a/src/app/common/status-icon/status-icon.component.html b/src/app/common/status-icon/status-icon.component.html index 45bd7cbd89..e50b255d47 100644 --- a/src/app/common/status-icon/status-icon.component.html +++ b/src/app/common/status-icon/status-icon.component.html @@ -1,10 +1,10 @@
    check_circle + check_circle

    Submitted files downloaded.

    - } @case ('failed') { - error + error

    Could not download submitted files.

    - diff --git a/src/app/common/unit-code/unit-code.component.html b/src/app/common/unit-code/unit-code.component.html index 3440a343ff..cd8724577c 100644 --- a/src/app/common/unit-code/unit-code.component.html +++ b/src/app/common/unit-code/unit-code.component.html @@ -1,5 +1,5 @@ -
    +
    @if (isDualBadge && shiftBetweenBadges) { @for (part of unitCodeParts; track part; let i = $index) { @if (i === currentIndex) { diff --git a/src/app/common/user-badge/user-badge.component.html b/src/app/common/user-badge/user-badge.component.html index 1d7a5b7806..4baab5ced6 100644 --- a/src/app/common/user-badge/user-badge.component.html +++ b/src/app/common/user-badge/user-badge.component.html @@ -1,32 +1,32 @@
    -
    +
    -

    +

    {{ selectedTask?.project.student.firstName }} {{ selectedTask?.project.student.lastName }}

    {{ selectedTask?.definition.name }}

    diff --git a/src/app/common/user-icon/user-icon.component.html b/src/app/common/user-icon/user-icon.component.html index 541a185dbe..82690f70c2 100644 --- a/src/app/common/user-icon/user-icon.component.html +++ b/src/app/common/user-icon/user-icon.component.html @@ -1,4 +1,4 @@ - + @if (unselected) { account_circle } diff --git a/src/app/errors/states/unauthorised/unauthorised.component.html b/src/app/errors/states/unauthorised/unauthorised.component.html index b8e7445b81..5f1e2da7ac 100644 --- a/src/app/errors/states/unauthorised/unauthorised.component.html +++ b/src/app/errors/states/unauthorised/unauthorised.component.html @@ -4,5 +4,5 @@

    Unauthorised

    You do not have sufficient permissions to access this resource, or your session has expired.

    - +
    diff --git a/src/app/errors/unavailable-card/unavailable-card.component.html b/src/app/errors/unavailable-card/unavailable-card.component.html index 6ff11c0f03..7ffa8ef259 100644 --- a/src/app/errors/unavailable-card/unavailable-card.component.html +++ b/src/app/errors/unavailable-card/unavailable-card.component.html @@ -1,6 +1,6 @@
    Temporarily Unavailable
    engineering diff --git a/src/app/eula/accept-eula/accept-eula.component.html b/src/app/eula/accept-eula/accept-eula.component.html index 621b43cb59..5de43cf604 100644 --- a/src/app/eula/accept-eula/accept-eula.component.html +++ b/src/app/eula/accept-eula/accept-eula.component.html @@ -7,10 +7,10 @@

    End User License Agreements

    -
    diff --git a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.html b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.html index 4fa53bfb59..3006223a53 100644 --- a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.html +++ b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.html @@ -1,35 +1,33 @@ - - + - - + - - + - - + +
    Team Member + Team Member {{ member.project.student.name }} Target Grade + Target Grade Contribution + Contribution @for (i of [].constructor(numStars); track $index) { person @@ -46,6 +46,6 @@
    diff --git a/src/app/groups/group-member-list/group-member-list.component.html b/src/app/groups/group-member-list/group-member-list.component.html index 164f335c9e..883b9b50a6 100644 --- a/src/app/groups/group-member-list/group-member-list.component.html +++ b/src/app/groups/group-member-list/group-member-list.component.html @@ -10,8 +10,8 @@ } @else { - - + - + - - + - + - - + +
    {{ unitRole ? 'Student ID' : '' }} + {{ unitRole ? 'Student ID' : '' }} @if (unitRole) { {{ member.student.username || 'N/A' }} } @@ -19,15 +19,15 @@ - Name + Name {{ member.student.name }} {{ unitRole ? 'Target Grade' : '' }} + {{ unitRole ? 'Target Grade' : '' }} @if (unitRole) { } @@ -35,11 +35,11 @@ - {{ canRemoveMembers ? 'Actions' : '' }} + {{ canRemoveMembers ? 'Actions' : '' }} @if (canRemoveMembers) { @if (!project && unitRole) { - } @else if (project && project.id === member.id) { @@ -49,7 +49,7 @@
    } diff --git a/src/app/groups/group-selector/group-selector.component.html b/src/app/groups/group-selector/group-selector.component.html index e5a6b7c5a0..ccc01c2506 100644 --- a/src/app/groups/group-selector/group-selector.component.html +++ b/src/app/groups/group-selector/group-selector.component.html @@ -12,7 +12,7 @@ @if (showGroupSetSelector) { - + @for (gs of unit.groupSets; track gs.id) { {{ gs.name }} } @@ -30,7 +30,7 @@ (ngModelChange)="onGroupNameChange()" /> -
    @@ -56,13 +56,13 @@

    There are no groups in this set

    } @else { - +
    - - + - + - - + - - - + +
    Name + Name @if (editing(group)) { - + } @else { {{ group.name || 'Not set' }} @@ -71,8 +71,8 @@ - Tutorial + Tutorial @if (editing(group)) { @@ -88,20 +88,20 @@ - + @if (unitRole) { Capacity Adjustment } + @if (unitRole) { @if (editing(group)) { } @else { @@ -112,8 +112,8 @@ - Capacity + Capacity @if (group.hasSpace()) { Available } @else { @@ -123,12 +123,12 @@ - + @if (unitRole || (project && selectedGroupSet.allowStudentsToManageGroups)) { Actions } + @if (isPartOfGroup(project, group)) {
    Joined
    } @else if (project && group.hasSpace() && selectedGroupSet.allowStudentsToManageGroups) { @@ -136,8 +136,8 @@ @if (!group.locked && !selectedGroupSet.locked) { @@ -172,7 +172,7 @@ lock_open } - } @@ -181,8 +181,8 @@
    } diff --git a/src/app/groups/group-set-manager/group-set-manager.component.html b/src/app/groups/group-set-manager/group-set-manager.component.html index b860cb4b14..72ecb5fec7 100644 --- a/src/app/groups/group-set-manager/group-set-manager.component.html +++ b/src/app/groups/group-set-manager/group-set-manager.component.html @@ -1,36 +1,36 @@
    @if (selectedGroup) { - + Members of @if (!editingGroupName) { {{ selectedGroup?.name }} @if (unitRole || selectedGroup.groupSet?.allowStudentsToManageGroups) { - } } @else { @if (unitRole || selectedGroup.groupSet?.allowStudentsToManageGroups) { - + - - } @@ -43,21 +43,21 @@ @if (unitRole) { - + @for (gs of unit.groupSets; track gs.id) { {{ gs.name }} } diff --git a/src/app/home/states/home/home.component.html b/src/app/home/states/home/home.component.html index e8ade77311..cdeeb9af4e 100644 --- a/src/app/home/states/home/home.component.html +++ b/src/app/home/states/home/home.component.html @@ -1,4 +1,4 @@ -
    +

    You are not enrolled in {{ externalName.value }}.

    Contact your unit convenor or tutor to enrol you in a subject.

    @@ -12,14 +12,14 @@

    You are not enrolled in any {{ externalName.value }} }

    Units you teach

    -
    - +
    +
    -
    +
    @for (unitRole of unitRoles | isActiveUnitRole; track unitRole) {
    @if (!unitRole.unit.teachingPeriod || unitRole.unit.teachingPeriod?.active) { -
    +
    {{ unitRole.unit?.name }} @@ -64,12 +64,12 @@

    Units you teach

    diff --git a/src/app/home/states/lti-dashboard/lti-dashboard.component.html b/src/app/home/states/lti-dashboard/lti-dashboard.component.html index 880914025d..430556fe2c 100644 --- a/src/app/home/states/lti-dashboard/lti-dashboard.component.html +++ b/src/app/home/states/lti-dashboard/lti-dashboard.component.html @@ -1,11 +1,10 @@ -
    +

    OnTrack

    @@ -23,53 +22,53 @@

    OnTrack

    @if (currentUser?.systemRole === 'Convenor' || currentUser?.systemRole === 'Admin') { }
    } @@ -88,7 +87,7 @@

    OnTrack

    @if (currentUser?.systemRole === 'Convenor' || currentUser?.systemRole === 'Admin') {
    - } @else { diff --git a/src/app/home/states/lti-unit-link/lti-unit-link.component.html b/src/app/home/states/lti-unit-link/lti-unit-link.component.html index 9975e20cb0..ff232c1bf8 100644 --- a/src/app/home/states/lti-unit-link/lti-unit-link.component.html +++ b/src/app/home/states/lti-unit-link/lti-unit-link.component.html @@ -1,11 +1,10 @@ -
    +

    OnTrack

    @@ -33,11 +32,11 @@

    OnTrack

    diff --git a/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html index a4c5164702..35c49cf9fa 100644 --- a/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html +++ b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.html @@ -21,11 +21,11 @@

    Targetting

    info - + Target grade @for (grade of grades; track grade) { - {{ + {{ grade.viewValue }} } @@ -45,14 +45,14 @@

    Targetting

    diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html index 02ac242529..cc01407796 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html @@ -10,7 +10,7 @@

    - +
    @@ -28,9 +28,9 @@

    Select Target Grade @for (grade of grades.values; track grade) { @@ -41,7 +41,7 @@

    To change your target grade, use the - + Task Planner
    @@ -52,7 +52,7 @@

    - +
    @@ -66,9 +66,9 @@

    Aim to keep your @@ -87,8 +87,8 @@

    diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.html b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.html index ee040cde96..c11ab4c597 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.html +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.html @@ -19,7 +19,7 @@ --> diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html index 7b30d385d6..a5cf691e16 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html @@ -13,7 +13,7 @@

    - +

    @@ -41,10 +41,10 @@

    @@ -63,10 +63,10 @@

    @@ -95,9 +95,9 @@

    } @else { @@ -138,8 +138,8 @@

    } @else { @@ -151,8 +151,8 @@

    @@ -162,7 +162,7 @@

    - +
    @if (isArchiveCodeOrTextFile(file)) { } @else if (isArchivePdfFile(file)) { @@ -193,8 +193,8 @@

    } @else { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.html index e8a1f50991..e5489003ec 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.html @@ -9,8 +9,8 @@ {{ taskDefinition.abbreviation }} {{ taskDefinition.name }}. diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html index 221c1f15fb..929ecc556e 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.html @@ -61,29 +61,29 @@ diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html index 69c416c606..4893c99cb4 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html @@ -22,8 +22,8 @@

    Similarities

    @for (part of similarity.parts; track part; let i = $index) { @@ -33,18 +33,18 @@

    Similarities

    @if (similarity.readyForViewer) { @if (similarity.type === 'JplagTaskSimilarity') { } @else if (similarity.type === 'TiiTaskSimilarity') { @@ -64,7 +64,7 @@
    {{ task?.statusLabel() }}

    -
    diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.html index 218a7cf028..90dd00e1d5 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.html @@ -36,10 +36,10 @@ Download submission @@ -49,8 +49,8 @@ - - diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html index e4ad3411dd..0c9ac2b5b4 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.html @@ -2,8 +2,8 @@
    @@ -52,10 +52,10 @@ @@ -77,17 +77,17 @@ @case (DashboardViews.details) {
    diff --git a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html index a54a599425..27ec1c0f3f 100644 --- a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html +++ b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.html @@ -38,20 +38,20 @@ @if (project$ | async; as project) {
    -
    +
    @if (subs$ | async) { @if (isProjectTaskListReady(project)) { } @else {
    @@ -61,13 +61,13 @@
    } diff --git a/src/app/projects/states/discussion-prompts/discussion-prompts.component.html b/src/app/projects/states/discussion-prompts/discussion-prompts.component.html index 4172ea915a..05f56f7cd3 100644 --- a/src/app/projects/states/discussion-prompts/discussion-prompts.component.html +++ b/src/app/projects/states/discussion-prompts/discussion-prompts.component.html @@ -4,8 +4,8 @@
    {{ prompt.taskDefinition.abbreviation }}
    diff --git a/src/app/projects/states/groups/project-groups-state.component.html b/src/app/projects/states/groups/project-groups-state.component.html index 452af94217..e02214e8b7 100644 --- a/src/app/projects/states/groups/project-groups-state.component.html +++ b/src/app/projects/states/groups/project-groups-state.component.html @@ -1,7 +1,7 @@ @if (project) { } diff --git a/src/app/projects/states/groups/project-groups/project-groups.component.html b/src/app/projects/states/groups/project-groups/project-groups.component.html index a375726a37..7eca48477b 100644 --- a/src/app/projects/states/groups/project-groups/project-groups.component.html +++ b/src/app/projects/states/groups/project-groups/project-groups.component.html @@ -1,6 +1,6 @@
    @if (unit.hasGroupwork()) { - + } @else {
    diff --git a/src/app/projects/states/jplag/jplag-report-viewer.component.html b/src/app/projects/states/jplag/jplag-report-viewer.component.html index 4474b7d14e..1b5e99f233 100644 --- a/src/app/projects/states/jplag/jplag-report-viewer.component.html +++ b/src/app/projects/states/jplag/jplag-report-viewer.component.html @@ -1,9 +1,9 @@ diff --git a/src/app/projects/states/plan/project-plan.component.html b/src/app/projects/states/plan/project-plan.component.html index a1e861bcbd..733eda3558 100644 --- a/src/app/projects/states/plan/project-plan.component.html +++ b/src/app/projects/states/plan/project-plan.component.html @@ -21,8 +21,8 @@

    Task Planner

    Target Grade @for (grade of gradeValues; track grade) { diff --git a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html index d75f59aa58..8bc5faa0fc 100644 --- a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html +++ b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.html @@ -11,8 +11,8 @@

    {{ taskDefinition.description }}

    @if (!task.hasPrerequisiteTasks()) {
    This task has no prerequisites.
    @@ -34,15 +34,15 @@ - - + - - + - + - - + +
    Task + Task {{ link.taskDefinition?.abbreviation }} {{ link.taskDefinition?.name }} Submission Open + Submission Open @if (link.taskDefinition.projectTask(project).blockedByPrerequisiteTasks()) { block_outlined } @else { @@ -56,17 +56,17 @@ - Required Status + Required Status
    diff --git a/src/app/projects/states/plan/task-planner/task-planner.component.html b/src/app/projects/states/plan/task-planner/task-planner.component.html index c4b4ee33c9..f30b4efdc0 100644 --- a/src/app/projects/states/plan/task-planner/task-planner.component.html +++ b/src/app/projects/states/plan/task-planner/task-planner.component.html @@ -4,14 +4,14 @@
    @if (unit.allowFlexibleDates) {
    - @@ -20,19 +20,19 @@ }
    @@ -44,8 +44,8 @@ >
    {{ item.title }} @@ -58,19 +58,19 @@ @if (showDatesColumn) { - + {{ toDateString(item.start) }} - + {{ toDateString(item.end) }} - + {{ item.task.localDeadlineDate() ? toDateString(item.task.localDeadlineDate()) : 'N/A' }} @@ -78,15 +78,15 @@
    @if (unsavedChanges(item)) { diff --git a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html index a596c34e0a..315af39ff8 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html +++ b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.html @@ -15,7 +15,7 @@ {{ icons[file.kind] }} {{ file.name }}
    - @@ -36,17 +36,17 @@
    - + diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html index e74d70a357..e8ce666a9a 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.html @@ -1,4 +1,4 @@ -
    +
    @@ -61,8 +61,8 @@

    Select Grade

    > @for (grade of gradeValues; track grade) { @@ -82,10 +82,10 @@

    Select Grade

    - + --> - +
    }
    @@ -79,10 +79,10 @@
    } diff --git a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.component.html index 661f2cb884..889d52931e 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.component.html +++ b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.component.html @@ -111,11 +111,11 @@ - diff --git a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.html b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.html index baedcd729a..26ec79f3a3 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.html +++ b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.html @@ -18,6 +18,6 @@

    - + diff --git a/src/app/projects/states/portfolio/portfolio-state.component.html b/src/app/projects/states/portfolio/portfolio-state.component.html index 148fd8477a..e464e313b9 100644 --- a/src/app/projects/states/portfolio/portfolio-state.component.html +++ b/src/app/projects/states/portfolio/portfolio-state.component.html @@ -1,15 +1,15 @@ @if (project) {
    @for (tab of orderedTabs; track tab.seq) { } @@ -20,29 +20,29 @@ } @if (activeTab === tabs.gradeStep) { } @if (activeTab === tabs.summaryStep) { } @if (activeTab === tabs.otherFilesStep) { } @if (activeTab === tabs.reviewStep) { }
    diff --git a/src/app/projects/states/staff-notes/staff-notes.component.html b/src/app/projects/states/staff-notes/staff-notes.component.html index 641eb63700..a806cf2c6f 100644 --- a/src/app/projects/states/staff-notes/staff-notes.component.html +++ b/src/app/projects/states/staff-notes/staff-notes.component.html @@ -32,12 +32,12 @@
    } -
    +
    @if (note.authorIsMe) { edit } @@ -46,14 +46,14 @@
    - + {{ note.user?.firstName }} {{ note.user?.lastName }}
    {{ note.createdAt | humanizedDate }}
    @@ -64,15 +64,15 @@ Update Note
    - - +
    @@ -115,12 +115,12 @@ Staff Note
    - +
    diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html index 843c67695b..52f7807b52 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html @@ -1,15 +1,15 @@
    @if (loadingStudentData) { }
    -
    +
    @@ -33,8 +33,8 @@ @for (td of unit?.taskDefinitionCache.values | async; track td) { {{ td.abbreviation }} - {{ td.name }} @@ -42,7 +42,7 @@ @if (selectedTaskDefinition) { - + }
    } @@ -66,7 +66,7 @@
    Click the QR code to open the scanner..
    } -
    @@ -74,10 +74,9 @@ @if (project && !filteredTasks.length) {
    No tasks to discuss.
    } - + @for (task of filteredTasks; track task) { @if (task) {
    - +

    {{ task.definition.name }}

    @@ -118,17 +118,17 @@

    {{ task.definition.name }}

    } } @else { - } @@ -168,8 +168,8 @@

    {{ task.definition.name }}

    @if (attendance) {
    diff --git a/src/app/projects/states/tutor-notes/tutor-notes.component.html b/src/app/projects/states/tutor-notes/tutor-notes.component.html index 6cc373d047..4a69c31a30 100644 --- a/src/app/projects/states/tutor-notes/tutor-notes.component.html +++ b/src/app/projects/states/tutor-notes/tutor-notes.component.html @@ -32,13 +32,13 @@
    }
    -
    +
    @if (note.authorIsMe) { edit } @@ -47,7 +47,7 @@
    @if (!note.readByUnitRole) { @if (note.noteIsForMe) { - } @@ -58,14 +58,14 @@
    - + {{ note.user?.firstName }} {{ note.user?.lastName }}
    {{ note.createdAt | humanizedDate }}
    @@ -94,15 +94,15 @@ Update Note
    - - +
    @@ -123,7 +123,7 @@
    - + @for (option of taskDefinitionFilters; track option) { {{ option }} @@ -163,12 +163,12 @@ Tutor note
    - +
    diff --git a/src/app/projects/states/tutorials/tutorials.component.html b/src/app/projects/states/tutorials/tutorials.component.html index 7a2dca17ff..b953b21592 100644 --- a/src/app/projects/states/tutorials/tutorials.component.html +++ b/src/app/projects/states/tutorials/tutorials.component.html @@ -9,16 +9,16 @@

    Tutorials

    - - + - + - - + - - + - - + - - + - - + - - + - - + +
    Stream + Stream @if (unit.tutorialStreamsCache.size > 0) {
    {{ tutorial.tutorialStream?.name || 'All' }}
    } @else { @@ -28,49 +28,49 @@

    Tutorials

    -
    Campus + Campus {{ tutorial.campus?.name || 'All' }} Code + Code {{ tutorial.abbreviation }} Day + Day {{ tutorial.meetingDay }} Time + Time {{ shortTime(tutorial.meetingTime) }} Room + Room {{ tutorial.meetingLocation }} Tutor + Tutor {{ tutorial.tutorName }} Actions + Actions @if (project.isEnrolledIn(tutorial)) { @if (unit.allowStudentChangeTutorial) { @@ -101,8 +101,8 @@

    Tutorials

    }
    } diff --git a/src/app/sessions/states/sign-in/sign-in.component.html b/src/app/sessions/states/sign-in/sign-in.component.html index 5eeb9fa752..2c57ca1db0 100644 --- a/src/app/sessions/states/sign-in/sign-in.component.html +++ b/src/app/sessions/states/sign-in/sign-in.component.html @@ -6,7 +6,7 @@
    - Homepage Logo + Homepage Logo

    {{ externalName.value }}

    @@ -14,6 +14,7 @@

    autoLogin: autoLogin, }) " - class="sign-in-form flex flex-col" > @if (showCredentials) { @@ -34,10 +34,10 @@

    Password @@ -52,8 +52,8 @@

    diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.html b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.html index c67f8463e5..30ae42e4c5 100644 --- a/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.html +++ b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.html @@ -14,19 +14,19 @@ @for (idx of gradeValues; track idx) { @@ -44,7 +44,7 @@ {{ task.definition.abbreviation }}

    - +
    @@ -57,10 +57,10 @@ diff --git a/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.html b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.html index 42044d1858..4938fc354e 100644 --- a/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.html +++ b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.html @@ -12,9 +12,9 @@

    Select submission type

    }

    I would like feedback
    @if (isGroupStage) { @@ -174,11 +174,11 @@

    Declaration

    @if (isDetailsStage && showCommentsSection) { @@ -194,12 +194,12 @@

    Declaration

    @if ((!showCommentsSection && isDetailsStage) || isCommentsStage) { diff --git a/src/app/tasks/project-tasks-list/project-tasks-list.component.html b/src/app/tasks/project-tasks-list/project-tasks-list.component.html index 243bba9805..ed091e545e 100644 --- a/src/app/tasks/project-tasks-list/project-tasks-list.component.html +++ b/src/app/tasks/project-tasks-list/project-tasks-list.component.html @@ -14,14 +14,14 @@
    {{ grouping.name }}
    ) { @if (task.similarityFlag) { diff --git a/src/app/tasks/task-comment-composer/attachment-confirmation-dialog/attachment-confirmation-dialog.component.html b/src/app/tasks/task-comment-composer/attachment-confirmation-dialog/attachment-confirmation-dialog.component.html index 30c3f7ed38..7a518ce359 100644 --- a/src/app/tasks/task-comment-composer/attachment-confirmation-dialog/attachment-confirmation-dialog.component.html +++ b/src/app/tasks/task-comment-composer/attachment-confirmation-dialog/attachment-confirmation-dialog.component.html @@ -8,8 +8,8 @@

    Post Attachment?

    @if (isImage) { } @else if (isPdf) {
    @@ -28,7 +28,7 @@

    Post Attachment?

    {{ file.type || 'Audio file' }}
    - +
    } @else {
    @@ -51,5 +51,5 @@

    Post Attachment?

    - + diff --git a/src/app/tasks/task-comment-composer/discussion-prompt-composer-dialog.html b/src/app/tasks/task-comment-composer/discussion-prompt-composer-dialog.html index 4257317bc5..153184e21f 100644 --- a/src/app/tasks/task-comment-composer/discussion-prompt-composer-dialog.html +++ b/src/app/tasks/task-comment-composer/discussion-prompt-composer-dialog.html @@ -1,15 +1,15 @@ - - + Introduction
    Discussion Splash Image

    Discussions are a great way for both you and your students to gauge student's understanding @@ -30,7 +30,7 @@

    -
    @@ -41,7 +41,7 @@
    -
    diff --git a/src/app/tasks/task-comment-composer/discussion-prompt-composer/discussion-prompt-composer.component.html b/src/app/tasks/task-comment-composer/discussion-prompt-composer/discussion-prompt-composer.component.html index f6d9dc8112..ed00a23c44 100644 --- a/src/app/tasks/task-comment-composer/discussion-prompt-composer/discussion-prompt-composer.component.html +++ b/src/app/tasks/task-comment-composer/discussion-prompt-composer/discussion-prompt-composer.component.html @@ -1,11 +1,11 @@

    Step 1. Record and add up to 3 prompts.

    -
    +
    @@ -59,12 +59,12 @@

    Prompt {{ i + 1 }}

    Step 3. Send.

    diff --git a/src/app/tasks/task-comment-composer/task-comment-composer.component.html b/src/app/tasks/task-comment-composer/task-comment-composer.component.html index 4e0d18d1da..9a5788207f 100644 --- a/src/app/tasks/task-comment-composer/task-comment-composer.component.html +++ b/src/app/tasks/task-comment-composer/task-comment-composer.component.html @@ -1,11 +1,11 @@ @@ -13,10 +13,10 @@
    @@ -31,10 +31,10 @@
    @@ -45,14 +45,14 @@ } @for (emoji of emojiSearchResults; track emoji) {
    - +
    {{ emoji.name }}
    {{ emoji.colons }}
    @@ -63,34 +63,34 @@ @if (task) { } -
    +
    @if ($userIsTyping | async) { @@ -113,13 +113,13 @@ @if (isStaff) { @if (!isEditing) { @@ -152,13 +152,13 @@ @if (!isEditing) { - +
    }
    diff --git a/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-dialog.html b/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-dialog.html index bc55f2507a..c4cb615fae 100644 --- a/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-dialog.html +++ b/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-dialog.html @@ -1,14 +1,14 @@ - - + Introduction
    Discussion Splash Image

    Your tutor would like to discuss some topics with you regarding this task Discussions are a @@ -27,7 +27,7 @@

    -
    @@ -36,21 +36,20 @@ Test everything is working -
    - + Ready to go! @@ -61,9 +60,9 @@ Discussion
    @@ -73,9 +72,9 @@
    diff --git a/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-player.component.html b/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-player.component.html index f0d129e741..9ed3747a9f 100644 --- a/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-player.component.html +++ b/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-player.component.html @@ -13,47 +13,47 @@

    }
    P1 @if (discussion.numberOfPrompts > 1) { P2 } @if (discussion.numberOfPrompts > 2) { P3 } Response diff --git a/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-recorder/intelligent-discussion-recorder.component.html b/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-recorder/intelligent-discussion-recorder.component.html index 91e633240a..675f751ba0 100644 --- a/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-recorder/intelligent-discussion-recorder.component.html +++ b/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-recorder/intelligent-discussion-recorder.component.html @@ -6,8 +6,8 @@
    diff --git a/src/app/tasks/task-comments-viewer/pdf-image-comment/pdf-image-comment.component.html b/src/app/tasks/task-comments-viewer/pdf-image-comment/pdf-image-comment.component.html index 8127bf8e59..01448c6420 100644 --- a/src/app/tasks/task-comments-viewer/pdf-image-comment/pdf-image-comment.component.html +++ b/src/app/tasks/task-comments-viewer/pdf-image-comment/pdf-image-comment.component.html @@ -1,6 +1,6 @@ @if (comment.commentType === 'image' && resourceUrl) { - Image attachment preview + Image attachment preview } @if (comment.commentType === 'pdf') {

    picture_as_pdf view pdf

    diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html index 6ea723e8dc..7fac5712c3 100644 --- a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.html @@ -1,10 +1,10 @@
    @@ -15,18 +15,18 @@ } diff --git a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html index cdc4a33b1e..a47e71f63a 100644 --- a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html +++ b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.html @@ -15,10 +15,10 @@

    @if (isNotStudent) { diff --git a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.html b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.html index 6ded1e08e2..1d45b3f397 100644 --- a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.html +++ b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.html @@ -28,20 +28,20 @@ > } @else if (comment.overseerStatus === 'failed') { highlight_off_outline } @else if (comment.overseerStatus === 'pre_queued') { - + } @if (comment.overseerStatus !== 'pre_queued') { diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html index f4088e9d6c..5c0be3594a 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.html @@ -1,18 +1,18 @@
    -
    - +
    +
    @if (!task || task.comments.length === 0) { @@ -26,10 +26,10 @@ @for (comment of task.comments; track comment) {
    @if (comment.shouldShowTimestamp) {

    @@ -39,22 +39,22 @@ }

    @if (!comment.authorIsMe && shouldShowAuthorIcon(comment.commentType)) {
    @if (comment.shouldShowAvatar && shouldShowAuthorIcon(comment.commentType)) { } @@ -63,16 +63,16 @@
    @switch (comment.commentType) { @case ('status') {

    @@ -81,18 +81,18 @@ @case ('discussed_in_class') {
    - + group {{ comment.text }} @@ -103,18 +103,18 @@ @case ('feedback_review_request') {
    - + comment {{ comment.text }} @@ -125,18 +125,18 @@ @case ('checked_in') {
    - + how_to_reg {{ comment.text }} @@ -154,8 +154,8 @@
    @if (overseerEnabled) { }
    @@ -164,7 +164,7 @@ @case ('scorm') {
    @if (scormEnabled) { - + }
    } @@ -173,8 +173,8 @@ diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.html b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.html index 3b9cd48700..13afa33ac6 100644 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.html +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.html @@ -32,10 +32,10 @@
    diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html index 4e844cabda..6298d27683 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html @@ -8,10 +8,10 @@

    Tutor Times Session Summary

    @if (role === 'Convenor') { @@ -19,10 +19,10 @@

    Tutor Times Session Summary

    @@ -31,11 +31,11 @@

    Tutor Times Session Summary

    - - +
    @@ -98,17 +98,17 @@

    Tutor Times Session Summary

    }
    diff --git a/src/app/units/states/analytics/unit-analytics-route.component.html b/src/app/units/states/analytics/unit-analytics-route.component.html index e821247f5b..39b3461d24 100644 --- a/src/app/units/states/analytics/unit-analytics-route.component.html +++ b/src/app/units/states/analytics/unit-analytics-route.component.html @@ -19,7 +19,7 @@

    Unit Statistics

    - +
    - +
    - } @else {

    {{ set.name }}

    - }
    -
    @@ -160,23 +160,23 @@

    {{ set.name }}

    - } @else {
    {{ rule.name }}
    @@ -190,9 +190,9 @@

    {{ set.name }}

    @@ -204,12 +204,12 @@

    {{ set.name }}

    - + Send action log to convenors after execution
    - @@ -221,10 +221,10 @@

    {{ set.name }}

    + } -
    @@ -70,7 +70,7 @@

    Unit Details

    Draft Learning Summary - + None @for (td of taskDefinitions; track td) { {{ td.abbreviation }} - {{ td.name }} @@ -96,9 +96,9 @@

    Unit Details

    Feedback warning after (days) @@ -111,9 +111,9 @@

    Unit Details

    Show task in overflow queue after (days) @@ -150,8 +150,8 @@

    Unit Details

    Has tasks assessed in portfolio

    @@ -240,7 +240,7 @@

    Unit Details

    }
    -

    > Copy - +
    diff --git a/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.component.html b/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.component.html index c072bf1999..4bdc0d0ce9 100644 --- a/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.component.html +++ b/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.component.html @@ -8,7 +8,7 @@

    A group set is a set of related group-work. A unit can have multiple group sets for various kinds of group work which has multiple teams. -

    @@ -16,10 +16,10 @@ @if (showHelp) {
    @@ -44,11 +44,11 @@

    No Group Sets Created

    } @else { - - + - + - + - + - + - +
    Name + Name @if (editingGroupSetId === groupSet.id && editingGroupSetModel) { - + } @else { {{ groupSet.name || 'No Name Set' }} @@ -57,14 +57,14 @@

    No Group Sets Created

    -
    Capacity + Capacity @if (editingGroupSetId === groupSet.id && editingGroupSetModel) { @@ -75,8 +75,8 @@

    No Group Sets Created

    -
    Create Groups + Create Groups @if (editingGroupSetId === groupSet.id && editingGroupSetModel) { @@ -92,8 +92,8 @@

    No Group Sets Created

    -
    Manage Groups + Manage Groups @if (editingGroupSetId === groupSet.id && editingGroupSetModel) { @@ -109,8 +109,8 @@

    No Group Sets Created

    -
    Restrict to Tutorials + Restrict to Tutorials @if (editingGroupSetId === groupSet.id && editingGroupSetModel) { @@ -126,11 +126,11 @@

    No Group Sets Created

    -
    Actions + Actions
    @if (editingGroupSetId === groupSet.id) { - @@ -151,7 +151,7 @@

    No Group Sets Created

    {{ groupSet.locked ? 'lock' : 'lock_open' }} {{ groupSet.locked ? 'Unlock' : 'Lock' }} - @@ -161,7 +161,6 @@

    No Group Sets Created

    } - @@ -200,9 +200,9 @@

    No Group Sets Created

    @if (selectedGroupSet && unit.groupSets.length > 0) {
    @@ -234,12 +234,12 @@

    No Group Sets Created

    @@ -271,12 +271,12 @@

    No Group Sets Created

    diff --git a/src/app/units/states/edit/directives/unit-staff-editor/bulk-import-staff-modal/bulk-import-staff-modal.component.html b/src/app/units/states/edit/directives/unit-staff-editor/bulk-import-staff-modal/bulk-import-staff-modal.component.html index 32c44da5da..8240189388 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/bulk-import-staff-modal/bulk-import-staff-modal.component.html +++ b/src/app/units/states/edit/directives/unit-staff-editor/bulk-import-staff-modal/bulk-import-staff-modal.component.html @@ -3,20 +3,20 @@

    Bulk Import Staff

    Paste one staff email per line to add them to this unit as tutors.

    - + Staff emails
    -
    - - +
    diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html index d01957ae86..1573f1b960 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.html @@ -3,52 +3,52 @@

    Unit Staff

    Manage unit staff by adding members and assigning them as convenors or tutors.

    - +
    - + - - - + - - + - + - - + - - + - + - - + +
    NameName +
    - {{ unitRole.user.name }}
    Role + Role Tutor Convenor Main Convenor + Main Convenor @if (unitRole?.role === 'Convenor') { Observer Only + Observer Only Overflow Marking + Overflow Marking Mentor + Mentor (None) @for (unitRole of unitStaff; track unitRole) { @@ -103,8 +103,8 @@

    Unit Staff

    -
    Actions + Actions
    -
    - + @for (staff of filteredStaff; track staff) { @@ -145,10 +145,10 @@

    Unit Staff

    - - + - - + - - + - - + - - + @@ -65,16 +65,16 @@

    Enrolled Students

    - - + - - + - + - - - + + +
    Username + Username {{ project.student.username }} First Name + First Name {{ project.student.firstName }} Last Name + Last Name {{ project.student.lastName }} Email + Email {{ project.student.email }} Campus + Campus Tutorial - + Tutorial + Enrolled + Enrolled Enrolled Students - +
    +
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.html index 093ab2b77b..f94c7e6037 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.html @@ -4,9 +4,9 @@ @@ -18,9 +18,9 @@ @@ -30,11 +30,11 @@ Final Feedback Date diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.html index 9828b6297a..b3d0eb258b 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.html @@ -2,22 +2,22 @@
    - - + - - + - + - - + +
    Discussion Prompt + Discussion Prompt @if (!editing(prompt)) { {{ prompt.content }} } @else { Discussion Prompt - + } Priority + Priority @if (!editing(prompt)) { {{ prompt.priorityLabel }} } @else { @@ -37,8 +37,8 @@ - Actions + Actions
    @if (editing(prompt)) {
    @if (!dataSource.data.length) { @@ -68,7 +68,7 @@ } @if (!creatingNewDiscussionPrompt) {
    -
    @@ -82,8 +82,8 @@ Discussion Prompt
    @@ -99,7 +99,7 @@
    - +
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html index 773af87979..8c01e34614 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.html @@ -1,4 +1,4 @@ -
    +

    Details for {{ taskDefinition.abbreviation }} - {{ taskDefinition.name }}

    @@ -8,8 +8,8 @@

    Details for {{ taskDefinition.abbreviation }} - {{ taskDefinition.name }} @for (section of visibleSections; track section.id) {

    -
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.html index cc9e2ed2b8..e302e6d17d 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.html @@ -1,7 +1,7 @@
    Grade where task appears - + @for (grade of grades; track grade) { {{ grade.viewValue }} } @@ -10,21 +10,21 @@ Abbreviation - Week, sequence, and grade. eg 1.1P - + Weight - Effort relative to other tasks. - +
    Descriptive task name - + Task description - + diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html index bd3109b9f2..92a1002ce2 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.html @@ -11,10 +11,10 @@
    Assess in Portfolio Only @@ -47,7 +47,7 @@
    Quality Stars - + Provide a number of stars alongside the task status. Make sure you have a clear reason for diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html index 415d4a14a6..38d28433b3 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.html @@ -9,6 +9,6 @@
    @if (!loading) { - + }
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html index 164bd31aaf..54f0c3a87b 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.html @@ -3,8 +3,8 @@ Automation Enabled @@ -15,9 +15,9 @@
    - + Docker Image - + @for (image of images | async; track image) { {{ image.description }} } @@ -26,24 +26,24 @@ @if (taskDefinition.hasTaskAssessmentResources) {
    - - @@ -109,14 +109,14 @@
    @if (this.selectedOverseerStep) { - - + + }
    - +
    @@ -128,12 +128,12 @@
    @for (step of overseerSteps; track step.id) {
    drag_indicator {{ step.sortOrder }}. {{ step.name ?? 'Untitled Step' }} @@ -141,9 +141,9 @@ } @if (newOverseerStep) {
    {{ newOverseerStep.sortOrder }}. {{ newOverseerStep.name || 'Untitled Step' }} @@ -158,7 +158,7 @@
    Step Name - + Visible to staff only @@ -166,8 +166,8 @@ Visible to staff only @@ -175,7 +175,7 @@ Step Type - + Custom Script Input/Output @@ -198,7 +198,7 @@ runs. - + Show input file to student
    @@ -214,15 +214,15 @@ Program output must exactly match this file to pass. Show expected output file to student
    Partial Output Comparison
    @@ -274,10 +274,10 @@ Time Limit (s) How long the code can execute for before overseer automatically kills the @@ -342,14 +342,14 @@ Shown to student in overseer report Description - + Shown to student in overseer report
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html index 740b01959e..530d31da43 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html @@ -2,10 +2,10 @@
    - + - - - + +
    TaskTask {{ link.prerequisite?.abbreviation }} {{ link.prerequisite?.name }} @@ -13,7 +13,7 @@ - + @if (staffView) { Minimum Required Status } @else { @@ -21,8 +21,8 @@ } @if (!staffView) { @@ -33,10 +33,10 @@ } @else { @if (link.taskStatus) { @for (state of stateOptions; track state) { @@ -51,20 +51,20 @@ - + @if (staffView) { Actions } @else { Required Status } + @if (staffView) {
    @@ -87,20 +87,20 @@
    -
    @@ -19,21 +19,21 @@
    @if (taskDefinition.hasTaskResources) {
    - diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html index d05d59d67e..10a029b6ba 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.html @@ -5,25 +5,25 @@ @if (taskDefinition.scormEnabled) { @if (taskDefinition.hasScormData) {
    - -
    @@ -42,8 +42,8 @@ Limit to this number of attempts - 0 is unlimited @@ -52,11 +52,11 @@
    Enable incremental time delays between test attempts diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html index 0649d98406..9c15a2ce78 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.html @@ -1,18 +1,18 @@ - +
    - - + - - + - + - - + - + - + - - - + + +
    Filename + Filename - + Type + Type Code Document @@ -23,19 +23,19 @@ - Submission History + Submission History Check Similarity + Check Similarity @if (upreq.type === 'document' && tiiEnabled()) { TurnItIn } @@ -47,11 +47,11 @@ - Flag At + Flag At @if (upreq.type === 'document' && upreq.tiiCheck) { - +  % } @@ -60,12 +60,12 @@ - + + - @@ -87,9 +87,9 @@
    @if (missingOverseerSubmissionHistory) { @@ -127,7 +127,7 @@ Similarity percent to flag for JPLAG checks - +
    diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html index 0a3be6d1ba..65dee44436 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html @@ -43,11 +43,11 @@ @if (taskDefinition.tutorialStream?.tutorialsIn(unit).length > 3) {
    @if (!showAllTutorials) { - } @else { - } diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html index 472c672b28..72d7153562 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.html @@ -33,7 +33,7 @@

    Task List

    @if (unit.allowFlexibleDates) { } - +
    @if (unit.allowFlexibleDates) { @@ -46,22 +46,22 @@

    Manage Target Dates

    Modify or add target dates for each target grade

    - +
    - - + @for (g of gradeColumns; track g) { - - - + +
    Task + Task {{ td.abbreviation }} {{ td.name }} +
    +
    Manage Target Dates Start Date @@ -94,13 +94,13 @@

    Manage Target Dates

    Target Date @if (isStartAfterTarget(td, g)) { @@ -115,8 +115,8 @@

    Manage Target Dates

    } -
    } @@ -140,9 +140,9 @@

    Manage Target Dates

    >
    @if (!isTaskListCollapsed) {
    @@ -185,14 +185,14 @@

    Manage Target Dates

    Manage Target Dates

    [ngClass]="{'justify-center': isTaskListCollapsed}" > @if (!isTaskListCollapsed) { @@ -220,18 +220,18 @@

    > @if (taskDefinitionHasChanges(taskDefinition)) { } - } @@ -37,37 +37,37 @@

    Tutorials without a stream

    - - - + - - - - + - - + - - - - + - - + - - - - + - - + - - - + - - - - + + +
    Abbreviation + + Abbreviation @if (!editing(tutorial)) {
    {{ tutorial.abbreviation }}
    } @else { - + }
    + - + Campus + + Campus @if (!editing(tutorial)) {
    {{ tutorial.campus ? tutorial.campus.name : '' }} @@ -75,7 +75,7 @@

    Tutorials without a stream

    } @else { Campus - + Not Specified @for (campus of campuses; track campus) { @@ -86,7 +86,7 @@

    Tutorials without a stream

    }
    + Campus @@ -102,30 +102,30 @@

    Tutorials without a stream

    - -
    Location + + Location @if (!editing(tutorial)) {
    {{ tutorial.meetingLocation }}
    } @else { - + }
    + - + Day + + Day @if (!editing(tutorial)) {
    {{ tutorial.meetingDay }} @@ -133,7 +133,7 @@

    Tutorials without a stream

    } @else { Day - + @for (day of days; track day) { {{ day }} @@ -143,10 +143,10 @@

    Tutorials without a stream

    }
    + Day - + @for (day of days; track day) { {{ day }} @@ -158,9 +158,9 @@

    Tutorials without a stream

    - -
    Time + + Time @if (!editing(tutorial)) {
    {{ tutorial.meetingTime }} @@ -168,26 +168,26 @@

    Tutorials without a stream

    } @else { }
    + - + Tutor + + Tutor @if (!editing(tutorial)) {
    {{ tutorial.tutor?.name }} @@ -195,7 +195,7 @@

    Tutorials without a stream

    } @else { Tutor - + @for (tutor of unit.staffUsers; track tutor) { {{ tutor.name }} @@ -205,10 +205,10 @@

    Tutorials without a stream

    }
    + Tutor - + @for (tutor of unit.staffUsers; track tutor) { {{ tutor.name }} @@ -220,28 +220,28 @@

    Tutorials without a stream

    - -
    Capacity + + Capacity @if (!editing(tutorial)) {
    {{ tutorial.numStudents }} / {{ tutorial.capacity }}
    } @else { - + }
    + - + + @if (!editing(tutorial)) {
    } @else {
    - - -
    }
    +
    -
    diff --git a/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html b/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html index e56b409a73..a37505ec5d 100644 --- a/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html +++ b/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.html @@ -1,7 +1,7 @@
    @for (stream of unit.tutorialStreams; track stream) { - + } @empty {
    @@ -14,7 +14,7 @@

    No Tutorials

    }
    - diff --git a/src/app/units/states/edit/unit-admin-state.component.html b/src/app/units/states/edit/unit-admin-state.component.html index 6a06b1e487..d808b3d7f1 100644 --- a/src/app/units/states/edit/unit-admin-state.component.html +++ b/src/app/units/states/edit/unit-admin-state.component.html @@ -1,8 +1,8 @@
    @for (tab of tabs; track tab.routeSegment) { @@ -33,7 +33,7 @@

    Unit Learning Outcomes

    @case ('staff') { @if (unit) {
    - +
    } } diff --git a/src/app/units/states/groups/unit-groups/unit-groups.component.html b/src/app/units/states/groups/unit-groups/unit-groups.component.html index 26576c5042..9696d512a3 100644 --- a/src/app/units/states/groups/unit-groups/unit-groups.component.html +++ b/src/app/units/states/groups/unit-groups/unit-groups.component.html @@ -1,6 +1,6 @@ @if (unit.hasGroupwork()) {
    - +
    } @else { diff --git a/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.html b/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.html index ccf3c460a1..d5f194b3c2 100644 --- a/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.html +++ b/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.html @@ -15,7 +15,7 @@

    D2L Grade Transfer

    1. -
      @@ -27,7 +27,7 @@

      D2L Grade Transfer

    2. -
      @@ -36,7 +36,7 @@

      D2L Grade Transfer

    3. -
      @@ -49,7 +49,7 @@

      D2L Grade Transfer

    4. -
      @@ -61,7 +61,7 @@

      D2L Grade Transfer

    5. -
      @@ -79,5 +79,5 @@

      D2L Grade Transfer

      - + diff --git a/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.html b/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.html index ffb0504623..73fe7e03fb 100644 --- a/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.html +++ b/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.html @@ -3,7 +3,7 @@

      Grade for {{ project.student.name }}

      Assign grade for this project.

      Rationale - + @for (group of gradeResults; track group) {
      @@ -15,11 +15,11 @@

      Grade for {{ project.student.name }}

      @for (score of group.scores; track score) { @@ -29,10 +29,10 @@

      Grade for {{ project.student.name }}

      }
      diff --git a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html index cce514ee07..f638212138 100644 --- a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html +++ b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.html @@ -6,72 +6,72 @@

      Mark portfolios

      Filter public menu_book account_balance edit All @for (grade of gradeValues; track grade) { @@ -86,11 +86,11 @@

      Mark portfolios

      @@ -106,7 +106,7 @@

      Mark portfolios

      @if (loading) { -
      +
      @for ( @@ -167,86 +167,86 @@

      Mark portfolios

      } - - + - - + - - + - - + - - + - - + - - + - - + - - + - + - - + - + - +
      Student + Student {{ project.student.studentId || project.student.username }} Name + Name {{ project.student.name }} Tutor + Tutor {{ project.tutorNames() }} Tutorial + Tutorial {{ project.shortTutorialDescription() }} Target + Target Submitted as + Submitted as Submission Date + Submission Date {{ project.portfolioSubmissionDate | date: 'EEE d MMM y, h:mm a' }} Has Portfolio + Has Portfolio {{ project.hasPortfolio ? 'Yes' : 'No' }} Stats + Stats
      @for (bar of project.taskStats; track bar) {
      @if (bar.key === 'not_started') { {{ bar.value }}% @@ -261,37 +261,37 @@

      Mark portfolios

      -
      Grade + Grade {{ project.grade }} View + View
      No students found
      diff --git a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html index acc95740ce..788f4d9502 100644 --- a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html +++ b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.html @@ -54,8 +54,8 @@

      Review progress of {{ project.student.name }}

      --> diff --git a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html index 2d454fd43c..89963fcfef 100644 --- a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html +++ b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.html @@ -1,3 +1,3 @@ - diff --git a/src/app/units/states/portfolios/portfolios.component.html b/src/app/units/states/portfolios/portfolios.component.html index a13d2cf25d..da789dafe0 100644 --- a/src/app/units/states/portfolios/portfolios.component.html +++ b/src/app/units/states/portfolios/portfolios.component.html @@ -2,12 +2,12 @@ @if (unit) { @for (tab of tabs; track tab.routeSegment) { - + } @@ -15,18 +15,18 @@ @switch (currentTab.routeSegment) { @case ('select') { } @case ('progress') { @if (selectedProject) { } } diff --git a/src/app/units/states/portfolios/upload-grades/upload-grades.component.html b/src/app/units/states/portfolios/upload-grades/upload-grades.component.html index a95e240410..f42a9a62a0 100644 --- a/src/app/units/states/portfolios/upload-grades/upload-grades.component.html +++ b/src/app/units/states/portfolios/upload-grades/upload-grades.component.html @@ -1,3 +1,3 @@ - diff --git a/src/app/units/states/rollover/rollover.component.html b/src/app/units/states/rollover/rollover.component.html index 1f55d654a7..a6f4ed56f2 100644 --- a/src/app/units/states/rollover/rollover.component.html +++ b/src/app/units/states/rollover/rollover.component.html @@ -40,17 +40,17 @@ } @else { {{ teachingPeriod.name }} Start Date - + {{ teachingPeriod.name }} End Date - + }
      - + diff --git a/src/app/units/states/students-list/students-list.component.html b/src/app/units/states/students-list/students-list.component.html index 89cd97d026..73be5a3f61 100644 --- a/src/app/units/states/students-list/students-list.component.html +++ b/src/app/units/states/students-list/students-list.component.html @@ -9,10 +9,10 @@

      Students

      Search for students or tutors... @for (suggestion of filteredSuggestions; track suggestion) { @@ -24,18 +24,18 @@

      Students

      - All Tutorials - My Tutorials + All Tutorials + My Tutorials
      @if (loadingStudents) { -
      +
      @for (width of ['4%', '10%', '16%', '28%', '8%', '8%', '8%', '10%', '10%']; track $index) { Students
      - - + - - + - - + - - + - + - - + - + - + - + - + - + @@ -201,8 +201,8 @@

      Students

      Export CSV diff --git a/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.html b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.html index 2524617f84..1b680fae11 100644 --- a/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.html +++ b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.html @@ -36,8 +36,8 @@

      } - - + diff --git a/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.html b/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.html index ae11125495..3862dc4a8b 100644 --- a/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.html +++ b/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.html @@ -2,57 +2,57 @@ @if (task.moderationType === 'random_sample' || task.moderationType === 'first_feedback') { } @else if (task.moderationType === 'escalation') { diff --git a/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.html b/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.html index 7b284ba2f7..d797a552a4 100644 --- a/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.html +++ b/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.html @@ -5,29 +5,29 @@ [ngClass]="{expanded: showSearchOptions, mobile: mobile}" >
      -
      @if (collapsable) { }
      @@ -195,7 +194,7 @@ -
      +
      @@ -206,7 +205,7 @@ [ngClass]="isNarrow ? 'narrow-width' : 'full-width'" >
      -
      @@ -227,9 +226,9 @@ [ngClass]="isNarrow ? 'justify-center gap-0 px-[5px]' : 'gap-[10px] pl-[6px] pr-[8px]'" >
      @@ -276,8 +275,8 @@ } @if (task) { @@ -290,11 +289,11 @@ }" >
      - +

      @if (task.moderationType === 'escalation') { gavel } @if (getWarningIcon(task) === 'warning') { warning } @else if (getWarningIcon(task) === 'overflow') { watch_later @@ -358,15 +357,15 @@

      }
      - -
      -
      +
      @if (loading) { } @else { diff --git a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.html b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.html index 066789a0b1..1aba157340 100644 --- a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.html +++ b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.html @@ -1,10 +1,10 @@ diff --git a/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.html b/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.html index 61c3af38a0..ffa6367f9b 100644 --- a/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.html +++ b/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.html @@ -2,8 +2,8 @@
      Task Details @@ -15,7 +15,7 @@
      -
      +
      subtitles_off
      diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html index fce6d21874..39af419726 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.html @@ -1,6 +1,6 @@
      - +
      @@ -110,11 +110,11 @@ @if (taskDef) { @if (isCollapsed) { @@ -214,8 +214,8 @@
      diff --git a/src/app/units/task-viewer/task-viewer-state.component.html b/src/app/units/task-viewer/task-viewer-state.component.html index ed0f00290b..33a824d88e 100644 --- a/src/app/units/task-viewer/task-viewer-state.component.html +++ b/src/app/units/task-viewer/task-viewer-state.component.html @@ -1,14 +1,14 @@ @if (unit$ | async; as unit) {
      -
      -
      +
      +
      -
      +
      @@ -29,26 +29,26 @@
      -
      +
      -
      +
      -
      +
      diff --git a/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html index 15ed9a8795..d4406f7937 100644 --- a/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html +++ b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html @@ -1,22 +1,22 @@
      diff --git a/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.html b/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.html index dfcdad3104..b4c56c857b 100644 --- a/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.html +++ b/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.html @@ -1,12 +1,12 @@
      diff --git a/src/app/visualisations/task-visualisation/task-visualisation.component.html b/src/app/visualisations/task-visualisation/task-visualisation.component.html index b54fdb86be..b5311d2fab 100644 --- a/src/app/visualisations/task-visualisation/task-visualisation.component.html +++ b/src/app/visualisations/task-visualisation/task-visualisation.component.html @@ -1,6 +1,6 @@ diff --git a/src/app/welcome/welcome.component.html b/src/app/welcome/welcome.component.html index 427ebdb6e2..49f3552f95 100644 --- a/src/app/welcome/welcome.component.html +++ b/src/app/welcome/welcome.component.html @@ -1,17 +1,17 @@
      - +
      - Homepage Logo + Homepage Logo

      {{ externalName.value }}

      Welcome to {{ externalName.value }}

      diff --git a/src/index.html b/src/index.html index b1c567c8e4..f2d5aa9c95 100644 --- a/src/index.html +++ b/src/index.html @@ -19,23 +19,23 @@ rel="stylesheet" /> Loading... - + - - + + - - + + - + - + From 6d005653d2c5026b14538b4ff303e6a3047cbe94 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 17 Jun 2026 12:12:58 +1000 Subject: [PATCH 1118/1280] chore: ignore formatting commit from git blame --- .git-blame-ignore-revs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs index 8af4e23280..260dc5e2fd 100644 --- a/.git-blame-ignore-revs +++ b/.git-blame-ignore-revs @@ -1,2 +1,5 @@ # 8 June 2026: Repository-wide formatting and lint configuration 26b4962794d16e90587fb179aab966b39459050c + +# 17 June 2026: Repository-wide sorting of HTML attributes +1ffc7ad7b9dc18f22be32bf6313bfde97957dd2f From d6b704908ba79827d94bf55d815fda390248c754 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 17 Jun 2026 12:15:48 +1000 Subject: [PATCH 1119/1280] chore(release): 11.0.0-24 --- CHANGELOG.md | 14 ++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index aa9e011908..68b40a39eb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,20 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-24](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-23...v11.0.0-24) (2026-06-17) + + +### Features + +* check access token expiry locally before attempting request ([#1270](https://github.com/b0ink/doubtfire-deploy/issues/1270)) ([4ff5562](https://github.com/b0ink/doubtfire-deploy/commit/4ff55627566f9004872c915658bd91bc348dd8e8)) +* submission history ([#1269](https://github.com/b0ink/doubtfire-deploy/issues/1269)) ([4cdae07](https://github.com/b0ink/doubtfire-deploy/commit/4cdae07eb5bef0f9866927892e92b6b80dde0c74)) +* upgrade gantt chart and add screenshotting ability ([#1263](https://github.com/b0ink/doubtfire-deploy/issues/1263)) ([08a8eee](https://github.com/b0ink/doubtfire-deploy/commit/08a8eee9337331aa328960e206722f8905c2a0f9)) + + +### Bug Fixes + +* use either portfolio available field ([f8d5142](https://github.com/b0ink/doubtfire-deploy/commit/f8d514261c7eca5465ac3af95da33b95a39d3f23)) + ## [11.0.0-23](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-22...v11.0.0-23) (2026-06-11) diff --git a/package-lock.json b/package-lock.json index 730fade0f0..9a65211e7c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-23", + "version": "11.0.0-24", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-23", + "version": "11.0.0-24", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.17", diff --git a/package.json b/package.json index 45843a3301..437fef8080 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-23", + "version": "11.0.0-24", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From 1fb4637cd2386f1aeff227043e0002bf9b77837b Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Wed, 17 Jun 2026 17:25:14 +1000 Subject: [PATCH 1120/1280] feat: add day of week to gantt chart --- src/app/doubtfire-angular.module.ts | 31 ++++- .../task-planner/task-planner.component.scss | 23 ++++ .../task-planner/task-planner.component.ts | 106 +++++++++++++++++- 3 files changed, 152 insertions(+), 8 deletions(-) diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 518f8f3eb5..f968ab15a7 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -6,9 +6,11 @@ import {CodeEditorModule} from '@ngstack/code-editor'; import {NgxChartsModule} from '@swimlane/ngx-charts'; import { GANTT_GLOBAL_CONFIG, - GanttI18nLocale, + GANTT_I18N_LOCALE_TOKEN, + type GanttI18nLocaleConfig, GanttLinkLineType, NgxGanttModule, + enUsLocale, } from '@worktile/gantt'; import {DateAdapter as CalendarDateAdapter, CalendarModule} from 'angular-calendar'; import {adapterFactory} from 'angular-calendar/date-adapters/date-fns'; @@ -388,10 +390,33 @@ const MY_DATE_FORMAT = { }, }; +const DOUBTFIRE_GANTT_LOCALE = 'doubtfire-en-au'; + +const DOUBTFIRE_GANTT_LOCALE_CONFIG: GanttI18nLocaleConfig = { + ...enUsLocale, + id: DOUBTFIRE_GANTT_LOCALE, + views: { + ...enUsLocale.views, + day: { + ...enUsLocale.views.day, + tickFormats: { + ...enUsLocale.views.day.tickFormats, + unit: 'd EEE', + }, + }, + }, +}; + +const GANTT_CHART_LOCALE_CONFIG = { + provide: GANTT_I18N_LOCALE_TOKEN, + useValue: DOUBTFIRE_GANTT_LOCALE_CONFIG, + multi: true, +}; + const GANTT_CHART_CONFIG = { provide: GANTT_GLOBAL_CONFIG, useValue: { - locale: GanttI18nLocale.enUs, + locale: DOUBTFIRE_GANTT_LOCALE, dateOptions: { weekStartsOn: 1, }, @@ -400,6 +425,7 @@ const GANTT_CHART_CONFIG = { lineType: GanttLinkLineType.curve, }, styleOptions: { + headerHeight: 52, // lineHeight: '25', // barHeight: '23', // headerHeight: '50px', @@ -712,6 +738,7 @@ const DEFAULT_TOOLTIP_OPTIONS: MatTooltipDefaultOptions = { TaskPrerequisiteService, MarkingSessionService, DiscussionPromptService, + GANTT_CHART_LOCALE_CONFIG, GANTT_CHART_CONFIG, TaskPlannerPrerequisitesModalService, OverseerStepService, diff --git a/src/app/projects/states/plan/task-planner/task-planner.component.scss b/src/app/projects/states/plan/task-planner/task-planner.component.scss index ddf668e57b..df94c4a868 100644 --- a/src/app/projects/states/plan/task-planner/task-planner.component.scss +++ b/src/app/projects/states/plan/task-planner/task-planner.component.scss @@ -9,6 +9,29 @@ pointer-events: none; } +:host ::ng-deep gantt-calendar-header .secondary-text { + font-size: 11px; + line-height: 1.15; + transform: translateY(-0.45em); + white-space: pre-line; +} + +:host ::ng-deep gantt-calendar-header .today-rect { + display: flex; + height: 28px !important; + transform: translateY(-0.35rem); + flex-direction: column; + align-items: center; + justify-content: center; + gap: 1px; + line-height: 1; +} + +:host ::ng-deep gantt-calendar-header .today-weekday { + font-size: 9px; + font-weight: 500; +} + .gantt-bar { background-color: var(--bar-bg); } diff --git a/src/app/projects/states/plan/task-planner/task-planner.component.ts b/src/app/projects/states/plan/task-planner/task-planner.component.ts index 207caf2d51..fa36cd35c6 100644 --- a/src/app/projects/states/plan/task-planner/task-planner.component.ts +++ b/src/app/projects/states/plan/task-planner/task-planner.component.ts @@ -9,7 +9,15 @@ import { GanttViewType, NgxGanttComponent, } from '@worktile/gantt'; -import {Component, Input, OnInit, ViewChild} from '@angular/core'; +import { + AfterViewInit, + Component, + ElementRef, + Input, + OnDestroy, + OnInit, + ViewChild, +} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {Project} from 'src/app/api/models/project'; import {Task} from 'src/app/api/models/task'; @@ -37,9 +45,11 @@ interface TaskGanttItem extends GanttItem { providers: [GanttPrintService], standalone: false, }) -export class TaskPlannerComponent implements OnInit { +export class TaskPlannerComponent implements OnInit, AfterViewInit, OnDestroy { // Show a warning if the task's target end date is within this many days of the feedback deadline public readonly CLOSE_TO_FEEDBACK_DEADLINE_THRESHOLD = 7; + private readonly svgNamespace = 'http://www.w3.org/2000/svg'; + private ganttHeaderObserver?: MutationObserver; @Input() project: Project; @Input() targetGrade: number; @@ -66,6 +76,7 @@ export class TaskPlannerComponent implements OnInit { } constructor( + private elementRef: ElementRef, private gradeService: GradeService, private alertService: AlertService, private confirmationModalService: ConfirmationModalService, @@ -76,6 +87,14 @@ export class TaskPlannerComponent implements OnInit { private ganttPrintService: GanttPrintService, ) {} + ngAfterViewInit(): void { + setTimeout(() => this.setupGanttHeaderObserver()); + } + + ngOnDestroy(): void { + this.ganttHeaderObserver?.disconnect(); + } + public get gradeValues() { return this.gradeService.gradeValues; } @@ -534,10 +553,7 @@ export class TaskPlannerComponent implements OnInit { precisionUnit: 'day', start: new GanttDate(this.earliestStartDate), end: new GanttDate(this.latestEndDate), - tickFormats: { - period: 'yyyy MMM', - unit: 'd', - }, + unitWidth: 40, dragTooltipFormat: 'MMM dd', }; @@ -574,6 +590,84 @@ export class TaskPlannerComponent implements OnInit { }); } + private setupGanttHeaderObserver(): void { + const ganttElement = this.elementRef.nativeElement.querySelector('ngx-gantt'); + + if (!ganttElement) { + return; + } + + this.ganttHeaderObserver?.disconnect(); + this.ganttHeaderObserver = new MutationObserver(() => this.formatGanttHeaderLabels()); + this.ganttHeaderObserver.observe(ganttElement, { + childList: true, + subtree: true, + characterData: true, + }); + this.formatGanttHeaderLabels(); + } + + private formatGanttHeaderLabels(): void { + this.formatGanttDayLabels(); + this.formatGanttTodayLabel(); + } + + private formatGanttDayLabels(): void { + const dayLabels = this.elementRef.nativeElement.querySelectorAll( + 'gantt-calendar-header .secondary-text', + ); + + dayLabels.forEach((label) => { + if (label.querySelector('tspan')) { + return; + } + + const [date, day] = label.textContent?.trim().split(/\s+/) ?? []; + + if (!date || !day) { + return; + } + + const x = label.getAttribute('x') ?? '0'; + const dateLine = document.createElementNS(this.svgNamespace, 'tspan'); + dateLine.setAttribute('x', x); + dateLine.textContent = date; + + const dayLine = document.createElementNS(this.svgNamespace, 'tspan'); + dayLine.setAttribute('x', x); + dayLine.setAttribute('dy', '1.15em'); + dayLine.textContent = day; + + label.textContent = ''; + label.append(dateLine, dayLine); + }); + } + + private formatGanttTodayLabel(): void { + const todayLabel = this.elementRef.nativeElement.querySelector( + 'gantt-calendar-header .today-rect', + ); + + if (!todayLabel || todayLabel.querySelector('.today-weekday')) { + return; + } + + const today = new Date(); + const date = todayLabel.textContent?.trim() || today.getDate().toString(); + const day = new Intl.DateTimeFormat('en-US', {weekday: 'short'}).format(today); + + todayLabel.replaceChildren(); + + const dateLine = document.createElement('span'); + dateLine.textContent = date; + + const dayLine = document.createElement('span'); + dayLine.classList.add('today-weekday'); + dayLine.textContent = day; + + todayLabel.append(dateLine, dayLine); + } + refreshItems(scroll: boolean = true) { this.taskPrerequisites = this.allTaskPrerequisites.filter((pre) => this.taskDefs().find((td) => td.id === pre.taskDefinitionId), From 83b6d5ea381604ae88585195314eafd239880632 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Thu, 18 Jun 2026 09:53:59 +1000 Subject: [PATCH 1121/1280] fix: web calendar (#1282) * refactor: improve calendar ui/ux * refactor: improve ui * chore: add install guide * chore: correct google calendar * fix: copy to clipboard * chore: add mock ics extension * feat: open web cal from task planner --- .../calendar-modal.component.html | 316 ++++++++++-------- .../calendar-modal.component.scss | 27 -- .../calendar-modal.component.ts | 36 +- .../calendar-modal/calendar-modal.service.ts | 7 +- .../states/plan/project-plan.component.html | 12 +- .../states/plan/project-plan.component.ts | 6 + 6 files changed, 221 insertions(+), 183 deletions(-) diff --git a/src/app/common/modals/calendar-modal/calendar-modal.component.html b/src/app/common/modals/calendar-modal/calendar-modal.component.html index d7fe452d00..c6ae782ace 100644 --- a/src/app/common/modals/calendar-modal/calendar-modal.component.html +++ b/src/app/common/modals/calendar-modal/calendar-modal.component.html @@ -1,11 +1,11 @@ -
      -
      -
      +
      +
      +

      Web calendar

      Web calendar

      > - -
      +
      @if (!webcal) { - + } - @if (webcal) { Your web calendar is currently {{ webcal.enabled ? 'enabled' : 'disabled' }}. @@ -41,7 +34,6 @@

      Web calendar

      } - @if (webcal.enabled) {
      @@ -49,150 +41,184 @@

      Web calendar

      The web calendar displays due dates of your tasks as calendar events. Use the following URL to subscribe to your web calendar from your iCalendar client.

      -
      - -
      - - + } + + + } + +
      + + - refresh - -
      -
      - + Remind me + + + Time + + + + Unit + + Weeks + Days + Hours + Minutes + + + before each event - -

      Options

      + + @if ( + (!webcal.reminder && newReminderActive) || + (webcal.reminder && + (newReminderTime !== webcal.reminder.time || + newReminderUnit !== webcal.reminder.unit)) + ) { + + + } +
      -
      - Included units in my calendar: -
      + Include task start dates in web calendar + + +
      +
      + + + + + -
      - - @for (project of includedProjects; track project) { - - {{ project.unit.code }} - cancel - +
      + @switch (selectedCalendarProviderIndex) { + @case (0) { + In Google Calendar, choose Add other calendars, choose + From URL, then paste the URL below. } - @if (excludedProjects.length > 0) { - - add - - @for (project of excludedProjects; track project) { - - } - - + @case (1) { + In Apple Calendar, choose File, + New Calendar Subscription, then paste the URL below. } - + @case (2) { + In Outlook Calendar, choose Add calendar, + Subscribe from web, then paste the URL below. + } + }
      - - - Remind me - - - Time - - - - Unit - - Weeks - Days - Hours - Minutes - - - before each event - - @if ( - (!webcal.reminder && newReminderActive) || - (webcal.reminder && - (newReminderTime !== webcal.reminder.time || - newReminderUnit !== webcal.reminder.unit)) - ) { - - - } - - -
      - - - Include task start dates in web calendar - -
      - +
      +
      +
      +
      + link{{ webcalUrl }}.ics +
      +
      +
      + + +
      +
      - +
      } - } -
      - + +
      + +
      diff --git a/src/app/common/modals/calendar-modal/calendar-modal.component.scss b/src/app/common/modals/calendar-modal/calendar-modal.component.scss index f5e8c6f195..e69de29bb2 100644 --- a/src/app/common/modals/calendar-modal/calendar-modal.component.scss +++ b/src/app/common/modals/calendar-modal/calendar-modal.component.scss @@ -1,27 +0,0 @@ -.calendar-modal-component { - max-width: 600px; - overflow-x: hidden; - - .webcal-progress-spinner { - margin: 0 auto; - } - - .webcal-url-container { - display: flex; - align-items: center; - } - - .webcal-options-card { - margin-top: 1em; - box-shadow: none; - padding: 0; - } - - .webcal-options-inclusions { - padding: 0.8em 0 0.4em 0; - } - - .webcal-options-inclusions-chips { - padding-bottom: 1em; - } -} diff --git a/src/app/common/modals/calendar-modal/calendar-modal.component.ts b/src/app/common/modals/calendar-modal/calendar-modal.component.ts index c0d2ac0dff..40e5856c6e 100644 --- a/src/app/common/modals/calendar-modal/calendar-modal.component.ts +++ b/src/app/common/modals/calendar-modal/calendar-modal.component.ts @@ -4,6 +4,7 @@ import {MatSlideToggle} from '@angular/material/slide-toggle'; import {Project, ProjectService, Webcal, WebcalService} from 'src/app/api/models/doubtfire-model'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {AlertService} from '../../services/alert.service'; +import {ConfirmationModalService} from '../confirmation-modal/confirmation-modal.service'; @Component({ selector: 'calendar-modal', @@ -17,6 +18,7 @@ export class CalendarModalComponent implements OnInit, AfterViewInit { webcal: Webcal | null; working: boolean = true; copying: boolean = false; + selectedCalendarProviderIndex: number = 0; projects: Project[] = []; // Used to store user interaction with the reminder option. These values aren't bound directly to `this.webcal` @@ -31,6 +33,7 @@ export class CalendarModalComponent implements OnInit, AfterViewInit { private alerts: AlertService, private projectService: ProjectService, @Inject(MAT_DIALOG_DATA) public data: object, + private confirmationModal: ConfirmationModalService, ) {} ngOnInit() { @@ -66,8 +69,21 @@ export class CalendarModalComponent implements OnInit, AfterViewInit { * Invoked when the user toggles the webcal. */ onWebcalToggle() { + if (this.webcal.enabled) { + this.confirmationModal.show( + 'Disable web calendar', + 'Disabling your web calendar will expire the current subscription URL. Any calendar apps using this URL will stop updating, and a new URL will be generated if you enable the calendar again.', + () => this.updateWebcalEnabled(false), + ); + return; + } + + this.updateWebcalEnabled(true); + } + + private updateWebcalEnabled(enabled: boolean) { this.working = true; - this.webcal.enabled = !this.webcal.enabled; + this.webcal.enabled = enabled; this.webcalService.update(this.webcal).subscribe((webcal) => { this.loadWebcal(webcal); @@ -93,12 +109,18 @@ export class CalendarModalComponent implements OnInit, AfterViewInit { * Invoked when the user requests their webcal URL to be changed. */ onChangeWebcalUrl() { - this.working = true; - this.webcal.shouldChangeGuid = true; - this.webcalService.update(this.webcal).subscribe((webcal) => { - this.loadWebcal(webcal); - this.working = false; - }); + this.confirmationModal.show( + 'Regenerate URL', + 'Regenerating your calendar URL will disable the current subscription link. Any calendar apps using the old URL will stop updating until you subscribe again with the new one.', + () => { + this.working = true; + this.webcal.shouldChangeGuid = true; + this.webcalService.update(this.webcal).subscribe((webcal) => { + this.loadWebcal(webcal); + this.working = false; + }); + }, + ); } /** diff --git a/src/app/common/modals/calendar-modal/calendar-modal.service.ts b/src/app/common/modals/calendar-modal/calendar-modal.service.ts index f26164d57d..fd1c6bec9f 100644 --- a/src/app/common/modals/calendar-modal/calendar-modal.service.ts +++ b/src/app/common/modals/calendar-modal/calendar-modal.service.ts @@ -10,6 +10,11 @@ export class CalendarModalService { constructor(public dialog: MatDialog) {} public show(_task?: Task) { - this.dialog.open(CalendarModalComponent); + this.dialog.open(CalendarModalComponent, { + height: 'h-min', + maxHeight: '90vh', + width: '800px', + maxWidth: '95vw', + }); } } diff --git a/src/app/projects/states/plan/project-plan.component.html b/src/app/projects/states/plan/project-plan.component.html index 733eda3558..863382897d 100644 --- a/src/app/projects/states/plan/project-plan.component.html +++ b/src/app/projects/states/plan/project-plan.component.html @@ -14,9 +14,6 @@

      Task Planner

      Click on a task in the timeline to see how it connects to other tasks. This will show you which tasks must be completed before it, and which tasks depend on it being completed first.

      - - -
      Target Grade @@ -31,6 +28,15 @@

      Task Planner

      +

      + Subscribe to your unit calendar to be reminded about your due dates. + +

      +
      + +
      } diff --git a/src/app/projects/states/plan/project-plan.component.ts b/src/app/projects/states/plan/project-plan.component.ts index 995a101df5..28129d6469 100644 --- a/src/app/projects/states/plan/project-plan.component.ts +++ b/src/app/projects/states/plan/project-plan.component.ts @@ -3,6 +3,7 @@ import {MatSelectChange} from '@angular/material/select'; import {ActivatedRoute} from '@angular/router'; import {Observable, Subscription, of} from 'rxjs'; import {Project, ProjectService} from 'src/app/api/models/doubtfire-model'; +import {CalendarModalService} from 'src/app/common/modals/calendar-modal/calendar-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {GradeService} from 'src/app/common/services/grade.service'; import {TaskPlannerComponent} from './task-planner/task-planner.component'; @@ -45,6 +46,7 @@ export class ProjectPlanComponent implements OnInit, OnDestroy { private projectService: ProjectService, private alertService: AlertService, private route: ActivatedRoute, + private calendarModal: CalendarModalService, ) {} ngOnInit(): void { @@ -64,6 +66,10 @@ export class ProjectPlanComponent implements OnInit, OnDestroy { this.projectSub?.unsubscribe(); } + openCalendar(): void { + this.calendarModal.show(null); + } + onTargetGradeChange(event: MatSelectChange) { const previousTargetGrade = this.project.targetGrade; this.project.targetGrade = event.value; From 38c0e85ebe698c71ea087f3aeecc6d7ca24c86d7 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 18 Jun 2026 10:01:25 +1000 Subject: [PATCH 1122/1280] feat: show students name if viewing other project --- .../progress-dashboard.component.html | 2 +- .../progress-dashboard.component.ts | 11 +++++++++-- .../projects/states/plan/project-plan.component.html | 7 ++++++- .../projects/states/plan/project-plan.component.ts | 10 +++++++++- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html index cc01407796..68901ff1fb 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html @@ -2,7 +2,7 @@

      Progress Dashboard - @if (tutor) { + @if (viewingOtherStudentProject) { for {{ project.student.name }} }

      diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.ts b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.ts index 5e5efd8a66..621544ee18 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.ts +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.ts @@ -1,6 +1,7 @@ import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; import {Project} from 'src/app/api/models/project'; import {ProjectService} from 'src/app/api/services/project.service'; +import {UserService} from 'src/app/api/services/user.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {GradeService} from 'src/app/common/services/grade.service'; @@ -14,7 +15,6 @@ export class ProgressDashboardComponent implements OnInit { @Input() project: Project; @Output() doUpdateTargetGrade: EventEmitter = new EventEmitter(); - tutor: boolean; grades = { names: this.gradeService.grades, values: this.gradeService.gradeValues, @@ -28,12 +28,19 @@ export class ProgressDashboardComponent implements OnInit { private gradeService: GradeService, private projectService: ProjectService, private alertService: AlertService, + private userService: UserService, ) {} ngOnInit(): void { this.updateTaskCompletionValues(); this.project?.refreshBurndownChartData(); - this.tutor = this.project.myRole === 'Tutor' ? true : false; + } + + public get viewingOtherStudentProject(): boolean { + const role = this.project?.unit?.myRole; + const currentUser = this.userService.currentUser; + + return !!role && role !== 'Student' && this.project?.student?.id !== currentUser?.id; } updateTargetGrade(newGrade: number): void { diff --git a/src/app/projects/states/plan/project-plan.component.html b/src/app/projects/states/plan/project-plan.component.html index 863382897d..50714cdf88 100644 --- a/src/app/projects/states/plan/project-plan.component.html +++ b/src/app/projects/states/plan/project-plan.component.html @@ -1,6 +1,11 @@ @if (project) {
      -

      Task Planner

      +

      + Task Planner + @if (viewingOtherStudentProject) { + for {{ project.student.name }} + } +

      @if (unit.allowFlexibleDates) { View and adjust the due dates for your tasks. Remember to leave time to get and respond to diff --git a/src/app/projects/states/plan/project-plan.component.ts b/src/app/projects/states/plan/project-plan.component.ts index 28129d6469..8a2a591ea9 100644 --- a/src/app/projects/states/plan/project-plan.component.ts +++ b/src/app/projects/states/plan/project-plan.component.ts @@ -2,7 +2,7 @@ import {Component, Input, OnDestroy, OnInit, ViewChild} from '@angular/core'; import {MatSelectChange} from '@angular/material/select'; import {ActivatedRoute} from '@angular/router'; import {Observable, Subscription, of} from 'rxjs'; -import {Project, ProjectService} from 'src/app/api/models/doubtfire-model'; +import {Project, ProjectService, UserService} from 'src/app/api/models/doubtfire-model'; import {CalendarModalService} from 'src/app/common/modals/calendar-modal/calendar-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {GradeService} from 'src/app/common/services/grade.service'; @@ -47,6 +47,7 @@ export class ProjectPlanComponent implements OnInit, OnDestroy { private alertService: AlertService, private route: ActivatedRoute, private calendarModal: CalendarModalService, + private userService: UserService, ) {} ngOnInit(): void { @@ -70,6 +71,13 @@ export class ProjectPlanComponent implements OnInit, OnDestroy { this.calendarModal.show(null); } + public get viewingOtherStudentProject(): boolean { + const role = this.project?.unit?.myRole; + const currentUser = this.userService.currentUser; + + return !!role && role !== 'Student' && this.project?.student?.id !== currentUser?.id; + } + onTargetGradeChange(event: MatSelectChange) { const previousTargetGrade = this.project.targetGrade; this.project.targetGrade = event.value; From 7a754dcc82ca228f5688abab4480774df75a007e Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Thu, 18 Jun 2026 11:23:04 +1000 Subject: [PATCH 1123/1280] feat: engagement passport (#1257) * feat: engagement passport * feat: connect engagements to backend * feat: view engagement comments * chore: render evidence url * chore: open engagement dialog from tutor discussion * chore: format * refactor: use placeholder text and default note if left empty * chore: swap occurred at and created at dates * chore: improve layout * chore: format * fix: prevent mobile devices from zooming in on modal inputs * chore: reorder engagement types * refactor: rename negative to needs attention --- src/app/api/models/doubtfire-model.ts | 3 + src/app/api/models/engagement.ts | 69 +++++ src/app/api/models/project.ts | 2 + .../services/engagement-comment.service.ts | 116 +++++++ src/app/api/services/engagement.service.ts | 177 +++++++++++ src/app/doubtfire-angular.module.ts | 10 + .../add-engagement-dialog.component.html | 121 ++++++++ .../add-engagement-dialog.component.scss | 12 + .../add-engagement-dialog.component.ts | 168 ++++++++++ .../engagement-detail-dialog.component.html | 288 ++++++++++++++++++ .../engagement-detail-dialog.component.scss | 14 + .../engagement-detail-dialog.component.ts | 178 +++++++++++ .../engagement-passport-card.component.html | 100 ++++++ .../engagement-passport-card.component.scss | 0 .../engagement-passport-card.component.ts | 195 ++++++++++++ .../progress-dashboard.component.html | 5 + .../tutor-discussion.component.html | 10 +- .../tutor-discussion.component.ts | 54 +++- 18 files changed, 1509 insertions(+), 13 deletions(-) create mode 100644 src/app/api/models/engagement.ts create mode 100644 src/app/api/services/engagement-comment.service.ts create mode 100644 src/app/api/services/engagement.service.ts create mode 100644 src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.html create mode 100644 src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.scss create mode 100644 src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.ts create mode 100644 src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.html create mode 100644 src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.scss create mode 100644 src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.ts create mode 100644 src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.html create mode 100644 src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.scss create mode 100644 src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.ts diff --git a/src/app/api/models/doubtfire-model.ts b/src/app/api/models/doubtfire-model.ts index 4c04633b82..60b3bfb8b9 100644 --- a/src/app/api/models/doubtfire-model.ts +++ b/src/app/api/models/doubtfire-model.ts @@ -40,6 +40,7 @@ export * from './task-comment/scorm-comment'; export * from './task-comment/scorm-extension-comment'; export * from './feedback-template'; export * from './communication'; +export * from './engagement'; // Users -- are students or staff export * from './user/user'; @@ -72,3 +73,5 @@ export * from '../services/communication-set.service'; export * from '../services/communication-rule.service'; export * from '../services/communication-condition.service'; export * from '../services/communication-action.service'; +export * from '../services/engagement.service'; +export * from '../services/engagement-comment.service'; diff --git a/src/app/api/models/engagement.ts b/src/app/api/models/engagement.ts new file mode 100644 index 0000000000..369fe42745 --- /dev/null +++ b/src/app/api/models/engagement.ts @@ -0,0 +1,69 @@ +import {Entity, EntityCache} from 'ngx-entity-service'; +import {AppInjector} from 'src/app/app-injector'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {Project, User, UserService} from './doubtfire-model'; + +export class Engagement extends Entity { + id: number; + project: Project; + user: User; + engagementType: string; + note: string; + occurredAt: Date; + evidenceUrl?: string; + contentType?: 'image' | 'pdf'; + hasAttachment: boolean; + attachmentFileName?: string; + commentCount: number; + createdAt: Date; + updatedAt: Date; + + readonly commentCache: EntityCache = new EntityCache(); + + constructor(project?: Project) { + super(); + this.project = project; + } + + get comments(): readonly EngagementComment[] { + return this.commentCache.currentValues; + } + + get attachmentUrl(): string { + return `${AppInjector.get(DoubtfireConstants).API_URL}/projects/${this.project.id}/engagements/${this.id}/attachment`; + } +} + +export class EngagementComment extends Entity { + private static readonly EDIT_WINDOW_MS = 10 * 60 * 1000; + + id: number; + engagement: Engagement; + user: User; + comment: string; + replyToId?: number; + replyTo?: EngagementComment; + createdAt: Date; + updatedAt: Date; + + constructor(engagement?: Engagement) { + super(); + this.engagement = engagement; + } + + get authorIsMe(): boolean { + return this.user.id === AppInjector.get(UserService).currentUser.id; + } + + get currentUserCanEdit(): boolean { + return ( + this.authorIsMe && + this.createdAt instanceof Date && + Date.now() - this.createdAt.getTime() <= EngagementComment.EDIT_WINDOW_MS + ); + } + + get currentUserCanDelete(): boolean { + return this.authorIsMe || this.engagement.project.unit.myRole === 'Convenor'; + } +} diff --git a/src/app/api/models/project.ts b/src/app/api/models/project.ts index 4d4e2f3dd8..574ec84ed1 100644 --- a/src/app/api/models/project.ts +++ b/src/app/api/models/project.ts @@ -21,6 +21,7 @@ import { Unit, User, } from './doubtfire-model'; +import {Engagement} from './engagement'; import {StaffNote} from './staff-note'; import {TaskOutcomeAlignment} from './task-outcome-alignment'; @@ -55,6 +56,7 @@ export class Project extends Entity { public burndownChartData: {key: string; values: number[]}[]; public readonly taskCache: EntityCache = new EntityCache(); public readonly staffNoteCache: EntityCache = new EntityCache(); + public readonly engagementCache: EntityCache = new EntityCache(); public readonly tutorialEnrolmentsCache: EntityCache = new EntityCache(); public readonly groupCache: EntityCache = new EntityCache(); public readonly taskOutcomeAlignmentsCache: EntityCache = diff --git a/src/app/api/services/engagement-comment.service.ts b/src/app/api/services/engagement-comment.service.ts new file mode 100644 index 0000000000..bceb22511e --- /dev/null +++ b/src/app/api/services/engagement-comment.service.ts @@ -0,0 +1,116 @@ +import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {Observable, tap} from 'rxjs'; +import {Engagement, EngagementComment, UserService} from 'src/app/api/models/doubtfire-model'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {MappingFunctions} from './mapping-fn'; + +@Injectable() +export class EngagementCommentService extends CachedEntityService { + protected readonly endpointFormat = + 'projects/:projectId:/engagements/:engagementId:/comments/:id:'; + + constructor( + httpClient: HttpClient, + private userService: UserService, + ) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'comment', + 'replyToId', + { + keys: 'user', + toEntityFn: (data: object, key: string) => { + return this.userService.cache.getOrCreate(data[key].id, this.userService, data[key]); + }, + }, + { + keys: 'createdAt', + toEntityFn: MappingFunctions.mapDate, + }, + { + keys: 'updatedAt', + toEntityFn: MappingFunctions.mapDate, + }, + ); + } + + createInstanceFrom(_json: object, other?: Engagement): EngagementComment { + return new EngagementComment(other); + } + + addComment( + engagement: Engagement, + comment: string, + replyTo?: EngagementComment, + ): Observable { + const options: RequestOptions = { + endpointFormat: this.endpointFormat, + cache: engagement.commentCache, + constructorParams: engagement, + body: { + comment, + ...(replyTo ? {reply_to_id: replyTo.id} : {}), + }, + }; + + return this.create( + { + projectId: engagement.project.id, + engagementId: engagement.id, + }, + options, + ).pipe( + tap(() => { + engagement.commentCount++; + this.updateCommentReplies(engagement.comments); + }), + ); + } + + updateComment(comment: EngagementComment, text: string): Observable { + return this.put( + { + projectId: comment.engagement.project.id, + engagementId: comment.engagement.id, + id: comment.id, + }, + { + endpointFormat: this.endpointFormat, + cache: comment.engagement.commentCache, + constructorParams: comment.engagement, + body: {comment: text}, + }, + ); + } + + deleteComment(comment: EngagementComment): Observable { + return this.delete( + { + projectId: comment.engagement.project.id, + engagementId: comment.engagement.id, + id: comment.id, + }, + { + endpointFormat: this.endpointFormat, + cache: comment.engagement.commentCache, + }, + ).pipe( + tap(() => { + comment.engagement.commentCount--; + this.updateCommentReplies(comment.engagement.comments); + }), + ); + } + + updateCommentReplies(comments: readonly EngagementComment[]): void { + for (const comment of comments) { + comment.replyTo = comment.replyToId + ? comments.find((candidate) => candidate.id === comment.replyToId) + : undefined; + } + } +} diff --git a/src/app/api/services/engagement.service.ts b/src/app/api/services/engagement.service.ts new file mode 100644 index 0000000000..89c63a189a --- /dev/null +++ b/src/app/api/services/engagement.service.ts @@ -0,0 +1,177 @@ +import {CachedEntityService, RequestOptions} from 'ngx-entity-service'; +import {HttpClient} from '@angular/common/http'; +import {Injectable} from '@angular/core'; +import {Observable} from 'rxjs'; +import { + Engagement, + EngagementCommentService, + Project, + UserService, +} from 'src/app/api/models/doubtfire-model'; +import API_URL from 'src/app/config/constants/apiUrl'; +import {MappingFunctions} from './mapping-fn'; + +export interface EngagementData { + engagementType: string; + note: string; + occurredAt: Date; + evidenceUrl?: string; + attachment?: File; +} + +export interface EngagementUpdate extends Partial { + removeEvidence?: boolean; +} + +@Injectable() +export class EngagementService extends CachedEntityService { + protected readonly endpointFormat = 'projects/:projectId:/engagements/:id:'; + + constructor( + httpClient: HttpClient, + private userService: UserService, + private engagementCommentService: EngagementCommentService, + ) { + super(httpClient, API_URL); + + this.mapping.addKeys( + 'id', + 'engagementType', + 'note', + 'evidenceUrl', + 'contentType', + 'hasAttachment', + 'attachmentFileName', + 'commentCount', + { + keys: 'user', + toEntityFn: (data: object, key: string) => { + return this.userService.cache.getOrCreate(data[key].id, this.userService, data[key]); + }, + }, + { + keys: 'occurredAt', + toEntityFn: MappingFunctions.mapDate, + }, + { + keys: 'createdAt', + toEntityFn: MappingFunctions.mapDate, + }, + { + keys: 'updatedAt', + toEntityFn: MappingFunctions.mapDate, + }, + { + keys: 'comments', + toEntityOp: (data: object, key: string, engagement: Engagement) => { + engagement.commentCache.clear(); + data[key]?.forEach((comment) => { + engagement.commentCache.getOrCreate( + comment.id, + this.engagementCommentService, + comment, + {constructorParams: engagement}, + ); + }); + this.engagementCommentService.updateCommentReplies(engagement.comments); + }, + }, + ); + } + + createInstanceFrom(_json: object, other?: Project): Engagement { + return new Engagement(other); + } + + loadEngagements(project: Project, refresh: boolean = false): Observable { + const options: RequestOptions = { + endpointFormat: this.endpointFormat, + cache: project.engagementCache, + sourceCache: project.engagementCache, + cacheBehaviourOnGet: 'cacheQuery', + constructorParams: project, + }; + const pathIds = {projectId: project.id}; + + return refresh ? this.fetchAll(pathIds, options) : this.query(pathIds, options); + } + + loadEngagement(engagement: Engagement): Observable { + return this.fetch( + { + projectId: engagement.project.id, + id: engagement.id, + }, + { + endpointFormat: this.endpointFormat, + cache: engagement.project.engagementCache, + constructorParams: engagement.project, + }, + ); + } + + createEngagement(project: Project, data: EngagementData): Observable { + return this.create( + {projectId: project.id}, + { + endpointFormat: this.endpointFormat, + cache: project.engagementCache, + constructorParams: project, + body: this.toFormData(data), + }, + ); + } + + updateEngagement(engagement: Engagement, data: EngagementUpdate): Observable { + return this.put( + { + projectId: engagement.project.id, + id: engagement.id, + }, + { + endpointFormat: this.endpointFormat, + cache: engagement.project.engagementCache, + constructorParams: engagement.project, + body: this.toFormData(data), + }, + ); + } + + deleteEngagement(engagement: Engagement): Observable { + return this.delete( + { + projectId: engagement.project.id, + id: engagement.id, + }, + { + endpointFormat: this.endpointFormat, + cache: engagement.project.engagementCache, + }, + ); + } + + private toFormData(data: EngagementUpdate): FormData { + const body = new FormData(); + + if (data.engagementType !== undefined) { + body.append('engagement_type', data.engagementType); + } + if (data.note !== undefined) { + body.append('note', data.note); + } + if (data.occurredAt !== undefined) { + body.append('occurred_at', data.occurredAt.toISOString()); + } + if (data.evidenceUrl !== undefined) { + body.append('evidence_url', data.evidenceUrl); + } + if (data.attachment !== undefined) { + body.append('attachment', data.attachment); + } + if (data.removeEvidence !== undefined) { + body.append('remove_evidence', String(data.removeEvidence)); + } + + return body; + } +} diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index f968ab15a7..f64afd172d 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -119,6 +119,8 @@ import { AuthenticationService, CampusService, D2lAssessmentMappingService, + EngagementCommentService, + EngagementService, GroupSetService, LearningOutcomeService, OverseerAssessmentService, @@ -245,6 +247,9 @@ import {LtiDashboardComponent} from './home/states/lti-dashboard/lti-dashboard.c import {LtiUnitLinkComponent} from './home/states/lti-unit-link/lti-unit-link.component'; import {LegacyRoutePlaceholderComponent} from './legacy-route-placeholder.component'; import {ProjectProgressDashboardComponent} from './projects/project-progress-dashboard/project-progress-dashboard.component'; +import {AddEngagementDialogComponent} from './projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component'; +import {EngagementDetailDialogComponent} from './projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component'; +import {EngagementPassportCardComponent} from './projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component'; import {ProgressDashboardComponent} from './projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component'; import {TaskPlannerCardComponent} from './projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component'; import {CreatePortfolioTaskListItemComponent} from './projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component'; @@ -446,6 +451,9 @@ const DEFAULT_TOOLTIP_OPTIONS: MatTooltipDefaultOptions = { AppComponent, TaskStatusPieChartComponent, AlertComponent, + AddEngagementDialogComponent, + EngagementPassportCardComponent, + EngagementDetailDialogComponent, ProgressDashboardComponent, UnitStudentEnrolmentModalComponent, AboutDoubtfireModalContent, @@ -701,6 +709,8 @@ const DEFAULT_TOOLTIP_OPTIONS: MatTooltipDefaultOptions = { {provide: DateAdapter, useClass: DateFnsAdapter, deps: [MAT_DATE_LOCALE]}, {provide: MAT_DATE_FORMATS, useValue: MY_DATE_FORMAT}, TaskCommentService, + EngagementCommentService, + EngagementService, { provide: HTTP_INTERCEPTORS, useClass: HttpAuthenticationInterceptor, diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.html b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.html new file mode 100644 index 0000000000..234ea67dff --- /dev/null +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.html @@ -0,0 +1,121 @@ +

      Add Engagement Stamp

      + + + + + Engagement type + + + @for (type of engagementTypes; track type) { + {{ type }} + } + + Choose a suggestion or enter another type. + @if (form.controls.engagementType.hasError('required')) { + Enter an engagement type. + } + + + + Note + + {{ form.controls.note.value.length }} / 4095 + + +
      + + Date + + + + @if (form.controls.occurredDate.hasError('required')) { + Select when the engagement occurred. + } + + + + Time + + @if (form.controls.occurredTime.hasError('required')) { + Select a time. + } + +
      + + + Evidence + + No evidence + External URL + Upload image or PDF + + + + @if (form.controls.evidenceMode.value === 'url') { + + Evidence URL + + @if ( + form.controls.evidenceUrl.hasError('pattern') || + (form.controls.evidenceUrl.touched && !form.controls.evidenceUrl.value.trim()) + ) { + Enter a valid HTTP or HTTPS URL. + } + + } + + @if (form.controls.evidenceMode.value === 'attachment') { +
      + + +

      Maximum file size: 30 MB.

      + @if (attachmentError) { +

      {{ attachmentError }}

      + } +
      + } + +
      + + + + + diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.scss b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.scss new file mode 100644 index 0000000000..cdca2a91a1 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.scss @@ -0,0 +1,12 @@ +// Prevent mobile devices from zooming in engagement stamp modal inputs +@media (max-width: 768px) { + :host ::ng-deep { + .mat-mdc-input-element, + .mat-mdc-select, + .mat-mdc-select-value, + .mat-mdc-select-trigger, + .mat-mdc-select-min-line { + font-size: 20px !important; + } + } +} diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.ts b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.ts new file mode 100644 index 0000000000..f3e3019c7a --- /dev/null +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.ts @@ -0,0 +1,168 @@ +import {Component, Inject} from '@angular/core'; +import {FormControl, FormGroup, Validators} from '@angular/forms'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {Engagement, EngagementService, Project} from 'src/app/api/models/doubtfire-model'; +import {AlertService} from 'src/app/common/services/alert.service'; + +type EvidenceMode = 'none' | 'url' | 'attachment'; + +interface AddEngagementForm { + engagementType: FormControl; + note: FormControl; + occurredDate: FormControl; + occurredTime: FormControl; + evidenceMode: FormControl; + evidenceUrl: FormControl; +} + +@Component({ + selector: 'f-add-engagement-dialog', + templateUrl: './add-engagement-dialog.component.html', + styleUrl: './add-engagement-dialog.component.scss', + standalone: false, +}) +export class AddEngagementDialogComponent { + readonly engagementTypes = ['Discuss', 'Attendance', 'Forum', 'Email', 'Attention']; + readonly notePlaceholders: Record = { + attendance: 'Attended tutorial and participated in class activities.', + discuss: 'Discussed tasks during tutorial.', + discussion: 'Discussed tasks during tutorial.', + forum: 'Posted to the unit forum and engaged with discussion.', + email: 'Discussed unit progress with the teaching team via email.', + attention: 'Engagement concern noted for follow-up.', + }; + readonly maxAttachmentSize = 30 * 1024 * 1024; + readonly form: FormGroup; + + attachment?: File; + attachmentError?: string; + saving = false; + + constructor( + @Inject(MAT_DIALOG_DATA) readonly data: {project: Project}, + private dialogRef: MatDialogRef, + private engagementService: EngagementService, + private alerts: AlertService, + ) { + const now = new Date(); + this.form = new FormGroup({ + engagementType: new FormControl('', { + nonNullable: true, + validators: [Validators.required, Validators.maxLength(255)], + }), + note: new FormControl('', { + nonNullable: true, + validators: [Validators.maxLength(4095)], + }), + occurredDate: new FormControl(now, { + nonNullable: true, + validators: [Validators.required], + }), + occurredTime: new FormControl(this.formatTime(now), { + nonNullable: true, + validators: [Validators.required], + }), + evidenceMode: new FormControl('none', {nonNullable: true}), + evidenceUrl: new FormControl('', { + nonNullable: true, + validators: [Validators.pattern(/^https?:\/\/.+/i)], + }), + }); + } + + get canSubmit(): boolean { + if (this.form.invalid || this.saving || this.attachmentError !== undefined) return false; + + const mode = this.form.controls.evidenceMode.value; + if (mode === 'url') return this.form.controls.evidenceUrl.value.trim().length > 0; + if (mode === 'attachment') return this.attachment !== undefined; + + return true; + } + + get notePlaceholder(): string { + const engagementType = this.form.controls.engagementType.value.trim().toLowerCase(); + return ( + this.notePlaceholders[engagementType] ?? 'Describe how the student engaged with the unit.' + ); + } + + engagementTypeSelected(input: HTMLInputElement): void { + window.setTimeout(() => input.blur()); + } + + evidenceModeChanged(): void { + const mode = this.form.controls.evidenceMode.value; + + if (mode !== 'url') { + this.form.controls.evidenceUrl.setValue(''); + } + this.attachment = undefined; + this.attachmentError = undefined; + } + + fileSelected(event: Event): void { + const input = event.target as HTMLInputElement; + const file = input.files?.[0]; + + this.attachment = undefined; + this.attachmentError = undefined; + + if (!file) return; + if (file.size === 0) { + this.attachmentError = 'The selected file is empty.'; + input.value = ''; + return; + } + if (file.size > this.maxAttachmentSize) { + this.attachmentError = 'The selected file must be no larger than 30 MB.'; + input.value = ''; + return; + } + if (file.type !== 'application/pdf' && !file.type.startsWith('image/')) { + this.attachmentError = 'Select an image or PDF file.'; + input.value = ''; + return; + } + + this.attachment = file; + } + + submit(): void { + if (!this.canSubmit) { + this.form.markAllAsTouched(); + return; + } + + const values = this.form.getRawValue(); + const occurredAt = new Date(values.occurredDate); + const [hours, minutes] = values.occurredTime.split(':').map(Number); + occurredAt.setHours(hours, minutes, 0, 0); + + this.saving = true; + this.engagementService + .createEngagement(this.data.project, { + engagementType: values.engagementType.trim(), + note: values.note.trim() || this.notePlaceholder, + occurredAt, + evidenceUrl: values.evidenceMode === 'url' ? values.evidenceUrl.trim() : undefined, + attachment: values.evidenceMode === 'attachment' ? this.attachment : undefined, + }) + .subscribe({ + next: (engagement: Engagement) => { + this.alerts.success('Engagement stamp added.'); + this.dialogRef.close(engagement); + }, + error: (error) => { + this.saving = false; + this.alerts.error(error?.error ?? 'Unable to add the engagement stamp.'); + }, + }); + } + + private formatTime(date: Date): string { + const hours = String(date.getHours()).padStart(2, '0'); + const minutes = String(date.getMinutes()).padStart(2, '0'); + return `${hours}:${minutes}`; + } +} diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.html b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.html new file mode 100644 index 0000000000..9eb0fe65b9 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.html @@ -0,0 +1,288 @@ +
      +
      +
      +
      +
      {{ engagement.engagementType }} Engagement
      +

      + Added by {{ engagement.user?.firstName }} {{ engagement.user?.lastName }} + · + + {{ engagement.occurredAt | humanizedDate }} + +

      +
      + + +
      +
      + + + @if (loading) { +
      + +
      + } @else if (loadFailed) { +

      Unable to load this engagement.

      + } @else { +
      + +
      + + + + {{ engagement.user?.firstName }} {{ engagement.user?.lastName }} + + +
      + + {{ engagement.createdAt | humanizedDate }} + +
      +
      + + +
      {{ engagement.note }}
      + + @if (engagement.evidenceUrl || engagement.hasAttachment) { +
      +

      Evidence

      + + @if (engagement.evidenceUrl) { + + link + {{ engagement.evidenceUrl }} + + } + + @if (engagement.hasAttachment && engagement.contentType === 'image') { + @if (evidenceLoading) { +
      + +
      + } @else if (evidenceBlobUrl) { + + } + } @else if (engagement.hasAttachment) { + + } + + @if (evidenceLoadFailed) { +

      Unable to load the attached evidence.

      + } +
      + } +
      +
      + + @for (comment of comments; track comment.id) { + @if (comment.replyToId) { +
      +
      + reply +
      + @if (comment.replyTo) { + + Replying to {{ comment.replyTo.user?.preferredName }} + {{ comment.replyTo.user?.lastName }} + + {{ comment.replyTo.comment }} + } @else { + Replying to: Deleted comment + } +
      +
      +
      + } + + +
      + @if (comment.currentUserCanEdit) { + + edit + + } + + reply + + @if (comment.currentUserCanDelete) { + + delete + + } +
      + +
      + + + {{ comment.user?.firstName }} {{ comment.user?.lastName }} + +
      + + {{ comment.createdAt | humanizedDate }} + +
      +
      + + + @if (editingComment?.id === comment.id) { + + Update Comment + +
      + + +
      +
      + } @else { +
      + } +
      +
      + } + + @if (comments.length === 0) { +

      No comments yet.

      + } + + +
      + } +
      + + @if (!loading && !loadFailed) { +
      + @if (replyingToComment) { +
      +
      +
      + reply +
      + + Replying to {{ replyingToComment.user?.preferredName }} + {{ replyingToComment.user?.lastName }} + + + {{ replyingToComment.comment }} + +
      +
      + +
      +
      + } + + + Comment + +
      + +
      +
      +
      + } +
      diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.scss b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.scss new file mode 100644 index 0000000000..684d95154b --- /dev/null +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.scss @@ -0,0 +1,14 @@ +.action .mat-icon { + color: #9696969d; + font-size: 20px; + width: 20px; + height: 20px; + cursor: pointer; + vertical-align: middle; + text-align: center; + margin-left: 0.3em; +} + +.action .mat-icon:hover { + color: black; +} diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.ts b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.ts new file mode 100644 index 0000000000..d86b756544 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.ts @@ -0,0 +1,178 @@ +import {Component, ElementRef, Inject, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; +import { + Engagement, + EngagementComment, + EngagementCommentService, + EngagementService, +} from 'src/app/api/models/doubtfire-model'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; + +@Component({ + selector: 'f-engagement-detail-dialog', + templateUrl: './engagement-detail-dialog.component.html', + styleUrl: './engagement-detail-dialog.component.scss', + standalone: false, +}) +export class EngagementDetailDialogComponent implements OnInit, OnDestroy { + @ViewChild('commentsEnd') commentsEnd?: ElementRef; + + engagement: Engagement; + commentText = ''; + loading = true; + loadFailed = false; + submitting = false; + replyingToComment?: EngagementComment; + hoveredCommentId?: number; + editingComment?: EngagementComment; + editingCommentText = ''; + evidenceBlobUrl?: string; + evidenceLoading = false; + evidenceLoadFailed = false; + + constructor( + @Inject(MAT_DIALOG_DATA) readonly data: {engagement: Engagement}, + private engagementService: EngagementService, + private engagementCommentService: EngagementCommentService, + private fileDownloader: FileDownloaderService, + private alerts: AlertService, + private confirmationModal: ConfirmationModalService, + ) { + this.engagement = data.engagement; + } + + get comments(): readonly EngagementComment[] { + return [...this.engagement.comments].sort( + (first, second) => first.createdAt.getTime() - second.createdAt.getTime(), + ); + } + + ngOnInit(): void { + this.engagementService.loadEngagement(this.engagement).subscribe({ + next: (engagement) => { + this.engagement = engagement; + this.loading = false; + this.loadAttachment(); + this.scrollToBottom(); + }, + error: () => { + this.loadFailed = true; + this.loading = false; + }, + }); + } + + ngOnDestroy(): void { + if (this.evidenceBlobUrl) this.fileDownloader.releaseBlob(this.evidenceBlobUrl); + } + + openAttachment(): void { + if (this.evidenceBlobUrl) window.open(this.evidenceBlobUrl, '_blank', 'noopener,noreferrer'); + } + + submitComment(): void { + const comment = this.commentText.trim(); + if (!comment || this.submitting) return; + + this.submitting = true; + this.engagementCommentService + .addComment(this.engagement, comment, this.replyingToComment) + .subscribe({ + next: () => { + this.commentText = ''; + this.submitting = false; + this.replyingToComment = undefined; + this.scrollToBottom(); + }, + error: (error) => { + this.submitting = false; + this.alerts.error(error?.error ?? 'Unable to add your comment.'); + }, + }); + } + + replyToComment(comment: EngagementComment): void { + this.replyingToComment = comment; + } + + cancelReply(): void { + this.replyingToComment = undefined; + } + + editComment(comment: EngagementComment): void { + if (!comment.currentUserCanEdit) return; + + this.editingComment = comment; + this.editingCommentText = comment.comment; + } + + cancelEdit(): void { + this.editingComment = undefined; + this.editingCommentText = ''; + } + + updateComment(): void { + const text = this.editingCommentText.trim(); + if (!this.editingComment || !text) return; + + this.engagementCommentService.updateComment(this.editingComment, text).subscribe({ + next: () => this.cancelEdit(), + error: (error) => this.alerts.error(error?.error ?? 'Unable to update this comment.'), + }); + } + + deleteComment(comment: EngagementComment): void { + if (!comment.currentUserCanDelete) return; + + this.confirmationModal.show( + 'Delete comment', + 'Are you sure you want to delete this engagement comment?', + () => { + this.engagementCommentService.deleteComment(comment).subscribe({ + next: () => { + if (this.replyingToComment?.id === comment.id) this.cancelReply(); + }, + error: (error) => this.alerts.error(error?.error ?? 'Unable to delete this comment.'), + }); + }, + ); + } + + scrollToComment(comment?: EngagementComment): void { + if (!comment) return; + + const element = document.getElementById(`engagement-comment-${comment.id}`); + element?.scrollIntoView({behavior: 'smooth', block: 'center'}); + } + + private loadAttachment(): void { + if (!this.engagement.hasAttachment) return; + + this.evidenceLoading = true; + this.fileDownloader.downloadBlob( + this.engagement.attachmentUrl, + (blobUrl) => { + this.evidenceBlobUrl = blobUrl; + this.evidenceLoading = false; + this.scrollToBottom(); + }, + () => { + this.evidenceLoadFailed = true; + this.evidenceLoading = false; + }, + ); + } + + scrollToBottom(): void { + requestAnimationFrame(() => { + requestAnimationFrame(() => { + const container = this.commentsEnd?.nativeElement.closest( + '.mat-mdc-dialog-content', + ) as HTMLElement | null; + container?.scrollTo({top: container.scrollHeight}); + }); + }); + } +} diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.html b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.html new file mode 100644 index 0000000000..aa79b48871 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.html @@ -0,0 +1,100 @@ + + +
      +
      + Engagement Passport + + A semester view of your engagement with the unit and teaching team. + +
      + + @if (currentUserCanAddEngagement) { + + } +
      +
      + + +
      + @for (item of legend; track item.type) { +
      + + + + {{ item.label }} +
      + } +
      + + @if (loading) { +
      + +
      + } @else { +
      +
      + @for (week of weeks; track week.week) { +
      +
      + @for (column of stampColumns(week.stamps); track $index) { +
      + @for (stamp of column; track $index) { + + } +
      + } +
      + +
      + Week + {{ week.week }} +
      +
      + } +
      +
      + } + + @if (loadFailed) { +

      Unable to load engagement stamps.

      + } + +

      + Each stamp records a moment of engagement. Hover over or focus a stamp for more detail. +

      +
      +
      diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.scss b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.scss new file mode 100644 index 0000000000..e69de29bb2 diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.ts b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.ts new file mode 100644 index 0000000000..8ef0cc2706 --- /dev/null +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.ts @@ -0,0 +1,195 @@ +import {Component, Input, OnChanges} from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; +import { + Engagement, + EngagementService, + Project, + UserService, +} from 'src/app/api/models/doubtfire-model'; +import {AddEngagementDialogComponent} from './add-engagement-dialog/add-engagement-dialog.component'; +import {EngagementDetailDialogComponent} from './engagement-detail-dialog/engagement-detail-dialog.component'; + +interface EngagementPresentation { + label: string; + icon: string; + classes: string; +} + +interface EngagementStamp { + engagement: Engagement; + type: string; + label: string; + icon: string; + classes: string; +} + +interface EngagementWeek { + week: number; + stamps: EngagementStamp[]; +} + +interface EngagementLegendItem extends EngagementPresentation { + type: string; +} + +@Component({ + selector: 'f-engagement-passport-card', + templateUrl: './engagement-passport-card.component.html', + styleUrl: './engagement-passport-card.component.scss', + standalone: false, +}) +export class EngagementPassportCardComponent implements OnChanges { + @Input() project: Project; + + loading = false; + loadFailed = false; + weeks: EngagementWeek[] = []; + + private readonly fallbackPresentation: EngagementPresentation = { + label: 'Other engagement', + icon: 'star', + classes: 'border-gray-300 bg-gray-50 text-gray-700', + }; + + private readonly presentations: Record = { + attendance: { + label: 'Class attendance', + icon: 'groups', + classes: 'border-green-300 bg-green-50 text-green-700', + }, + discussion: { + label: 'Discussion', + icon: 'record_voice_over', + classes: 'border-cyan-300 bg-cyan-50 text-cyan-700', + }, + forum: { + label: 'Forum post', + icon: 'forum', + classes: 'border-blue-300 bg-blue-50 text-blue-700', + }, + email: { + label: 'Tutor email', + icon: 'mail', + classes: 'border-violet-300 bg-violet-50 text-violet-700', + }, + attention: { + label: 'Needs attention', + icon: 'feedback', + classes: 'border-yellow-300 bg-yellow-50 text-yellow-700', + }, + }; + + readonly legend: EngagementLegendItem[] = Object.entries(this.presentations).map( + ([type, presentation]) => ({type, ...presentation}), + ); + + constructor( + private engagementService: EngagementService, + private dialog: MatDialog, + private userService: UserService, + ) {} + + get currentWeek(): number | null { + return this.project?.unit?.currentUnitWeek ?? null; + } + + get currentUserCanAddEngagement(): boolean { + const currentUserId = this.userService.currentUser?.id; + return ( + currentUserId !== undefined && + this.project?.unit?.staff.some((unitRole) => unitRole.user.id === currentUserId) + ); + } + + ngOnChanges(): void { + if (!this.project?.id) return; + + const cachedEngagements = this.project.engagementCache.currentValues; + this.buildWeeks(cachedEngagements); + this.loading = cachedEngagements.length === 0; + this.loadFailed = false; + + this.engagementService.loadEngagements(this.project, true).subscribe({ + next: (engagements) => { + this.buildWeeks(engagements); + this.loading = false; + }, + error: () => { + this.loadFailed = true; + this.loading = false; + }, + }); + } + + stampColumns(stamps: EngagementStamp[]): EngagementStamp[][] { + const columns: EngagementStamp[][] = []; + + for (let index = 0; index < stamps.length; index += 5) { + columns.push(stamps.slice(index, index + 5)); + } + + return columns; + } + + weekWidth(stamps: EngagementStamp[]): number { + const columnCount = Math.max(1, Math.ceil(stamps.length / 5)); + const stampWidth = 35; + const columnGap = 5; + const horizontalPadding = 16; + + return Math.max( + 58, + columnCount * stampWidth + (columnCount - 1) * columnGap + horizontalPadding, + ); + } + + openAddEngagementDialog(): void { + const dialogRef = this.dialog.open(AddEngagementDialogComponent, { + data: {project: this.project}, + width: 'calc(100vw - 32px)', + maxWidth: '640px', + autoFocus: false, + }); + + dialogRef.afterClosed().subscribe((engagement?: Engagement) => { + if (engagement) this.buildWeeks(this.project.engagementCache.currentValues); + }); + } + + openEngagement(engagement: Engagement): void { + this.dialog.open(EngagementDetailDialogComponent, { + data: {engagement}, + width: 'calc(100vw - 32px)', + maxWidth: '900px', + autoFocus: false, + }); + } + + private buildWeeks(engagements: readonly Engagement[]): void { + const totalWeeks = Math.max(1, this.project.unit.totalWeeks); + this.weeks = Array.from({length: totalWeeks}, (_, index) => ({ + week: index + 1, + stamps: [], + })); + + for (const engagement of engagements) { + const weekNumber = this.project.unit.weekNumber(engagement.occurredAt); + if (weekNumber === null || weekNumber < 1 || weekNumber > totalWeeks) continue; + + const type = this.normalizeEngagementType(engagement.engagementType); + const presentation = this.presentations[type] ?? this.fallbackPresentation; + this.weeks[weekNumber - 1].stamps.push({ + engagement, + type, + label: engagement.note, + icon: presentation.icon, + classes: presentation.classes, + }); + } + } + + private normalizeEngagementType(engagementType: string): string { + const type = engagementType?.trim().toLowerCase(); + return type === 'discuss' ? 'discussion' : type; + } +} diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html index 68901ff1fb..726788dc39 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.html @@ -55,6 +55,11 @@

      + +
      + +
      +
      diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html index 52f7807b52..d41f5095af 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html @@ -50,7 +50,15 @@
      @if (project && project?.student) { -
      +
      {{ project?.student?.firstName }} {{ project?.student?.lastName }} diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts index 99ca6117dd..bc6819ee40 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts @@ -9,6 +9,7 @@ import { ViewChild, ViewEncapsulation, } from '@angular/core'; +import {MatDialog} from '@angular/material/dialog'; import {MatSelectionList} from '@angular/material/list'; import {MatTabChangeEvent} from '@angular/material/tabs'; import {ActivatedRoute, Router} from '@angular/router'; @@ -30,6 +31,7 @@ import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal import {DiscussedInClassReasonModalService} from 'src/app/common/modals/discussed-in-class-reason-modal/discussed-in-class-reason-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; import {GradeService} from 'src/app/common/services/grade.service'; +import {AddEngagementDialogComponent} from '../dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component'; enum TutorDiscussionTabView { SHOW_COMMENTS, @@ -90,6 +92,7 @@ export class TutorDiscussionComponent implements AfterViewInit, OnDestroy { private discussedInClassReasonModal: DiscussedInClassReasonModalService, private taskCommentService: TaskCommentService, private taskService: TaskService, + private dialog: MatDialog, ) {} public ngOnDestroy(): void { @@ -133,17 +136,17 @@ export class TutorDiscussionComponent implements AfterViewInit, OnDestroy { } public ngAfterViewInit(): void { - this.unitId = - this.unitId ?? - Number( - this.activatedRoute.parent?.snapshot.paramMap.get('unitId') ?? - this.activatedRoute.snapshot.queryParamMap.get('unitId'), - ); - this.username = this.username ?? this.activatedRoute.snapshot.queryParamMap.get('username'); - this.attendance = - this.attendance ?? - this.activatedRoute.snapshot.data.attendance ?? - this.activatedRoute.snapshot.queryParamMap.get('attendance') === 'true'; + // this.unitId = + // this.unitId ?? + // Number( + // this.activatedRoute.parent?.snapshot.paramMap.get('unitId') ?? + // this.activatedRoute.snapshot.queryParamMap.get('unitId'), + // ); + // this.username = this.username ?? this.activatedRoute.snapshot.queryParamMap.get('username'); + // this.attendance = + // this.attendance ?? + // this.activatedRoute.snapshot.data.attendance ?? + // this.activatedRoute.snapshot.queryParamMap.get('attendance') === 'true'; this.authService.afterAuthCall((result) => { if (!result) { @@ -153,6 +156,10 @@ export class TutorDiscussionComponent implements AfterViewInit, OnDestroy { // Avoid prompting students for camera permissions before redirecting to unauthorised state return; } + this._unitId = 1; + this.unitId = 1; + this._username = 'student_9'; + this.username = 'student_9'; if (this.unitId) { this._unitId = Number(this.unitId); if (!this.attendance) { @@ -163,6 +170,17 @@ export class TutorDiscussionComponent implements AfterViewInit, OnDestroy { } else { setTimeout(() => this.scanQrCode()); } + + setTimeout(() => { + this.changeProject(); + }, 2000); + + // if (this.username) { + // this._username = this.username; + // this.getStudentTasks(); + // } else { + // this.scanQrCode(); + // } } else { this.getUnit().then((u) => { this.unit = u; @@ -216,7 +234,8 @@ export class TutorDiscussionComponent implements AfterViewInit, OnDestroy { } private changeProject() { - this.html5QrcodeScanner?.pause(true); + // this.html5QrcodeScanner?.pause(true); + // this.html5QrcodeScanner.pause(true); this.loadingStudentData = true; setTimeout(() => { try { @@ -371,6 +390,17 @@ export class TutorDiscussionComponent implements AfterViewInit, OnDestroy { } } + public openAddEngagementDialog(): void { + if (!this.project) return; + + this.dialog.open(AddEngagementDialogComponent, { + data: {project: this.project}, + width: 'calc(100vw - 32px)', + maxWidth: '640px', + autoFocus: false, + }); + } + public loadTaskComments(event: MouseEvent, task: Task) { event.stopPropagation(); this.selectedTask = task; From e73d68274ccde94cfc23bb81a2216f8ff83fbf75 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 18 Jun 2026 11:30:26 +1000 Subject: [PATCH 1124/1280] chore: inform staff that students can access engagements --- .../add-engagement-dialog.component.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.html b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.html index 234ea67dff..15d8a2d71d 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.html +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.html @@ -1,6 +1,10 @@

      Add Engagement Stamp

      +

      + Students can see engagement stamps, including any notes and evidence you add. They can also + leave comments under each engagement. +

      Engagement type From 1ba5d1e42d302218520f8be4c0875673ad5d7a3f Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 18 Jun 2026 11:38:20 +1000 Subject: [PATCH 1125/1280] fix: ensure dashboard dropdown switches from task details view --- .../directives/unit-task-list/unit-task-list.component.ts | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts index 044f6a0b6b..19b0e9c736 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts @@ -1,4 +1,3 @@ -import {Location} from '@angular/common'; import {Component, HostBinding, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {BehaviorSubject} from 'rxjs'; @@ -37,7 +36,6 @@ export class FUnitTaskListComponent implements OnChanges, OnInit { protected gradeNames: string[] = Grade.GRADES; constructor( - private location: Location, private angularRouter: Router, private route: ActivatedRoute, ) {} @@ -152,7 +150,7 @@ export class FUnitTaskListComponent implements OnChanges, OnInit { return; } - this.location.replaceState(this.angularRouter.serializeUrl(urlTree)); + this.angularRouter.navigateByUrl(urlTree, {replaceUrl: true}); } private buildSelectionUrlTree(taskDef: TaskDefinition | null) { From 2ea216b1b090575697de7aa27be5bfca7220615d Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 18 Jun 2026 12:19:40 +1000 Subject: [PATCH 1126/1280] chore(release): 11.0.0-25 --- CHANGELOG.md | 15 +++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 18 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 68b40a39eb..de1a8686cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,21 @@ All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines. +## [11.0.0-25](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-24...v11.0.0-25) (2026-06-18) + + +### Features + +* add day of week to gantt chart ([1fb4637](https://github.com/b0ink/doubtfire-deploy/commit/1fb4637cd2386f1aeff227043e0002bf9b77837b)) +* engagement passport ([#1257](https://github.com/b0ink/doubtfire-deploy/issues/1257)) ([7a754dc](https://github.com/b0ink/doubtfire-deploy/commit/7a754dcc82ca228f5688abab4480774df75a007e)) +* show students name if viewing other project ([38c0e85](https://github.com/b0ink/doubtfire-deploy/commit/38c0e85ebe698c71ea087f3aeecc6d7ca24c86d7)) + + +### Bug Fixes + +* ensure dashboard dropdown switches from task details view ([1ba5d1e](https://github.com/b0ink/doubtfire-deploy/commit/1ba5d1e42d302218520f8be4c0875673ad5d7a3f)) +* web calendar ([#1282](https://github.com/b0ink/doubtfire-deploy/issues/1282)) ([83b6d5e](https://github.com/b0ink/doubtfire-deploy/commit/83b6d5ea381604ae88585195314eafd239880632)) + ## [11.0.0-24](https://github.com/b0ink/doubtfire-deploy/compare/v11.0.0-23...v11.0.0-24) (2026-06-17) diff --git a/package-lock.json b/package-lock.json index 9a65211e7c..547ed63e77 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "doubtfire", - "version": "11.0.0-24", + "version": "11.0.0-25", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "doubtfire", - "version": "11.0.0-24", + "version": "11.0.0-25", "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^21.2.17", diff --git a/package.json b/package.json index 437fef8080..35e3ae4c28 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "doubtfire", - "version": "11.0.0-24", + "version": "11.0.0-25", "homepage": "http://github.com/doubtfire-lms/", "description": "Learning and feedback tool.", "license": "AGPL-3.0", From d48af3740f1acbf2c2120e83edb565347474d705 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 18 Jun 2026 02:22:07 +0000 Subject: [PATCH 1127/1280] chore(deps-dev): bump ip from 1.1.9 to 2.0.1 Bumps [ip](https://github.com/indutny/node-ip) from 1.1.9 to 2.0.1. - [Commits](https://github.com/indutny/node-ip/compare/v1.1.9...v2.0.1) --- updated-dependencies: - dependency-name: ip dependency-version: 2.0.1 dependency-type: direct:development update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 547ed63e77..104b5c1641 100644 --- a/package-lock.json +++ b/package-lock.json @@ -99,7 +99,7 @@ "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tailwindcss": "^3.18.3", "husky": "~8", - "ip": "^1.1.2", + "ip": "^2.0.1", "jasmine-core": "~4.1.0", "jasmine-spec-reporter": "~5.0.0", "karma": "^6.3.4", @@ -10044,9 +10044,9 @@ } }, "node_modules/ip": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/ip/-/ip-1.1.9.tgz", - "integrity": "sha512-cyRxvOEpNHNtchU3Ln9KC/auJgup87llfQpQ+t5ghoC/UhL16SWzbueiCsdTnWmqAWl7LadfuwhlqmtOaqMHdQ==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==", "dev": true, "license": "MIT" }, diff --git a/package.json b/package.json index 35e3ae4c28..6762d1d408 100644 --- a/package.json +++ b/package.json @@ -115,7 +115,7 @@ "eslint-plugin-prettier": "^5.5.6", "eslint-plugin-tailwindcss": "^3.18.3", "husky": "~8", - "ip": "^1.1.2", + "ip": "^2.0.1", "jasmine-core": "~4.1.0", "jasmine-spec-reporter": "~5.0.0", "karma": "^6.3.4", From d356de31b76f9de7692bc9a57909846cf0720d3d Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 18 Jun 2026 12:37:59 +1000 Subject: [PATCH 1128/1280] chore: bump ngx-lottie from 11.0.2 to 21.2.0 --- package-lock.json | 10 +++++----- package.json | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 104b5c1641..d666c71457 100644 --- a/package-lock.json +++ b/package-lock.json @@ -55,7 +55,7 @@ "ng-flex-layout": "^17.3.7-beta.1", "ng2-pdf-viewer": "10.2.2", "ngx-entity-service": "^0.0.43", - "ngx-lottie": "^11.0.2", + "ngx-lottie": "^21.2.0", "ngx-monaco-editor-v2": "^21", "ngx-skeleton-loader": "^12.0.0", "nvd3": "1.8.6", @@ -12237,16 +12237,16 @@ } }, "node_modules/ngx-lottie": { - "version": "11.0.2", - "resolved": "https://registry.npmjs.org/ngx-lottie/-/ngx-lottie-11.0.2.tgz", - "integrity": "sha512-sQhCTxfrzWpjN2HVFCSyAQYQg8ZjZVtO1xIhOkrJNHY3/TR/zZkVrhakWcaM5bVxyA7gfUnK3ox+iK59Yd8Bsw==", + "version": "21.2.0", + "resolved": "https://registry.npmjs.org/ngx-lottie/-/ngx-lottie-21.2.0.tgz", + "integrity": "sha512-x0EaM0CXT98/gDVw7cxbvo46mOTg6QeZxUqzTelpszCy6J66zFryy/++x8cg4q8QKTfpTKvlpFDV4rZACpTQOQ==", "license": "MIT", "dependencies": { "@scarf/scarf": "^1.1.1", "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/core": ">=17", + "@angular/core": ">=21", "lottie-web": ">=5.9.2" } }, diff --git a/package.json b/package.json index 6762d1d408..12cfd69870 100644 --- a/package.json +++ b/package.json @@ -71,7 +71,7 @@ "ng-flex-layout": "^17.3.7-beta.1", "ng2-pdf-viewer": "10.2.2", "ngx-entity-service": "^0.0.43", - "ngx-lottie": "^11.0.2", + "ngx-lottie": "^21.2.0", "ngx-monaco-editor-v2": "^21", "ngx-skeleton-loader": "^12.0.0", "nvd3": "1.8.6", From edab0928c3419cb7babb3363cc1c2046decb3c0b Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Thu, 18 Jun 2026 13:26:38 +1000 Subject: [PATCH 1129/1280] chore: remove unused/deprecated bootstrap styles (#1266) --- src/styles/common/center-full-screen.scss | 9 - src/styles/common/doubtfire-cards.scss | 7 - src/styles/common/extensions/col-xl.scss | 110 --------- .../common/extensions/fa-document-o.scss | 4 - .../extensions/panel-footer-toolbar.scss | 35 --- .../extensions/panel-heading-toolbar.scss | 58 ----- src/styles/common/extensions/pointer.scss | 7 - src/styles/common/extensions/strong.scss | 6 - src/styles/common/five-cols.scss | 25 -- src/styles/common/grade-colors.scss | 15 -- .../common/overrides/badge-overrides.scss | 8 - .../common/overrides/body-overrides.scss | 36 --- .../common/overrides/header-overrides.scss | 12 - .../common/overrides/label-overrides.scss | 11 - .../common/overrides/nav-tabs-overrides.scss | 16 -- .../overrides/nvd3-graph-overrides.scss | 6 - .../common/overrides/panel-overrides.scss | 127 ----------- .../common/overrides/rating-overrides.scss | 17 -- .../common/overrides/table-overrides.scss | 15 -- src/styles/common/text.scss | 4 - src/styles/config/font-awesome.scss | 7 - src/styles/mixins/animations/fade-in.scss | 14 -- src/styles/mixins/animations/grow.scss | 28 --- src/styles/mixins/animations/slide-down.scss | 14 -- src/styles/mixins/animations/wobble.scss | 47 ---- src/styles/mixins/callout.scss | 28 --- src/styles/mixins/dropdown-selector.scss | 50 ---- src/styles/mixins/flex-center.scss | 11 - src/styles/mixins/flex-panel.scss | 8 - src/styles/mixins/large-notice-block.scss | 22 -- src/styles/mixins/logo-font-rendering.scss | 9 - src/styles/mixins/no-select.scss | 4 - src/styles/mixins/remove-list-padding.scss | 4 - src/styles/modules/callout.scss | 25 -- src/styles/modules/cards.scss | 86 ------- src/styles/modules/doubtfire-logo.scss | 34 --- src/styles/modules/drilldown-visualiser.scss | 22 -- src/styles/modules/panel-fullscreen.scss | 63 ------ src/styles/modules/project-task-bar.scss | 104 --------- src/styles/modules/rationale-wrapper.scss | 30 --- src/styles/modules/tabset-icon.scss | 19 -- src/styles/modules/task-status.scss | 214 ------------------ src/styles/vendor-config/bootstrap.scss | 13 -- src/styles/vendor-config/font-awesome.scss | 7 - 44 files changed, 1391 deletions(-) delete mode 100644 src/styles/common/center-full-screen.scss delete mode 100644 src/styles/common/doubtfire-cards.scss delete mode 100644 src/styles/common/extensions/col-xl.scss delete mode 100644 src/styles/common/extensions/fa-document-o.scss delete mode 100644 src/styles/common/extensions/panel-footer-toolbar.scss delete mode 100644 src/styles/common/extensions/panel-heading-toolbar.scss delete mode 100644 src/styles/common/extensions/pointer.scss delete mode 100644 src/styles/common/extensions/strong.scss delete mode 100644 src/styles/common/five-cols.scss delete mode 100644 src/styles/common/grade-colors.scss delete mode 100644 src/styles/common/overrides/badge-overrides.scss delete mode 100644 src/styles/common/overrides/body-overrides.scss delete mode 100644 src/styles/common/overrides/header-overrides.scss delete mode 100644 src/styles/common/overrides/label-overrides.scss delete mode 100644 src/styles/common/overrides/nav-tabs-overrides.scss delete mode 100644 src/styles/common/overrides/nvd3-graph-overrides.scss delete mode 100644 src/styles/common/overrides/panel-overrides.scss delete mode 100644 src/styles/common/overrides/rating-overrides.scss delete mode 100644 src/styles/common/overrides/table-overrides.scss delete mode 100644 src/styles/common/text.scss delete mode 100644 src/styles/config/font-awesome.scss delete mode 100644 src/styles/mixins/animations/fade-in.scss delete mode 100644 src/styles/mixins/animations/grow.scss delete mode 100644 src/styles/mixins/animations/slide-down.scss delete mode 100644 src/styles/mixins/animations/wobble.scss delete mode 100644 src/styles/mixins/callout.scss delete mode 100644 src/styles/mixins/dropdown-selector.scss delete mode 100644 src/styles/mixins/flex-center.scss delete mode 100644 src/styles/mixins/flex-panel.scss delete mode 100644 src/styles/mixins/large-notice-block.scss delete mode 100644 src/styles/mixins/logo-font-rendering.scss delete mode 100644 src/styles/mixins/no-select.scss delete mode 100644 src/styles/mixins/remove-list-padding.scss delete mode 100644 src/styles/modules/callout.scss delete mode 100644 src/styles/modules/cards.scss delete mode 100644 src/styles/modules/doubtfire-logo.scss delete mode 100644 src/styles/modules/drilldown-visualiser.scss delete mode 100644 src/styles/modules/panel-fullscreen.scss delete mode 100644 src/styles/modules/project-task-bar.scss delete mode 100644 src/styles/modules/rationale-wrapper.scss delete mode 100644 src/styles/modules/tabset-icon.scss delete mode 100644 src/styles/modules/task-status.scss delete mode 100644 src/styles/vendor-config/bootstrap.scss delete mode 100644 src/styles/vendor-config/font-awesome.scss diff --git a/src/styles/common/center-full-screen.scss b/src/styles/common/center-full-screen.scss deleted file mode 100644 index 0ddbddf36d..0000000000 --- a/src/styles/common/center-full-screen.scss +++ /dev/null @@ -1,9 +0,0 @@ -// -// Ensures an element takes up the full screen and centered -// -.center-full-screen { - @include flex-center; - @media (min-width: $screen-sm) { - height: 100vh; - } -} diff --git a/src/styles/common/doubtfire-cards.scss b/src/styles/common/doubtfire-cards.scss deleted file mode 100644 index a2edcc816f..0000000000 --- a/src/styles/common/doubtfire-cards.scss +++ /dev/null @@ -1,7 +0,0 @@ -@mixin doubtfire-card { - border-radius: 10px; -} - -.mat-mdc-card.danger-card { - @include doubtfire-card(); -} diff --git a/src/styles/common/extensions/col-xl.scss b/src/styles/common/extensions/col-xl.scss deleted file mode 100644 index e7cee6aff7..0000000000 --- a/src/styles/common/extensions/col-xl.scss +++ /dev/null @@ -1,110 +0,0 @@ -// From https://gist.github.com/juukie/d71133e69877b46f060e - -$screen-xl: 1560px !default; -$screen-xl-min: $screen-xl !default; -$screen-xl-desktop: $screen-xl-min !default; -$screen-lg-max: ($screen-xl-min - 1) !default; -$container-xlarge-desktop: (1530px + $grid-gutter-width) !default; -$container-xl: $container-xlarge-desktop !default; - -.container { - // @include container-fixed; No need for, already done. - @media (min-width: $screen-xl-min) { - width: $container-xl; - } -} - -// xLarge grid -// -// Columns, offsets, pushes, and pulls for the large desktop device range. - -@media (min-width: $screen-xl-min) { - @include make-grid(xl); -} - -// Generate the xlarge columns -@mixin make-xl-column($columns, $gutter: $grid-gutter-width) { - position: relative; - min-height: 1px; - padding-left: ($gutter / 2); - padding-right: ($gutter / 2); - - @media (min-width: $screen-xl-min) { - float: left; - width: percentage(($columns / $grid-columns)); - } -} -@mixin make-xl-column-offset($columns) { - @media (min-width: $screen-xl-min) { - margin-left: percentage(($columns / $grid-columns)); - } -} -@mixin make-xl-column-push($columns) { - @media (min-width: $screen-xl-min) { - left: percentage(($columns / $grid-columns)); - } -} -@mixin make-xl-column-pull($columns) { - @media (min-width: $screen-xl-min) { - right: percentage(($columns / $grid-columns)); - } -} - -@mixin make-grid-columns($i: 1, $list: '.col-xl-#{$i}') { - @for $i from (1 + 1) through $grid-columns { - $list: '#{$list}, .col-xl-#{$i}'; - } - #{$list} { - position: relative; - // Prevent columns from collapsing when empty - min-height: 1px; - // Inner gutter via padding - padding-left: ($grid-gutter-width / 2); - padding-right: ($grid-gutter-width / 2); - } -} - -@include make-grid-columns; - -@include responsive-invisibility('.visible-xl'); - -.visible-xl-block, -.visible-xl-inline, -.visible-xl-inline-block { - display: none !important; -} - -@media (min-width: $screen-xl-min) { - @include responsive-invisibility('.visible-lg'); - @include responsive-visibility('.visible-xl'); -} -.visible-xl-block { - @media (min-width: $screen-xl-min) { - display: block !important; - } -} -.visible-xl-inline { - @media (min-width: $screen-xl-min) { - display: inline !important; - } -} -.visible-xl-inline-block { - @media (min-width: $screen-xl-min) { - display: inline-block !important; - } -} - -@media (min-width: $screen-lg-min) and (max-width: $screen-lg-max) { - @include responsive-invisibility('.hidden-lg'); -} - -@media (min-width: $screen-xl-min) { - @include responsive-invisibility('.hidden-xl'); - @include responsive-visibility('.hidden-lg'); - - .visible-lg-block, - .visible-lg-inline, - .visible-lg-inline-block { - display: none !important; - } -} diff --git a/src/styles/common/extensions/fa-document-o.scss b/src/styles/common/extensions/fa-document-o.scss deleted file mode 100644 index 62c97e0d4d..0000000000 --- a/src/styles/common/extensions/fa-document-o.scss +++ /dev/null @@ -1,4 +0,0 @@ -// Alias for .fa-file-pdf-o -.#{$fa-css-prefix}-file-document-o:before { - content: $fa-var-file-pdf-o; -} diff --git a/src/styles/common/extensions/panel-footer-toolbar.scss b/src/styles/common/extensions/panel-footer-toolbar.scss deleted file mode 100644 index dd6ffaa97d..0000000000 --- a/src/styles/common/extensions/panel-footer-toolbar.scss +++ /dev/null @@ -1,35 +0,0 @@ -.panel .panel-footer { - // With buttons in a small screen - @media (max-width: $screen-sm) { - // Increase tapping area - & > * { - width: 100%; - } - .btn-group, - .btn, - input { - height: 4em; - width: 100%; - } - .btn { - margin-top: 1em; - } - ul.pagination { - margin-top: 1em; - width: 100%; - flex: 1; - display: flex; - overflow: auto; - li { - flex: 1; - } - li > a { - width: 100%; - height: 4em; - display: flex; - align-items: center; - justify-content: center; - } - } - } -} diff --git a/src/styles/common/extensions/panel-heading-toolbar.scss b/src/styles/common/extensions/panel-heading-toolbar.scss deleted file mode 100644 index cc8d10e8d2..0000000000 --- a/src/styles/common/extensions/panel-heading-toolbar.scss +++ /dev/null @@ -1,58 +0,0 @@ -// For all panel headings -.panel .panel-heading { - // With buttons in a small screen - @media (max-width: $screen-sm) { - // Increase tapping area - & > * { - width: 100%; - } - .btn-group, - .btn, - input { - height: 4em; - width: 100%; - } - } - .toolbar { - @media (max-width: $screen-sm) { - margin: 1.5em auto; - width: 100%; - text-align: left; - } - .btn-group, - .buttons > .btn { - @media (min-width: $screen-sm-max) { - margin-right: 1ex; - } - } - .buttons { - float: right; - @media (max-width: $screen-sm) { - width: 100%; - .btn-group { - margin-top: 1em; - display: flex; - float: left; - float: right; - clear: both; - .btn { - flex: 1; - } - .btn { - @include flex-center; - } - } - } - } - form[role='search'] { - float: right; - margin-right: 1.5ex; - @media (max-width: $screen-sm) { - margin-right: 0; - width: 100%; - margin-top: 1em; - padding: 0 !important; - } - } - } -} diff --git a/src/styles/common/extensions/pointer.scss b/src/styles/common/extensions/pointer.scss deleted file mode 100644 index 0840082215..0000000000 --- a/src/styles/common/extensions/pointer.scss +++ /dev/null @@ -1,7 +0,0 @@ -// -// All anchors are pointers, as well as anything with the .pointer class -// -a, -.pointer { - cursor: pointer; -} diff --git a/src/styles/common/extensions/strong.scss b/src/styles/common/extensions/strong.scss deleted file mode 100644 index bb400cbf84..0000000000 --- a/src/styles/common/extensions/strong.scss +++ /dev/null @@ -1,6 +0,0 @@ -// -// Strong font weight using a .strong class -// -.strong { - font-weight: bold; -} diff --git a/src/styles/common/five-cols.scss b/src/styles/common/five-cols.scss deleted file mode 100644 index de94a27e74..0000000000 --- a/src/styles/common/five-cols.scss +++ /dev/null @@ -1,25 +0,0 @@ -.col-xs-15 { - width: 20%; - float: left; -} - -@media (min-width: 768px) { - .col-sm-15 { - width: 20%; - float: left; - } -} - -@media (min-width: 992px) { - .col-md-15 { - width: 20%; - float: left; - } -} - -@media (min-width: 1200px) { - .col-lg-15 { - width: 20%; - float: left; - } -} diff --git a/src/styles/common/grade-colors.scss b/src/styles/common/grade-colors.scss deleted file mode 100644 index 45e498c0eb..0000000000 --- a/src/styles/common/grade-colors.scss +++ /dev/null @@ -1,15 +0,0 @@ -@use 'sass:color'; - -// -// Colors for associated grades -// -// ******************************************************** -// IMPORTANT: Grade colours must also be matched -// in the grade-service.coffee file -// ******************************************************** -// - -$grade-color-p: color.adjust(#ff0000, $lightness: -10%); -$grade-color-c: color.adjust(#ff8000, $lightness: -5%); -$grade-color-d: color.adjust(#0080ff, $lightness: -10%); -$grade-color-hd: color.adjust(#80ff00, $lightness: -15%); diff --git a/src/styles/common/overrides/badge-overrides.scss b/src/styles/common/overrides/badge-overrides.scss deleted file mode 100644 index 32057cdf12..0000000000 --- a/src/styles/common/overrides/badge-overrides.scss +++ /dev/null @@ -1,8 +0,0 @@ -// -// Overrides for all badges -// -.badge { - border-radius: 1em; - text-align: center; - display: inline-block; -} diff --git a/src/styles/common/overrides/body-overrides.scss b/src/styles/common/overrides/body-overrides.scss deleted file mode 100644 index c2b92ccf27..0000000000 --- a/src/styles/common/overrides/body-overrides.scss +++ /dev/null @@ -1,36 +0,0 @@ -// -// Overrides for the body (i.e., global overrdies) -// -$main-view-top-padding: 30px; -$main-view-bottom-padding: $main-view-top-padding; - -$main-view-max-height: calc((var(--vh, 1vh) * (100)) - 85px); - -/* override browser default */ -html, -body { - margin: 0; - padding: 0; - // background-color: #f5f5f5; -} - -/* use viewport-relative units to cover page fully */ -body { - height: 100vh; - height: $main-view-max-height; - width: 100vw; - // font-family: 'Roboto', Helvetica; - // font-size: 1.2em; - // line-height: 2; - // font-weight: normal; -} - -/* include border and padding in element width and height */ -* { - box-sizing: border-box; -} - -// body>[ui-view="header"]:not(:empty)+[ui-view="main"] { -// padding-top: $main-view-top-padding; -// padding-bottom: $main-view-bottom-padding; -// } diff --git a/src/styles/common/overrides/header-overrides.scss b/src/styles/common/overrides/header-overrides.scss deleted file mode 100644 index cb4237edfc..0000000000 --- a/src/styles/common/overrides/header-overrides.scss +++ /dev/null @@ -1,12 +0,0 @@ -// -// Sets all font weights to the headers as 400 -// - -h1, -h2, -h3, -h4, -h5, -h6 { - font-weight: 400; -} diff --git a/src/styles/common/overrides/label-overrides.scss b/src/styles/common/overrides/label-overrides.scss deleted file mode 100644 index 3280c214cb..0000000000 --- a/src/styles/common/overrides/label-overrides.scss +++ /dev/null @@ -1,11 +0,0 @@ -// -// Overrides for the font size to make labels larger -// -.label { - font-size: 100% !important; -} - -.label.label-unit { - @include label-variant($label-info-bg); - margin-right: 1ex; -} diff --git a/src/styles/common/overrides/nav-tabs-overrides.scss b/src/styles/common/overrides/nav-tabs-overrides.scss deleted file mode 100644 index 8a20557cf2..0000000000 --- a/src/styles/common/overrides/nav-tabs-overrides.scss +++ /dev/null @@ -1,16 +0,0 @@ -// -// Override nav tabs's content to be separated -// -.nav.nav-tabs + .tab-content { - margin-top: 1.5em; -} - -// Support badges in nav pills -.nav.nav-pills tab-heading { - display: flex; - justify-content: center; - align-items: center; - .comment-count { - margin-left: 1ex; - } -} diff --git a/src/styles/common/overrides/nvd3-graph-overrides.scss b/src/styles/common/overrides/nvd3-graph-overrides.scss deleted file mode 100644 index 108d0fe58a..0000000000 --- a/src/styles/common/overrides/nvd3-graph-overrides.scss +++ /dev/null @@ -1,6 +0,0 @@ -// -// Override to center all nvd3 SVGs -// -svg.nvd3-svg { - margin: 0 auto; -} diff --git a/src/styles/common/overrides/panel-overrides.scss b/src/styles/common/overrides/panel-overrides.scss deleted file mode 100644 index f1ed83d293..0000000000 --- a/src/styles/common/overrides/panel-overrides.scss +++ /dev/null @@ -1,127 +0,0 @@ -@use 'sass:color'; - -// -// Global overrides for panels -// -.panel-footer .pagination, -.modal-footer .pagination { - margin: 0; -} - -.panel-body + .panel-heading, -.panel-body + * > .panel-heading { - border-top: 1px solid #ddd !important; - border-radius: 0 !important; -} - -.panel-heading > .pull-left { - padding-left: 0 !important; // Override for col-sm-* -} -.panel-heading > .pull-right { - padding-right: 0 !important; // Override for col-sm-* -} - -@mixin panel-row { - display: flex; - .panel { - flex: 1; - display: flex; - flex-direction: column; - } - .panel > *:not(.panel-heading):not(.panel-footer):not(.panel-toolbar) { - flex: 1; - } - .panel-heading, - .panel-body, - .panel-footer { - width: 100%; - } - .panel + .panel { - margin-left: $panel-body-padding; - } - // Panels with file dropzones - .panel-footer .well { - background-color: #fff; - } - .panel h3.file-title { - margin-top: 0; - font-size: 1em; - } - .panel .drop.well, - .panel .file-uploader { - margin: 0; - } -} -.panel-row { - @include panel-row(); -} - -// New panel loading panel -.panel-body.panel-loading { - @extend .text-muted; - @extend .text-center; - @extend .strong; - font-size: 1.3em; - padding-top: $panel-body-padding * 4; - padding-bottom: $panel-body-padding * 4; - i { - margin-right: 0.9ex; - } -} - -.panel.panel-scrollable { - overflow: hidden; - .panel-body { - overflow: scroll; - height: 100%; - padding-bottom: $panel-body-padding * 3; - } -} - -// Search options panel -.panel-body.panel-collapseable { - background-color: color.adjust($gray-lighter, $lightness: 2%); -} - -// Two panel bodies next to eachother (include those with one nested in custom element) -.panel-body:not(.ng-hide) + * > .panel-body, -.panel-body:not(.ng-hide) + .panel-body { - padding-top: 0; -} -// Remove extra margin for callouts in padding -.panel-body > .callout:first-child { - margin-top: 0; -} -.panel-body > .callout:last-child { - margin-bottom: 0; -} - -// Full screen set of panels -.panel-full-screen { - height: $main-view-max-height; - & > *, - & > * > .panel { - height: 100%; - } -} - -.panel-marking-context { - padding: 0; - .panel { - margin: 0; - border: none; - border-radius: 0; - background-color: transparent; - } - .panel-submission-marking-context .panel-body { - padding: 60px; - } -} - -.panel.panel-pdf { - @include flex-panel; - .panel-body.has-pdf { - padding: 0; - position: relative; - } -} diff --git a/src/styles/common/overrides/rating-overrides.scss b/src/styles/common/overrides/rating-overrides.scss deleted file mode 100644 index 0c9e44aa6f..0000000000 --- a/src/styles/common/overrides/rating-overrides.scss +++ /dev/null @@ -1,17 +0,0 @@ -@use 'sass:color'; - -// The generated from ui-bootstrap becomes this -span[role='slider'] { - outline: none; -} -.rating-outline { - color: color.adjust($brand-warning, $lightness: 30%); - -webkit-text-stroke-width: 1px; - -webkit-text-stroke-color: $brand-warning; -} -.rating-disabled { - color: color.adjust($text-muted, $lightness: 30%); -} -.rating-star::before { - content: 'star'; -} diff --git a/src/styles/common/overrides/table-overrides.scss b/src/styles/common/overrides/table-overrides.scss deleted file mode 100644 index 2b03bc8575..0000000000 --- a/src/styles/common/overrides/table-overrides.scss +++ /dev/null @@ -1,15 +0,0 @@ -// -// Global overrides for tables -// -table.table-pointer { - tr { - cursor: pointer; - } -} - -table > tbody > tr { - & > td, - & > th { - vertical-align: middle !important; - } -} diff --git a/src/styles/common/text.scss b/src/styles/common/text.scss deleted file mode 100644 index 69586f5d2e..0000000000 --- a/src/styles/common/text.scss +++ /dev/null @@ -1,4 +0,0 @@ -.with-icon { - display: flex; - align-items: center; -} diff --git a/src/styles/config/font-awesome.scss b/src/styles/config/font-awesome.scss deleted file mode 100644 index 87945b4a94..0000000000 --- a/src/styles/config/font-awesome.scss +++ /dev/null @@ -1,7 +0,0 @@ -// -// This config file provides overrides for bootstrap and is injected before -// font awesome is imported -// - -// Provide the font path to the fa-fonts -$fa-font-path: './fonts/font-awesome'; diff --git a/src/styles/mixins/animations/fade-in.scss b/src/styles/mixins/animations/fade-in.scss deleted file mode 100644 index 008d7a6ead..0000000000 --- a/src/styles/mixins/animations/fade-in.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// A fade in animation -// -@keyframes animation-fade-in { - from { - opacity: 0; - } - to { - opacity: 1; - } -} -@mixin animation-fade-in($seconds) { - animation: animation-fade-in $seconds; -} diff --git a/src/styles/mixins/animations/grow.scss b/src/styles/mixins/animations/grow.scss deleted file mode 100644 index e8cef776ce..0000000000 --- a/src/styles/mixins/animations/grow.scss +++ /dev/null @@ -1,28 +0,0 @@ -// -// Grow animation from 0 scale to 1 scale -// -@keyframes animation-grow { - 0% { - opacity: 0; - transform: scale(0.3); - } - - 50% { - opacity: 1; - transform: scale(1.05); - } - - 70% { - transform: scale(0.9); - } - - 100% { - transform: scale(1); - } -} - -@mixin animation-grow($time: 0.5s) { - animation-name: animation-grow; - animation-duration: $time; - animation-fill-mode: both; -} diff --git a/src/styles/mixins/animations/slide-down.scss b/src/styles/mixins/animations/slide-down.scss deleted file mode 100644 index 1bb14c5d1c..0000000000 --- a/src/styles/mixins/animations/slide-down.scss +++ /dev/null @@ -1,14 +0,0 @@ -// -// Slide animation from -2em to initial top -// -@keyframes animation-slide-down { - from { - margin-top: -2em; - } - to { - margin-top: inherit; - } -} -@mixin animation-slide-down($seconds) { - animation: animation-slide-down $seconds; -} diff --git a/src/styles/mixins/animations/wobble.scss b/src/styles/mixins/animations/wobble.scss deleted file mode 100644 index e06fbdfecb..0000000000 --- a/src/styles/mixins/animations/wobble.scss +++ /dev/null @@ -1,47 +0,0 @@ -// -// Animation to wobble an element side to side -// -@keyframes animation-wobble { - 0%, - 100% { - transform: translateX(+5px); - } - 25%, - 75% { - transform: translateX(0); - } - 50% { - transform: translateX(-5px); - } -} - -@mixin animation-wobble { - animation-duration: 1s; - animation-fill-mode: both; - animation-timing-function: ease-in-out; - animation-iteration-count: infinite; - animation-name: animation-wobble; -} - -// -// Animation to wobble an element side but only once -// -@keyframes animation-wobble-once { - 0%, - 100% { - transform: translateX(0); - } - 25% { - transform: translateX(+5px); - } - 75% { - transform: translateX(-5px); - } -} - -@mixin animation-wobble-once { - animation-duration: 0.15s; - animation-fill-mode: both; - animation-iteration-count: 2; - animation-name: animation-wobble-once; -} diff --git a/src/styles/mixins/callout.scss b/src/styles/mixins/callout.scss deleted file mode 100644 index fa9d52c3b2..0000000000 --- a/src/styles/mixins/callout.scss +++ /dev/null @@ -1,28 +0,0 @@ -@use 'sass:color'; - -// -// A callout -// -@mixin callout($color, $bgcolor: color.adjust($color, $lightness: 35%)) { - display: block; - margin: 20px 0; - padding: 15px 30px 15px 15px; - border-left: 5px solid $color; - background-color: $bgcolor; - h1, - h2, - h3, - h4, - h5, - h6 { - margin-top: 0; - color: $color; - } - p:last-child { - margin-bottom: 0; - } - code, - .highlight { - background-color: #fff; - } -} diff --git a/src/styles/mixins/dropdown-selector.scss b/src/styles/mixins/dropdown-selector.scss deleted file mode 100644 index c5ca2742a2..0000000000 --- a/src/styles/mixins/dropdown-selector.scss +++ /dev/null @@ -1,50 +0,0 @@ -@mixin dropdown-selector { - height: 100%; - padding-left: 0px; - padding-right: 0px; - // first button - & > button { - height: 100%; - width: 100%; - label, - i { - text-align: center; - } - label { - font-size: 1.5em; - margin: 0px; - } - label.label.label-info { - font-size: 1em; - margin-left: 0.5ex; - cursor: pointer; - } - // not a split button group - span.caret { - margin-left: 1ex; - } - } - // open button - &.open > button { - border-bottom-left-radius: 0px; - border-bottom-right-radius: 0px; - } - // menu underneath - .dropdown-menu { - margin-top: 0px; - border-top-left-radius: 0px; - border-top-right-radius: 0px; - @media (max-width: $screen-sm) { - position: relative; - bottom: 0; - left: 0; - right: 0; - top: 0; - width: 100%; - } - } -} - -.dropdown-selector { - @include dropdown-selector; -} diff --git a/src/styles/mixins/flex-center.scss b/src/styles/mixins/flex-center.scss deleted file mode 100644 index e741a95c92..0000000000 --- a/src/styles/mixins/flex-center.scss +++ /dev/null @@ -1,11 +0,0 @@ -// -// Uses flex to align the div contents in the center -// -@mixin flex-center { - display: flex; - flex-wrap: wrap; - align-items: center; - align-content: center; - justify-content: center; - height: 100%; -} diff --git a/src/styles/mixins/flex-panel.scss b/src/styles/mixins/flex-panel.scss deleted file mode 100644 index a74cd163fd..0000000000 --- a/src/styles/mixins/flex-panel.scss +++ /dev/null @@ -1,8 +0,0 @@ -@mixin flex-panel { - display: flex; - flex-wrap: wrap; - flex-direction: column; - .panel-body { - flex: 1; - } -} diff --git a/src/styles/mixins/large-notice-block.scss b/src/styles/mixins/large-notice-block.scss deleted file mode 100644 index 7f138f6551..0000000000 --- a/src/styles/mixins/large-notice-block.scss +++ /dev/null @@ -1,22 +0,0 @@ -// -// A large notice block is a large text with an icon -// -@mixin large-notice-block { - @include flex-center; - font-size: 2em; - text-align: center; - font-weight: 300; - & > * { - display: block; - width: 100%; - margin-top: 0.75em; - margin-bottom: 0.75em; - } - &.panel-body { - padding: 30px; - } -} - -.large-notice-block { - @include large-notice-block; -} diff --git a/src/styles/mixins/logo-font-rendering.scss b/src/styles/mixins/logo-font-rendering.scss deleted file mode 100644 index 68624bc823..0000000000 --- a/src/styles/mixins/logo-font-rendering.scss +++ /dev/null @@ -1,9 +0,0 @@ -// -// Font rendering for the DF logo -// - -@mixin logo-font-rendering { - -webkit-font-smoothing: antialiased; - letter-spacing: -1px; - font-weight: 300; -} diff --git a/src/styles/mixins/no-select.scss b/src/styles/mixins/no-select.scss deleted file mode 100644 index cb2ed50433..0000000000 --- a/src/styles/mixins/no-select.scss +++ /dev/null @@ -1,4 +0,0 @@ -@mixin no-select { - user-select: none; - cursor: default; -} diff --git a/src/styles/mixins/remove-list-padding.scss b/src/styles/mixins/remove-list-padding.scss deleted file mode 100644 index 1b5a1b0690..0000000000 --- a/src/styles/mixins/remove-list-padding.scss +++ /dev/null @@ -1,4 +0,0 @@ -@mixin remove-list-padding { - -webkit-padding-start: 0; - padding-left: 0; -} diff --git a/src/styles/modules/callout.scss b/src/styles/modules/callout.scss deleted file mode 100644 index 389ccdbb73..0000000000 --- a/src/styles/modules/callout.scss +++ /dev/null @@ -1,25 +0,0 @@ -@use 'sass:color'; -@use 'styles/mixins/callout' as *; - -// -// Callouts used for standout information -// -.callout-primary { - @include callout($brand-primary, color.adjust($brand-primary, $lightness: 45%)); -} - -.callout-danger { - @include callout($brand-danger, color.adjust($brand-danger, $lightness: 30%)); -} - -.callout-warning { - @include callout($brand-warning, color.adjust($brand-warning, $lightness: 30%)); -} - -.callout-info { - @include callout($brand-info, color.adjust($brand-info, $lightness: 30%)); -} - -.callout-success { - @include callout($brand-success, color.adjust($brand-success, $lightness: 30%)); -} diff --git a/src/styles/modules/cards.scss b/src/styles/modules/cards.scss deleted file mode 100644 index 2114a71f81..0000000000 --- a/src/styles/modules/cards.scss +++ /dev/null @@ -1,86 +0,0 @@ -@use 'sass:color'; - -.card { - $card-height-lg: 500px; - $card-height-md: $card-height-lg / 2; - $card-height-sm: $card-height-md / 2; - $card-body-padding: $panel-body-padding; - $card-footer-padding: $card-body-padding + 5px; - $card-header-padding: $card-body-padding $card-footer-padding; - - margin-bottom: $card-footer-padding; - background-color: color.adjust(#fff, $lightness: -0.75%); - transition: box-shadow 0.25s; - box-shadow: - 0 2px 2px 0 rgba(0, 0, 0, 0.14), - 0 1px 5px 0 rgba(0, 0, 0, 0.12), - 0 3px 1px -2px rgba(0, 0, 0, 0.2); - - &.card-default > .card-heading { - background-color: $panel-default-heading-bg; - } - &.card-primary > .card-heading { - background-color: $brand-primary; - } - &.card-danger > .card-heading { - background-color: $brand-danger; - } - &.card-success > .card-heading { - background-color: $brand-success; - } - &.card-warning > .card-heading { - background-color: $brand-warning; - } - &.card-info > .card-heading { - background-color: $brand-info; - } - &.card-danger, - &.card-success, - &.card-warning, - &.card-info, - &.card-primary { - .card-heading { - color: #fff; - .text-muted { - color: color.adjust(#fff, $lightness: -1%); - } - } - } - .card-heading { - padding: $card-header-padding; - border-bottom: 1px solid rgba(160, 160, 160, 0.2); - } - .card-body { - padding: $card-body-padding; - } - .card-footer { - position: relative; - background-color: inherit; - padding: $card-footer-padding; - border-top: 1px solid rgba(160, 160, 160, 0.2); - } - - &.card-lg { - min-height: $card-height-lg; - } - &.card-md { - min-height: $card-height-md; - } - &.card-sm { - min-height: $card-height-sm; - } - - & > .list-group { - margin-bottom: 0; - .list-group-item { - border-width: 1px 0; - border-radius: 0; - &:first-child { - border-top-width: 0; - } - &:last-child { - border-bottom-width: 0; - } - } - } -} diff --git a/src/styles/modules/doubtfire-logo.scss b/src/styles/modules/doubtfire-logo.scss deleted file mode 100644 index aaf9cf1fc9..0000000000 --- a/src/styles/modules/doubtfire-logo.scss +++ /dev/null @@ -1,34 +0,0 @@ -// -// Styles for the Doubtfire Logo -// - -h1.logo { - @include logo-font-rendering; - font-size: 4em; -} -i.logo { - display: inline-block; - width: 1em; - height: 1em; - background-image: url('/assets/images/logo.svg'); - background-size: 100%; - background-repeat: no-repeat; - background-position: center; -} - -.welcome-to-doubtfire { - margin-top: 6em; - margin-bottom: 3em; - h1, - p { - @include logo-font-rendering; - font-family: 'Grotesk'; - } - p.lead { - color: #000; - } - i.logo { - width: 10em; - height: 10em; - } -} diff --git a/src/styles/modules/drilldown-visualiser.scss b/src/styles/modules/drilldown-visualiser.scss deleted file mode 100644 index 5f382b2719..0000000000 --- a/src/styles/modules/drilldown-visualiser.scss +++ /dev/null @@ -1,22 +0,0 @@ -// -// A drilldown for visualisations to click into graphs and see more -// about those graphs -// -.drilldown-visualiser { - .overview-chart { - cursor: pointer; - } - .overview-charts .overview-chart { - height: 250px; - cursor: pointer; - .no-data-to-display { - height: 60%; - text-align: center; - padding-top: 30%; - border: 1px dashed #ddd; - color: #ddd; - border-radius: 1em; - margin: 10%; - } - } -} diff --git a/src/styles/modules/panel-fullscreen.scss b/src/styles/modules/panel-fullscreen.scss deleted file mode 100644 index 7e6ff08b3e..0000000000 --- a/src/styles/modules/panel-fullscreen.scss +++ /dev/null @@ -1,63 +0,0 @@ -// -// Fullscreen panel mode styles -// -.panel.fullscreen { - border-radius: 0; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - margin: 0; - z-index: 4; - border-bottom: none; - - // Flex stuff - display: flex; - flex-direction: column; - - .panel-heading { - border-radius: 0; - } - - .panel-body.student-list { - height: 20vh; - resize: vertical; - max-height: 40vh; - overflow: scroll; - border-bottom: 2px solid #428bca; - box-shadow: 1px 1px 3px; - } - .panel-body.project-show { - overflow-y: scroll; - flex: 1; - position: relative; - - &.no-padding { - padding: 0px; - } - - .panel, - .panel-heading { - border-radius: 0; - } - - .nothing-selected { - @include large-notice-block; - position: absolute; - bottom: 0; - top: 0; - left: 0; - right: 0; - font-size: 3em; - text-align: center; - font-weight: 300; - i, - p { - display: block; - width: 100%; - margin-bottom: 0.75em; - } - } - } -} diff --git a/src/styles/modules/project-task-bar.scss b/src/styles/modules/project-task-bar.scss deleted file mode 100644 index 771c60ce4e..0000000000 --- a/src/styles/modules/project-task-bar.scss +++ /dev/null @@ -1,104 +0,0 @@ -@use 'styles/mixins/task-status-colors-generator' as *; - -// -// Student's progress bar styling -// -.task-progress { - tr { - vertical-align: middle; - } - - margin-bottom: 0px; -} - -.progress-bar { - span { - font-size: 8pt; - } - - &[aria-valuenow='1'], - &[aria-valuenow='2'] { - min-width: 0px; - } - - &[aria-valuenow='0'] { - min-width: 0px; - } -} - -.task-progress-bar { - min-width: 128px; - width: 360px; - - .panel-group { - margin-bottom: 0px; - } -} - -.task-progress-accordion, -.progress-progress-bar { - .panel-heading { - padding-top: 5px; - padding-bottom: 5px; - padding-left: 10px; - padding-right: 10px; - } -} - -.progress-bar-ready-for-feedback { - @include task-status-color-ready-for-feedback; -} -.progress-bar-not-started { - @include task-status-color-not-started; -} -.progress-bar-working-on-it { - @include task-status-color-working-on-it; -} -.progress-bar-need-help { - @include task-status-color-need-help; -} -.progress-bar-fix-and-resubmit { - @include task-status-color-fix-and-resubmit; -} -.progress-bar-feedback-exceeded { - @include task-status-color-feedback-exceeded; -} -.progress-bar-fail { - @include task-status-color-fail; -} -.progress-bar-redo { - @include task-status-color-redo; -} -.progress-bar-discuss { - @include task-status-color-discuss; -} -.progress-bar-demonstrate { - @include task-status-color-demonstrate; -} -.progress-bar-complete { - @include task-status-color-complete; -} -.progress-bar-assess-in-portfolio { - @include task-status-color-assess-in-portfolio; -} -.progress-bar-attention-required { - @include task-status-color-attention-required; -} - -.progress-bar-not-started { - @include task-status-color-not-started; -} -.progress-bar-one-week-late { - @include task-status-color-working-on-it; -} -.progress-bar-two-weeks-late { - @include task-status-color-fail; -} -.progress-bar-on-time { - @include task-status-color-complete; -} - -.progress-progress-bar { - height: 30px; - margin-bottom: 0px; -} diff --git a/src/styles/modules/rationale-wrapper.scss b/src/styles/modules/rationale-wrapper.scss deleted file mode 100644 index 08693f7810..0000000000 --- a/src/styles/modules/rationale-wrapper.scss +++ /dev/null @@ -1,30 +0,0 @@ -// -// Text editor for rationale-providers -// -.rationale-wrapper { - display: table; - margin-top: 2em; -} -.rationale { - display: table-cell; - height: 200px; - overflow: scroll; - padding: 30px; - border-radius: 6px; - font-size: 1.5em; - cursor: pointer; - label { - font-size: 0.75em; - text-transform: uppercase; - } - &.no-rationale { - border: 1px dashed #aaa; - vertical-align: middle; - text-align: center; - color: #aaa; - } - &:hover { - border-color: #428bca; - color: #428bca; - } -} diff --git a/src/styles/modules/tabset-icon.scss b/src/styles/modules/tabset-icon.scss deleted file mode 100644 index 0a1a4004d6..0000000000 --- a/src/styles/modules/tabset-icon.scss +++ /dev/null @@ -1,19 +0,0 @@ -// -// Styling for tab headers with icons in them -// -.tabset-icon tab-heading { - text-align: center; - i { - display: block; - width: 100%; - padding-bottom: 5px; - } - i:not(:last-child) { - margin-right: 1ex; - } - i:not(:last-child), - i + i:last-child { - display: inline-block; - width: inherit; - } -} diff --git a/src/styles/modules/task-status.scss b/src/styles/modules/task-status.scss deleted file mode 100644 index 7592e018ec..0000000000 --- a/src/styles/modules/task-status.scss +++ /dev/null @@ -1,214 +0,0 @@ -@use 'sass:color'; -@use 'styles/mixins/task-status-colors-generator' as *; - -// -// Styling for all task status classes -// -.task-status { - &.ready-for-feedback { - @include task-status-color-ready-for-feedback; - } - &.not-started { - @include task-status-color-not-started; - } - &.working-on-it { - @include task-status-color-working-on-it; - } - &.need-help { - @include task-status-color-need-help; - } - &.fix-and-resubmit { - @include task-status-color-fix-and-resubmit; - } - &.feedback-exceeded { - @include task-status-color-feedback-exceeded; - } - &.fail { - @include task-status-color-fail; - } - &.redo { - @include task-status-color-redo; - } - &.discuss { - @include task-status-color-discuss; - } - &.demonstrate { - @include task-status-color-demonstrate; - } - &.complete { - @include task-status-color-complete; - } - &.time-exceeded { - @include task-status-color-time-exceeded; - } - &.assess-in-portfolio { - @include task-status-color-assess-in-portfolio; - } - &.attention-required { - @include task-status-color-attention-required; - } - - &.ready-for-feedback:hover { - background-color: task-status-color('ready-for-feedback'); - } - &.not-started:hover { - background-color: task-status-color('not-started'); - } - &.working-on-it:hover { - background-color: task-status-color('working-on-it'); - } - &.need-help:hover { - background-color: task-status-color('need-help'); - } - &.fix-and-resubmit:hover { - background-color: task-status-color('fix-and-resubmit'); - } - &.feedback-exceeded:hover { - background-color: task-status-color('feedback-exceeded'); - } - &.fail:hover { - background-color: task-status-color('fail'); - } - &.redo:hover { - background-color: task-status-color('redo'); - } - &.discuss:hover { - background-color: task-status-color('discuss'); - } - &.demonstrate:hover { - background-color: task-status-color('demonstrate'); - } - &.complete:hover { - background-color: task-status-color('complete'); - } - &.time-exceeded:hover { - background-color: task-status-color('time-exceeded'); - } - &.assess-in-portfolio:hover { - background-color: task-status-color('assess-in-portfolio'); - } - &.attention-required:hover { - background-color: task-status-color('attention-required'); - } -} - -.task-status > .btn-default { - &.ready-for-feedback, - &.ready-for-feedback.active, - &.ready-for-feedback:hover { - @include task-status-color-ready-for-feedback; - } - &.not-started, - &.not-started.active, - &.not-started:hover { - @include task-status-color-not-started; - } - &.working-on-it, - &.working-on-it.active, - &.working-on-it:hover { - @include task-status-color-working-on-it; - } - &.need-help, - &.need-help.active, - &.need-help:hover { - @include task-status-color-need-help; - } - &.fix-and-resubmit, - &.fix-and-resubmit.active, - &.fix-and-resubmit:hover { - @include task-status-color-fix-and-resubmit; - } - &.feedback-exceeded, - &.feedback-exceeded.active, - &.feedback-exceeded:hover { - @include task-status-color-feedback-exceeded; - } - &.fail, - &.fail.active, - &.fail:hover { - @include task-status-color-fail; - } - &.redo, - &.redo.active, - &.redo:hover { - @include task-status-color-redo; - } - &.discuss, - &.discuss.active, - &.discuss:hover { - @include task-status-color-discuss; - } - &.demonstrate, - &.demonstrate.active, - &.demonstrate:hover { - @include task-status-color-demonstrate; - } - &.complete, - &.complete.active, - &.complete:hover { - @include task-status-color-complete; - } - &.time-exceeded, - &.time-exceeded.active, - &.time-exceeded:hover { - @include task-status-color-time-exceeded; - } - &.assess-in-portfolio, - &.assess-in-portfolio.active, - &.assess-in-portfolio:hover { - @include task-status-color-assess-in-portfolio; - } - &.attention-required, - &.attention-required.active, - &.attention-required:hover { - @include task-status-color-attention-required; - } - - &.ready-for-feedback { - background-color: color.adjust(task-status-color('ready-for-feedback'), $lightness: 15%); - } - &.not-started { - background-color: color.adjust(task-status-color('not-started'), $lightness: 15%); - } - &.working-on-it { - background-color: color.adjust(task-status-color('working-on-it'), $lightness: 15%); - } - &.need-help { - background-color: color.adjust(task-status-color('need-help'), $lightness: 10%); - } - &.fix-and-resubmit { - background-color: color.adjust(task-status-color('fix-and-resubmit'), $lightness: 15%); - } - &.feedback-exceeded { - background-color: color.adjust(task-status-color('feedback-exceeded'), $lightness: 15%); - } - &.fail { - background-color: color.adjust(task-status-color('fail'), $lightness: 15%); - } - &.redo { - background-color: color.adjust(task-status-color('redo'), $lightness: 15%); - } - &.discuss { - background-color: color.adjust(task-status-color('discuss'), $lightness: 15%); - } - &.demonstrate { - background-color: color.adjust(task-status-color('demonstrate'), $lightness: 15%); - } - &.complete { - background-color: color.adjust(task-status-color('complete'), $lightness: 15%); - } - &.time-exceeded { - background-color: color.adjust(task-status-color('time-exceeded'), $lightness: 15%); - } - &.assess-in-portfolio { - background-color: color.adjust(task-status-color('assess-in-portfolio'), $lightness: 15%); - } - &.attention-required { - background-color: color.adjust(task-status-color('attention-required'), $lightness: 15%); - } -} - -i.task-status-icon { - display: block; - margin-bottom: 7px; -} diff --git a/src/styles/vendor-config/bootstrap.scss b/src/styles/vendor-config/bootstrap.scss deleted file mode 100644 index e086df4bd0..0000000000 --- a/src/styles/vendor-config/bootstrap.scss +++ /dev/null @@ -1,13 +0,0 @@ -// -// This config file provides overrides for bootstrap and is injected before -// bootstrap is imported -// - -// Provide the font path to the glyphicons -$icon-font-path: './fonts/bootstrap/'; - -// (Re)definition of screen sizes -$screen-xl: 1900px !default; -$screen-xl-min: $screen-xl !default; -$screen-lg: 1400px !default; -$screen-lg-max: ($screen-xl-min - 1) !default; diff --git a/src/styles/vendor-config/font-awesome.scss b/src/styles/vendor-config/font-awesome.scss deleted file mode 100644 index e073ddedf2..0000000000 --- a/src/styles/vendor-config/font-awesome.scss +++ /dev/null @@ -1,7 +0,0 @@ -// -// This config file provides overrides for bootstrap and is injected before -// font awesome is imported -// - -// Provide the font path to the glyphicons -$fa-font-path: './fonts/font-awesome'; From 356b3b871cb22f8d22172f4257ac730e4b296767 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Thu, 18 Jun 2026 14:23:10 +1000 Subject: [PATCH 1130/1280] refactor: add staff notes header in portfolio view --- .../units/states/portfolios/portfolios.component.html | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/app/units/states/portfolios/portfolios.component.html b/src/app/units/states/portfolios/portfolios.component.html index da789dafe0..3c6aa16b18 100644 --- a/src/app/units/states/portfolios/portfolios.component.html +++ b/src/app/units/states/portfolios/portfolios.component.html @@ -32,7 +32,15 @@ } @case ('staff-notes') { @if (selectedProject) { - +
      +

      Staff Notes for {{ selectedProject.student.name }}

      +

      + Use these notes for private staff discussions about the student. Students cannot + view them. +

      + + +
      } } @case ('portfolio') { From 5555e27db610aba47b385a095e71d7f72c26a68d Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:31:55 +1000 Subject: [PATCH 1131/1280] refactor: replace karma with vitest (#1274) * chore: replace karma with vitest and remove empty tests * ci: add test workflow * test: add test for welcome component * chore: restore default tests * chore: format * chore: add missing imports --- .github/workflows/test.yml | 19 + angular.json | 21 +- package-lock.json | 3162 ++++++++--------- package.json | 18 +- .../edit-profile.component.spec.ts | 18 +- .../teaching-period-list.component.spec.ts | 20 +- .../states/units/units.component.spec.ts | 39 + .../tii-action-log.component.spec.ts | 23 +- .../api/services/spec/campus.service.spec.ts | 23 +- .../api/services/spec/user.service.spec.ts | 146 +- src/app/api/services/tii.service.spec.ts | 1 + .../directives/drag-drop.directive.spec.ts | 1 + .../edit-profile-form.component.spec.ts | 26 +- src/app/common/f-chip/chip.component.spec.ts | 1 + .../file-viewer/file-viewer.component.spec.ts | 1 + .../common/footer/footer.component.spec.ts | 32 +- .../grade-icon/grade-icon.component.spec.ts | 67 +- .../common/header/header.component.spec.ts | 80 +- .../task-dropdown.component.spec.ts | 1 + .../unit-dropdown.component.spec.ts | 19 +- .../hero-sidebar.component.spec.ts | 1 + .../edit-profile-dialog.service.spec.ts | 1 + .../sidekiq-progress-modal.component.spec.ts | 27 +- .../pdf-viewer-panel.component.spec.ts | 26 +- .../common/pipes/humanized-date.pipe.spec.ts | 1 + src/app/common/pipes/marked.pipe.spec.ts | 1 + src/app/common/pipes/safe.pipe.spec.ts | 2 + .../project-progress-bar.component.spec.ts | 10 +- .../scorm-player.component.spec.ts | 25 +- .../services/alert-service.service.spec.ts | 1 + .../common/services/confetti.service.spec.ts | 1 + src/app/common/services/date.service.spec.ts | 1 + src/app/common/services/grade.service.spec.ts | 1 + .../status-icon/status-icon.component.spec.ts | 17 +- .../user-badge/user-badge.component.spec.ts | 10 +- .../privacy-policy/privacy-policy.spec.ts | 22 +- .../unauthorised.component.spec.ts | 12 +- .../accept-eula/accept-eula.component.spec.ts | 29 +- .../splash-screen.component.spec.ts | 34 +- .../task-assessment-card.component.spec.ts | 18 +- .../task-due-card.component.spec.ts | 10 +- .../task-status-card.component.spec.ts | 34 +- .../task-submission-card.component.spec.ts | 20 +- .../task-dashboard.component.spec.ts | 24 +- .../dashboard/selected-task.service.spec.ts | 13 +- .../staff-notes/staff-notes.component.spec.ts | 24 +- .../tutor-discussion.component.spec.ts | 43 +- .../states/sign-in/sign-in.component.spec.ts | 27 +- .../sessions/transition-hooks.service.spec.ts | 15 - .../grade-task-modal.component.spec.ts | 57 +- .../comment-bubble-action.component.spec.ts | 54 +- .../task-comments-viewer.component.spec.ts | 87 +- src/app/test.service.spec.ts | 1 + .../unit-student-enrolment-modal.spec.ts | 31 +- .../staff-task-list.component.spec.ts | 120 +- .../tasks/inbox/inbox.component.spec.ts | 38 +- .../task-sheet-view.component.spec.ts | 27 + .../unit-task-list.component.spec.ts | 22 +- src/app/welcome/welcome.component.spec.ts | 63 + src/karma-ci.conf.js | 32 - src/karma.conf.js | 40 - src/test.ts | 27 - src/tsconfig.spec.json | 6 +- src/vitest-setup.ts | 1 + 64 files changed, 2494 insertions(+), 2280 deletions(-) create mode 100644 .github/workflows/test.yml delete mode 100644 src/app/sessions/transition-hooks.service.spec.ts delete mode 100644 src/karma-ci.conf.js delete mode 100644 src/karma.conf.js delete mode 100644 src/test.ts create mode 100644 src/vitest-setup.ts diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000000..5a5dc93556 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,19 @@ +name: Test CI + +on: + push: + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + - name: Use Node.js 20 + uses: actions/setup-node@v4 + with: + node-version: 20 + cache: npm + - run: npm ci + - run: npm run test:ci diff --git a/angular.json b/angular.json index 2f517eeb5b..cbb09abdb1 100644 --- a/angular.json +++ b/angular.json @@ -93,6 +93,13 @@ "extractLicenses": false, "sourceMap": true }, + "testing": { + "aot": false, + "optimization": false, + "extractLicenses": false, + "sourceMap": true, + "polyfills": ["zone.js"] + }, "devcontainer": { "optimization": false, "extractLicenses": false, @@ -137,18 +144,12 @@ } }, "test": { - "builder": "@angular/build:karma", + "builder": "@angular/build:unit-test", "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", + "buildTarget": "doubtfire:build:testing", "tsConfig": "src/tsconfig.spec.json", - "karmaConfig": "src/karma.conf.js", - "styles": [], - "stylePreprocessorOptions": { - "includePaths": ["src"] - }, - "scripts": [], - "assets": ["src/favicon.ico", "src/assets", "src/manifest.webmanifest"] + "runner": "vitest", + "setupFiles": ["src/vitest-setup.ts"] } }, "lint": { diff --git a/package-lock.json b/package-lock.json index 0591296990..e8e4016114 100644 --- a/package-lock.json +++ b/package-lock.json @@ -65,7 +65,7 @@ "tslib": "^2.8.1", "typescript-eslint": "^8.12.0", "underscore.string": "2.3.3", - "zone.js": "~0.15.1" + "zone.js": "~0.16.2" }, "devDependencies": { "@angular-eslint/builder": "^21.4.0", @@ -84,8 +84,6 @@ "@types/canvas-confetti": "^1.6.0", "@types/d3": "^3.5.17", "@types/file-saver": "^2.0.1", - "@types/jasmine": "~6.0.0", - "@types/jasminewd2": "~2.0.3", "@types/lodash": "^4.14.115", "@types/node": "^20.9.0", "@typescript-eslint/eslint-plugin": "^8.60.1", @@ -100,23 +98,17 @@ "eslint-plugin-tailwindcss": "^3.18.3", "husky": "~8", "ip": "^2.0.1", - "jasmine-core": "~4.1.0", - "jasmine-spec-reporter": "~5.0.0", - "karma": "^6.3.4", - "karma-chrome-launcher": "~3.1.0", - "karma-coverage-istanbul-reporter": "~3.0.2", - "karma-jasmine": "~4.0.0", - "karma-jasmine-html-reporter": "^1.5.0", + "jsdom": "^29.1.1", "npm-run-all2": "^7.0", "postcss": "^8.5.10", "postcss-scss": "^0.1.7", "prettier": "^3.8.3", - "protractor": "~7.0.0", "sass": "^1.48.0", "tailwindcss": "~3.4.17", "ts-node": "~10.9", "typescript": "~5.9.3", - "underscore": "^1.8.3" + "underscore": "^1.8.3", + "vitest": "^4.1.8" }, "engines": { "node": ">=20.9.0" @@ -1001,6 +993,57 @@ "@angular/platform-browser-dynamic": "21.2.17" } }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, "node_modules/@babel/code-frame": { "version": "7.29.7", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", @@ -1294,12 +1337,27 @@ "node": ">=6.9.0" } }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, "node_modules/@colors/colors": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=0.1.90" } @@ -1767,6 +1825,146 @@ "@jridgewell/sourcemap-codec": "^1.4.10" } }, + "node_modules/@csstools/color-helpers": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.0.2.tgz", + "integrity": "sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.2.1.tgz", + "integrity": "sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.7.tgz", + "integrity": "sha512-CmjJFQTFQx/U/xNJhSjCQ0ilpesPmNQ8+eOUeM/+kDOVW33qsIjeOXc27vrQDdWVkf83ZSWwtg7kXSUvKDJ8cQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.0.2", + "@csstools/css-calc": "^3.2.1" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.5.tgz", + "integrity": "sha512-oNjBvzLq2GPZtJphCjLqXow/cHySHSgtxvKZb7OqSZ/xHgw6NWNhfad+6AB9cLeVm6eA9d/qMll3JdEHjy6M+A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, "node_modules/@ctrl/ngx-emoji-mart": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@ctrl/ngx-emoji-mart/-/ngx-emoji-mart-9.3.0.tgz", @@ -2408,6 +2606,24 @@ "node": "^20.19.0 || ^22.13.0 || >=24" } }, + "node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, "node_modules/@gar/promise-retry": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/@gar/promise-retry/-/promise-retry-1.0.3.tgz", @@ -5180,7 +5396,9 @@ "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/@standard-schema/spec": { "version": "1.1.0", @@ -5381,12 +5599,25 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, "node_modules/@types/cors": { "version": "2.8.19", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@types/node": "*" } @@ -5398,6 +5629,13 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/esrecurse": { "version": "4.3.1", "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", @@ -5417,23 +5655,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/jasmine": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@types/jasmine/-/jasmine-6.0.0.tgz", - "integrity": "sha512-18lgGsLmEh3VJk9eZ5wAjTISxdqzl6YOwu8UdMpolajN57QOCNbl+AbHUd+Yu9ItrsFdB+c8LSZSGNg8nHaguw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/jasminewd2": { - "version": "2.0.13", - "resolved": "https://registry.npmjs.org/@types/jasminewd2/-/jasminewd2-2.0.13.tgz", - "integrity": "sha512-aJ3wj8tXMpBrzQ5ghIaqMisD8C3FIrcO6sDKHqFbuqAsI7yOxj0fA7MrRCPLZHIVUjERIwsMmGn/vB0UQ9u0Hg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/jasmine": "*" - } - }, "node_modules/@types/jquery": { "version": "1.10.45", "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-1.10.45.tgz", @@ -5464,20 +5685,6 @@ "undici-types": "~6.21.0" } }, - "node_modules/@types/q": { - "version": "0.0.32", - "resolved": "https://registry.npmjs.org/@types/q/-/q-0.0.32.tgz", - "integrity": "sha512-qYi3YV9inU/REEfxwVcGZzbS3KG/Xs90lv0Pr+lDtuVjBPGd1A+eciXzVSaRvLify132BfcvhvEjeVahrUl0Ug==", - "dev": true, - "license": "MIT" - }, - "node_modules/@types/selenium-webdriver": { - "version": "3.0.26", - "resolved": "https://registry.npmjs.org/@types/selenium-webdriver/-/selenium-webdriver-3.0.26.tgz", - "integrity": "sha512-dyIGFKXfUFiwkMfNGn1+F6b80ZjR3uSYv1j6xVJSDlft5waZ2cwkHW4e7zNzvq7hiEackcgvBpmnXZrI1GltPg==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/trusted-types": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", @@ -5491,6 +5698,8 @@ "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@types/node": "*" } @@ -5766,6 +5975,126 @@ "vite": "^6.0.0 || ^7.0.0" } }, + "node_modules/@vitest/expect": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.8.tgz", + "integrity": "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.8.tgz", + "integrity": "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.8", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.8.tgz", + "integrity": "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.8.tgz", + "integrity": "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.8", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.8.tgz", + "integrity": "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.8", + "@vitest/utils": "4.1.8", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.8.tgz", + "integrity": "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.8.tgz", + "integrity": "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.8", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, "node_modules/@worktile/gantt": { "version": "21.0.0", "resolved": "https://registry.npmjs.org/@worktile/gantt/-/gantt-21.0.0.tgz", @@ -5848,16 +6177,6 @@ "node": ">=0.4.0" } }, - "node_modules/adm-zip": { - "version": "0.5.17", - "resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.5.17.tgz", - "integrity": "sha512-+Ut8d9LLqwEvHHJl1+PIHqoyDxFgVN847JTVM3Izi3xHDWPE4UtzzXysMZQs64DMcrJfBeS/uoEP4AD3HQHnQQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0" - } - }, "node_modules/agent-base": { "version": "7.1.4", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", @@ -6186,66 +6505,16 @@ "dev": true, "license": "MIT" }, - "node_modules/array-union": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-1.0.2.tgz", - "integrity": "sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng==", + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", "dev": true, "license": "MIT", - "dependencies": { - "array-uniq": "^1.0.1" - }, "engines": { - "node": ">=0.10.0" + "node": ">=12" } }, - "node_modules/array-uniq": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz", - "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/arrify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", - "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/asn1": { - "version": "0.2.6", - "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", - "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "safer-buffer": "~2.1.0" - } - }, - "node_modules/assert-plus": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", - "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", - "dev": true, - "license": "MIT" - }, "node_modules/autoprefixer": { "version": "6.7.7", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-6.7.7.tgz", @@ -6362,23 +6631,6 @@ "node": ">=0.10.0" } }, - "node_modules/aws-sign2": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", - "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/aws4": { - "version": "1.13.2", - "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.13.2.tgz", - "integrity": "sha512-lHe62zvbTB5eEABUVi/AwVh0ZKY9rMMDhmm+eeyuuUQbQ3+J+fONVQOZyj+DdrvD4BY33uYniyRJ4UJIaSKAfw==", - "dev": true, - "license": "MIT" - }, "node_modules/axobject-query": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", @@ -6404,12 +6656,37 @@ "node": ">= 0.6.0" } }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/base64id": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": "^4.5.0 || >= 5.9" } @@ -6427,16 +6704,6 @@ "node": ">=6.0.0" } }, - "node_modules/bcrypt-pbkdf": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", - "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "tweetnacl": "^0.14.3" - } - }, "node_modules/beasties": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.4.1.tgz", @@ -6458,6 +6725,16 @@ "node": ">=18.0.0" } }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, "node_modules/binary-extensions": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz", @@ -6471,20 +6748,35 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/blocking-proxy": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/blocking-proxy/-/blocking-proxy-1.0.1.tgz", - "integrity": "sha512-KE8NFMZr3mN2E0HcvCgRtX7DjhiIQrwle+nSVJVC/yqFb9+xznHl2ZcoBp2L9qzkI4t4cBFJ1efXF8Dwi132RA==", + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "minimist": "^1.2.0" - }, - "bin": { - "blocking-proxy": "built/lib/bin.js" + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" }, "engines": { - "node": ">=6.9.x" + "node": ">= 6" } }, "node_modules/body-parser": { @@ -6576,51 +6868,31 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, - "node_modules/browserstack": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/browserstack/-/browserstack-1.6.1.tgz", - "integrity": "sha512-GxtFjpIaKdbAyzHfFDKixKO8IBT7wR3NjbzrGc78nNs/Ciys9wU3/nBtsqsWv5nDSrdI5tz0peKuzCPuNXNUiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "https-proxy-agent": "^2.2.1" - } - }, - "node_modules/browserstack/node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/browserstack/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/browserstack/node_modules/https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" } }, "node_modules/buffer-from": { @@ -6831,19 +7103,20 @@ "license": "MIT" }, "node_modules/canvas": { - "version": "2.11.2", - "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", - "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-3.2.3.tgz", + "integrity": "sha512-PzE5nJZPz72YUAfo8oTp0u3fqqY7IzlTubneAihqDYAUcBk7ryeCmBbdJBEdaH0bptSOe2VT2Zwcb3UaFyaSWw==", + "dev": true, "hasInstallScript": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { - "@mapbox/node-pre-gyp": "^1.0.0", - "nan": "^2.17.0", - "simple-get": "^3.0.3" + "node-addon-api": "^7.0.0", + "prebuild-install": "^7.1.3" }, "engines": { - "node": ">=6" + "node": "^18.12.0 || >= 20.9.0" } }, "node_modules/canvas-confetti": { @@ -6856,12 +7129,24 @@ "url": "https://www.paypal.me/kirilvatev" } }, - "node_modules/caseless": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", - "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "node_modules/canvas/node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", "dev": true, - "license": "Apache-2.0" + "license": "MIT", + "optional": true, + "peer": true + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } }, "node_modules/chalk": { "version": "2.4.2", @@ -7093,29 +7378,6 @@ "dev": true, "license": "MIT" }, - "node_modules/colors": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz", - "integrity": "sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.1.90" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dev": true, - "license": "MIT", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, "node_modules/commander": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", @@ -7141,8 +7403,8 @@ "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "devOptional": true, - "license": "MIT" + "license": "MIT", + "optional": true }, "node_modules/concurrently": { "version": "3.6.1", @@ -7189,6 +7451,8 @@ "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "debug": "2.6.9", "finalhandler": "1.1.2", @@ -7205,6 +7469,8 @@ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "ms": "2.0.0" } @@ -7215,6 +7481,8 @@ "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 0.8" } @@ -7225,6 +7493,8 @@ "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "debug": "2.6.9", "encodeurl": "~1.0.2", @@ -7243,7 +7513,9 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/connect/node_modules/on-finished": { "version": "2.3.0", @@ -7251,6 +7523,8 @@ "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "ee-first": "1.1.1" }, @@ -7264,6 +7538,8 @@ "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 0.6" } @@ -7496,6 +7772,20 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/css-what": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-7.0.0.tgz", @@ -7527,7 +7817,9 @@ "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", "integrity": "sha512-GAj5FOq0Hd+RsCGVJxZuKaIDXDf3h6GQoNEjFgbLLI/trgtavwUbSnZ5pVfg27DVCaWjIohryS0JFwIJyT2cMg==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/d3": { "version": "3.5.17", @@ -7792,17 +8084,18 @@ "d3-selection": "2 - 3" } }, - "node_modules/dashdash": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", - "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", "dev": true, "license": "MIT", "dependencies": { - "assert-plus": "^1.0.0" + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" }, "engines": { - "node": ">=0.10" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/date-fns": { @@ -7821,6 +8114,8 @@ "integrity": "sha512-39BOQLs9ZjKh0/patS9nrT8wc3ioX3/eA/zgbKNopnF2wCqJEoxywwwElATYvRsXdnOxA/OQeQoFZ3rFjVajhg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=4.0" } @@ -7851,17 +8146,41 @@ "node": ">=0.10.0" } }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-6.0.0.tgz", + "integrity": "sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==", + "dev": true, "license": "MIT", "optional": true, + "peer": true, "dependencies": { - "mimic-response": "^2.0.0" + "mimic-response": "^3.1.0" }, "engines": { - "node": ">=8" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=4.0.0" } }, "node_modules/deep-is": { @@ -7870,74 +8189,21 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "license": "MIT" }, - "node_modules/del": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/del/-/del-2.2.2.tgz", - "integrity": "sha512-Z4fzpbIRjOu7lO5jCETSWoqUDVe0IPOlfugBsF6suen2LKDlVb4QZpKEM9P+buNJ4KI1eN7I083w/pbKUpsrWQ==", + "node_modules/delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", + "license": "MIT", + "optional": true + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", "dev": true, "license": "MIT", - "dependencies": { - "globby": "^5.0.0", - "is-path-cwd": "^1.0.0", - "is-path-in-cwd": "^1.0.0", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0", - "rimraf": "^2.2.8" - }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/del/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==", - "license": "MIT", - "optional": true - }, - "node_modules/depd": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", - "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.8" + "node": ">= 0.8" } }, "node_modules/destroy": { @@ -7946,6 +8212,8 @@ "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 0.8", "npm": "1.2.8000 || >= 1.4.16" @@ -7966,7 +8234,9 @@ "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", "integrity": "sha512-uJaamHkagcZtHPqCIHZxnFrXlunQXgBOsZSUOWwFw31QJCAbyTBoHMW75YOTur5ZNx8pIeAKgf6GWIgaqqiLhA==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/didyoumean": { "version": "1.2.2", @@ -8004,6 +8274,8 @@ "integrity": "sha512-Yra4DbvoW7/Z6LBN560ZwXMjoNOSAN2wRsKFGc4iBeso+mpIA6qj1vfdf9HpMaKAqG6wXTy+1SYEzmNpKXOSsQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "custom-event": "~1.0.0", "ent": "~2.2.0", @@ -8107,17 +8379,6 @@ "node": ">= 0.4" } }, - "node_modules/ecc-jsbn": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", - "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", - "dev": true, - "license": "MIT", - "dependencies": { - "jsbn": "~0.1.0", - "safer-buffer": "^2.1.0" - } - }, "node_modules/ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -8148,12 +8409,26 @@ "node": ">= 0.8" } }, + "node_modules/end-of-stream": { + "version": "1.4.5", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.5.tgz", + "integrity": "sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/engine.io": { "version": "6.6.8", "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.8.tgz", "integrity": "sha512-2agL3ueZhqxoVrfmntO8yuVj+uNSlIOnhykYHk3Cq0ShYPdUjjUiSJrQvXjq01I9jAuI0Zl2YO8Evv5Mqytm5g==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", @@ -8176,6 +8451,8 @@ "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=10.0.0" } @@ -8186,6 +8463,8 @@ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -8200,6 +8479,8 @@ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 0.6" } @@ -8210,6 +8491,8 @@ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "mime-db": "1.52.0" }, @@ -8223,6 +8506,8 @@ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 0.6" } @@ -8247,6 +8532,8 @@ "integrity": "sha512-kKvD1tO6BM+oK9HzCPpUdRb4vKFQY/FPTFmurMvh6LlN68VMrdj77w8yp51/kDbpkFOS9J8w5W6zIzgM2H8/hw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "call-bound": "^1.0.3", "es-errors": "^1.3.0", @@ -8330,6 +8617,13 @@ "node": ">= 0.4" } }, + "node_modules/es-module-lexer": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.1.0.tgz", + "integrity": "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ==", + "dev": true, + "license": "MIT" + }, "node_modules/es-object-atoms": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", @@ -8363,23 +8657,6 @@ "node": ">=0.4.0" } }, - "node_modules/es6-promise": { - "version": "4.2.8", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", - "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", - "dev": true, - "license": "MIT" - }, - "node_modules/es6-promisify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", - "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es6-promise": "^4.0.3" - } - }, "node_modules/esbuild": { "version": "0.27.3", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.27.3.tgz", @@ -8756,6 +9033,16 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -8780,7 +9067,9 @@ "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/eventsource": { "version": "3.0.7", @@ -8805,13 +9094,26 @@ "node": ">=18.0.0" } }, - "node_modules/exit": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", - "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "node_modules/expand-template": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/expand-template/-/expand-template-2.0.3.tgz", + "integrity": "sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==", + "dev": true, + "license": "(MIT OR WTFPL)", + "optional": true, + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/expect-type": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.3.0.tgz", + "integrity": "sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==", "dev": true, + "license": "Apache-2.0", "engines": { - "node": ">= 0.8.0" + "node": ">=12.0.0" } }, "node_modules/exponential-backoff": { @@ -8896,17 +9198,9 @@ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", "dev": true, - "license": "MIT" - }, - "node_modules/extsprintf": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", - "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/fast-deep-equal": { "version": "3.1.3", @@ -9107,6 +9401,8 @@ } ], "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=4.0" }, @@ -9125,54 +9421,6 @@ "node": ">=0.10.3" } }, - "node_modules/forever-agent": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", - "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, - "node_modules/form-data": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", - "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.6", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 0.12" - } - }, - "node_modules/form-data/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/form-data/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -9193,12 +9441,23 @@ "node": ">= 0.8" } }, + "node_modules/fs-constants": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", + "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/fs-extra": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "graceful-fs": "^4.2.0", "jsonfile": "^4.0.0", @@ -9225,8 +9484,8 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", - "devOptional": true, - "license": "ISC" + "license": "ISC", + "optional": true }, "node_modules/fsevents": { "version": "2.3.3", @@ -9401,16 +9660,6 @@ "node": ">= 0.4" } }, - "node_modules/getpass": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", - "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", - "dev": true, - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0" - } - }, "node_modules/git-raw-commits": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/git-raw-commits/-/git-raw-commits-5.0.1.tgz", @@ -9428,13 +9677,22 @@ "node": ">=18" } }, + "node_modules/github-from-package": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", + "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "fs.realpath": "^1.0.0", "inflight": "^1.0.4", @@ -9473,8 +9731,8 @@ "version": "1.1.15", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", - "devOptional": true, "license": "MIT", + "optional": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -9484,8 +9742,8 @@ "version": "3.1.5", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -9509,34 +9767,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globby": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/globby/-/globby-5.0.0.tgz", - "integrity": "sha512-HJRTIH2EeH44ka+LWig+EqT2ONSYpVlNfx6pyd592/VF1TbfljJ7elwie7oSwcViLGqOdWocSdu2txwBF9bjmQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-union": "^1.0.1", - "arrify": "^1.0.0", - "glob": "^7.0.3", - "object-assign": "^4.0.1", - "pify": "^2.0.0", - "pinkie-promise": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/globby/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/gopd": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", @@ -9557,55 +9787,6 @@ "dev": true, "license": "ISC" }, - "node_modules/har-schema": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", - "integrity": "sha512-Oqluz6zhGX8cyRaTQlFMPw80bSJVG2x/cFb8ZPhUILGgHka9SsokCCOQgpveePerqidZOrT14ipqfJb7ILcW5Q==", - "dev": true, - "license": "ISC", - "engines": { - "node": ">=4" - } - }, - "node_modules/har-validator": { - "version": "5.1.5", - "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.5.tgz", - "integrity": "sha512-nmT2T0lljbxdQZfspsno9hgrG3Uir6Ks5afism62poxqBM6sDnMEuPmzTq8XN0OEwqKLLdh1jQI3qyE66Nzb3w==", - "deprecated": "this library is no longer supported", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "^6.12.3", - "har-schema": "^2.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/har-validator/node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/har-validator/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true, - "license": "MIT" - }, "node_modules/has-ansi": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", @@ -9658,6 +9839,8 @@ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "has-symbols": "^1.0.3" }, @@ -9721,12 +9904,18 @@ "node": "20 || >=22" } }, - "node_modules/html-escaper": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", - "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } }, "node_modules/html2canvas": { "version": "1.0.0-rc.7", @@ -9813,6 +10002,8 @@ "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "eventemitter3": "^4.0.0", "follow-redirects": "^1.0.0", @@ -9836,22 +10027,6 @@ "node": ">= 14" } }, - "node_modules/http-signature": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", - "integrity": "sha512-CAbnr6Rz4CYQkLYUtSNXxQPUH2gK8f3iWexVlsnMeD+GjlsQ0Xsy1cOX+mN3dtxYomRy21CiOzU8Uhw6OwncEQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0", - "jsprim": "^1.2.2", - "sshpk": "^1.7.0" - }, - "engines": { - "node": ">=0.8", - "npm": ">=1.3.7" - } - }, "node_modules/https-proxy-agent": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", @@ -9899,6 +10074,29 @@ "url": "https://opencollective.com/express" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause", + "optional": true, + "peer": true + }, "node_modules/ignore": { "version": "7.0.5", "resolved": "https://registry.npmjs.org/ignore/-/ignore-7.0.5.tgz", @@ -10025,8 +10223,8 @@ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -10190,42 +10388,6 @@ "node": ">=8" } }, - "node_modules/is-path-cwd": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-path-cwd/-/is-path-cwd-1.0.0.tgz", - "integrity": "sha512-cnS56eR9SPAscL77ik76ATVqoPARTqPIVkMDVxRaWH06zT+6+CzIroYRJ0VVvm0Z1zfAvxvz9i/D3Ppjaqt5Nw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-in-cwd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-in-cwd/-/is-path-in-cwd-1.0.1.tgz", - "integrity": "sha512-FjV1RTW48E7CWM7eE/J2NJvAEEVektecDBVBE5Hh3nM1Jd0kvhHtX68Pr3xsDf857xt3Y4AkwVULK1Vku62aaQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-path-inside": "^1.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-path-inside": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-1.0.1.tgz", - "integrity": "sha512-qhsCR/Esx4U4hg/9I19OVUAJkGWtjRYHMRgUMZE2TDdj+Ag+kttZanLupfddNyglzz50cUlmWzUaI37GDfNx/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "path-is-inside": "^1.0.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/is-plain-obj": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", @@ -10239,6 +10401,13 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, "node_modules/is-promise": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/is-promise/-/is-promise-4.0.0.tgz", @@ -10252,6 +10421,8 @@ "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "call-bound": "^1.0.2", "gopd": "^1.2.0", @@ -10265,13 +10436,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/is-typedarray": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", - "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", - "dev": true, - "license": "MIT" - }, "node_modules/is-unicode-supported": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", @@ -10297,6 +10461,8 @@ "integrity": "sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 8.0.0" }, @@ -10310,13 +10476,6 @@ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, - "node_modules/isstream": { - "version": "0.1.2", - "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", - "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", - "dev": true, - "license": "MIT" - }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", @@ -10344,192 +10503,6 @@ "node": ">=10" } }, - "node_modules/istanbul-lib-report": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", - "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "make-dir": "^4.0.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/istanbul-lib-report/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-report/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/istanbul-lib-source-maps": { - "version": "3.0.6", - "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-3.0.6.tgz", - "integrity": "sha512-R47KzMtDJH6X4/YW9XTx+jrLnZnscW4VpNN+1PViSYTejLVPWv7oov+Duf8YQSPyVRUvueQqz1TcsC6mooZTXw==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "debug": "^4.1.1", - "istanbul-lib-coverage": "^2.0.5", - "make-dir": "^2.1.0", - "rimraf": "^2.6.3", - "source-map": "^0.6.1" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/istanbul-lib-coverage": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.5.tgz", - "integrity": "sha512-8aXznuEPCJvGnMSRft4udDRDtb1V3pkQkMMI5LI+6HuQz5oQ4J2UFn1H82raA3qJtyOLkkwVqICBQkjnGtn5mA==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/make-dir": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", - "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^4.0.1", - "semver": "^5.6.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/pify": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", - "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" - } - }, - "node_modules/istanbul-lib-source-maps/node_modules/source-map": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", - "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/istanbul-reports": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", - "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", - "dev": true, - "license": "BSD-3-Clause", - "dependencies": { - "html-escaper": "^2.0.0", - "istanbul-lib-report": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/jasmine": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine/-/jasmine-2.8.0.tgz", - "integrity": "sha512-KbdGQTf5jbZgltoHs31XGiChAPumMSY64OZMWLNYnEnMfG5uwGBhffePwuskexjT+/Jea/gU3qAU8344hNohSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "exit": "^0.1.2", - "glob": "^7.0.6", - "jasmine-core": "~2.8.0" - }, - "bin": { - "jasmine": "bin/jasmine.js" - } - }, - "node_modules/jasmine-core": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-4.1.1.tgz", - "integrity": "sha512-lmUfT5XcK9KKvt3lLYzn93hc4MGzlUBowExFVgzbSW0ZCrdeyS574dfsyfRhxbg81Wj4gk+RxUiTnj7KBfDA1g==", - "dev": true, - "license": "MIT" - }, - "node_modules/jasmine-spec-reporter": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/jasmine-spec-reporter/-/jasmine-spec-reporter-5.0.2.tgz", - "integrity": "sha512-6gP1LbVgJ+d7PKksQBc2H0oDGNRQI3gKUsWlswKaQ2fif9X5gzhQcgM5+kiJGCQVurOG09jqNhk7payggyp5+g==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "colors": "1.4.0" - } - }, - "node_modules/jasmine/node_modules/jasmine-core": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-2.8.0.tgz", - "integrity": "sha512-SNkOkS+/jMZvLhuSx1fjhcNWUC/KG6oVyFUGkSBEr9n1axSNduWU8GlI7suaHXr4yxjet6KjrUZxUTE5WzzWwQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/jasminewd2": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/jasminewd2/-/jasminewd2-2.2.0.tgz", - "integrity": "sha512-Rn0nZe4rfDhzA63Al3ZGh0E+JTmM6ESZYXJGKuqKGZObsAB9fwXPD03GjtIEvJBDOhN94T5MzbwZSqzFHSQPzg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6.9.x" - } - }, "node_modules/javascript-natural-sort": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/javascript-natural-sort/-/javascript-natural-sort-0.7.1.tgz", @@ -10600,12 +10573,79 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/jsbn": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", - "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "node_modules/jsdom": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.1", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/lru-cache": { + "version": "11.5.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", + "integrity": "sha512-RPimw/7aMdv2oqRrxKwvZXcPfwBrn/JZ2xYcY9Hus/6LaS3VOAKVWKWgNLCFSiOm1ESXinjsDlidVU7JlnCN2A==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jsdom/node_modules/tough-cookie": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.1.tgz", + "integrity": "sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/jsdom/node_modules/undici": { + "version": "7.27.2", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.27.2.tgz", + "integrity": "sha512-uZsKNuzQxDMUY6M3pIMvy5tvlGmtq8XJ2oLAkfRKGNu+1VQAIvLy2xIVG5ATZl5wDXl/tddByAWCizRbOme+TA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } }, "node_modules/jsesc": { "version": "3.1.0", @@ -10643,13 +10683,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/json-schema": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", - "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", - "dev": true, - "license": "(AFL-2.1 OR BSD-3-Clause)" - }, "node_modules/json-schema-traverse": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", @@ -10670,13 +10703,6 @@ "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", "license": "MIT" }, - "node_modules/json-stringify-safe": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", - "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", - "dev": true, - "license": "ISC" - }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -10703,6 +10729,8 @@ "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "optionalDependencies": { "graceful-fs": "^4.1.6" } @@ -10717,22 +10745,6 @@ ], "license": "MIT" }, - "node_modules/jsprim": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.2.tgz", - "integrity": "sha512-P2bSOMAc/ciLz6DzgjVlGJP9+BrJWu5UDGK70C2iweC5QBIeFf0ZXRvGjEj2uYgrY2MkAAhsSWHDWlFtEroZWw==", - "dev": true, - "license": "MIT", - "dependencies": { - "assert-plus": "1.0.0", - "extsprintf": "1.3.0", - "json-schema": "0.4.0", - "verror": "1.10.0" - }, - "engines": { - "node": ">=0.6.0" - } - }, "node_modules/jszip": { "version": "3.10.1", "resolved": "https://registry.npmjs.org/jszip/-/jszip-3.10.1.tgz", @@ -10751,6 +10763,8 @@ "integrity": "sha512-LrtUxbdvt1gOpo3gxG+VAJlJAEMhbWlM4YrFQgql98FwF7+K8K12LYO4hnDdUkNjeztYrOXEMqgTajSWgmtI/w==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@colors/colors": "1.5.0", "body-parser": "^1.19.0", @@ -10784,111 +10798,14 @@ "node": ">= 10" } }, - "node_modules/karma-chrome-launcher": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/karma-chrome-launcher/-/karma-chrome-launcher-3.1.1.tgz", - "integrity": "sha512-hsIglcq1vtboGPAN+DGCISCFOxW+ZVnIqhDQcCMqqCp+4dmJ0Qpq5QAjkbA0X2L9Mi6OBkHi2Srrbmm7pUKkzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "which": "^1.2.1" - } - }, - "node_modules/karma-chrome-launcher/node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "which": "bin/which" - } - }, - "node_modules/karma-coverage-istanbul-reporter": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/karma-coverage-istanbul-reporter/-/karma-coverage-istanbul-reporter-3.0.3.tgz", - "integrity": "sha512-wE4VFhG/QZv2Y4CdAYWDbMmcAHeS926ZIji4z+FkB2aF/EposRb6DP6G5ncT/wXhqUfAb/d7kZrNKPonbvsATw==", - "dev": true, - "license": "MIT", - "dependencies": { - "istanbul-lib-coverage": "^3.0.0", - "istanbul-lib-report": "^3.0.0", - "istanbul-lib-source-maps": "^3.0.6", - "istanbul-reports": "^3.0.2", - "minimatch": "^3.0.4" - }, - "funding": { - "url": "https://github.com/sponsors/mattlewis92" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/brace-expansion": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.15.tgz", - "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/karma-coverage-istanbul-reporter/node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/karma-jasmine": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/karma-jasmine/-/karma-jasmine-4.0.2.tgz", - "integrity": "sha512-ggi84RMNQffSDmWSyyt4zxzh2CQGwsxvYYsprgyR1j8ikzIduEdOlcLvXjZGwXG/0j41KUXOWsUCBfbEHPWP9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "jasmine-core": "^3.6.0" - }, - "engines": { - "node": ">= 10" - }, - "peerDependencies": { - "karma": "*" - } - }, - "node_modules/karma-jasmine-html-reporter": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/karma-jasmine-html-reporter/-/karma-jasmine-html-reporter-1.7.0.tgz", - "integrity": "sha512-pzum1TL7j90DTE86eFt48/s12hqwQuiD+e5aXx2Dc9wDEn2LfGq6RoAxEZZjFiN0RDSCOnosEKRZWxbQ+iMpQQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "jasmine-core": ">=3.8", - "karma": ">=0.9", - "karma-jasmine": ">=1.1" - } - }, - "node_modules/karma-jasmine/node_modules/jasmine-core": { - "version": "3.99.1", - "resolved": "https://registry.npmjs.org/jasmine-core/-/jasmine-core-3.99.1.tgz", - "integrity": "sha512-Hu1dmuoGcZ7AfyynN3LsfruwMbxMALMka+YtZeGoLuDEySVmVAPaonkNoBRIw/ectu8b9tVQCJNgp4a4knp+tg==", - "dev": true, - "license": "MIT" - }, - "node_modules/karma/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/karma/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -10899,6 +10816,8 @@ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "color-convert": "^2.0.1" }, @@ -10915,6 +10834,8 @@ "integrity": "sha512-3grm+/2tUOvu2cjJkvsIxrv/wVpfXQW4PsQHYm7yk4vfpu7Ekl6nEsYBoJUL6qDwZUx8wUhQ8tR2qz+ad9c9OA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "bytes": "~3.1.2", "content-type": "~1.0.5", @@ -10940,6 +10861,8 @@ "integrity": "sha512-EwOCDEex4quD37XhqM3omwtMoJjr//isUZz1JopUNWms+4Z2ViyM/k1YIRePpoVNnQhENnxtFjLaxNHrT7xIUg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -10951,6 +10874,8 @@ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "anymatch": "~3.1.2", "braces": "~3.0.2", @@ -10976,6 +10901,8 @@ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", "dev": true, "license": "ISC", + "optional": true, + "peer": true, "dependencies": { "string-width": "^4.2.0", "strip-ansi": "^6.0.0", @@ -10988,6 +10915,8 @@ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "color-name": "~1.1.4" }, @@ -11000,7 +10929,9 @@ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/karma/node_modules/debug": { "version": "2.6.9", @@ -11008,6 +10939,8 @@ "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "ms": "2.0.0" } @@ -11018,6 +10951,8 @@ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", "dev": true, "license": "ISC", + "optional": true, + "peer": true, "dependencies": { "is-glob": "^4.0.1" }, @@ -11031,6 +10966,8 @@ "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "safer-buffer": ">= 2.1.2 < 3" }, @@ -11044,6 +10981,8 @@ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -11054,6 +10993,8 @@ "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 0.6" } @@ -11064,6 +11005,8 @@ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 0.6" } @@ -11074,6 +11017,8 @@ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "mime-db": "1.52.0" }, @@ -11087,6 +11032,8 @@ "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", "dev": true, "license": "ISC", + "optional": true, + "peer": true, "dependencies": { "brace-expansion": "^1.1.7" }, @@ -11099,7 +11046,9 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/karma/node_modules/picomatch": { "version": "2.3.2", @@ -11107,6 +11056,8 @@ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=8.6" }, @@ -11120,6 +11071,8 @@ "integrity": "sha512-s4VSOf6yN0rvbRZGxs8Om5CWj6seneMwK3oDb4lWDH0UPhWcxwOWw5+qk24bxq87szX1ydrwylIOp2uG1ojUpA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "bytes": "~3.1.2", "http-errors": "~2.0.1", @@ -11136,6 +11089,8 @@ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "picomatch": "^2.2.1" }, @@ -11149,6 +11104,8 @@ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", "dev": true, "license": "BSD-3-Clause", + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -11159,6 +11116,8 @@ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "emoji-regex": "^8.0.0", "is-fullwidth-code-point": "^3.0.0", @@ -11174,6 +11133,8 @@ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "ansi-regex": "^5.0.1" }, @@ -11187,6 +11148,8 @@ "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "media-typer": "0.3.0", "mime-types": "~2.1.24" @@ -11201,6 +11164,8 @@ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "ansi-styles": "^4.0.0", "string-width": "^4.1.0", @@ -11219,6 +11184,8 @@ "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "cliui": "^7.0.2", "escalade": "^3.1.1", @@ -11238,6 +11205,8 @@ "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", "dev": true, "license": "ISC", + "optional": true, + "peer": true, "engines": { "node": ">=10" } @@ -11595,6 +11564,8 @@ "integrity": "sha512-1somDdy9sChrr9/f4UlzhdaGfDR2c/SaD2a4T7qEkG4jTS57/B3qmnjLYePwQ8cqWnUHZI0iAKxMBpCZICiZ2g==", "dev": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", @@ -11632,22 +11603,6 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/make-dir": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", - "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.5.3" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/make-error": { "version": "1.3.6", "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", @@ -11701,6 +11656,13 @@ "node": ">= 0.4" } }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, "node_modules/media-typer": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", @@ -11789,6 +11751,8 @@ "integrity": "sha512-USPkMeET31rOMiarsBNIHZKLGgvKc/LrjofAnBlOttf5ajRvqiRA8QsenbcooctK6d6Ts6aqZXBA+XbkKthiQg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "bin": { "mime": "cli.js" }, @@ -11837,13 +11801,15 @@ } }, "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-3.1.0.tgz", + "integrity": "sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==", + "dev": true, "license": "MIT", "optional": true, + "peer": true, "engines": { - "node": ">=8" + "node": ">=10" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -12014,6 +11980,8 @@ "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "minimist": "^1.2.6" }, @@ -12021,6 +11989,15 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/mlly": { "version": "1.8.2", "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.8.2.tgz", @@ -12182,6 +12159,15 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, + "node_modules/napi-build-utils": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/napi-build-utils/-/napi-build-utils-2.0.0.tgz", + "integrity": "sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true + }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -12291,6 +12277,21 @@ "@angular/core": ">=19.0.0" } }, + "node_modules/node-abi": { + "version": "3.92.0", + "resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.92.0.tgz", + "integrity": "sha512-KdHvFWZjEKDf0cakgFjebl371GPsISX2oZHcuyKqM7DtogIsHrqKeLTo8wBHxaXRAQlY2PsPlZmfo+9ZCxEREQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/node-addon-api": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-6.1.0.tgz", @@ -12320,6 +12321,31 @@ } } }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT", + "optional": true + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause", + "optional": true + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "optional": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/node-gyp": { "version": "12.4.0", "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-12.4.0.tgz", @@ -12684,16 +12710,6 @@ "d3": "^3.4.4" } }, - "node_modules/oauth-sign": { - "version": "0.9.0", - "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", - "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": "*" - } - }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -12727,6 +12743,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/obug": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.3.tgz", + "integrity": "sha512-9miFgM2OFba7hB+pRgvtV84pYTBaoTHohvmIgiRt6dRIzbwEOIaNaP+dIlGs2fNFoB0SeISs0Jz5WFVRid6Xyg==", + "dev": true, + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], + "license": "MIT", + "engines": { + "node": ">=12.20.0" + } + }, "node_modules/on-finished": { "version": "2.4.1", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", @@ -12827,16 +12857,6 @@ "license": "MIT", "optional": true }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -13071,19 +13091,12 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "devOptional": true, "license": "MIT", + "optional": true, "engines": { "node": ">=0.10.0" } }, - "node_modules/path-is-inside": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/path-is-inside/-/path-is-inside-1.0.2.tgz", - "integrity": "sha512-DUWJr3+ULp4zXmol/SZkFf3JGsS9/SIv+Y3Rt93/UjPpDpklB5f1er4O3POIbUuUJ3FXgqte2Q7SrU6zAqwk8w==", - "dev": true, - "license": "(WTFPL OR MIT)" - }, "node_modules/path-key": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", @@ -13181,76 +13194,100 @@ "path2d-polyfill": "^2.0.1" } }, - "node_modules/performance-now": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", - "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", - "dev": true, - "license": "MIT" - }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", - "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", + "node_modules/pdfjs-dist/node_modules/canvas": { + "version": "2.11.2", + "resolved": "https://registry.npmjs.org/canvas/-/canvas-2.11.2.tgz", + "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", + "hasInstallScript": true, "license": "MIT", - "engines": { - "node": ">=12" + "optional": true, + "dependencies": { + "@mapbox/node-pre-gyp": "^1.0.0", + "nan": "^2.17.0", + "simple-get": "^3.0.3" }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "engines": { + "node": ">=6" } }, - "node_modules/pidtree": { - "version": "0.6.1", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.1.tgz", - "integrity": "sha512-e0F9AOF1JMrCfBsyJOwU9lNvQ0WtXTq0j/4jk0BQ5JSI9VAybPXmDpPRw/2FQ3e5d3ZFN1mLh7jW99m/jjaptw==", - "dev": true, + "node_modules/pdfjs-dist/node_modules/decompress-response": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/decompress-response/-/decompress-response-4.2.1.tgz", + "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", "license": "MIT", - "bin": { - "pidtree": "bin/pidtree.js" + "optional": true, + "dependencies": { + "mimic-response": "^2.0.0" }, "engines": { - "node": ">=0.10" + "node": ">=8" } }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", - "dev": true, + "node_modules/pdfjs-dist/node_modules/mimic-response": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-response/-/mimic-response-2.1.0.tgz", + "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", "license": "MIT", + "optional": true, "engines": { - "node": ">=4" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/pinkie": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", - "integrity": "sha512-MnUuEycAemtSaeFSjXKW/aroV7akBbY+Sv+RkyqFjgAe73F+MR0TBWKBRDkmfWq/HiFmdavfZ1G7h4SPZXaCSg==", + "node_modules/pdfjs-dist/node_modules/simple-get": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", + "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "license": "MIT", + "optional": true, + "dependencies": { + "decompress-response": "^4.2.0", + "once": "^1.3.1", + "simple-concat": "^1.0.0" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", + "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/pinkie-promise": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", - "integrity": "sha512-0Gni6D4UcLTbv9c57DfxDGdr41XfgUjqWZu492f0cIGr16zDU06BWP/RAEvOuo7CQ0CNjHaLlM59YJJFm3NWlw==", + "node_modules/pidtree": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.6.1.tgz", + "integrity": "sha512-e0F9AOF1JMrCfBsyJOwU9lNvQ0WtXTq0j/4jk0BQ5JSI9VAybPXmDpPRw/2FQ3e5d3ZFN1mLh7jW99m/jjaptw==", "dev": true, "license": "MIT", - "dependencies": { - "pinkie": "^2.0.0" + "bin": { + "pidtree": "bin/pidtree.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=0.10" + } + }, + "node_modules/pify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", + "integrity": "sha512-C3FsVNH1udSEX48gGX1xfvwTWfsYWj5U+8/uK15BGzIGrKoUpghX8hWZwa/OFnakBiiVNmBvemTJR5mcy7iPcg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" } }, "node_modules/pirates": { @@ -13613,6 +13650,36 @@ "dev": true, "license": "MIT" }, + "node_modules/prebuild-install": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/prebuild-install/-/prebuild-install-7.1.3.tgz", + "integrity": "sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==", + "deprecated": "No longer maintained. Please contact the author of the relevant native addon; alternatives are available.", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "detect-libc": "^2.0.0", + "expand-template": "^2.0.3", + "github-from-package": "0.0.0", + "minimist": "^1.2.3", + "mkdirp-classic": "^0.5.3", + "napi-build-utils": "^2.0.0", + "node-abi": "^3.3.0", + "pump": "^3.0.0", + "rc": "^1.2.7", + "simple-get": "^4.0.0", + "tar-fs": "^2.0.0", + "tunnel-agent": "^0.6.0" + }, + "bin": { + "prebuild-install": "bin.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/prelude-ls": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", @@ -13678,302 +13745,7 @@ "retry": "^0.12.0" }, "engines": { - "node": ">=10" - } - }, - "node_modules/protractor": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/protractor/-/protractor-7.0.0.tgz", - "integrity": "sha512-UqkFjivi4GcvUQYzqGYNe0mLzfn5jiLmO8w9nMhQoJRLhy2grJonpga2IWhI6yJO30LibWXJJtA4MOIZD2GgZw==", - "deprecated": "We have news to share - Protractor is deprecated and will reach end-of-life by Summer 2023. To learn more and find out about other options please refer to this post on the Angular blog. Thank you for using and contributing to Protractor. https://goo.gle/state-of-e2e-in-angular", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/q": "^0.0.32", - "@types/selenium-webdriver": "^3.0.0", - "blocking-proxy": "^1.0.0", - "browserstack": "^1.5.1", - "chalk": "^1.1.3", - "glob": "^7.0.3", - "jasmine": "2.8.0", - "jasminewd2": "^2.1.0", - "q": "1.4.1", - "saucelabs": "^1.5.0", - "selenium-webdriver": "3.6.0", - "source-map-support": "~0.4.0", - "webdriver-js-extender": "2.1.0", - "webdriver-manager": "^12.1.7", - "yargs": "^15.3.1" - }, - "bin": { - "protractor": "bin/protractor", - "webdriver-manager": "bin/webdriver-manager" - }, - "engines": { - "node": ">=10.13.x" - } - }, - "node_modules/protractor/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/protractor/node_modules/cliui/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/cliui/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-try": "^2.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/protractor/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/source-map-support": { - "version": "0.4.18", - "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.4.18.tgz", - "integrity": "sha512-try0/JqxPLF9nOjvSta7tVondkP5dwgyLDjVoyMDlmjugT2lRZ1OfsrYTkCd2hkDnJTKRbO/Rl3orm8vlsUzbA==", - "dev": true, - "license": "MIT", - "dependencies": { - "source-map": "^0.5.6" - } - }, - "node_modules/protractor/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/string-width/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/string-width/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/protractor/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/protractor/node_modules/y18n": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", - "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", - "dev": true, - "license": "ISC" - }, - "node_modules/protractor/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/protractor/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" + "node": ">=10" } }, "node_modules/proxy-addr": { @@ -13990,27 +13762,17 @@ "node": ">= 0.10" } }, - "node_modules/psl": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/psl/-/psl-1.15.0.tgz", - "integrity": "sha512-JZd3gMVBAVQkSs6HdNZo9Sdo0LNcQeMNP3CozBJb3JYC/QUYZTnKxP+f8oWRX4rHP5EurWxqAHTSwUCjlNKa1w==", + "node_modules/pump": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.4.tgz", + "integrity": "sha512-VS7sjc6KR7e1ukRFhQSY5LM2uBWAUPiOPa/A3mkKmiMwSmRFUITt0xuj+/lesgnCv+dPIEYlkzrcyXgquIHMcA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { - "punycode": "^2.3.1" - }, - "funding": { - "url": "https://github.com/sponsors/lupomontero" - } - }, - "node_modules/psl/node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" + "end-of-stream": "^1.1.0", + "once": "^1.3.1" } }, "node_modules/punycode": { @@ -14018,19 +13780,9 @@ "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", "dev": true, - "license": "MIT" - }, - "node_modules/q": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/q/-/q-1.4.1.tgz", - "integrity": "sha512-/CdEdaw49VZVmyIDGUQKDDT53c7qBkO6g5CefWz91Ae+l4+cRtcDYwMTXh6me4O8TMldeGHG3N2Bl84V78Ywbg==", - "deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)", - "dev": true, "license": "MIT", - "engines": { - "node": ">=0.6.0", - "teleport": ">=0.2.0" - } + "optional": true, + "peer": true }, "node_modules/qjobs": { "version": "1.2.0", @@ -14038,6 +13790,8 @@ "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=0.9" } @@ -14287,6 +14041,45 @@ "node": ">= 0.10" } }, + "node_modules/rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "license": "(BSD-2-Clause OR MIT OR Apache-2.0)", + "optional": true, + "peer": true, + "dependencies": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "bin": { + "rc": "cli.js" + } + }, + "node_modules/rc/node_modules/ini": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", + "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true + }, + "node_modules/rc/node_modules/strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/read-cache": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", @@ -14392,72 +14185,6 @@ "dev": true, "license": "Apache-2.0" }, - "node_modules/request": { - "version": "2.88.2", - "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", - "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", - "deprecated": "request has been deprecated, see https://github.com/request/request/issues/3142", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "aws-sign2": "~0.7.0", - "aws4": "^1.8.0", - "caseless": "~0.12.0", - "combined-stream": "~1.0.6", - "extend": "~3.0.2", - "forever-agent": "~0.6.1", - "form-data": "~2.3.2", - "har-validator": "~5.1.3", - "http-signature": "~1.2.0", - "is-typedarray": "~1.0.0", - "isstream": "~0.1.2", - "json-stringify-safe": "~5.0.1", - "mime-types": "~2.1.19", - "oauth-sign": "~0.9.0", - "performance-now": "^2.1.0", - "qs": "~6.5.2", - "safe-buffer": "^5.1.2", - "tough-cookie": "~2.5.0", - "tunnel-agent": "^0.6.0", - "uuid": "^3.3.2" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/request/node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/request/node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/request/node_modules/qs": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.5.tgz", - "integrity": "sha512-mzR4sElr1bfCaPJe7m8ilJ6ZXdDaGoObcYR0ZHSsktM/Lt21MVHj5De30GQH2eiZ1qGRTO7LCAzQsUeXTNexWQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.6" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -14488,7 +14215,9 @@ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==", "dev": true, - "license": "MIT" + "license": "MIT", + "optional": true, + "peer": true }, "node_modules/resolve": { "version": "1.22.12", @@ -14571,8 +14300,8 @@ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", "deprecated": "Rimraf versions prior to v4 are no longer supported", - "devOptional": true, "license": "ISC", + "optional": true, "dependencies": { "glob": "^7.1.3" }, @@ -14728,6 +14457,8 @@ "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", @@ -14768,106 +14499,17 @@ "@parcel/watcher": "^2.4.1" } }, - "node_modules/saucelabs": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/saucelabs/-/saucelabs-1.5.0.tgz", - "integrity": "sha512-jlX3FGdWvYf4Q3LFfFWS1QvPg3IGCGWxIc8QBFdPTbpTJnt/v17FHXYVAn7C8sHf1yUXo2c7yIM0isDryfYtHQ==", - "dev": true, - "dependencies": { - "https-proxy-agent": "^2.2.1" - }, - "engines": { - "node": "*" - } - }, - "node_modules/saucelabs/node_modules/agent-base": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz", - "integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es6-promisify": "^5.0.0" - }, - "engines": { - "node": ">= 4.0.0" - } - }, - "node_modules/saucelabs/node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/saucelabs/node_modules/https-proxy-agent": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz", - "integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==", - "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^4.3.0", - "debug": "^3.1.0" - }, - "engines": { - "node": ">= 4.5.0" - } - }, - "node_modules/sax": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/sax/-/sax-1.6.0.tgz", - "integrity": "sha512-6R3J5M4AcbtLUdZmRv2SygeVaM7IhrLXu9BmnOGmmACak8fiUtOsYNWUS4uK7upbmHIBbLBeFeI//477BKLBzA==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=11.0.0" - } - }, - "node_modules/selenium-webdriver": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/selenium-webdriver/-/selenium-webdriver-3.6.0.tgz", - "integrity": "sha512-WH7Aldse+2P5bbFBO4Gle/nuQOdVwpHMTL6raL3uuBj/vPG07k6uzt3aiahu352ONBr5xXh0hDlM3LhtXPOC4Q==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "jszip": "^3.1.3", - "rimraf": "^2.5.4", - "tmp": "0.0.30", - "xml2js": "^0.4.17" - }, - "engines": { - "node": ">= 6.9.0" - } - }, - "node_modules/selenium-webdriver/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", "dev": true, "license": "ISC", "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/selenium-webdriver/node_modules/tmp": { - "version": "0.0.30", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.30.tgz", - "integrity": "sha512-HXdTB7lvMwcb55XFfrTM8CPr/IYREk4hVBFaQ4b/6nInrluSL86hfHm7vu0luYKCfyBZp2trCjpc8caC3vVM3w==", - "dev": true, - "license": "MIT", - "dependencies": { - "os-tmpdir": "~1.0.1" + "xmlchars": "^2.2.0" }, "engines": { - "node": ">=0.4.0" + "node": ">=v12.22.7" } }, "node_modules/semver": { @@ -15241,6 +14883,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, "node_modules/signal-exit": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", @@ -15294,13 +14943,29 @@ "optional": true }, "node_modules/simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/simple-get/-/simple-get-4.0.1.tgz", + "integrity": "sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], "license": "MIT", "optional": true, + "peer": true, "dependencies": { - "decompress-response": "^4.2.0", + "decompress-response": "^6.0.0", "once": "^1.3.1", "simple-concat": "^1.0.0" } @@ -15352,6 +15017,8 @@ "integrity": "sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", @@ -15371,6 +15038,8 @@ "integrity": "sha512-e0LyK91f3cUxTmv95/KzoLg47+zF+s/sbxRGDNsyG4dmIP8ZSX8ax6byOxfJXeNNtS/8AZlfD+uP7gBeR7DLlg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "debug": "~4.4.1", "ws": "~8.20.1" @@ -15382,6 +15051,8 @@ "integrity": "sha512-asJqbVBDsBCJx0pTqw3WfesSY0iRX+2xzWEWzrpcH7L6fLzrhyF8WPI8UaeM4YCuDfpwA/cgsdugMsmtz8EJeg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "@socket.io/component-emitter": "~3.1.0", "debug": "~4.4.1" @@ -15396,6 +15067,8 @@ "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "mime-types": "~2.1.34", "negotiator": "0.6.3" @@ -15410,6 +15083,8 @@ "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 0.6" } @@ -15420,6 +15095,8 @@ "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "mime-db": "1.52.0" }, @@ -15433,6 +15110,8 @@ "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 0.6" } @@ -15561,32 +15240,6 @@ "dev": true, "license": "CC0-1.0" }, - "node_modules/sshpk": { - "version": "1.18.0", - "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.18.0.tgz", - "integrity": "sha512-2p2KJZTSqQ/I3+HX42EpYOa2l3f8Erv8MWKsy2I9uf4wA7yFIkXRffYdsx86y6z4vHtV8u7g+pPlr8/4ouAxsQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "asn1": "~0.2.3", - "assert-plus": "^1.0.0", - "bcrypt-pbkdf": "^1.0.0", - "dashdash": "^1.12.0", - "ecc-jsbn": "~0.1.1", - "getpass": "^0.1.1", - "jsbn": "~0.1.0", - "safer-buffer": "^2.0.2", - "tweetnacl": "~0.14.0" - }, - "bin": { - "sshpk-conv": "bin/sshpk-conv", - "sshpk-sign": "bin/sshpk-sign", - "sshpk-verify": "bin/sshpk-verify" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/ssri": { "version": "13.0.1", "resolved": "https://registry.npmjs.org/ssri/-/ssri-13.0.1.tgz", @@ -15600,6 +15253,13 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -15610,6 +15270,13 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", + "dev": true, + "license": "MIT" + }, "node_modules/stdin-discarder": { "version": "0.3.2", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.3.2.tgz", @@ -15629,6 +15296,8 @@ "integrity": "sha512-KFxaM7XT+irxvdqSP1LGLgNWbYN7ay5owZ3r/8t77p+EtSUAfUgtl7be3xtqtOmGUl9K9YPO2ca8133RlTjvKw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "date-format": "^4.0.14", "debug": "^4.3.4", @@ -15762,6 +15431,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, "node_modules/synckit": { "version": "0.11.13", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.13.tgz", @@ -15936,7 +15612,67 @@ "yallist": "^5.0.0" }, "engines": { - "node": ">=18" + "node": ">=18" + } + }, + "node_modules/tar-fs": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/tar-fs/-/tar-fs-2.1.4.tgz", + "integrity": "sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "chownr": "^1.1.1", + "mkdirp-classic": "^0.5.2", + "pump": "^3.0.0", + "tar-stream": "^2.1.4" + } + }, + "node_modules/tar-fs/node_modules/chownr": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz", + "integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true + }, + "node_modules/tar-stream": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz", + "integrity": "sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "bl": "^4.0.3", + "end-of-stream": "^1.4.1", + "fs-constants": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tar-stream/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" } }, "node_modules/tar/node_modules/yallist": { @@ -15972,6 +15708,13 @@ "node": ">=0.8" } }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, "node_modules/tinyexec": { "version": "1.2.4", "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.2.4.tgz", @@ -15998,12 +15741,44 @@ "url": "https://github.com/sponsors/SuperchupuDev" } }, + "node_modules/tinyrainbow": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.0.tgz", + "integrity": "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.2.tgz", + "integrity": "sha512-kCwffuaH8ntKtygnWe1b4BJKWiCUH30n5KfoTr6IchcXOwR7chAOFJxFrH3vjANafUYrIA4a7SDL+nn7SiR4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.2" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.2.tgz", + "integrity": "sha512-nwEyF4vl4RSJjwSjBUmOSxc3BFPoIFdlRthJ6e+5v9P3bHNsoD06UjuqMUspqp7vsEZ1beaHi1km+optiE17yA==", + "dev": true, + "license": "MIT" + }, "node_modules/tmp": { "version": "0.2.7", "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.7.tgz", "integrity": "sha512-e0votIpp4Uo2AJYSzVHV6xCcawuiez3DzqDAbrTc3YxBkplN6e+dM13ZeIcZnDg/QpSuU2zfZ3rzwY8ukEnaXw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=14.14" } @@ -16031,21 +15806,20 @@ "node": ">=0.6" } }, - "node_modules/tough-cookie": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", - "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", "dev": true, - "license": "BSD-3-Clause", + "license": "MIT", "dependencies": { - "psl": "^1.1.28", - "punycode": "^2.1.1" + "punycode": "^2.3.1" }, "engines": { - "node": ">=0.8" + "node": ">=20" } }, - "node_modules/tough-cookie/node_modules/punycode": { + "node_modules/tr46/node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", @@ -16055,13 +15829,6 @@ "node": ">=6" } }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", - "license": "MIT", - "optional": true - }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -16178,6 +15945,8 @@ "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", "dev": true, "license": "Apache-2.0", + "optional": true, + "peer": true, "dependencies": { "safe-buffer": "^5.0.1" }, @@ -16185,13 +15954,6 @@ "node": "*" } }, - "node_modules/tweetnacl": { - "version": "0.14.5", - "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", - "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", - "dev": true, - "license": "Unlicense" - }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -16293,6 +16055,8 @@ } ], "license": "MIT", + "optional": true, + "peer": true, "bin": { "ua-parser-js": "script/cli.js" }, @@ -16345,6 +16109,8 @@ "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 4.0.0" } @@ -16420,21 +16186,12 @@ "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">= 0.4.0" } }, - "node_modules/uuid": { - "version": "3.4.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", - "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", - "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", - "dev": true, - "license": "MIT", - "bin": { - "uuid": "bin/uuid" - } - }, "node_modules/v8-compile-cache-lib": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", @@ -16484,28 +16241,6 @@ "node": ">= 0.8" } }, - "node_modules/verror": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", - "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", - "dev": true, - "engines": [ - "node >=0.6.0" - ], - "license": "MIT", - "dependencies": { - "assert-plus": "^1.0.0", - "core-util-is": "1.0.2", - "extsprintf": "^1.2.0" - } - }, - "node_modules/verror/node_modules/core-util-is": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", - "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==", - "dev": true, - "license": "MIT" - }, "node_modules/vite": { "version": "7.3.2", "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", @@ -16581,16 +16316,121 @@ } } }, + "node_modules/vitest": { + "version": "4.1.8", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.8.tgz", + "integrity": "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "4.1.8", + "@vitest/mocker": "4.1.8", + "@vitest/pretty-format": "4.1.8", + "@vitest/runner": "4.1.8", + "@vitest/snapshot": "4.1.8", + "@vitest/spy": "4.1.8", + "@vitest/utils": "4.1.8", + "es-module-lexer": "^2.0.0", + "expect-type": "^1.3.0", + "magic-string": "^0.30.21", + "obug": "^2.1.1", + "pathe": "^2.0.3", + "picomatch": "^4.0.3", + "std-env": "^4.0.0-rc.1", + "tinybench": "^2.9.0", + "tinyexec": "^1.0.2", + "tinyglobby": "^0.2.15", + "tinyrainbow": "^3.1.0", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^20.0.0 || ^22.0.0 || >=24.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@opentelemetry/api": "^1.9.0", + "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", + "@vitest/browser-playwright": "4.1.8", + "@vitest/browser-preview": "4.1.8", + "@vitest/browser-webdriverio": "4.1.8", + "@vitest/coverage-istanbul": "4.1.8", + "@vitest/coverage-v8": "4.1.8", + "@vitest/ui": "4.1.8", + "happy-dom": "*", + "jsdom": "*", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@opentelemetry/api": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser-playwright": { + "optional": true + }, + "@vitest/browser-preview": { + "optional": true + }, + "@vitest/browser-webdriverio": { + "optional": true + }, + "@vitest/coverage-istanbul": { + "optional": true + }, + "@vitest/coverage-v8": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + }, + "vite": { + "optional": false + } + } + }, "node_modules/void-elements": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", "integrity": "sha512-qZKX4RnBzH2ugr8Lxa7x+0V6XD9Sb/ouARtiasEQCHB1EVU4NXtmHsDDrx1dO4ne5fc3J6EW05BP1Dl0z0iung==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/watchpack": { "version": "2.5.1", "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.1.tgz", @@ -16613,153 +16453,39 @@ "license": "MIT", "optional": true }, - "node_modules/webdriver-js-extender": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/webdriver-js-extender/-/webdriver-js-extender-2.1.0.tgz", - "integrity": "sha512-lcUKrjbBfCK6MNsh7xaY2UAUmZwe+/ib03AjVOpFobX4O7+83BUveSrLfU0Qsyb1DaKJdQRbuU+kM9aZ6QUhiQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/selenium-webdriver": "^3.0.0", - "selenium-webdriver": "^3.0.1" - }, - "engines": { - "node": ">=6.9.x" - } - }, - "node_modules/webdriver-manager": { - "version": "12.1.9", - "resolved": "https://registry.npmjs.org/webdriver-manager/-/webdriver-manager-12.1.9.tgz", - "integrity": "sha512-Yl113uKm8z4m/KMUVWHq1Sjtla2uxEBtx2Ue3AmIlnlPAKloDn/Lvmy6pqWCUersVISpdMeVpAaGbNnvMuT2LQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "adm-zip": "^0.5.2", - "chalk": "^1.1.1", - "del": "^2.2.0", - "glob": "^7.0.3", - "ini": "^1.3.4", - "minimist": "^1.2.0", - "q": "^1.4.1", - "request": "^2.87.0", - "rimraf": "^2.5.2", - "semver": "^5.3.0", - "xml2js": "^0.4.17" - }, - "bin": { - "webdriver-manager": "bin/webdriver-manager" - }, - "engines": { - "node": ">=6.9.x" - } - }, - "node_modules/webdriver-manager/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", "dev": true, - "license": "MIT", + "license": "BSD-2-Clause", "engines": { - "node": ">=0.10.0" + "node": ">=20" } }, - "node_modules/webdriver-manager/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", "dev": true, "license": "MIT", - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/ini": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz", - "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==", - "dev": true, - "license": "ISC" - }, - "node_modules/webdriver-manager/node_modules/rimraf": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz", - "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dev": true, - "license": "ISC", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - } - }, - "node_modules/webdriver-manager/node_modules/semver": { - "version": "5.7.2", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", - "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver" + "node": ">=20" } }, - "node_modules/webdriver-manager/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^2.0.0" + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" }, "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/webdriver-manager/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", - "license": "BSD-2-Clause", - "optional": true - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "license": "MIT", - "optional": true, - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, "node_modules/which": { @@ -16783,6 +16509,23 @@ "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", "license": "ISC" }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -16954,6 +16697,8 @@ "integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=10.0.0" }, @@ -16970,29 +16715,22 @@ } } }, - "node_modules/xml2js": { - "version": "0.4.23", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.23.tgz", - "integrity": "sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug==", + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", "dev": true, - "license": "MIT", - "dependencies": { - "sax": ">=0.6.0", - "xmlbuilder": "~11.0.0" - }, + "license": "Apache-2.0", "engines": { - "node": ">=4.0.0" + "node": ">=18" } }, - "node_modules/xmlbuilder": { - "version": "11.0.1", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-11.0.1.tgz", - "integrity": "sha512-fDlsI/kFEx7gLvbecc0/ohLG50fugQp8ryHzMTuW9vSa1GJ0XYWKnhsUx7oie3G98+r56aTQIUB4kht42R3JvA==", + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", "dev": true, - "license": "MIT", - "engines": { - "node": ">=4.0" - } + "license": "MIT" }, "node_modules/y18n": { "version": "5.0.8", @@ -17133,9 +16871,9 @@ } }, "node_modules/zone.js": { - "version": "0.15.1", - "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.15.1.tgz", - "integrity": "sha512-XE96n56IQpJM7NAoXswY3XRLcWFW83xe0BiAOeMD7K5k5xecOeul3Qcpx6GqEeeHNkW5DWL5zOyTbEfB4eti8w==", + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.16.2.tgz", + "integrity": "sha512-Eky7p2Z1Ig3NnbfodSPoARCjKBSTFMnE/ACsP1L/XJEfY4SdOFce19BsUCWVwL6K5ABZFy5J3bjcMWffX+YM3Q==", "license": "MIT" } } diff --git a/package.json b/package.json index 4e0a4dfec0..f7646cab11 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,7 @@ "deploy": "run-s -l deploy:build2api", "prepare": "husky install", "test": "ng test", - "test:ci": "ng test --karma-config=src/karma-ci.conf.js --no-progress" + "test:ci": "ng test --no-watch --no-progress" }, "keywords": [], "author": "", @@ -81,7 +81,7 @@ "tslib": "^2.8.1", "typescript-eslint": "^8.12.0", "underscore.string": "2.3.3", - "zone.js": "~0.15.1" + "zone.js": "~0.16.2" }, "devDependencies": { "@angular-eslint/builder": "^21.4.0", @@ -100,8 +100,6 @@ "@types/canvas-confetti": "^1.6.0", "@types/d3": "^3.5.17", "@types/file-saver": "^2.0.1", - "@types/jasmine": "~6.0.0", - "@types/jasminewd2": "~2.0.3", "@types/lodash": "^4.14.115", "@types/node": "^20.9.0", "@typescript-eslint/eslint-plugin": "^8.60.1", @@ -116,23 +114,17 @@ "eslint-plugin-tailwindcss": "^3.18.3", "husky": "~8", "ip": "^2.0.1", - "jasmine-core": "~4.1.0", - "jasmine-spec-reporter": "~5.0.0", - "karma": "^6.3.4", - "karma-chrome-launcher": "~3.1.0", - "karma-coverage-istanbul-reporter": "~3.0.2", - "karma-jasmine": "~4.0.0", - "karma-jasmine-html-reporter": "^1.5.0", + "jsdom": "^29.1.1", "npm-run-all2": "^7.0", "postcss": "^8.5.10", "postcss-scss": "^0.1.7", "prettier": "^3.8.3", - "protractor": "~7.0.0", "sass": "^1.48.0", "tailwindcss": "~3.4.17", "ts-node": "~10.9", "typescript": "~5.9.3", - "underscore": "^1.8.3" + "underscore": "^1.8.3", + "vitest": "^4.1.8" }, "optionalDependencies": { "@nx/nx-darwin-arm64": "^18.0", diff --git a/src/app/account/edit-profile/edit-profile.component.spec.ts b/src/app/account/edit-profile/edit-profile.component.spec.ts index 04b0a4eb05..b15e0bfc85 100644 --- a/src/app/account/edit-profile/edit-profile.component.spec.ts +++ b/src/app/account/edit-profile/edit-profile.component.spec.ts @@ -1,6 +1,12 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {Router} from '@angular/router'; +import {AuthenticationService} from 'src/app/api/services/authentication.service'; import {EditProfileComponent} from './edit-profile.component'; +const emptyProvider = {}; + describe('EditProfileComponent', () => { let component: EditProfileComponent; let fixture: ComponentFixture; @@ -8,11 +14,19 @@ describe('EditProfileComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [EditProfileComponent], - }).compileComponents(); + providers: [ + {provide: AuthenticationService, useValue: emptyProvider}, + {provide: Router, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(EditProfileComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(EditProfileComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.spec.ts b/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.spec.ts index 22e88fc195..6b38a84b69 100644 --- a/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.spec.ts +++ b/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.spec.ts @@ -1,6 +1,13 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {MatDialog} from '@angular/material/dialog'; +import {TeachingPeriodService} from 'src/app/api/services/teaching-period.service'; +import {TeachingPeriodUnitImportService} from '../teaching-period-unit-import/teaching-period-unit-import.dialog'; import {TeachingPeriodListComponent} from './teaching-period-list.component'; +const emptyProvider = {}; + describe('TeachingPeriodListComponent', () => { let component: TeachingPeriodListComponent; let fixture: ComponentFixture; @@ -8,11 +15,20 @@ describe('TeachingPeriodListComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [TeachingPeriodListComponent], - }).compileComponents(); + providers: [ + {provide: TeachingPeriodService, useValue: emptyProvider}, + {provide: MatDialog, useValue: emptyProvider}, + {provide: TeachingPeriodUnitImportService, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(TeachingPeriodListComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(TeachingPeriodListComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/admin/states/units/units.component.spec.ts b/src/app/admin/states/units/units.component.spec.ts index e69de29bb2..b5ca421a3a 100644 --- a/src/app/admin/states/units/units.component.spec.ts +++ b/src/app/admin/states/units/units.component.spec.ts @@ -0,0 +1,39 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {ActivatedRoute} from '@angular/router'; +import {UnitService} from 'src/app/api/services/unit.service'; +import {GlobalStateService} from 'src/app/projects/states/index/global-state.service'; +import {CreateNewUnitModal} from '../../modals/create-new-unit-modal/create-new-unit-modal.component'; +import {FUnitsComponent} from './units.component'; + +const emptyProvider = {}; + +describe('FUnitsComponent', () => { + let component: FUnitsComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [FUnitsComponent], + providers: [ + {provide: CreateNewUnitModal, useValue: emptyProvider}, + {provide: GlobalStateService, useValue: emptyProvider}, + {provide: UnitService, useValue: emptyProvider}, + {provide: ActivatedRoute, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(FUnitsComponent, {set: {template: ''}}) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(FUnitsComponent); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/admin/tii-action-log/tii-action-log.component.spec.ts b/src/app/admin/tii-action-log/tii-action-log.component.spec.ts index 38e5d9ec65..d9cd6e6310 100644 --- a/src/app/admin/tii-action-log/tii-action-log.component.spec.ts +++ b/src/app/admin/tii-action-log/tii-action-log.component.spec.ts @@ -1,17 +1,32 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {TiiActionService} from 'src/app/api/services/tii-action.service'; +import {AlertService} from 'src/app/common/services/alert.service'; import {TiiActionLogComponent} from './tii-action-log.component'; +const emptyProvider = {}; + describe('TiiActionLogComponent', () => { let component: TiiActionLogComponent; let fixture: ComponentFixture; - beforeEach(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [TiiActionLogComponent], - }); + providers: [ + {provide: TiiActionService, useValue: emptyProvider}, + {provide: AlertService, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(TiiActionLogComponent, {set: {template: ''}}) + .compileComponents(); + }); + + beforeEach(() => { fixture = TestBed.createComponent(TiiActionLogComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/api/services/spec/campus.service.spec.ts b/src/app/api/services/spec/campus.service.spec.ts index e89adef628..d96c869e4c 100644 --- a/src/app/api/services/spec/campus.service.spec.ts +++ b/src/app/api/services/spec/campus.service.spec.ts @@ -1,6 +1,7 @@ +import {afterEach, beforeEach, describe, expect, it} from 'vitest'; import {HttpRequest, provideHttpClient, withInterceptorsFromDi} from '@angular/common/http'; import {HttpTestingController, provideHttpClientTesting} from '@angular/common/http/testing'; -import {TestBed, fakeAsync, tick} from '@angular/core/testing'; +import {TestBed} from '@angular/core/testing'; import {Campus} from 'src/app/api/models/doubtfire-model'; import {CampusService} from '../campus.service'; @@ -26,18 +27,22 @@ describe('CampusService', () => { httpMock.verify(); }); - it('should return expected campuses (HttpClient called once)', fakeAsync(() => { + it('should return expected campuses (HttpClient called once)', () => { const c = new Campus(); c.name = 'Melbourne'; c.mode = 'automatic'; c.abbreviation = 'melb'; - const expectedCampuses: Campus[] = [c]; - - campusService - .query() - .subscribe((campuses) => expect(campuses).toEqual(expectedCampuses, 'expected campuses')); + campusService.query().subscribe((campuses) => { + expect(campuses).toHaveLength(1); + expect(campuses[0]).toMatchObject({ + id: 1, + name: 'Melbourne', + mode: 'automatic', + abbreviation: 'melb', + }); + }); const req = httpMock.expectOne((request: HttpRequest): boolean => { expect(request.url).toEqual('http://localhost:3000/api/campuses/'); @@ -47,7 +52,5 @@ describe('CampusService', () => { c.id = 1; req.flush(c); - - tick(); - })); + }); }); diff --git a/src/app/api/services/spec/user.service.spec.ts b/src/app/api/services/spec/user.service.spec.ts index 9c5a2439fd..6f39dc81eb 100644 --- a/src/app/api/services/spec/user.service.spec.ts +++ b/src/app/api/services/spec/user.service.spec.ts @@ -1,6 +1,7 @@ +import {afterEach, beforeEach, describe, expect, it} from 'vitest'; import {HttpRequest, provideHttpClient, withInterceptorsFromDi} from '@angular/common/http'; import {HttpTestingController, provideHttpClientTesting} from '@angular/common/http/testing'; -import {TestBed, fakeAsync, tick} from '@angular/core/testing'; +import {TestBed} from '@angular/core/testing'; import {User, UserService} from 'src/app/api/models/doubtfire-model'; describe('UserService', () => { @@ -25,7 +26,7 @@ describe('UserService', () => { httpMock.verify(); }); - it('should return expected users (HttpClient called once)', fakeAsync(() => { + it('should return expected users (HttpClient called once)', () => { const u = new User(); u.id = 1; u.lastName = 'renzella'; @@ -40,24 +41,39 @@ describe('UserService', () => { u.receiveFeedbackNotifications = false; u.receiveTaskNotifications = false; - const expectedUsers: User[] = [u]; - - userService - .query() - .subscribe((users) => expect(users).toEqual(expectedUsers, 'expected users')); + userService.query().subscribe((users) => { + expect(users).toHaveLength(1); + expect(users[0]).toMatchObject({ + id: 1, + firstName: 'Jake', + lastName: 'renzella', + email: 'jake@jake.jake', + }); + }); const req = httpMock.expectOne((request: HttpRequest): boolean => { expect(request.url).toEqual('http://localhost:3000/api/users/'); expect(request.method).toBe('GET'); return true; }); - req.flush(u); - tick(); - })); + req.flush({ + id: 1, + last_name: 'renzella', + first_name: 'Jake', + nickname: 'jake', + has_run_first_time_setup: false, + email: 'jake@jake.jake', + student_id: '1', + username: 'test', + opt_in_to_research: true, + receive_portfolio_notifications: false, + receive_feedback_notifications: false, + receive_task_notifications: false, + }); + }); - it('should create a new user', fakeAsync(() => { + it('should create a new user', () => { const user = new User(); - user.id = 1; user.lastName = 'renzella'; user.firstName = 'Jake'; user.nickname = 'jake'; @@ -71,43 +87,57 @@ describe('UserService', () => { user.receiveTaskNotifications = false; userService.create(user).subscribe((result) => { - expect(result).toEqual(user, 'expected users'); + expect(result).toMatchObject({ + id: 1, + firstName: 'Jake', + lastName: 'renzella', + email: 'jake@jake.jake', + }); }); - const expectedUser = user; - expectedUser.id = 1; - const req = httpMock.expectOne((request: HttpRequest): boolean => { expect(request.url).toEqual('http://localhost:3000/api/users/'); expect(request.method).toBe('POST'); return true; }); - req.flush(expectedUser); - tick(); - })); - - xit('should delete a user', fakeAsync(() => { - // let user = new User(); - // user.updateFromJson({ - // name: 'jake', lastName: 'renzella', firstName: 'Jake', nickname: 'jake', - // systemRole: 'admin', hasRunFirstTimeSetup: false, email: 'jake@jake.jake', - // student_id: '1', username: 'test', optInToResearch: true, receivePortfolioNotifications: false, - // receiveFeedbackNotifications: false, receiveTaskNotifications: false - // }); - // userService.delete(1).subscribe( - // result => expect(result).toEqual(user, 'expected users') - // ); - // const req = httpMock.expectOne((request: HttpRequest): boolean => { - // expect(request.url).toEqual('http://localhost:3000/api/users/1'); - // expect(request.method).toBe('DELETE'); - // return true; - // }); - // req.flush(user); - // tick(); - })); - - it('should update a User', fakeAsync(() => { + req.flush({ + id: 1, + last_name: 'renzella', + first_name: 'Jake', + nickname: 'jake', + has_run_first_time_setup: false, + email: 'jake@jake.jake', + student_id: '1', + username: 'test', + opt_in_to_research: true, + receive_portfolio_notifications: false, + receive_feedback_notifications: false, + receive_task_notifications: false, + }); + }); + + // it.skip('should delete a user', () => { + // let user = new User(); + // user.updateFromJson({ + // name: 'jake', lastName: 'renzella', firstName: 'Jake', nickname: 'jake', + // systemRole: 'admin', hasRunFirstTimeSetup: false, email: 'jake@jake.jake', + // student_id: '1', username: 'test', optInToResearch: true, receivePortfolioNotifications: false, + // receiveFeedbackNotifications: false, receiveTaskNotifications: false + // }); + // userService.delete(1).subscribe( + // result => expect(result).toEqual(user, 'expected users') + // ); + // const req = httpMock.expectOne((request: HttpRequest): boolean => { + // expect(request.url).toEqual('http://localhost:3000/api/users/1'); + // expect(request.method).toBe('DELETE'); + // return true; + // }); + // req.flush(user); + // tick(); + // }); + + it('should update a User', () => { const u = new User(); u.id = 1; u.lastName = 'renzella'; @@ -122,9 +152,14 @@ describe('UserService', () => { u.receiveFeedbackNotifications = false; u.receiveTaskNotifications = false; - userService.update(u).subscribe((result) => { - expect(result.firstName).toBe(u.firstName); - }, fail); + userService.update(u).subscribe( + (result) => { + expect(result.firstName).toBe(u.firstName); + }, + (error) => { + throw error; + }, + ); let req = httpMock.expectOne((request: HttpRequest): boolean => { expect(request.url).toEqual('http://localhost:3000/api/users/1'); @@ -132,14 +167,15 @@ describe('UserService', () => { return true; }); req.flush(u); - tick(); u.firstName = 'andrew'; userService.update(u).subscribe({ next: (result) => { expect(result.firstName).toBe('andrew'); }, - error: fail, + error: (error) => { + throw error; + }, }); req = httpMock.expectOne((request: HttpRequest): boolean => { @@ -149,10 +185,9 @@ describe('UserService', () => { }); req.flush(u); - tick(); - })); + }); - it('should cache the result of a get request', fakeAsync(() => { + it('should cache the result of a get request', () => { const user = new User(); user.id = 1; user.lastName = 'renzella'; @@ -177,17 +212,15 @@ describe('UserService', () => { const user2 = user; user2.id = 1; req.flush(user2); - tick(); userService.get(1).subscribe(); httpMock.expectNone((_request: HttpRequest): boolean => { return true; }); - tick(); - })); + }); - it('should cache fetch/get', fakeAsync(() => { + it('should cache fetch/get', () => { let user = new User(); user.id = 1; user.lastName = 'renzella'; @@ -217,9 +250,8 @@ describe('UserService', () => { Object.keys(user).forEach((key) => (user2[key] = user[key])); user2.id = 1; req.flush(user2); - tick(); - let _user3; + let user3: User; // 1 request here userService.fetch(1).subscribe((data) => { @@ -237,10 +269,10 @@ describe('UserService', () => { Object.keys(user2).forEach((key) => (user4[key] = user2[key])); user4.firstName = 'fred'; req.flush(user4); + expect(user3).toBe(user); httpMock.expectNone((_request: HttpRequest): boolean => { return true; }); - tick(); - })); + }); }); diff --git a/src/app/api/services/tii.service.spec.ts b/src/app/api/services/tii.service.spec.ts index 5aefcb548c..4cf7e6de2d 100644 --- a/src/app/api/services/tii.service.spec.ts +++ b/src/app/api/services/tii.service.spec.ts @@ -1,3 +1,4 @@ +import {beforeEach, describe, expect, it} from 'vitest'; import {TestBed} from '@angular/core/testing'; import {TiiService} from './tii.service'; diff --git a/src/app/common/directives/drag-drop.directive.spec.ts b/src/app/common/directives/drag-drop.directive.spec.ts index 101b686e5a..50b65a31a7 100644 --- a/src/app/common/directives/drag-drop.directive.spec.ts +++ b/src/app/common/directives/drag-drop.directive.spec.ts @@ -1,3 +1,4 @@ +import {describe, expect, it} from 'vitest'; import {DragDropDirective} from './drag-drop.directive'; describe('DragDropDirective', () => { diff --git a/src/app/common/edit-profile-form/edit-profile-form.component.spec.ts b/src/app/common/edit-profile-form/edit-profile-form.component.spec.ts index 18f1c2815b..a3bfc9285a 100644 --- a/src/app/common/edit-profile-form/edit-profile-form.component.spec.ts +++ b/src/app/common/edit-profile-form/edit-profile-form.component.spec.ts @@ -1,20 +1,40 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {MAT_DIALOG_DATA} from '@angular/material/dialog'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {Router} from '@angular/router'; +import {AuthenticationService} from 'src/app/api/services/authentication.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {EditProfileFormComponent} from './edit-profile-form.component'; -describe('EditProfileComponent', () => { +const emptyProvider = {}; + +describe('EditProfileFormComponent', () => { let component: EditProfileFormComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [EditProfileFormComponent], - }).compileComponents(); + providers: [ + {provide: DoubtfireConstants, useValue: emptyProvider}, + {provide: UserService, useValue: emptyProvider}, + {provide: Router, useValue: emptyProvider}, + {provide: AuthenticationService, useValue: emptyProvider}, + {provide: MAT_DIALOG_DATA, useValue: emptyProvider}, + {provide: MatSnackBar, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(EditProfileFormComponent, {set: {template: ''}}) + .compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(EditProfileFormComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/common/f-chip/chip.component.spec.ts b/src/app/common/f-chip/chip.component.spec.ts index 2360020249..23dfb6fbc5 100644 --- a/src/app/common/f-chip/chip.component.spec.ts +++ b/src/app/common/f-chip/chip.component.spec.ts @@ -1,3 +1,4 @@ +import {beforeEach, describe, expect, it} from 'vitest'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {FChipComponent} from './chip.component'; diff --git a/src/app/common/file-viewer/file-viewer.component.spec.ts b/src/app/common/file-viewer/file-viewer.component.spec.ts index d3e256c208..21eeaf7660 100644 --- a/src/app/common/file-viewer/file-viewer.component.spec.ts +++ b/src/app/common/file-viewer/file-viewer.component.spec.ts @@ -1,3 +1,4 @@ +import {beforeEach, describe, expect, it} from 'vitest'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {FileViewerComponent} from './file-viewer.component'; diff --git a/src/app/common/footer/footer.component.spec.ts b/src/app/common/footer/footer.component.spec.ts index a948a43d62..dfe700e594 100644 --- a/src/app/common/footer/footer.component.spec.ts +++ b/src/app/common/footer/footer.component.spec.ts @@ -1,6 +1,19 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {ProjectService} from 'src/app/api/services/project.service'; +import {TaskService} from 'src/app/api/services/task.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {SelectedTaskService} from 'src/app/projects/states/dashboard/selected-task.service'; +import {FileDownloaderService} from '../file-downloader/file-downloader.service'; +import {ConfirmationModalService} from '../modals/confirmation-modal/confirmation-modal.service'; +import {DiscussedInClassReasonModalService} from '../modals/discussed-in-class-reason-modal/discussed-in-class-reason-modal.service'; +import {TaskAssessmentModalService} from '../modals/task-assessment-modal/task-assessment-modal.service'; +import {AlertService} from '../services/alert.service'; import {FooterComponent} from './footer.component'; +const emptyProvider = {}; + describe('FooterComponent', () => { let component: FooterComponent; let fixture: ComponentFixture; @@ -8,11 +21,26 @@ describe('FooterComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [FooterComponent], - }).compileComponents(); + providers: [ + {provide: SelectedTaskService, useValue: emptyProvider}, + {provide: TaskService, useValue: emptyProvider}, + {provide: FileDownloaderService, useValue: emptyProvider}, + {provide: TaskAssessmentModalService, useValue: emptyProvider}, + {provide: UserService, useValue: emptyProvider}, + {provide: ProjectService, useValue: emptyProvider}, + {provide: ConfirmationModalService, useValue: emptyProvider}, + {provide: DiscussedInClassReasonModalService, useValue: emptyProvider}, + {provide: AlertService, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(FooterComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(FooterComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/common/grade-icon/grade-icon.component.spec.ts b/src/app/common/grade-icon/grade-icon.component.spec.ts index fff4eaa353..886ce73c90 100644 --- a/src/app/common/grade-icon/grade-icon.component.spec.ts +++ b/src/app/common/grade-icon/grade-icon.component.spec.ts @@ -1,36 +1,23 @@ -import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {GradeService} from 'src/app/common/services/grade.service'; import {GradeIconComponent} from './grade-icon.component'; describe('GradeIconComponent', () => { let component: GradeIconComponent; let fixture: ComponentFixture; - let gradeServiceStub: Pick; + let gradeService: GradeService; - beforeEach(waitForAsync(() => { - gradeServiceStub = { - grades: ['Pass', 'Credit', 'Distinction', 'High Distinction'], - gradeAcronyms: { - Fail: 'F', - Pass: 'P', - Credit: 'C', - Distinction: 'D', - 'High Distinction': 'HD', - 0: 'P', - 1: 'C', - 2: 'D', - 3: 'HD', - }, - }; + beforeEach(async () => { + gradeService = new GradeService(); - gradeServiceStub.grades[-1] = 'Fail'; - gradeServiceStub.gradeAcronyms[-1] = 'F'; - - TestBed.configureTestingModule({ + await TestBed.configureTestingModule({ declarations: [GradeIconComponent], - providers: [{provide: GradeService, useValue: gradeServiceStub}], + providers: [{provide: GradeService, useValue: gradeService}], + schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(GradeIconComponent); @@ -42,43 +29,39 @@ describe('GradeIconComponent', () => { expect(component).toBeTruthy(); }); - it('should set the index value when undefined', () => { - component.index = undefined; + it('should show the default icon when the grade is undefined', () => { + component.grade = undefined; component.ngOnInit(); - expect(component.index).toEqual(-1); + expect(component.gradeText).toEqual('Grade'); + expect(component.gradeLetter).toEqual('G'); }); - it('should set the grade to Fail when given invalid input', () => { - component.index = undefined; + it('should show the default icon when given invalid input', () => { component.grade = 'Tomato'; component.ngOnInit(); - expect(component.index).toEqual(-1); - expect(component.gradeText).toEqual('Fail'); - expect(component.gradeLetter).toEqual('F'); + expect(component.gradeText).toEqual('Grade'); + expect(component.gradeLetter).toEqual('G'); }); - it('should appropriate set the grade when passed a grade value', () => { - gradeServiceStub.grades.forEach((grade: string) => { + it('should set the grade when passed a grade name', () => { + Object.entries(gradeService.gradeIndex).forEach(([grade, value]) => { component.grade = grade; - component.index = undefined; component.ngOnInit(); - expect(component.index).toEqual(gradeServiceStub.grades.indexOf(grade)); expect(component.gradeText).toEqual(grade); - expect(component.gradeLetter).toEqual(gradeServiceStub.gradeAcronyms[grade]); + expect(component.gradeLetter).toEqual(gradeService.gradeAcronyms[value]); }); }); - it('should appropriate set the grade when passed a grade index', () => { - gradeServiceStub.grades.forEach((_, index: number) => { - component.index = index - 1; + it('should set the grade when passed a numeric grade', () => { + gradeService.allGradeValues.forEach((grade) => { + component.grade = grade; component.ngOnInit(); - expect(component.index).toEqual(index - 1); - expect(component.gradeText).toEqual(gradeServiceStub.grades[component.index]); - expect(component.gradeLetter).toEqual(gradeServiceStub.gradeAcronyms[component.gradeText]); + expect(component.gradeText).toEqual(gradeService.grades[grade]); + expect(component.gradeLetter).toEqual(gradeService.gradeAcronyms[grade]); }); }); }); diff --git a/src/app/common/header/header.component.spec.ts b/src/app/common/header/header.component.spec.ts index 185d36fae4..b0ee436584 100644 --- a/src/app/common/header/header.component.spec.ts +++ b/src/app/common/header/header.component.spec.ts @@ -1,60 +1,56 @@ -import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; -import {MatMenuModule} from '@angular/material/menu'; -import {BehaviorSubject, Subject} from 'rxjs'; -import {Project, Unit, UnitRole} from 'src/app/api/models/doubtfire-model'; -import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global-state.service'; +import {MediaObserver} from 'ng-flex-layout'; +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {Router} from '@angular/router'; +import {AuthenticationService} from 'src/app/api/models/doubtfire-model'; +import {SidekiqJobService} from 'src/app/api/services/sidekiq-job.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {GlobalStateService} from 'src/app/projects/states/index/global-state.service'; import {CheckForUpdateService} from 'src/app/sessions/service-worker-updater/check-for-update.service'; +import {AboutDoubtfireModal} from '../modals/about-doubtfire-modal/about-doubtfire-modal.component'; +import {CalendarModalService} from '../modals/calendar-modal/calendar-modal.service'; +import {QrModalService} from '../modals/qr-modal/qr-modal.service'; +import {SidekiqJobsModalService} from '../modals/sidekiq-jobs-modal/sidekiq-jobs-modal.service'; +import {TutorNotesModalService} from '../modals/tutor-notes-modal/tutor-notes-modal.service'; import {IsActiveUnitRole} from '../pipes/is-active-unit-role.pipe'; import {HeaderComponent} from './header.component'; +const emptyProvider = {}; + describe('HeaderComponent', () => { let component: HeaderComponent; let fixture: ComponentFixture; - // let currentUserStub: jasmine.SpyObj; - // let calendarModalStub: jasmine.SpyObj; - // let aboutDoubtfireModalStub: jasmine.SpyObj; - const isActiveUnitRoleStub: Partial = {}; - const checkForUpdateServiceStub: Partial = {}; - let globalStateServiceStub: Partial; - - beforeEach(waitForAsync(() => { - const showHideHeader: Subject = new Subject(); - const unitRolesSubject: BehaviorSubject = new BehaviorSubject(null); - const projectsSubject: BehaviorSubject = new BehaviorSubject(null); - const currentViewAndEntitySubject$: BehaviorSubject<{ - viewType: ViewType; - entity: Unit | Project | UnitRole; - }> = new BehaviorSubject(null); - - // currentUserStub = { - // role: 'tutor', - // }; - globalStateServiceStub = { - showHideHeader: showHideHeader, - unitRolesSubject: unitRolesSubject, - projectsSubject: projectsSubject, - currentViewAndEntitySubject$: currentViewAndEntitySubject$, - }; - - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [HeaderComponent], - imports: [MatMenuModule], providers: [ - // { provide: currentUser, useValue: currentUserStub }, - // { provide: calendarModal, useValue: calendarModalStub }, - // { provide: aboutDoubtfireModal, useValue: aboutDoubtfireModalStub }, - {provide: IsActiveUnitRole, useValue: isActiveUnitRoleStub}, - {provide: CheckForUpdateService, useValue: checkForUpdateServiceStub}, - {provide: GlobalStateService, useValue: globalStateServiceStub}, + {provide: CalendarModalService, useValue: emptyProvider}, + {provide: AboutDoubtfireModal, useValue: emptyProvider}, + {provide: IsActiveUnitRole, useValue: emptyProvider}, + {provide: CheckForUpdateService, useValue: emptyProvider}, + {provide: GlobalStateService, useValue: emptyProvider}, + {provide: UserService, useValue: emptyProvider}, + {provide: AuthenticationService, useValue: emptyProvider}, + {provide: MediaObserver, useValue: emptyProvider}, + {provide: DoubtfireConstants, useValue: emptyProvider}, + {provide: SidekiqJobService, useValue: emptyProvider}, + {provide: SidekiqJobsModalService, useValue: emptyProvider}, + {provide: QrModalService, useValue: emptyProvider}, + {provide: Router, useValue: emptyProvider}, + {provide: TutorNotesModalService, useValue: emptyProvider}, ], - }).compileComponents(); - })); + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(HeaderComponent, {set: {template: ''}}) + .compileComponents(); + }); beforeEach(() => { fixture = TestBed.createComponent(HeaderComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/common/header/task-dropdown/task-dropdown.component.spec.ts b/src/app/common/header/task-dropdown/task-dropdown.component.spec.ts index 298ab4f769..bc4976e202 100644 --- a/src/app/common/header/task-dropdown/task-dropdown.component.spec.ts +++ b/src/app/common/header/task-dropdown/task-dropdown.component.spec.ts @@ -1,3 +1,4 @@ +import {beforeEach, describe, expect, it} from 'vitest'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {RouterTestingModule} from '@angular/router/testing'; import {TaskDropdownComponent} from './task-dropdown.component'; diff --git a/src/app/common/header/unit-dropdown/unit-dropdown.component.spec.ts b/src/app/common/header/unit-dropdown/unit-dropdown.component.spec.ts index b8dbc45dc5..bcf7ff444d 100644 --- a/src/app/common/header/unit-dropdown/unit-dropdown.component.spec.ts +++ b/src/app/common/header/unit-dropdown/unit-dropdown.component.spec.ts @@ -1,22 +1,21 @@ -import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; +import {MediaObserver} from 'ng-flex-layout'; +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {MatMenuModule} from '@angular/material/menu'; -import {DateService} from 'src/app/common/services/date.service'; import {UnitDropdownComponent} from './unit-dropdown.component'; describe('UnitDropdownComponent', () => { let component: UnitDropdownComponent; let fixture: ComponentFixture; - let dateServiceStub: Pick; - - beforeEach(waitForAsync(() => { - dateServiceStub = {showDate: true}; - - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [UnitDropdownComponent], imports: [MatMenuModule], - providers: [{provide: DateService, useValue: dateServiceStub}], + providers: [{provide: MediaObserver, useValue: {isActive: () => false}}], + schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(UnitDropdownComponent); diff --git a/src/app/common/hero-sidebar/hero-sidebar.component.spec.ts b/src/app/common/hero-sidebar/hero-sidebar.component.spec.ts index aeefe2f6cd..19ed7c2b1a 100644 --- a/src/app/common/hero-sidebar/hero-sidebar.component.spec.ts +++ b/src/app/common/hero-sidebar/hero-sidebar.component.spec.ts @@ -1,3 +1,4 @@ +import {beforeEach, describe, expect, it} from 'vitest'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {HeroSidebarComponent} from './hero-sidebar.component'; diff --git a/src/app/common/modals/edit-profile-dialog/edit-profile-dialog.service.spec.ts b/src/app/common/modals/edit-profile-dialog/edit-profile-dialog.service.spec.ts index 3e7432e180..664fe42413 100644 --- a/src/app/common/modals/edit-profile-dialog/edit-profile-dialog.service.spec.ts +++ b/src/app/common/modals/edit-profile-dialog/edit-profile-dialog.service.spec.ts @@ -1,3 +1,4 @@ +import {beforeEach, describe, expect, it} from 'vitest'; import {TestBed} from '@angular/core/testing'; import {EditProfileDialogService} from './edit-profile-dialog.service'; diff --git a/src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.component.spec.ts b/src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.component.spec.ts index 73dcf27fd6..6bedbb62b2 100644 --- a/src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.component.spec.ts +++ b/src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.component.spec.ts @@ -1,5 +1,14 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {MatSnackBar} from '@angular/material/snack-bar'; +import {SidekiqJobService} from 'src/app/api/services/sidekiq-job.service'; +import {AlertService} from '../../services/alert.service'; import {SidekiqProgressModalComponent} from './sidekiq-progress-modal.component'; +import {SidekiqProgressModalService} from './sidekiq-progress-modal.service'; + +const emptyProvider = {}; describe('SidekiqProgressModalComponent', () => { let component: SidekiqProgressModalComponent; @@ -7,12 +16,24 @@ describe('SidekiqProgressModalComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [SidekiqProgressModalComponent], - }).compileComponents(); + declarations: [SidekiqProgressModalComponent], + providers: [ + {provide: AlertService, useValue: emptyProvider}, + {provide: MAT_DIALOG_DATA, useValue: emptyProvider}, + {provide: MatDialogRef, useValue: emptyProvider}, + {provide: SidekiqJobService, useValue: emptyProvider}, + {provide: SidekiqProgressModalService, useValue: emptyProvider}, + {provide: MatSnackBar, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(SidekiqProgressModalComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(SidekiqProgressModalComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/common/pdf-viewer-panel/pdf-viewer-panel.component.spec.ts b/src/app/common/pdf-viewer-panel/pdf-viewer-panel.component.spec.ts index 80de1d50c9..ff24c419cf 100644 --- a/src/app/common/pdf-viewer-panel/pdf-viewer-panel.component.spec.ts +++ b/src/app/common/pdf-viewer-panel/pdf-viewer-panel.component.spec.ts @@ -1,28 +1,28 @@ -import {provideHttpClient, withInterceptorsFromDi} from '@angular/common/http'; -import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {FileDownloaderService} from '../file-downloader/file-downloader.service'; import {PdfViewerPanelComponent} from './pdf-viewer-panel.component'; +const emptyProvider = {}; + describe('PdfViewerPanelComponent', () => { let component: PdfViewerPanelComponent; let fixture: ComponentFixture; - const fileDownloaderServiceStub: Partial = {}; - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [PdfViewerPanelComponent], - imports: [], - providers: [ - {provide: FileDownloaderService, useValue: fileDownloaderServiceStub}, - provideHttpClient(withInterceptorsFromDi()), - ], - }).compileComponents(); - })); + providers: [{provide: FileDownloaderService, useValue: emptyProvider}], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(PdfViewerPanelComponent, {set: {template: ''}}) + .compileComponents(); + }); beforeEach(() => { fixture = TestBed.createComponent(PdfViewerPanelComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/common/pipes/humanized-date.pipe.spec.ts b/src/app/common/pipes/humanized-date.pipe.spec.ts index eff49c7a3c..62839a0c26 100644 --- a/src/app/common/pipes/humanized-date.pipe.spec.ts +++ b/src/app/common/pipes/humanized-date.pipe.spec.ts @@ -1,3 +1,4 @@ +import {describe, expect, it} from 'vitest'; import {HumanizedDatePipe} from './humanized-date.pipe'; describe('HumanizedDatePipe', () => { diff --git a/src/app/common/pipes/marked.pipe.spec.ts b/src/app/common/pipes/marked.pipe.spec.ts index 4f50279ce7..5ac4060da5 100644 --- a/src/app/common/pipes/marked.pipe.spec.ts +++ b/src/app/common/pipes/marked.pipe.spec.ts @@ -1,3 +1,4 @@ +import {describe, expect, it} from 'vitest'; import {MarkedPipe} from './marked.pipe'; describe('MarkedPipe', () => { diff --git a/src/app/common/pipes/safe.pipe.spec.ts b/src/app/common/pipes/safe.pipe.spec.ts index 76a111c558..1a1332fcd4 100644 --- a/src/app/common/pipes/safe.pipe.spec.ts +++ b/src/app/common/pipes/safe.pipe.spec.ts @@ -1,3 +1,5 @@ +import {describe, it} from 'vitest'; + describe('SafePipe', () => { it('create an instance', () => { /* empty */ diff --git a/src/app/common/project-progress-bar/project-progress-bar.component.spec.ts b/src/app/common/project-progress-bar/project-progress-bar.component.spec.ts index 2281d48791..0bd437cb91 100644 --- a/src/app/common/project-progress-bar/project-progress-bar.component.spec.ts +++ b/src/app/common/project-progress-bar/project-progress-bar.component.spec.ts @@ -1,3 +1,5 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {ProjectProgressBarComponent} from './project-progress-bar.component'; @@ -8,11 +10,15 @@ describe('ProjectProgressBarComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ProjectProgressBarComponent], - }).compileComponents(); + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(ProjectProgressBarComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(ProjectProgressBarComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/common/scorm-player/scorm-player.component.spec.ts b/src/app/common/scorm-player/scorm-player.component.spec.ts index 88a15d8e31..677d27327f 100644 --- a/src/app/common/scorm-player/scorm-player.component.spec.ts +++ b/src/app/common/scorm-player/scorm-player.component.spec.ts @@ -1,6 +1,15 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {DomSanitizer} from '@angular/platform-browser'; +import {ActivatedRoute} from '@angular/router'; +import {AuthenticationService, UserService} from 'src/app/api/models/doubtfire-model'; +import {ScormAdapterService} from 'src/app/api/services/scorm-adapter.service'; +import {GlobalStateService} from 'src/app/projects/states/index/global-state.service'; import {ScormPlayerComponent} from './scorm-player.component'; +const emptyProvider = {}; + describe('ScormPlayerComponent', () => { let component: ScormPlayerComponent; let fixture: ComponentFixture; @@ -8,11 +17,23 @@ describe('ScormPlayerComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [ScormPlayerComponent], - }).compileComponents(); + providers: [ + {provide: GlobalStateService, useValue: emptyProvider}, + {provide: ScormAdapterService, useValue: emptyProvider}, + {provide: UserService, useValue: emptyProvider}, + {provide: AuthenticationService, useValue: emptyProvider}, + {provide: DomSanitizer, useValue: emptyProvider}, + {provide: ActivatedRoute, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(ScormPlayerComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(ScormPlayerComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/common/services/alert-service.service.spec.ts b/src/app/common/services/alert-service.service.spec.ts index a2906dab0f..72cf8816c6 100644 --- a/src/app/common/services/alert-service.service.spec.ts +++ b/src/app/common/services/alert-service.service.spec.ts @@ -1,3 +1,4 @@ +import {beforeEach, describe, expect, it} from 'vitest'; import {TestBed} from '@angular/core/testing'; import {AlertService} from './alert.service'; diff --git a/src/app/common/services/confetti.service.spec.ts b/src/app/common/services/confetti.service.spec.ts index 52427bb60f..5adbef2d05 100644 --- a/src/app/common/services/confetti.service.spec.ts +++ b/src/app/common/services/confetti.service.spec.ts @@ -1,3 +1,4 @@ +import {beforeEach, describe, expect, it} from 'vitest'; import {TestBed} from '@angular/core/testing'; import {ConfettiService} from './confetti.service'; diff --git a/src/app/common/services/date.service.spec.ts b/src/app/common/services/date.service.spec.ts index 8a419a94a4..9f4df416bb 100644 --- a/src/app/common/services/date.service.spec.ts +++ b/src/app/common/services/date.service.spec.ts @@ -1,3 +1,4 @@ +import {beforeEach, describe, expect, it} from 'vitest'; import {TestBed} from '@angular/core/testing'; import {DateService} from './date.service'; diff --git a/src/app/common/services/grade.service.spec.ts b/src/app/common/services/grade.service.spec.ts index 60794470b9..0e0122b8f9 100644 --- a/src/app/common/services/grade.service.spec.ts +++ b/src/app/common/services/grade.service.spec.ts @@ -1,3 +1,4 @@ +import {beforeEach, describe, expect, it} from 'vitest'; import {TestBed} from '@angular/core/testing'; import {GradeService} from './grade.service'; diff --git a/src/app/common/status-icon/status-icon.component.spec.ts b/src/app/common/status-icon/status-icon.component.spec.ts index 5c61910e3a..15cba56103 100644 --- a/src/app/common/status-icon/status-icon.component.spec.ts +++ b/src/app/common/status-icon/status-icon.component.spec.ts @@ -1,21 +1,24 @@ -import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {StatusIconComponent} from './status-icon.component'; describe('StatusIconComponent', () => { let component: StatusIconComponent; let fixture: ComponentFixture; - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [StatusIconComponent], - providers: [], - }).compileComponents(); - })); + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(StatusIconComponent, {set: {template: ''}}) + .compileComponents(); + }); beforeEach(() => { fixture = TestBed.createComponent(StatusIconComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/common/user-badge/user-badge.component.spec.ts b/src/app/common/user-badge/user-badge.component.spec.ts index 9ecc96953c..87b04a194d 100644 --- a/src/app/common/user-badge/user-badge.component.spec.ts +++ b/src/app/common/user-badge/user-badge.component.spec.ts @@ -1,3 +1,5 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {UserBadgeComponent} from './user-badge.component'; @@ -8,11 +10,15 @@ describe('UserBadgeComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [UserBadgeComponent], - }).compileComponents(); + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(UserBadgeComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(UserBadgeComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/config/privacy-policy/privacy-policy.spec.ts b/src/app/config/privacy-policy/privacy-policy.spec.ts index bde9c19cd3..4371a4c972 100644 --- a/src/app/config/privacy-policy/privacy-policy.spec.ts +++ b/src/app/config/privacy-policy/privacy-policy.spec.ts @@ -1,15 +1,33 @@ +import {afterEach, beforeEach, describe, expect, it} from 'vitest'; +import {provideHttpClient} from '@angular/common/http'; +import {HttpTestingController, provideHttpClientTesting} from '@angular/common/http/testing'; import {TestBed} from '@angular/core/testing'; import {PrivacyPolicy} from './privacy-policy'; describe('PrivacyPolicy', () => { let service: PrivacyPolicy; + let httpMock: HttpTestingController; beforeEach(() => { - TestBed.configureTestingModule({}); + TestBed.configureTestingModule({ + providers: [provideHttpClient(), provideHttpClientTesting()], + }); service = TestBed.inject(PrivacyPolicy); + httpMock = TestBed.inject(HttpTestingController); }); - it('should be created', () => { + afterEach(() => { + httpMock.verify(); + }); + + it('should load the privacy and plagiarism policies', () => { + httpMock + .expectOne('http://localhost:3000/api/settings/privacy') + .flush({privacy: 'Privacy policy', plagiarism: 'Plagiarism policy'}); + expect(service).toBeTruthy(); + expect(service.privacy).toBe('Privacy policy'); + expect(service.plagiarism).toBe('Plagiarism policy'); + expect(service.loaded).toBe(true); }); }); diff --git a/src/app/errors/states/unauthorised/unauthorised.component.spec.ts b/src/app/errors/states/unauthorised/unauthorised.component.spec.ts index 83c64c3549..b0902a02aa 100644 --- a/src/app/errors/states/unauthorised/unauthorised.component.spec.ts +++ b/src/app/errors/states/unauthorised/unauthorised.component.spec.ts @@ -1,6 +1,11 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {Location} from '@angular/common'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {UnauthorisedComponent} from './unauthorised.component'; +const emptyProvider = {}; + describe('UnauthorisedComponent', () => { let component: UnauthorisedComponent; let fixture: ComponentFixture; @@ -8,13 +13,16 @@ describe('UnauthorisedComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [UnauthorisedComponent], - }).compileComponents(); + providers: [{provide: Location, useValue: emptyProvider}], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(UnauthorisedComponent, {set: {template: ''}}) + .compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(UnauthorisedComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/eula/accept-eula/accept-eula.component.spec.ts b/src/app/eula/accept-eula/accept-eula.component.spec.ts index 8a896ee187..9912d785e5 100644 --- a/src/app/eula/accept-eula/accept-eula.component.spec.ts +++ b/src/app/eula/accept-eula/accept-eula.component.spec.ts @@ -1,6 +1,20 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {Router} from '@angular/router'; +import {EMPTY} from 'rxjs'; +import {UserService} from 'src/app/api/models/doubtfire-model'; +import {TiiService} from 'src/app/api/services/tii.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {AcceptEulaComponent} from './accept-eula.component'; +const constantsStub = { + ExternalName: EMPTY, + IsTiiEnabled: EMPTY, +}; +const emptyProvider = {}; + describe('AcceptEulaComponent', () => { let component: AcceptEulaComponent; let fixture: ComponentFixture; @@ -8,11 +22,22 @@ describe('AcceptEulaComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [AcceptEulaComponent], - }).compileComponents(); + providers: [ + {provide: DoubtfireConstants, useValue: constantsStub}, + {provide: TiiService, useValue: emptyProvider}, + {provide: UserService, useValue: emptyProvider}, + {provide: AlertService, useValue: emptyProvider}, + {provide: Router, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(AcceptEulaComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(AcceptEulaComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/home/splash-screen/splash-screen.component.spec.ts b/src/app/home/splash-screen/splash-screen.component.spec.ts index a1337fe240..6f13f45e5f 100644 --- a/src/app/home/splash-screen/splash-screen.component.spec.ts +++ b/src/app/home/splash-screen/splash-screen.component.spec.ts @@ -1,32 +1,32 @@ -import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; -import {BrowserAnimationsModule} from '@angular/platform-browser/animations'; -import {BehaviorSubject} from 'rxjs'; +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {GlobalStateService} from 'src/app/projects/states/index/global-state.service'; +import {LoadingService} from './LoadingService.service'; import {SplashScreenComponent} from './splash-screen.component'; +const emptyProvider = {}; + describe('SplashScreenComponent', () => { let component: SplashScreenComponent; let fixture: ComponentFixture; - let globalStateServiceStub: Partial; - - beforeEach(waitForAsync(() => { - const isLoadingSubject: BehaviorSubject = new BehaviorSubject(true); - globalStateServiceStub = { - isLoadingSubject: isLoadingSubject, - }; - - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [SplashScreenComponent], - imports: [BrowserAnimationsModule], - providers: [{provide: GlobalStateService, useValue: globalStateServiceStub}], - }).compileComponents(); - })); + providers: [ + {provide: GlobalStateService, useValue: emptyProvider}, + {provide: LoadingService, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(SplashScreenComponent, {set: {template: ''}}) + .compileComponents(); + }); beforeEach(() => { fixture = TestBed.createComponent(SplashScreenComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.spec.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.spec.ts index d1b100354a..ced1674ccc 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.spec.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.spec.ts @@ -1,6 +1,12 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {TaskService} from 'src/app/api/services/task.service'; +import {GradeService} from 'src/app/common/services/grade.service'; import {TaskAssessmentCardComponent} from './task-assessment-card.component'; +const emptyProvider = {}; + describe('TaskAssessmentCardComponent', () => { let component: TaskAssessmentCardComponent; let fixture: ComponentFixture; @@ -8,11 +14,19 @@ describe('TaskAssessmentCardComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [TaskAssessmentCardComponent], - }).compileComponents(); + providers: [ + {provide: TaskService, useValue: emptyProvider}, + {provide: GradeService, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(TaskAssessmentCardComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(TaskAssessmentCardComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.spec.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.spec.ts index 1b973c53f4..ea4330e5de 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.spec.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.spec.ts @@ -1,3 +1,5 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; import {TaskDueCardComponent} from './task-due-card.component'; @@ -8,11 +10,15 @@ describe('TaskDueCardComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [TaskDueCardComponent], - }).compileComponents(); + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(TaskDueCardComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(TaskDueCardComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.spec.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.spec.ts index c1f5ef4abf..d377730a00 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.spec.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.spec.ts @@ -1,6 +1,22 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {ActivatedRoute} from '@angular/router'; +import {EMPTY} from 'rxjs'; +import {TaskService} from 'src/app/api/services/task.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {ExtensionModalService} from 'src/app/common/modals/extension-modal/extension-modal.service'; +import {QrModalService} from 'src/app/common/modals/qr-modal/qr-modal.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {FeedbackAppealModalService} from 'src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.service'; +import {SubmissionTypeModalService} from 'src/app/tasks/modals/submission-type-modal/submission-type-modal.service'; import {TaskStatusCardComponent} from './task-status-card.component'; +const taskServiceStub = { + taskStatusUpdated$: EMPTY, +}; +const emptyProvider = {}; + describe('TaskStatusCardComponent', () => { let component: TaskStatusCardComponent; let fixture: ComponentFixture; @@ -8,11 +24,25 @@ describe('TaskStatusCardComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [TaskStatusCardComponent], - }).compileComponents(); + providers: [ + {provide: ExtensionModalService, useValue: emptyProvider}, + {provide: TaskService, useValue: taskServiceStub}, + {provide: ActivatedRoute, useValue: emptyProvider}, + {provide: QrModalService, useValue: emptyProvider}, + {provide: DoubtfireConstants, useValue: emptyProvider}, + {provide: SubmissionTypeModalService, useValue: emptyProvider}, + {provide: UserService, useValue: emptyProvider}, + {provide: FeedbackAppealModalService, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(TaskStatusCardComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(TaskStatusCardComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.spec.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.spec.ts index bdfd4708ab..21b537a0ca 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.spec.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.spec.ts @@ -1,6 +1,13 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {TaskService} from 'src/app/api/services/task.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {AlertService} from 'src/app/common/services/alert.service'; import {TaskSubmissionCardComponent} from './task-submission-card.component'; +const emptyProvider = {}; + describe('TaskSubmissionCardComponent', () => { let component: TaskSubmissionCardComponent; let fixture: ComponentFixture; @@ -8,11 +15,20 @@ describe('TaskSubmissionCardComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [TaskSubmissionCardComponent], - }).compileComponents(); + providers: [ + {provide: TaskService, useValue: emptyProvider}, + {provide: AlertService, useValue: emptyProvider}, + {provide: FileDownloaderService, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(TaskSubmissionCardComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(TaskSubmissionCardComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.spec.ts b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.spec.ts index 4695f366d0..195716d110 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.spec.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.spec.ts @@ -1,6 +1,15 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {ActivatedRoute} from '@angular/router'; +import {TaskService} from 'src/app/api/services/task.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {SelectedTaskService} from '../../selected-task.service'; import {TaskDashboardComponent} from './task-dashboard.component'; +const emptyProvider = {}; + describe('TaskDashboardComponent', () => { let component: TaskDashboardComponent; let fixture: ComponentFixture; @@ -8,11 +17,22 @@ describe('TaskDashboardComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [TaskDashboardComponent], - }).compileComponents(); + providers: [ + {provide: TaskService, useValue: emptyProvider}, + {provide: FileDownloaderService, useValue: emptyProvider}, + {provide: ActivatedRoute, useValue: emptyProvider}, + {provide: UserService, useValue: emptyProvider}, + {provide: SelectedTaskService, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(TaskDashboardComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(TaskDashboardComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/projects/states/dashboard/selected-task.service.spec.ts b/src/app/projects/states/dashboard/selected-task.service.spec.ts index c1ce156e72..cecaef3b82 100644 --- a/src/app/projects/states/dashboard/selected-task.service.spec.ts +++ b/src/app/projects/states/dashboard/selected-task.service.spec.ts @@ -1,11 +1,22 @@ +import {beforeEach, describe, expect, it} from 'vitest'; import {TestBed} from '@angular/core/testing'; +import {TaskService} from 'src/app/api/services/task.service'; +import {GlobalStateService} from '../index/global-state.service'; import {SelectedTaskService} from './selected-task.service'; +const emptyProvider = {}; + describe('SelectedTaskService', () => { let service: SelectedTaskService; beforeEach(() => { - TestBed.configureTestingModule({}); + TestBed.configureTestingModule({ + providers: [ + SelectedTaskService, + {provide: TaskService, useValue: emptyProvider}, + {provide: GlobalStateService, useValue: emptyProvider}, + ], + }); service = TestBed.inject(SelectedTaskService); }); diff --git a/src/app/projects/states/staff-notes/staff-notes.component.spec.ts b/src/app/projects/states/staff-notes/staff-notes.component.spec.ts index 150a9e5afd..270c10d536 100644 --- a/src/app/projects/states/staff-notes/staff-notes.component.spec.ts +++ b/src/app/projects/states/staff-notes/staff-notes.component.spec.ts @@ -1,18 +1,36 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {UserService} from 'src/app/api/models/doubtfire-model'; +import {StaffNoteService} from 'src/app/api/services/staff-note.service'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; import {StaffNotesComponent} from './staff-notes.component'; +const emptyProvider = {}; + describe('StaffNotesComponent', () => { let component: StaffNotesComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [StaffNotesComponent], - }).compileComponents(); + declarations: [StaffNotesComponent], + providers: [ + {provide: UserService, useValue: emptyProvider}, + {provide: StaffNoteService, useValue: emptyProvider}, + {provide: AlertService, useValue: emptyProvider}, + {provide: ConfirmationModalService, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(StaffNotesComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(StaffNotesComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.spec.ts b/src/app/projects/states/tutor-discussion/tutor-discussion.component.spec.ts index 9f471f8d55..75306dc282 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.spec.ts +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.spec.ts @@ -1,18 +1,55 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {MatDialog} from '@angular/material/dialog'; +import {ActivatedRoute, Router} from '@angular/router'; +import { + AuthenticationService, + ProjectService, + TaskCommentService, + TaskService, + UnitService, + UserService, +} from 'src/app/api/models/doubtfire-model'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {DiscussedInClassReasonModalService} from 'src/app/common/modals/discussed-in-class-reason-modal/discussed-in-class-reason-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {GradeService} from 'src/app/common/services/grade.service'; import {TutorDiscussionComponent} from './tutor-discussion.component'; +const emptyProvider = {}; + describe('TutorDiscussionComponent', () => { let component: TutorDiscussionComponent; let fixture: ComponentFixture; beforeEach(async () => { await TestBed.configureTestingModule({ - imports: [TutorDiscussionComponent], - }).compileComponents(); + declarations: [TutorDiscussionComponent], + providers: [ + {provide: UnitService, useValue: emptyProvider}, + {provide: AuthenticationService, useValue: emptyProvider}, + {provide: UserService, useValue: emptyProvider}, + {provide: ProjectService, useValue: emptyProvider}, + {provide: GradeService, useValue: emptyProvider}, + {provide: Router, useValue: emptyProvider}, + {provide: ActivatedRoute, useValue: emptyProvider}, + {provide: AlertService, useValue: emptyProvider}, + {provide: ConfirmationModalService, useValue: emptyProvider}, + {provide: DiscussedInClassReasonModalService, useValue: emptyProvider}, + {provide: TaskCommentService, useValue: emptyProvider}, + {provide: TaskService, useValue: emptyProvider}, + {provide: MatDialog, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(TutorDiscussionComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(TutorDiscussionComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/sessions/states/sign-in/sign-in.component.spec.ts b/src/app/sessions/states/sign-in/sign-in.component.spec.ts index ccc7662322..f80e7c1961 100644 --- a/src/app/sessions/states/sign-in/sign-in.component.spec.ts +++ b/src/app/sessions/states/sign-in/sign-in.component.spec.ts @@ -1,6 +1,17 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {HttpClient} from '@angular/common/http'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {ActivatedRoute, Router} from '@angular/router'; +import {AuthenticationService} from 'src/app/api/services/authentication.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {GlobalStateService} from 'src/app/projects/states/index/global-state.service'; import {SignInComponent} from './sign-in.component'; +const emptyProvider = {}; + describe('SignInComponent', () => { let component: SignInComponent; let fixture: ComponentFixture; @@ -8,13 +19,25 @@ describe('SignInComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [SignInComponent], - }).compileComponents(); + providers: [ + {provide: AuthenticationService, useValue: emptyProvider}, + {provide: UserService, useValue: emptyProvider}, + {provide: Router, useValue: emptyProvider}, + {provide: ActivatedRoute, useValue: emptyProvider}, + {provide: DoubtfireConstants, useValue: emptyProvider}, + {provide: HttpClient, useValue: emptyProvider}, + {provide: GlobalStateService, useValue: emptyProvider}, + {provide: AlertService, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(SignInComponent, {set: {template: ''}}) + .compileComponents(); }); beforeEach(() => { fixture = TestBed.createComponent(SignInComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/sessions/transition-hooks.service.spec.ts b/src/app/sessions/transition-hooks.service.spec.ts deleted file mode 100644 index 3addee99f2..0000000000 --- a/src/app/sessions/transition-hooks.service.spec.ts +++ /dev/null @@ -1,15 +0,0 @@ -import {TestBed} from '@angular/core/testing'; -import {TransitionHooksService} from './transition-hooks.service'; - -describe('TransitionHooksService', () => { - let service: TransitionHooksService; - - beforeEach(() => { - TestBed.configureTestingModule({}); - service = TestBed.inject(TransitionHooksService); - }); - - it('should be created', () => { - expect(service).toBeTruthy(); - }); -}); diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.spec.ts b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.spec.ts index ff7c7d796a..5ee4e03498 100644 --- a/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.spec.ts +++ b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.spec.ts @@ -1,4 +1,6 @@ -import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; +import {beforeEach, describe, expect, it, vi} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {GradeService} from 'src/app/common/services/grade.service'; import {GradeTaskModalComponent} from './grade-task-modal.component'; @@ -6,41 +8,25 @@ import {GradeTaskModalComponent} from './grade-task-modal.component'; describe('GradeTaskModalComponent', () => { let component: GradeTaskModalComponent; let fixture: ComponentFixture; - let gradeServiceStub: Pick; + let gradeServiceStub: GradeService; let dialogRefMock: {close: () => void}; let dialogDataStub: { task: { grade?: number; - quality_pts?: number; - definition: {max_quality_pts?: number}; + qualityPts?: number; + definition: {maxQualityPts?: number}; }; }; - beforeEach(waitForAsync(() => { - gradeServiceStub = { - grades: ['Pass', 'Credit', 'Distinction', 'High Distinction'], - gradeAcronyms: { - Fail: 'F', - Pass: 'P', - Credit: 'C', - Distinction: 'D', - 'High Distinction': 'HD', - 0: 'P', - 1: 'C', - 2: 'D', - 3: 'HD', - }, - allGradeValues: [-1, 0, 1, 2, 3], - }; - gradeServiceStub.grades[-1] = 'Fail'; - gradeServiceStub.gradeAcronyms[-1] = 'F'; + beforeEach(async () => { + gradeServiceStub = new GradeService(); dialogDataStub = { task: { grade: undefined, - quality_pts: undefined, + qualityPts: undefined, definition: { - max_quality_pts: undefined, + maxQualityPts: undefined, }, }, }; @@ -51,15 +37,16 @@ describe('GradeTaskModalComponent', () => { }, }; - TestBed.configureTestingModule({ + await TestBed.configureTestingModule({ declarations: [GradeTaskModalComponent], providers: [ {provide: GradeService, useValue: gradeServiceStub}, {provide: MatDialogRef, useValue: dialogRefMock}, {provide: MAT_DIALOG_DATA, useValue: dialogDataStub}, ], + schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); - })); + }); beforeEach(() => { fixture = TestBed.createComponent(GradeTaskModalComponent); @@ -72,7 +59,7 @@ describe('GradeTaskModalComponent', () => { }); it('should return rating & grade when closed', () => { - spyOn(component.dialogRef, 'close'); + vi.spyOn(component.dialogRef, 'close'); component.rating = 5; component.selectedGrade = 2; @@ -85,7 +72,7 @@ describe('GradeTaskModalComponent', () => { }); it('should dismiss', () => { - spyOn(component.dialogRef, 'close'); + vi.spyOn(component.dialogRef, 'close'); component.dismiss(); expect(component.dialogRef.close).toHaveBeenCalled(); }); @@ -96,18 +83,18 @@ describe('GradeTaskModalComponent', () => { it('should accept a new task object', () => { const newRatingTask = { grade: undefined, - quality_pts: 5, + qualityPts: 5, definition: { - max_quality_pts: 10, + maxQualityPts: 10, }, }; dialogDataStub.task = newRatingTask; component.ngOnInit(); expect(component.task).toEqual(newRatingTask); - expect(component.rating).toEqual(newRatingTask.quality_pts); - expect(component.selectedGrade).toEqual(newRatingTask.grade); - expect(component.totalRating).toEqual(newRatingTask.definition.max_quality_pts); + expect(component.rating).toEqual(newRatingTask.qualityPts); + expect(component.selectedGrade).toEqual(0); + expect(component.totalRating).toEqual(newRatingTask.definition.maxQualityPts); }); it('should not allow a rating higher than the max rating', () => { @@ -167,9 +154,9 @@ describe('GradeTaskModalComponent', () => { it('should not accept a new invalid grade', () => { component.ngOnInit(); component.updateGrade(10); - expect(component.selectedGrade).toEqual(undefined); + expect(component.selectedGrade).toEqual(0); component.updateGrade(-10); - expect(component.selectedGrade).toEqual(undefined); + expect(component.selectedGrade).toEqual(0); }); }); diff --git a/src/app/tasks/task-comments-viewer/comment-bubble-action/comment-bubble-action.component.spec.ts b/src/app/tasks/task-comments-viewer/comment-bubble-action/comment-bubble-action.component.spec.ts index 5bb9a879fa..7e7508a7d2 100644 --- a/src/app/tasks/task-comments-viewer/comment-bubble-action/comment-bubble-action.component.spec.ts +++ b/src/app/tasks/task-comments-viewer/comment-bubble-action/comment-bubble-action.component.spec.ts @@ -1,33 +1,31 @@ -// import { async, ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -// import { TaskComment } from 'src/app/api/models/doubtfire-model'; +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; +import {CommentBubbleActionComponent} from './comment-bubble-action.component'; -// import { CommentBubbleActionComponent } from './comment-bubble-action.component'; +const emptyProvider = {}; -// describe('CommentBubbleActionComponent', () => { -// let component: CommentBubbleActionComponent; -// let fixture: ComponentFixture; -// let taskComment: TaskComment; +describe('CommentBubbleActionComponent', () => { + let component: CommentBubbleActionComponent; + let fixture: ComponentFixture; -// beforeEach( -// waitForAsync(() => { -// TestBed.configureTestingModule({ -// declarations: [CommentBubbleActionComponent], -// }).compileComponents(); -// }) -// ); + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [CommentBubbleActionComponent], + providers: [{provide: ConfirmationModalService, useValue: emptyProvider}], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(CommentBubbleActionComponent, {set: {template: ''}}) + .compileComponents(); + }); -// beforeEach(() => { -// fixture = TestBed.createComponent(CommentBubbleActionComponent); -// component = fixture.componentInstance; + beforeEach(() => { + fixture = TestBed.createComponent(CommentBubbleActionComponent); + component = fixture.componentInstance; + }); -// taskComment = jasmine.createSpyObj('TaskComment', ['currentUserCanEdit']); -// taskComment.currentUserCanEdit.and.returnValue(false); -// component.comment = taskComment; - -// fixture.detectChanges(); -// }); - -// it('should create', () => { -// expect(component).toBeTruthy(); -// }); -// }); + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.spec.ts b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.spec.ts index d28e56ff6b..908c92e587 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.spec.ts +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.spec.ts @@ -1,47 +1,50 @@ -// import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -// import { EventEmitter } from '@angular/core'; -// import { alertService, commentsModal } from 'src/app/ajs-upgraded-providers'; -// import { TaskComment, TaskCommentService } from 'src/app/api/models/doubtfire-model'; -// import { DoubtfireConstants } from 'src/app/config/constants/doubtfire-constants'; +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {EMPTY} from 'rxjs'; +import {TaskCommentService, TaskService, UserService} from 'src/app/api/models/doubtfire-model'; +import {FeedbackTemplateService} from 'src/app/api/services/feedback-template.service'; +import {CommentsModalService} from 'src/app/common/modals/comments-modal/comments-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {TaskCommentsViewerComponent} from './task-comments-viewer.component'; -// import { TaskCommentsViewerComponent } from './task-comments-viewer.component'; +const taskCommentServiceStub = { + commentAdded$: EMPTY, +}; +const taskServiceStub = { + taskStatusUpdated$: EMPTY, +}; +const emptyProvider = {}; -// describe('TaskCommentsViewerComponent', () => { -// let component: TaskCommentsViewerComponent; -// let fixture: ComponentFixture; -// let taskCommentServiceStub: Partial; -// let doubtfireConstantsStub: Partial; -// let commentsModalStub: jasmine.SpyObj; -// let taskStub: jasmine.SpyObj; -// let alertServiceStub: jasmine.SpyObj; +describe('TaskCommentsViewerComponent', () => { + let component: TaskCommentsViewerComponent; + let fixture: ComponentFixture; -// beforeEach( -// waitForAsync(() => { -// const commentAdded: EventEmitter = new EventEmitter(); -// taskCommentServiceStub = { -// commentAdded$: commentAdded, -// }; + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [TaskCommentsViewerComponent], + providers: [ + {provide: TaskCommentService, useValue: taskCommentServiceStub}, + {provide: FeedbackTemplateService, useValue: emptyProvider}, + {provide: UserService, useValue: emptyProvider}, + {provide: TaskService, useValue: taskServiceStub}, + {provide: DoubtfireConstants, useValue: emptyProvider}, + {provide: CommentsModalService, useValue: emptyProvider}, + {provide: AlertService, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(TaskCommentsViewerComponent, {set: {template: ''}}) + .compileComponents(); + }); -// TestBed.configureTestingModule({ -// declarations: [TaskCommentsViewerComponent], -// providers: [ -// { provide: TaskCommentService, useValue: taskCommentServiceStub }, -// { provide: DoubtfireConstants, useValue: doubtfireConstantsStub }, -// { provide: commentsModal, useValue: commentsModalStub }, -// { provide: Task, useValue: taskStub }, -// { provide: alertService, useValue: alertServiceStub }, -// ], -// }).compileComponents(); -// }) -// ); + beforeEach(() => { + fixture = TestBed.createComponent(TaskCommentsViewerComponent); + component = fixture.componentInstance; + }); -// beforeEach(() => { -// fixture = TestBed.createComponent(TaskCommentsViewerComponent); -// component = fixture.componentInstance; -// fixture.detectChanges(); -// }); - -// it('should create', () => { -// expect(component).toBeTruthy(); -// }); -// }); + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/test.service.spec.ts b/src/app/test.service.spec.ts index c8a75e8168..6c5f5a280c 100644 --- a/src/app/test.service.spec.ts +++ b/src/app/test.service.spec.ts @@ -1,3 +1,4 @@ +import {beforeEach, describe, expect, it} from 'vitest'; import {TestBed} from '@angular/core/testing'; import {TestService} from './test.service'; diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.spec.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.spec.ts index 0563c6366a..c6869756c4 100644 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.spec.ts +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.spec.ts @@ -1,22 +1,35 @@ -import {ComponentFixture, TestBed, waitForAsync} from '@angular/core/testing'; -import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; +import {CampusService} from 'src/app/api/services/campus.service'; +import {AlertService} from 'src/app/common/services/alert.service'; import {UnitStudentEnrolmentModalComponent} from './unit-student-enrolment-modal.component'; -describe('RolloverTeachingPeriodModalComponent', () => { +const emptyProvider = {}; + +describe('UnitStudentEnrolmentModalComponent', () => { let component: UnitStudentEnrolmentModalComponent; let fixture: ComponentFixture; - beforeEach(waitForAsync(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [UnitStudentEnrolmentModalComponent], - providers: [{provide: DoubtfireConstants}], - }).compileComponents(); - })); + providers: [ + {provide: MatDialogRef, useValue: emptyProvider}, + {provide: MAT_DIALOG_DATA, useValue: emptyProvider}, + {provide: AlertService, useValue: emptyProvider}, + {provide: CampusService, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(UnitStudentEnrolmentModalComponent, {set: {template: ''}}) + .compileComponents(); + }); beforeEach(() => { fixture = TestBed.createComponent(UnitStudentEnrolmentModalComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.spec.ts b/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.spec.ts index fbf1d43a79..e80775b77a 100644 --- a/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.spec.ts +++ b/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.spec.ts @@ -1,63 +1,57 @@ -// import { ComponentFixture, TestBed, waitForAsync } from '@angular/core/testing'; -// import { MatDialogModule } from '@angular/material/dialog'; -// import { MatMenuModule } from '@angular/material/menu'; -// import { alertService, currentUser, groupService, taskDefinition, Unit } from 'src/app/ajs-upgraded-providers'; - -// import { StaffTaskListComponent } from './staff-task-list.component'; - -// describe('StaffTaskListComponent', () => { -// let component: StaffTaskListComponent; -// let fixture: ComponentFixture; -// let taskDefinitionStub: jasmine.SpyObj; -// let unitStub: jasmine.SpyObj; -// let currentUserStub: jasmine.SpyObj; -// let groupServiceStub: jasmine.SpyObj; -// let alertServiceStub: jasmine.SpyObj; - -// beforeEach( -// waitForAsync(() => { -// unitStub = { -// tasksForDefinition: [], -// }; -// currentUserStub = { -// profile: { name: 'Bob Marley' }, -// }; - -// TestBed.configureTestingModule({ -// declarations: [StaffTaskListComponent], -// imports: [ -// MatDialogModule, -// MatMenuModule -// ], -// providers: [ -// { provide: taskDefinition, useValue: taskDefinitionStub }, -// { provide: currentUser, useValue: currentUserStub }, -// { provide: groupService, useValue: groupServiceStub }, -// { provide: alertService, useValue: alertServiceStub }, -// ], -// }).compileComponents(); -// }) -// ); - -// beforeEach(() => { -// fixture = TestBed.createComponent(StaffTaskListComponent); -// component = fixture.componentInstance; - -// component.taskData = { -// selectedTask: null, -// }; -// component.unit = { -// tutorialsForUserName: () => [], -// tutorials: [], -// }; -// component.unitRole = { -// role: 'Convenor', -// }; - -// fixture.detectChanges(); -// }); - -// it('should create', () => { -// expect(component).toBeTruthy(); -// }); -// }); +import {HotkeysService} from '@ngneat/hotkeys'; +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {MatDialog} from '@angular/material/dialog'; +import {ActivatedRoute, Router} from '@angular/router'; +import {UserService} from 'src/app/api/models/doubtfire-model'; +import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {CsvResultModalService} from 'src/app/common/modals/csv-result-modal/csv-result-modal.service'; +import {CsvUploadModalService} from 'src/app/common/modals/csv-upload-modal/csv-upload-modal.service'; +import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; +import {AlertService} from 'src/app/common/services/alert.service'; +import {SelectedTaskService} from 'src/app/projects/states/dashboard/selected-task.service'; +import {StaffTaskListComponent} from './staff-task-list.component'; + +const hotkeysServiceStub = { + removeShortcuts: () => {}, +}; +const emptyProvider = {}; + +describe('StaffTaskListComponent', () => { + let component: StaffTaskListComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [StaffTaskListComponent], + providers: [ + {provide: SelectedTaskService, useValue: emptyProvider}, + {provide: AlertService, useValue: emptyProvider}, + {provide: FileDownloaderService, useValue: emptyProvider}, + {provide: MatDialog, useValue: emptyProvider}, + {provide: CsvUploadModalService, useValue: emptyProvider}, + {provide: CsvResultModalService, useValue: emptyProvider}, + {provide: UserService, useValue: emptyProvider}, + {provide: HotkeysService, useValue: hotkeysServiceStub}, + {provide: Router, useValue: emptyProvider}, + {provide: ActivatedRoute, useValue: emptyProvider}, + {provide: TaskDefinitionService, useValue: emptyProvider}, + {provide: SidekiqProgressModalService, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(StaffTaskListComponent, {set: {template: ''}}) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(StaffTaskListComponent); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/units/states/tasks/inbox/inbox.component.spec.ts b/src/app/units/states/tasks/inbox/inbox.component.spec.ts index 9112a31a49..408a72a359 100644 --- a/src/app/units/states/tasks/inbox/inbox.component.spec.ts +++ b/src/app/units/states/tasks/inbox/inbox.component.spec.ts @@ -1,6 +1,26 @@ +import {HotkeysService} from '@ngneat/hotkeys'; +import {MediaObserver} from 'ng-flex-layout'; +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {MatDialog} from '@angular/material/dialog'; +import {Router} from '@angular/router'; +import {EMPTY} from 'rxjs'; +import {UserService} from 'src/app/api/services/user.service'; +import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {SelectedTaskService} from 'src/app/projects/states/dashboard/selected-task.service'; import {InboxComponent} from './inbox.component'; +const selectedTaskServiceStub = { + currentPdfUrl$: EMPTY, + selectedTask$: EMPTY, +}; +const hotkeysServiceStub = { + removeShortcuts: () => {}, +}; +const emptyProvider = {}; + describe('InboxComponent', () => { let component: InboxComponent; let fixture: ComponentFixture; @@ -8,11 +28,25 @@ describe('InboxComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [InboxComponent], - }).compileComponents(); + providers: [ + {provide: HotkeysService, useValue: hotkeysServiceStub}, + {provide: SelectedTaskService, useValue: selectedTaskServiceStub}, + {provide: MediaObserver, useValue: emptyProvider}, + {provide: FileDownloaderService, useValue: emptyProvider}, + {provide: Router, useValue: emptyProvider}, + {provide: MatDialog, useValue: emptyProvider}, + {provide: UserService, useValue: emptyProvider}, + {provide: DoubtfireConstants, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(InboxComponent, {set: {template: ''}}) + .compileComponents(); + }); + beforeEach(() => { fixture = TestBed.createComponent(InboxComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.spec.ts b/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.spec.ts index e69de29bb2..2767eb6e97 100644 --- a/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.spec.ts +++ b/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.spec.ts @@ -0,0 +1,27 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; +import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {FTaskSheetViewComponent} from './task-sheet-view.component'; + +describe('FTaskSheetViewComponent', () => { + let component: FTaskSheetViewComponent; + let fixture: ComponentFixture; + + beforeEach(async () => { + await TestBed.configureTestingModule({ + declarations: [FTaskSheetViewComponent], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(FTaskSheetViewComponent, {set: {template: ''}}) + .compileComponents(); + }); + + beforeEach(() => { + fixture = TestBed.createComponent(FTaskSheetViewComponent); + component = fixture.componentInstance; + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.spec.ts b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.spec.ts index 09f4be518b..70a5cbc79d 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.spec.ts +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.spec.ts @@ -1,17 +1,31 @@ +import {beforeEach, describe, expect, it} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {ActivatedRoute, Router} from '@angular/router'; import {FUnitTaskListComponent} from './unit-task-list.component'; +const emptyProvider = {}; + describe('FUnitTaskListComponent', () => { let component: FUnitTaskListComponent; let fixture: ComponentFixture; - beforeEach(() => { - TestBed.configureTestingModule({ + beforeEach(async () => { + await TestBed.configureTestingModule({ declarations: [FUnitTaskListComponent], - }); + providers: [ + {provide: Router, useValue: emptyProvider}, + {provide: ActivatedRoute, useValue: emptyProvider}, + ], + schemas: [NO_ERRORS_SCHEMA], + }) + .overrideComponent(FUnitTaskListComponent, {set: {template: ''}}) + .compileComponents(); + }); + + beforeEach(() => { fixture = TestBed.createComponent(FUnitTaskListComponent); component = fixture.componentInstance; - fixture.detectChanges(); }); it('should create', () => { diff --git a/src/app/welcome/welcome.component.spec.ts b/src/app/welcome/welcome.component.spec.ts index 8c834e5b2b..4725c4d866 100644 --- a/src/app/welcome/welcome.component.spec.ts +++ b/src/app/welcome/welcome.component.spec.ts @@ -1,13 +1,58 @@ +import {beforeEach, describe, expect, it, vi} from 'vitest'; +import {NO_ERRORS_SCHEMA} from '@angular/core'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {Router} from '@angular/router'; +import {BehaviorSubject} from 'rxjs'; +import {AuthenticationService} from 'src/app/api/services/authentication.service'; +import {UserService} from 'src/app/api/services/user.service'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; +import {GlobalStateService} from 'src/app/projects/states/index/global-state.service'; import {WelcomeComponent} from './welcome.component'; describe('WelcomeComponent', () => { let component: WelcomeComponent; let fixture: ComponentFixture; + let afterAuthCallback: ((result: boolean) => void) | undefined; + let routerStub: {navigateByUrl: ReturnType}; + let globalStateStub: {hideHeader: ReturnType}; + let userServiceStub: {currentUser: {hasRunFirstTimeSetup: boolean}}; beforeEach(async () => { + afterAuthCallback = undefined; + routerStub = { + navigateByUrl: vi.fn(), + }; + globalStateStub = { + hideHeader: vi.fn(), + }; + userServiceStub = { + currentUser: { + hasRunFirstTimeSetup: false, + }, + }; + await TestBed.configureTestingModule({ declarations: [WelcomeComponent], + providers: [ + { + provide: DoubtfireConstants, + useValue: { + ExternalName: new BehaviorSubject('OnTrack'), + }, + }, + {provide: GlobalStateService, useValue: globalStateStub}, + { + provide: AuthenticationService, + useValue: { + afterAuthCall: vi.fn((callback: (result: boolean) => void) => { + afterAuthCallback = callback; + }), + }, + }, + {provide: Router, useValue: routerStub}, + {provide: UserService, useValue: userServiceStub}, + ], + schemas: [NO_ERRORS_SCHEMA], }).compileComponents(); }); @@ -20,4 +65,22 @@ describe('WelcomeComponent', () => { it('should create', () => { expect(component).toBeTruthy(); }); + + it('should hide the header while the welcome page is active', () => { + expect(globalStateStub.hideHeader).toHaveBeenCalled(); + }); + + it('should redirect unauthenticated users to sign in', () => { + expect(afterAuthCallback).toBeDefined(); + + afterAuthCallback?.(false); + + expect(routerStub.navigateByUrl).toHaveBeenCalledWith('/sign_in'); + }); + + it('should show the expected welcome heading', () => { + const element: HTMLElement = fixture.nativeElement; + + expect(element.textContent).toContain('Welcome to OnTrack'); + }); }); diff --git a/src/karma-ci.conf.js b/src/karma-ci.conf.js deleted file mode 100644 index 4393b51ebf..0000000000 --- a/src/karma-ci.conf.js +++ /dev/null @@ -1,32 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/0.13/config/configuration-file.html - -module.exports = function (config) { - config.set({ - logLevel: config.LOG_DEBUG, - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage-istanbul-reporter'), - require('@angular-devkit/build-angular/plugins/karma'), - ], - client: { - clearContext: false, // leave Jasmine Spec Runner output visible in browser - }, - coverageIstanbulReporter: { - dir: require('path').join(__dirname, 'coverage'), - reports: ['html', 'lcovonly'], - fixWebpackSourcePaths: true, - }, - angularCli: { - environment: 'dev', - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - singleRun: true, - browsers: ['ChromeHeadless'], - }); -}; diff --git a/src/karma.conf.js b/src/karma.conf.js deleted file mode 100644 index d5edcff1cb..0000000000 --- a/src/karma.conf.js +++ /dev/null @@ -1,40 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/0.13/config/configuration-file.html - -module.exports = function (config) { - config.set({ - logLevel: config.LOG_DEBUG, - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage-istanbul-reporter'), - - ], - client: { - clearContext: false, // leave Jasmine Spec Runner output visible in browser - }, - coverageIstanbulReporter: { - dir: require('path').join(__dirname, 'coverage'), - reports: ['html', 'lcovonly'], - fixWebpackSourcePaths: true, - }, - angularCli: { - environment: 'dev', - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - autoWatch: true, - browsers: ['Chrome'], - singleRun: false, - customLaunchers: { - ChromeDebug: { - base: 'Chrome', - flags: ['--remote-debugging-port=9333'], - }, - }, - }); -}; diff --git a/src/test.ts b/src/test.ts deleted file mode 100644 index 5f03b6f001..0000000000 --- a/src/test.ts +++ /dev/null @@ -1,27 +0,0 @@ -// This file is required by karma.conf.js and loads recursively all the .spec and framework files - -import 'zone.js/dist/long-stack-trace-zone'; -import 'zone.js/dist/proxy.js'; -import 'zone.js/dist/sync-test'; -import 'zone.js/dist/jasmine-patch'; -import 'zone.js/dist/async-test'; -import 'zone.js/dist/fake-async-test'; -import { getTestBed } from '@angular/core/testing'; -import { BrowserDynamicTestingModule, platformBrowserDynamicTesting } from '@angular/platform-browser-dynamic/testing'; - -declare const __karma__: { - loaded: () => void; - start: () => void; -}; - -// Prevent Karma from running prematurely. -__karma__.loaded = () => { - /* empty */ -}; - -// First, initialize the Angular testing environment. -getTestBed().initTestEnvironment(BrowserDynamicTestingModule, platformBrowserDynamicTesting(), { - teardown: { destroyAfterEach: false } -}); -// Finally, start Karma to run the tests. -__karma__.start(); diff --git a/src/tsconfig.spec.json b/src/tsconfig.spec.json index 70add2d529..5fa6abff5f 100644 --- a/src/tsconfig.spec.json +++ b/src/tsconfig.spec.json @@ -2,8 +2,8 @@ "extends": "../tsconfig.json", "compilerOptions": { "outDir": "../out-tsc/spec", - "types": ["jasmine", "node"] + "typeRoots": ["../node_modules/@types", "../node_modules"], + "types": ["vitest/globals", "node"] }, - "files": ["test.ts", "polyfills.ts"], - "include": ["**/*.spec.ts", "**/*.d.ts"] + "include": ["**/*.spec.ts", "**/*.d.ts", "vitest-setup.ts"] } diff --git a/src/vitest-setup.ts b/src/vitest-setup.ts new file mode 100644 index 0000000000..9ee7140bc8 --- /dev/null +++ b/src/vitest-setup.ts @@ -0,0 +1 @@ +import 'zone.js/plugins/vitest-patch'; From b5d57a5698f4477f8e5c5eff89c4961bfccf8d74 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:39:04 +1000 Subject: [PATCH 1132/1280] chore: upgrade to angular 22 --- package-lock.json | 2702 +++++++++++------ package.json | 30 +- .../edit-profile/edit-profile.component.ts | 3 +- .../activity-type-list.component.ts | 3 +- .../campus-list/campus-list.component.ts | 3 +- .../institution-settings.component.ts | 3 +- .../overseer-image-list.component.ts | 9 +- ...create-new-unit-modal-content.component.ts | 3 +- .../create-new-unit-modal.component.ts | 3 +- .../teaching-period-list.component.ts | 4 +- .../teaching-period-unit-import.dialog.ts | 10 +- src/app/admin/states/units/units.component.ts | 10 +- src/app/admin/states/users/users.component.ts | 10 +- .../tii-action-log.component.ts | 3 +- .../api/services/spec/campus.service.spec.ts | 9 +- .../api/services/spec/user.service.spec.ts | 9 +- src/app/app.component.ts | 3 +- .../archive-viewer.component.ts | 2 + .../audio-player/audio-player.component.ts | 11 +- .../audio-comment-recorder.ts | 3 +- .../microphone-tester.component.ts | 3 +- .../chart-base-component.component.ts | 3 +- .../edit-profile-form.component.ts | 3 +- src/app/common/f-chip/chip.component.ts | 3 +- .../feedback-template-editor.component.ts | 11 +- .../common/file-drop/file-drop.component.html | 4 +- .../common/file-drop/file-drop.component.ts | 3 +- .../file-uploader.component.html | 5 +- .../file-uploader/file-uploader.component.ts | 2 + .../file-viewer/file-viewer.component.ts | 10 +- src/app/common/footer/footer.component.ts | 11 +- .../common/grade-icon/grade-icon.component.ts | 10 +- src/app/common/header/header.component.ts | 3 +- .../task-dropdown/task-dropdown.component.ts | 3 +- .../unit-dropdown.component.html | 2 +- .../unit-dropdown/unit-dropdown.component.ts | 3 +- .../hero-sidebar/hero-sidebar.component.ts | 3 +- .../learning-outcome-editor.component.ts | 2 + .../nested-csv-download-modal.component.ts | 3 +- .../about-doubtfire-modal.component.ts | 3 +- .../calendar-modal.component.ts | 10 +- .../comments-modal.component.ts | 3 +- .../confirmation-modal.component.ts | 3 +- .../csv-result-modal.component.ts | 3 +- .../csv-upload-modal.component.ts | 3 +- .../task-date-slider.component.ts | 3 +- ...scussed-in-class-reason-modal.component.ts | 3 +- .../extension-modal.component.ts | 3 +- .../modals/qr-modal/qr-modal.component.ts | 3 +- .../scorm-extension-modal.component.ts | 3 +- .../sidekiq-jobs-modal.component.ts | 3 +- .../sidekiq-progress-modal.component.ts | 3 +- .../spec-con-modal.component.ts | 3 +- .../task-assessment-modal.component.ts | 3 +- .../tutor-notes-modal.component.ts | 3 +- .../obect-select/object-select.component.ts | 3 +- .../pdf-viewer-panel.component.ts | 3 +- .../common/pdf-viewer/pdf-viewer.component.ts | 2 + .../project-progress-bar.component.ts | 3 +- .../project-progress-gauge.component.ts | 10 +- .../scorm-player/scorm-player.component.ts | 3 +- src/app/common/services/alert.service.ts | 3 +- .../status-icon/status-icon.component.ts | 3 +- .../submission-files-download.component.ts | 3 +- .../success-close/success-close.component.ts | 3 +- .../common/task-badge/task-badge.component.ts | 3 +- .../common/unit-code/unit-code.component.ts | 3 +- .../user-badge/user-badge.component.html | 2 +- .../common/user-badge/user-badge.component.ts | 3 +- .../common/user-icon/user-icon.component.ts | 2 + .../privacy-policy/privacy-policy.spec.ts | 4 +- .../states/timeout/timeout.component.ts | 3 +- .../unauthorised/unauthorised.component.ts | 3 +- .../unavailable-card.component.ts | 3 +- .../eula/accept-eula/accept-eula.component.ts | 3 +- ...-member-contribution-assigner.component.ts | 2 + .../group-member-list.component.ts | 10 +- .../group-selector.component.ts | 2 + .../group-set-manager.component.ts | 3 +- .../group-set-selector.component.ts | 10 +- .../splash-screen/splash-screen.component.ts | 3 +- src/app/home/states/home/home.component.html | 12 +- src/app/home/states/home/home.component.ts | 3 +- .../lti-dashboard/lti-dashboard.component.ts | 3 +- .../lti-unit-link/lti-unit-link.component.ts | 3 +- src/app/legacy-route-placeholder.component.ts | 3 +- .../project-progress-dashboard.component.ts | 3 +- .../add-engagement-dialog.component.ts | 3 +- .../engagement-detail-dialog.component.ts | 11 +- .../engagement-passport-card.component.ts | 3 +- .../progress-dashboard.component.ts | 10 +- .../task-planner-card.component.ts | 3 +- ...eate-portfolio-task-list-item.component.ts | 3 +- .../task-list-item.component.ts | 3 +- .../discussion-prompts-view.component.ts | 3 +- .../staff-notes-view.component.ts | 3 +- .../task-assessment-card.component.ts | 3 +- .../task-description-card.component.html | 5 +- .../task-description-card.component.ts | 10 +- .../task-due-card.component.html | 14 +- .../task-due-card/task-due-card.component.ts | 3 +- .../task-ilos-card.component.ts | 10 +- .../submission-files-modal.component.html | 6 +- .../submission-files-modal.component.ts | 3 +- .../task-overseer-report.component.ts | 3 +- .../task-prerequisites-card.component.ts | 3 +- .../task-scorm-card.component.ts | 3 +- .../task-similarity-view.component.html | 5 +- .../task-similarity-view.component.ts | 10 +- .../task-status-card.component.html | 12 +- .../task-status-card.component.ts | 11 +- .../task-submission-card.component.ts | 10 +- .../tutor-notes-view.component.ts | 3 +- .../task-dashboard.component.ts | 10 +- .../project-dashboard.component.ts | 3 +- .../discussion-prompts.component.ts | 10 +- .../groups/project-groups-state.component.ts | 3 +- .../project-groups.component.ts | 3 +- .../jplag/jplag-report-viewer.component.ts | 3 +- .../states/plan/project-plan.component.ts | 10 +- ...k-planner-prerequisites-modal.component.ts | 3 +- .../task-planner/task-planner.component.ts | 2 + ...ortfolio-add-extra-files-step.component.ts | 3 +- .../portfolio-grade-select-step.component.ts | 3 +- ...-learning-summary-report-step.component.ts | 3 +- .../portfolio-included-tasks.component.ts | 11 +- .../portfolio-review-step.component.ts | 3 +- .../portfolio-welcome-step.component.ts | 3 +- .../portfolio/portfolio-state.component.ts | 3 +- .../states/project-root-state.component.ts | 3 +- .../staff-notes/staff-notes.component.ts | 10 +- .../tutor-discussion.component.html | 16 +- .../tutor-discussion.component.ts | 2 + .../tutor-notes/tutor-notes.component.ts | 10 +- .../states/tutorials/tutorials.component.ts | 3 +- .../states/sign-in/sign-in.component.ts | 3 +- .../feedback-appeal-modal.component.ts | 3 +- .../grade-task-modal.component.ts | 3 +- .../submission-type-modal.component.ts | 3 +- .../upload-submission-modal.component.ts | 3 +- .../project-tasks-list.component.ts | 10 +- ...ttachment-confirmation-dialog.component.ts | 3 +- .../discussion-prompt-composer.component.ts | 11 +- .../task-comment-composer.component.ts | 3 + .../task-feedback-templates.component.ts | 2 + .../comment-bubble-action.component.ts | 3 +- .../extension-comment.component.ts | 3 +- ...intelligent-discussion-player.component.ts | 11 +- ...telligent-discussion-recorder.component.ts | 3 +- .../pdf-image-comment.component.ts | 3 +- .../scorm-comment/scorm-comment.component.ts | 3 +- .../scorm-extension-comment.component.ts | 3 +- .../task-assessment-comment.component.ts | 3 +- .../task-comments-viewer.component.ts | 2 + .../unit-student-enrolment-modal.component.ts | 3 +- .../analytics-tutor-times.component.ts | 3 +- .../unit-analytics-route.component.ts | 3 +- .../change-target-grade-action.component.ts | 3 +- .../communication-actions.component.ts | 3 +- .../email-staff-action.component.ts | 3 +- .../email-student-action.component.ts | 3 +- .../task-comment-action.component.ts | 3 +- .../communication-schedule-modal.component.ts | 3 +- .../communication-schedules.component.ts | 3 +- .../communication-conditions.component.ts | 3 +- .../unit-communications-editor.component.ts | 11 +- .../d2l-unit-details-form.component.ts | 3 +- .../unit-details-editor.component.html | 14 +- .../unit-details-editor.component.ts | 3 +- .../unit-group-set-editor.component.ts | 3 +- .../bulk-import-staff-modal.component.ts | 3 +- .../unit-staff-editor.component.ts | 3 +- .../student-campus-select.component.ts | 3 +- .../student-tutorial-select.component.ts | 3 +- .../unit-students-editor.component.ts | 11 +- .../task-definition-dates.component.ts | 3 +- ...definition-discussion-prompts.component.ts | 10 +- .../task-definition-editor.component.ts | 2 + .../task-definition-general.component.ts | 3 +- .../task-definition-options.component.ts | 3 +- .../overseer-script-editor-modal.component.ts | 3 +- .../task-definition-overseer.component.ts | 11 +- ...sk-definition-prerequisites.component.html | 9 +- ...task-definition-prerequisites.component.ts | 10 +- .../task-definition-resources.component.ts | 3 +- .../task-definition-scorm.component.ts | 3 +- .../task-definition-upload.component.ts | 3 +- .../task-definition-who.component.html | 2 +- .../task-definition-who.component.ts | 3 +- .../unit-task-editor.component.ts | 3 +- .../unit-tutorials-list.component.ts | 3 +- .../unit-tutorials-manager.component.ts | 3 +- .../states/edit/unit-admin-state.component.ts | 3 +- .../unit-groups/unit-groups.component.ts | 3 +- .../d2l-transfer.component.ts | 3 +- .../portfolios-assessment.component.ts | 3 +- .../portfolios-list.component.ts | 2 + .../portfolios-portfolio-view.component.ts | 3 +- .../portfolios-project-progress.component.ts | 10 +- .../download-staff-notes.component.ts | 3 +- .../states/portfolios/portfolios.component.ts | 3 +- .../upload-grades/upload-grades.component.ts | 3 +- .../states/rollover/rollover.component.html | 14 +- .../states/rollover/rollover.component.ts | 3 +- .../students-list/students-list.component.ts | 11 +- .../inbox-dashboard.component.html | 4 +- .../inbox-dashboard.component.ts | 11 +- .../confirm-moderation-modal.component.ts | 3 +- .../moderation/moderation.component.ts | 3 +- ...atch-feedback-workflow-dialog.component.ts | 3 +- .../staff-task-list.component.ts | 2 + .../task-claim/task-claim.component.ts | 3 +- .../states/tasks/inbox/inbox.component.html | 4 +- .../states/tasks/inbox/inbox.component.ts | 11 +- .../inbox/unit-task-inbox-state.component.ts | 3 +- .../task-details-view.component.ts | 3 +- .../task-sheet-view.component.ts | 3 +- .../unit-task-list.component.ts | 11 +- .../task-viewer-state.component.ts | 3 +- src/app/units/unit-root-state.component.ts | 3 +- .../progress-burndown-chart.component.ts | 2 + .../task-status-pie-chart.component.ts | 10 +- .../task-visualisation.component.ts | 10 +- src/app/welcome/welcome.component.ts | 3 +- src/tsconfig.app.json | 11 +- src/tsconfig.spec.json | 10 +- tsconfig.json | 2 + 227 files changed, 2624 insertions(+), 1176 deletions(-) diff --git a/package-lock.json b/package-lock.json index e8e4016114..cf8a3ab19e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,19 +9,19 @@ "version": "11.0.0-25", "license": "AGPL-3.0", "dependencies": { - "@angular/animations": "^21.2.17", + "@angular/animations": "^22.0.2", "@angular/cdk": "^21.2.9", - "@angular/common": "^21.2.17", - "@angular/compiler": "^21.2.17", - "@angular/core": "^21.2.17", - "@angular/forms": "^21.2.17", + "@angular/common": "^22.0.2", + "@angular/compiler": "^22.0.2", + "@angular/core": "^22.0.2", + "@angular/forms": "^22.0.2", "@angular/material": "^21.2.9", "@angular/material-date-fns-adapter": "^21.2.9", - "@angular/platform-browser": "^21.2.17", - "@angular/platform-browser-dynamic": "^21.2.17", - "@angular/router": "^21.2.17", - "@angular/service-worker": "^21.2.17", - "@angular/upgrade": "^21.2.17", + "@angular/platform-browser": "^22.0.2", + "@angular/platform-browser-dynamic": "^22.0.2", + "@angular/router": "^22.0.2", + "@angular/service-worker": "^22.0.2", + "@angular/upgrade": "^22.0.2", "@ctrl/ngx-emoji-mart": "^9.3.0", "@eslint/js": "^10.0.1", "@ngneat/hotkeys": "^4.0.0", @@ -73,10 +73,10 @@ "@angular-eslint/eslint-plugin-template": "^21.4.0", "@angular-eslint/schematics": "^21.4.0", "@angular-eslint/template-parser": "^21.4.0", - "@angular/build": "^21.2.15", - "@angular/cli": "^21.2.15", - "@angular/compiler-cli": "^21.2.17", - "@angular/language-service": "^21.2.17", + "@angular/build": "^22.0.3", + "@angular/cli": "^22.0.3", + "@angular/compiler-cli": "^22.0.2", + "@angular/language-service": "^22.0.2", "@commitlint/cli": "^20.5.0", "@commitlint/config-conventional": "^21", "@trivago/prettier-plugin-sort-imports": "^6.0.2", @@ -106,7 +106,7 @@ "sass": "^1.48.0", "tailwindcss": "~3.4.17", "ts-node": "~10.9", - "typescript": "~5.9.3", + "typescript": "~6.0.3", "underscore": "^1.8.3", "vitest": "^4.1.8" }, @@ -124,57 +124,57 @@ } }, "node_modules/@algolia/abtesting": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.14.1.tgz", - "integrity": "sha512-Dkj0BgPiLAaim9sbQ97UKDFHJE/880wgStAM18U++NaJ/2Cws34J5731ovJifr6E3Pv4T2CqvMXf8qLCC417Ew==", + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/@algolia/abtesting/-/abtesting-1.18.0.tgz", + "integrity": "sha512-8siuLG+FIns1AjZ/g2SDVwHz9S+ObacDQISEJvS8XsNei1zl3FXqfqQrBpmrG7ACWCyesXHbicMJtvRbg00FEw==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-abtesting": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.48.1.tgz", - "integrity": "sha512-LV5qCJdj+/m9I+Aj91o+glYszrzd7CX6NgKaYdTOj4+tUYfbS62pwYgUfZprYNayhkQpVFcrW8x8ZlIHpS23Vw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-abtesting/-/client-abtesting-5.52.0.tgz", + "integrity": "sha512-wtwPgyPmO7b7sQPVgoK29c1VpfS08DnnJCmxX/oU1pV2DlMRJCzQcLN7JSloYpodyKHwM8+9wOzlAM0co3TDmA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-analytics": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.48.1.tgz", - "integrity": "sha512-/AVoMqHhPm14CcHq7mwB+bUJbfCv+jrxlNvRjXAuO+TQa+V37N8k1b0ijaRBPdmSjULMd8KtJbQyUyabXOu6Kg==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-analytics/-/client-analytics-5.52.0.tgz", + "integrity": "sha512-9KY36bRl4AH7RjqSeDDOKnjsz4IxQFBEOB8/fWmEbdQe+Isbs5jGzVJu9NEPQ1Tgwxlf8Uf07Swj3jZyMNUZ2g==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-common": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.48.1.tgz", - "integrity": "sha512-VXO+qu2Ep6ota28ktvBm3sG53wUHS2n7bgLWmce5jTskdlCD0/JrV4tnBm1l7qpla1CeoQb8D7ShFhad+UoSOw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-common/-/client-common-5.52.0.tgz", + "integrity": "sha512-3a/qM3dzJqqfTx7Yrw7uGQ98I3Q0rDfb4Vkv0wEzko96l7YQMxfBVz/VbLq2N+c59GweYv6Vhp8mPeqnWJSITw==", "dev": true, "license": "MIT", "engines": { @@ -182,151 +182,151 @@ } }, "node_modules/@algolia/client-insights": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.48.1.tgz", - "integrity": "sha512-zl+Qyb0nLg+Y5YvKp1Ij+u9OaPaKg2/EPzTwKNiVyOHnQJlFxmXyUZL1EInczAZsEY8hVpPCLtNfhMhfxluXKQ==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-insights/-/client-insights-5.52.0.tgz", + "integrity": "sha512-Rki7ACbMcvbQW0BuM84x9dkGHY47ABmv4jU6tYssat2k02p3mIUms2YOLUAMeknhmnFsj6lb6ZzOXdMWMyc1sA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-personalization": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.48.1.tgz", - "integrity": "sha512-r89Qf9Oo9mKWQXumRu/1LtvVJAmEDpn8mHZMc485pRfQUMAwSSrsnaw1tQ3sszqzEgAr1c7rw6fjBI+zrAXTOw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-personalization/-/client-personalization-5.52.0.tgz", + "integrity": "sha512-96s4Uzc3kk+/f4jJXIVVGWP5XlngOGNQ1x6hW9AT59pOixHlOs5tqJg+ZUS/GQ6h/iYP0ceQcmxDQeLyCLTaDQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-query-suggestions": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.48.1.tgz", - "integrity": "sha512-TPKNPKfghKG/bMSc7mQYD9HxHRUkBZA4q1PEmHgICaSeHQscGqL4wBrKkhfPlDV1uYBKW02pbFMUhsOt7p4ZpA==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-query-suggestions/-/client-query-suggestions-5.52.0.tgz", + "integrity": "sha512-lqeycNpSPe5Qa0OUWpejVvYQjQWV5nQuLT0a4aq7XzRAvCxprV/6Lf841EygdD2nrFnuS58ok7Au1uOtXzpnkg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/client-search": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.48.1.tgz", - "integrity": "sha512-4Fu7dnzQyQmMFknYwTiN/HxPbH4DyxvQ1m+IxpPp5oslOgz8m6PG5qhiGbqJzH4HiT1I58ecDiCAC716UyVA8Q==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/client-search/-/client-search-5.52.0.tgz", + "integrity": "sha512-ly1wETVGRo30cx61O7fetESN+ElL9c9K+bD/AVgnT1ar4c6v+/Yqjrhdtu6Fm4D0s4NZP081Isf6tunH1wUXHg==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/ingestion": { - "version": "1.48.1", - "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.48.1.tgz", - "integrity": "sha512-/RFq3TqtXDUUawwic/A9xylA2P3LDMO8dNhphHAUOU51b1ZLHrmZ6YYJm3df1APz7xLY1aht6okCQf+/vmrV9w==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@algolia/ingestion/-/ingestion-1.52.0.tgz", + "integrity": "sha512-U4EeTvgmluRjj39ykZSAd5X+a6LD5m7/mcOWDmB7hqm1R6QY0yT8jLxpNVEjYhzgEN5hcDGW6X67EWQY8KiYGQ==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/monitoring": { - "version": "1.48.1", - "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.48.1.tgz", - "integrity": "sha512-Of0jTeAZRyRhC7XzDSjJef0aBkgRcvRAaw0ooYRlOw57APii7lZdq+layuNdeL72BRq1snaJhoMMwkmLIpJScw==", + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/@algolia/monitoring/-/monitoring-1.52.0.tgz", + "integrity": "sha512-FCPnDcILfpTE94u7BVlV4DmnSV5wE3+j25EEF+3dYPrVzkVCSoAHs318oWDGxnxsAgiL4HpL12Jc4XHmw9shpA==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/recommend": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.48.1.tgz", - "integrity": "sha512-bE7JcpFXzxF5zHwj/vkl2eiCBvyR1zQ7aoUdO+GDXxGp0DGw7nI0p8Xj6u8VmRQ+RDuPcICFQcCwRIJT5tDJFw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/recommend/-/recommend-5.52.0.tgz", + "integrity": "sha512-br3DO7n4N8CXwTRbZS0MnB4WQ9YHfNjCwkCEzVR/wek/qNTDQKDb0nROmkFaNZ8ucUqUVKZi074dbwMwRDlK8Q==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/client-common": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-browser-xhr": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.48.1.tgz", - "integrity": "sha512-MK3wZ2koLDnvH/AmqIF1EKbJlhRS5j74OZGkLpxI4rYvNi9Jn/C7vb5DytBnQ4KUWts7QsmbdwHkxY5txQHXVw==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-browser-xhr/-/requester-browser-xhr-5.52.0.tgz", + "integrity": "sha512-b0T/Ca2c9KyEslKsVrGZvbe1UrrKKSdfXhBZ2pbpKahFUzJfziRZ0urbOm7V65O0tO/jwU+Lo/+bIiiyhzGt8w==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1" + "@algolia/client-common": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-fetch": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.48.1.tgz", - "integrity": "sha512-2oDT43Y5HWRSIQMPQI4tA/W+TN/N2tjggZCUsqQV440kxzzoPGsvv9QP1GhQ4CoDa+yn6ygUsGp6Dr+a9sPPSg==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-fetch/-/requester-fetch-5.52.0.tgz", + "integrity": "sha512-ozBT8J/mtD4H4IAojw8QPirlcL2gHrI1BGuZ4/ZXXO/rTE1yQ4VIPJj4mTTbwo4FbkS1MoJsD/DsrqLzhnc4/g==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1" + "@algolia/client-common": "5.52.0" }, "engines": { "node": ">= 14.0.0" } }, "node_modules/@algolia/requester-node-http": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.48.1.tgz", - "integrity": "sha512-xcaCqbhupVWhuBP1nwbk1XNvwrGljozutEiLx06mvqDf3o8cHyEgQSHS4fKJM+UAggaWVnnFW+Nne5aQ8SUJXg==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/@algolia/requester-node-http/-/requester-node-http-5.52.0.tgz", + "integrity": "sha512-gyyWcLD22tnabmoit4iukCXuoRc5HYJuUjPSEa8a0D/f/NlRafpWi52AlAaa4Uu/rsl7saHsJFTNjTptWbu2+A==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/client-common": "5.48.1" + "@algolia/client-common": "5.52.0" }, "engines": { "node": ">= 14.0.0" @@ -535,80 +535,79 @@ } }, "node_modules/@angular/animations": { - "version": "21.2.17", - "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-21.2.17.tgz", - "integrity": "sha512-zOW8FFa9qfbVkZ5TulxDkl1C3+gEjWfAAD5Z2MycA6pjVJQlLYPiTAGq+flOQ3yZfTT0z6kd5rejQMXWI81Dvg==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-22.0.2.tgz", + "integrity": "sha512-l9lVG9k+baFMWXNsFUxwmxQaUZMkpkTn3vRpa1hs/vABzT/KnaDeweDtvvkS0NS1RYJenoxhONlMNEWuJ4VR1A==", "deprecated": "@angular/animations is deprecated. Use `animate.enter` and `animate.leave` instead. For more information see: https://v22.angular.dev/guide/animations.", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/core": "21.2.17" + "@angular/core": "22.0.2" } }, "node_modules/@angular/build": { - "version": "21.2.15", - "resolved": "https://registry.npmjs.org/@angular/build/-/build-21.2.15.tgz", - "integrity": "sha512-APJ5v0/hL38CKSqSQDos5Y8/O2LSiSSqP9FagdcMT5j9JAlENXdhVaA3IxPMXDWcxtzD5T1IlN8Z9aFxDXxHyg==", + "version": "22.0.3", + "resolved": "https://registry.npmjs.org/@angular/build/-/build-22.0.3.tgz", + "integrity": "sha512-pwFDRCp+r8JK+fCtScPldizcS75wSpn3u/4goDf2FRa4Y9wzTvq6T0XpFHqdpgq6HcIlIZWwAqqW6XqEM9/pKQ==", "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "2.3.0", - "@angular-devkit/architect": "0.2102.15", + "@angular-devkit/architect": "0.2200.3", "@babel/core": "7.29.0", "@babel/helper-annotate-as-pure": "7.27.3", "@babel/helper-split-export-declaration": "7.24.7", - "@inquirer/confirm": "5.1.21", - "@vitejs/plugin-basic-ssl": "2.1.4", - "beasties": "0.4.1", + "@inquirer/confirm": "6.0.12", + "@vitejs/plugin-basic-ssl": "2.3.0", + "beasties": "0.4.2", "browserslist": "^4.26.0", - "esbuild": "0.27.3", - "https-proxy-agent": "7.0.6", - "istanbul-lib-instrument": "6.0.3", + "esbuild": "0.28.1", + "https-proxy-agent": "9.0.0", "jsonc-parser": "3.3.1", - "listr2": "9.0.5", + "listr2": "10.2.1", "magic-string": "0.30.21", "mrmime": "2.0.1", - "parse5-html-rewriting-stream": "8.0.0", + "parse5-html-rewriting-stream": "8.0.1", "picomatch": "4.0.4", "piscina": "5.1.4", - "rolldown": "1.0.0-rc.4", - "sass": "1.97.3", + "rollup": "4.60.2", + "sass": "1.99.0", "semver": "7.7.4", "source-map-support": "0.5.21", - "tinyglobby": "0.2.15", - "undici": "7.24.4", - "vite": "7.3.2", + "tinyglobby": "0.2.16", + "vite": "7.3.5", "watchpack": "2.5.1" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, "optionalDependencies": { - "lmdb": "3.5.1" + "lmdb": "3.5.4" }, "peerDependencies": { - "@angular/compiler": "^21.0.0", - "@angular/compiler-cli": "^21.0.0", - "@angular/core": "^21.0.0", - "@angular/localize": "^21.0.0", - "@angular/platform-browser": "^21.0.0", - "@angular/platform-server": "^21.0.0", - "@angular/service-worker": "^21.0.0", - "@angular/ssr": "^21.2.15", + "@angular/compiler": "^22.0.0", + "@angular/compiler-cli": "^22.0.0", + "@angular/core": "^22.0.0", + "@angular/localize": "^22.0.0", + "@angular/platform-browser": "^22.0.0", + "@angular/platform-server": "^22.0.0", + "@angular/service-worker": "^22.0.0", + "@angular/ssr": "^22.0.3", + "istanbul-lib-instrument": "^6.0.0", "karma": "^6.4.0", "less": "^4.2.0", - "ng-packagr": "^21.0.0", + "ng-packagr": "^22.0.0", "postcss": "^8.4.0", "tailwindcss": "^2.0.0 || ^3.0.0 || ^4.0.0", "tslib": "^2.3.0", - "typescript": ">=5.9 <6.0", + "typescript": ">=6.0 <6.1", "vitest": "^4.0.8" }, "peerDependenciesMeta": { @@ -630,6 +629,9 @@ "@angular/ssr": { "optional": true }, + "istanbul-lib-instrument": { + "optional": true + }, "karma": { "optional": true }, @@ -650,20 +652,909 @@ } } }, - "node_modules/@angular/build/node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "node_modules/@angular/build/node_modules/@angular-devkit/architect": { + "version": "0.2200.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2200.3.tgz", + "integrity": "sha512-Ru+ucNkTZr98gmeaBYjq3zZwh32yGofAeB8+GJL/ZNy0x+7NzK6b+OatdzwT4l7mCWFC5vL8iYu0B4++M66Jpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "22.0.3", + "rxjs": "7.8.2" + }, + "bin": { + "architect": "bin/cli.js" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/build/node_modules/@angular-devkit/core": { + "version": "22.0.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-22.0.3.tgz", + "integrity": "sha512-pBjo1JKwI8GbNdTo/Z0g+ZekqlTBCJWmzIC5fgGW9q5eRjl1y+5N5jlX8UAyyMCeUTTwsfpQdkAM2jyi/jcvjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.20.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.2", + "source-map": "0.7.6" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^5.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular/build/node_modules/@esbuild/aix-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", + "integrity": "sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/android-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.1.tgz", + "integrity": "sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/android-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.1.tgz", + "integrity": "sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/android-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.1.tgz", + "integrity": "sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/darwin-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.1.tgz", + "integrity": "sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/darwin-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.1.tgz", + "integrity": "sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.1.tgz", + "integrity": "sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/freebsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.1.tgz", + "integrity": "sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/linux-arm": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.1.tgz", + "integrity": "sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/linux-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.1.tgz", + "integrity": "sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/linux-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.1.tgz", + "integrity": "sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/linux-loong64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.1.tgz", + "integrity": "sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/linux-mips64el": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.1.tgz", + "integrity": "sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/linux-ppc64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.1.tgz", + "integrity": "sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/linux-riscv64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.1.tgz", + "integrity": "sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/linux-s390x": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.1.tgz", + "integrity": "sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/linux-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.1.tgz", + "integrity": "sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.1.tgz", + "integrity": "sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/netbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.1.tgz", + "integrity": "sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.1.tgz", + "integrity": "sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/openbsd-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.1.tgz", + "integrity": "sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.1.tgz", + "integrity": "sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/sunos-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.1.tgz", + "integrity": "sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/win32-arm64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.1.tgz", + "integrity": "sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/win32-ia32": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.1.tgz", + "integrity": "sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@esbuild/win32-x64": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.1.tgz", + "integrity": "sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.60.2.tgz", + "integrity": "sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-android-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.60.2.tgz", + "integrity": "sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.60.2.tgz", + "integrity": "sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-darwin-x64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.60.2.tgz", + "integrity": "sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.60.2.tgz", + "integrity": "sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.60.2.tgz", + "integrity": "sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.60.2.tgz", + "integrity": "sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.60.2.tgz", + "integrity": "sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.60.2.tgz", + "integrity": "sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.60.2.tgz", + "integrity": "sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.60.2.tgz", + "integrity": "sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.60.2.tgz", + "integrity": "sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.60.2.tgz", + "integrity": "sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.60.2.tgz", + "integrity": "sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.60.2.tgz", + "integrity": "sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.60.2.tgz", + "integrity": "sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.60.2.tgz", + "integrity": "sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.60.2.tgz", + "integrity": "sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.60.2.tgz", + "integrity": "sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.60.2.tgz", + "integrity": "sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.60.2.tgz", + "integrity": "sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.60.2.tgz", + "integrity": "sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.60.2.tgz", + "integrity": "sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.60.2.tgz", + "integrity": "sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular/build/node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.60.2.tgz", + "integrity": "sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@angular/build/node_modules/@types/estree": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", + "integrity": "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==", + "dev": true, + "license": "MIT" + }, + "node_modules/@angular/build/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { - "readdirp": "^4.0.1" + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@angular/build/node_modules/esbuild": { + "version": "0.28.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", + "integrity": "sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": ">= 14.16.0" + "node": ">=18" }, - "funding": { - "url": "https://paulmillr.com/funding/" + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.1", + "@esbuild/android-arm": "0.28.1", + "@esbuild/android-arm64": "0.28.1", + "@esbuild/android-x64": "0.28.1", + "@esbuild/darwin-arm64": "0.28.1", + "@esbuild/darwin-x64": "0.28.1", + "@esbuild/freebsd-arm64": "0.28.1", + "@esbuild/freebsd-x64": "0.28.1", + "@esbuild/linux-arm": "0.28.1", + "@esbuild/linux-arm64": "0.28.1", + "@esbuild/linux-ia32": "0.28.1", + "@esbuild/linux-loong64": "0.28.1", + "@esbuild/linux-mips64el": "0.28.1", + "@esbuild/linux-ppc64": "0.28.1", + "@esbuild/linux-riscv64": "0.28.1", + "@esbuild/linux-s390x": "0.28.1", + "@esbuild/linux-x64": "0.28.1", + "@esbuild/netbsd-arm64": "0.28.1", + "@esbuild/netbsd-x64": "0.28.1", + "@esbuild/openbsd-arm64": "0.28.1", + "@esbuild/openbsd-x64": "0.28.1", + "@esbuild/openharmony-arm64": "0.28.1", + "@esbuild/sunos-x64": "0.28.1", + "@esbuild/win32-arm64": "0.28.1", + "@esbuild/win32-ia32": "0.28.1", + "@esbuild/win32-x64": "0.28.1" } }, "node_modules/@angular/build/node_modules/readdirp": { @@ -680,15 +1571,60 @@ "url": "https://paulmillr.com/funding/" } }, + "node_modules/@angular/build/node_modules/rollup": { + "version": "4.60.2", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.60.2.tgz", + "integrity": "sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.8" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.60.2", + "@rollup/rollup-android-arm64": "4.60.2", + "@rollup/rollup-darwin-arm64": "4.60.2", + "@rollup/rollup-darwin-x64": "4.60.2", + "@rollup/rollup-freebsd-arm64": "4.60.2", + "@rollup/rollup-freebsd-x64": "4.60.2", + "@rollup/rollup-linux-arm-gnueabihf": "4.60.2", + "@rollup/rollup-linux-arm-musleabihf": "4.60.2", + "@rollup/rollup-linux-arm64-gnu": "4.60.2", + "@rollup/rollup-linux-arm64-musl": "4.60.2", + "@rollup/rollup-linux-loong64-gnu": "4.60.2", + "@rollup/rollup-linux-loong64-musl": "4.60.2", + "@rollup/rollup-linux-ppc64-gnu": "4.60.2", + "@rollup/rollup-linux-ppc64-musl": "4.60.2", + "@rollup/rollup-linux-riscv64-gnu": "4.60.2", + "@rollup/rollup-linux-riscv64-musl": "4.60.2", + "@rollup/rollup-linux-s390x-gnu": "4.60.2", + "@rollup/rollup-linux-x64-gnu": "4.60.2", + "@rollup/rollup-linux-x64-musl": "4.60.2", + "@rollup/rollup-openbsd-x64": "4.60.2", + "@rollup/rollup-openharmony-arm64": "4.60.2", + "@rollup/rollup-win32-arm64-msvc": "4.60.2", + "@rollup/rollup-win32-ia32-msvc": "4.60.2", + "@rollup/rollup-win32-x64-gnu": "4.60.2", + "@rollup/rollup-win32-x64-msvc": "4.60.2", + "fsevents": "~2.3.2" + } + }, "node_modules/@angular/build/node_modules/sass": { - "version": "1.97.3", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.97.3.tgz", - "integrity": "sha512-fDz1zJpd5GycprAbu4Q2PV/RprsRtKC/0z82z0JLgdytmcq0+ujJbJ/09bPGDxCLkKY3Np5cRAOcWiVkLXJURg==", + "version": "1.99.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.99.0.tgz", + "integrity": "sha512-kgW13M54DUB7IsIRM5LvJkNlpH+WhMpooUcaWGFARkF1Tc82v9mIWkCbCYf+MBvpIUBSeSOTilpZjEPr2VYE6Q==", "dev": true, "license": "MIT", "dependencies": { "chokidar": "^4.0.0", - "immutable": "^5.0.2", + "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "bin": { @@ -701,6 +1637,22 @@ "@parcel/watcher": "^2.4.1" } }, + "node_modules/@angular/build/node_modules/sass/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@angular/cdk": { "version": "21.2.14", "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.14.tgz", @@ -718,72 +1670,191 @@ } }, "node_modules/@angular/cli": { - "version": "21.2.15", - "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-21.2.15.tgz", - "integrity": "sha512-8CT1iST5CwdxHEzC0NVFUsMenAY7aE30ayTAw5PpA6MPs6bdHlL6QxTmkqThW7hoCj6PJ56YfQMzSQU+aYRLQA==", + "version": "22.0.3", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-22.0.3.tgz", + "integrity": "sha512-YgFzfQu3Il6Aka8IdH4pk7faieICaca5Wklke0jMTKBUxzLGWw82X7+J/Lox7FERb6LHtxiHpa6ttXqerCZvgg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": "0.2102.15", - "@angular-devkit/core": "21.2.15", - "@angular-devkit/schematics": "21.2.15", - "@inquirer/prompts": "7.10.1", - "@listr2/prompt-adapter-inquirer": "3.0.5", - "@modelcontextprotocol/sdk": "1.26.0", - "@schematics/angular": "21.2.15", + "@angular-devkit/architect": "0.2200.3", + "@angular-devkit/core": "22.0.3", + "@angular-devkit/schematics": "22.0.3", + "@inquirer/prompts": "8.4.2", + "@listr2/prompt-adapter-inquirer": "4.2.3", + "@modelcontextprotocol/sdk": "1.29.0", + "@schematics/angular": "22.0.3", "@yarnpkg/lockfile": "1.1.0", - "algoliasearch": "5.48.1", + "algoliasearch": "5.52.0", "ini": "6.0.0", "jsonc-parser": "3.3.1", - "listr2": "9.0.5", + "listr2": "10.2.1", "npm-package-arg": "13.0.2", - "pacote": "21.3.1", - "parse5-html-rewriting-stream": "8.0.0", + "pacote": "21.5.1", + "parse5-html-rewriting-stream": "8.0.1", "semver": "7.7.4", "yargs": "18.0.0", - "zod": "4.3.6" + "zod": "4.4.2" }, "bin": { "ng": "bin/ng.js" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/@angular-devkit/architect": { + "version": "0.2200.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2200.3.tgz", + "integrity": "sha512-Ru+ucNkTZr98gmeaBYjq3zZwh32yGofAeB8+GJL/ZNy0x+7NzK6b+OatdzwT4l7mCWFC5vL8iYu0B4++M66Jpg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "22.0.3", + "rxjs": "7.8.2" + }, + "bin": { + "architect": "bin/cli.js" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/@angular-devkit/core": { + "version": "22.0.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-22.0.3.tgz", + "integrity": "sha512-pBjo1JKwI8GbNdTo/Z0g+ZekqlTBCJWmzIC5fgGW9q5eRjl1y+5N5jlX8UAyyMCeUTTwsfpQdkAM2jyi/jcvjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.20.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.2", + "source-map": "0.7.6" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^5.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular/cli/node_modules/@angular-devkit/schematics": { + "version": "22.0.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-22.0.3.tgz", + "integrity": "sha512-aIp5sQDHdhyLbeVJF/k3w079XhW91mNAo2OliZllBCjoYhkIXNnWECOx5y2nXtCChyFJA2+ZgNST7NIDvtz1/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "22.0.3", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.21", + "ora": "9.4.0", + "rxjs": "7.8.2" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" } }, + "node_modules/@angular/cli/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@angular/cli/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@angular/cli/node_modules/ora": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-9.4.0.tgz", + "integrity": "sha512-84cglkRILFxdtA8hAvLNdMrtBpPNBTrQ9/ulg0FA7xLMnD6mifv+enAIeRmvtv+WgdCE+LPGOfQmtJRrVaIVhQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^5.6.2", + "cli-cursor": "^5.0.0", + "cli-spinners": "^3.2.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.1.0", + "log-symbols": "^7.0.1", + "stdin-discarder": "^0.3.2", + "string-width": "^8.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/@angular/common": { - "version": "21.2.17", - "resolved": "https://registry.npmjs.org/@angular/common/-/common-21.2.17.tgz", - "integrity": "sha512-hqAQxRfi5ldFE42suAXRcY+JCANrUh7fuSQ/DtZ7L896id5BT/exuv6dWNBC1PyAfQmRbpD5Pt6/pd+tNLyhDQ==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-22.0.2.tgz", + "integrity": "sha512-XSkHYRwrM54v4GZ+fg9KU1KbSIE/iQF33VXKo5zqVNKO11MnAbJ59qzyqX/5EzSeogHyBoHApprFKACsCAKm/Q==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/core": "21.2.17", + "@angular/core": "22.0.2", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/compiler": { - "version": "21.2.17", - "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-21.2.17.tgz", - "integrity": "sha512-p+NdjYiwAz9Zmu2yul0LlMXaFjMISVVa24+/MVMoKFeQeI82QE8jDywPlnOSHQHvdCcQVpS7saeEriZzX3JuBQ==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-22.0.2.tgz", + "integrity": "sha512-5G+h/4/iCfqdTBsSgjB46Oe4oC6jXutCpFc5JYWRpnJWsbp3UfwRhwGVWIV1DBPnR8H/3QZzteRP1jINiH5+hg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" } }, "node_modules/@angular/compiler-cli": { - "version": "21.2.17", - "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-21.2.17.tgz", - "integrity": "sha512-KithZ3b0HBFH0NbUcswBcjpN9y09vLbarMD7qmGWTnGUBk4W8cn4sbT8zJyv9CRKg9ZcuUBeJYKUfUPn/u/5OQ==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-22.0.2.tgz", + "integrity": "sha512-jBGGWdbrPQhIHWUz523CLQqEh/iYWxzZt7U9y0Ocdbas4/OlHcqaERO/K4ULkxclWX8MWYQoxal/MZbYOBfXgw==", "dev": true, "license": "MIT", "dependencies": { @@ -801,11 +1872,11 @@ "ngc": "bundles/src/bin/ngc.js" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.17", - "typescript": ">=5.9 <6.1" + "@angular/compiler": "22.0.2", + "typescript": ">=6.0 <6.1" }, "peerDependenciesMeta": { "typescript": { @@ -814,18 +1885,18 @@ } }, "node_modules/@angular/core": { - "version": "21.2.17", - "resolved": "https://registry.npmjs.org/@angular/core/-/core-21.2.17.tgz", - "integrity": "sha512-wYHpwIdnUnjQFOJJNqRcGx7LS3u64jT+R9L0TnMR/ViBM9dQgGYImlSikkftg2yrFCNo5aKRxhG2LLskQurVdg==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-22.0.2.tgz", + "integrity": "sha512-YMs6OZNeXh4tg67ePwSRN426WYvjqGdjxEwLrdOONKAruOmJAzW/Tqe328k/4SHfdbJTR87GPpRi5FzVP43DRA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.17", + "@angular/compiler": "22.0.2", "rxjs": "^6.5.3 || ^7.4.0", "zone.js": "~0.15.0 || ~0.16.0" }, @@ -839,32 +1910,33 @@ } }, "node_modules/@angular/forms": { - "version": "21.2.17", - "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-21.2.17.tgz", - "integrity": "sha512-WKu8XeRSNZo+a+aDDZ3M5OtReF7KYqR/PmZ2l1lSf6N5EEAmc+Ky4aqbRhTL/mTSfHrO4+TDJ4C5A2tFmuwIeA==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-22.0.2.tgz", + "integrity": "sha512-k2WhkE8Of8/JRYEojSgfygiXbP6I7f/yZ/jgJzFGRC1FlF5w5erQMFx8KPg1J5CRE8kYPzW8rM4tSVCq7AaDUg==", "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.0.0", - "tslib": "^2.3.0" + "tslib": "^2.3.0", + "zod": "^4.0.10" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/common": "21.2.17", - "@angular/core": "21.2.17", - "@angular/platform-browser": "21.2.17", + "@angular/common": "22.0.2", + "@angular/core": "22.0.2", + "@angular/platform-browser": "22.0.2", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/language-service": { - "version": "21.2.17", - "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-21.2.17.tgz", - "integrity": "sha512-Pq0V7VBkShQThA6QME2FjZgHLuxFpsioEoppx1i8rHFTGoJuXtBJK8iaArF7XuYaMzMRInUGfMQzsXc2WE+rmg==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-22.0.2.tgz", + "integrity": "sha512-J7QXjv9R/wFVwK4CZBjzE6B1owFQTKsb0KWVhuuPcglD3jtVAJ5xipUI9gco93GmCT3EU9oANmN8jQcAn67h4A==", "dev": true, "license": "MIT", "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" } }, "node_modules/@angular/material": { @@ -899,20 +1971,20 @@ } }, "node_modules/@angular/platform-browser": { - "version": "21.2.17", - "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-21.2.17.tgz", - "integrity": "sha512-ROdSliejY37g1EphYmweYdm5cHM8HY3X4tbWt4ubxmhTyYgfN3nxrxfGQ/n7Mz5tDY9VXVLIGDgjLOGYOo4uTQ==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-22.0.2.tgz", + "integrity": "sha512-xUkpJo/Jwa7rgpoSnZs5TeuOD3SDQL+CPJrMGjHivsqWMcAqzSNnIOcbNDJRSxAYkZ9zlJ1+h39JWSUk99rRBw==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/animations": "21.2.17", - "@angular/common": "21.2.17", - "@angular/core": "21.2.17" + "@angular/animations": "22.0.2", + "@angular/common": "22.0.2", + "@angular/core": "22.0.2" }, "peerDependenciesMeta": { "@angular/animations": { @@ -921,45 +1993,46 @@ } }, "node_modules/@angular/platform-browser-dynamic": { - "version": "21.2.17", - "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-21.2.17.tgz", - "integrity": "sha512-r/BU/T8bOTghP3fIXhzYf5wcMcAmhWnAFv3p4asCCPXomaktoas70wYcMaDH+pK1LAFBxLwzBWHm36MpFlTMFg==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-22.0.2.tgz", + "integrity": "sha512-5jDZzbesBBPCt41oq166B23TCW4ue9ZJyX4KlSRpGP/x8fjPGF22+AKASU6OPRnCNmmUsNk8DpenaBj+eFg/Sw==", + "deprecated": "@angular/platform-browser-dynamic is deprecated. Use `@angular/platform-browser` instead.", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/common": "21.2.17", - "@angular/compiler": "21.2.17", - "@angular/core": "21.2.17", - "@angular/platform-browser": "21.2.17" + "@angular/common": "22.0.2", + "@angular/compiler": "22.0.2", + "@angular/core": "22.0.2", + "@angular/platform-browser": "22.0.2" } }, "node_modules/@angular/router": { - "version": "21.2.17", - "resolved": "https://registry.npmjs.org/@angular/router/-/router-21.2.17.tgz", - "integrity": "sha512-RSCtK5ppAV6y6wfRLHSK2a9Wc/vm8j0wsC+/j9PH9yQmppWFVXDWsg5E39MKOIpnoYVx2+hI6eak6+wYtZTe1A==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-22.0.2.tgz", + "integrity": "sha512-uiYlcbOyBliFq1v7O3nMyZtM8scDBurjk4AU2wEPWxSVAXuEjyfnAvowyPzVzGYAEKrsYtcg2TWSsQraqHUbnA==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/common": "21.2.17", - "@angular/core": "21.2.17", - "@angular/platform-browser": "21.2.17", + "@angular/common": "22.0.2", + "@angular/core": "22.0.2", + "@angular/platform-browser": "22.0.2", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/service-worker": { - "version": "21.2.17", - "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-21.2.17.tgz", - "integrity": "sha512-6/uKwxBA3udngVHuIVqD8kdMV1whfym9ESB1UyjoNINx+2zj7A749X89tiV0TW2CvWpUYUE7VxpoapEiv5lvfw==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-22.0.2.tgz", + "integrity": "sha512-mUGA3PwTltRI2i3/fbJrlprqdtzD/qRZeoGc70Z9fL/4kVYUfz9lC2PNkKf5vgsl3Z4om5BXKM11uZGWtI9urQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" @@ -968,29 +2041,29 @@ "ngsw-config": "ngsw-config.js" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/core": "21.2.17", + "@angular/core": "22.0.2", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/upgrade": { - "version": "21.2.17", - "resolved": "https://registry.npmjs.org/@angular/upgrade/-/upgrade-21.2.17.tgz", - "integrity": "sha512-dy1ZgG7QveN8q3cBD3Sfce8KY3sX8I/LPhlhHetdQU0bDZHF/+LLSQlnciV/UFDBvck7vJZ5pifOnk6JdQ+RpA==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/upgrade/-/upgrade-22.0.2.tgz", + "integrity": "sha512-FrETq4hwyDZ3v/6p6HZDSxSCDe7eQPopGJCdA8GdL/RjxHzKsoz7XHgM/lFKHx6JJK5yzof1mqK4BQz64G6YLQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": "^22.22.3 || ^24.15.0 || >=26.0.0" }, "peerDependencies": { - "@angular/compiler": "21.2.17", - "@angular/core": "21.2.17", - "@angular/platform-browser": "21.2.17", - "@angular/platform-browser-dynamic": "21.2.17" + "@angular/compiler": "22.0.2", + "@angular/core": "22.0.2", + "@angular/platform-browser": "22.0.2", + "@angular/platform-browser-dynamic": "22.0.2" } }, "node_modules/@asamuzakjp/css-color": { @@ -1984,43 +3057,6 @@ "license": "MIT", "peer": true }, - "node_modules/@emnapi/core": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.0.tgz", - "integrity": "sha512-l9Oo58x0HOP5znGzVhYW9U3e5wVuA4LAZU2AGezTmkhO1CgQRFDhDg4nneHsu/t3WniXg9QrG2nIXL/ZS8ln8Q==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.2", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.11.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.0.tgz", - "integrity": "sha512-55coeOFKHv1ywEcUXJtWU5f+Jr/W5tZDvZig8DLKSwUN1JpROQ4rk/SNOQiFWmaR/VKF4zuFyW1B8JduOSv6Pg==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.2.tgz", - "integrity": "sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@esbuild/aix-ppc64": { "version": "0.27.3", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.27.3.tgz", @@ -2717,30 +3753,29 @@ } }, "node_modules/@inquirer/ansi": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-1.0.2.tgz", - "integrity": "sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.7.tgz", + "integrity": "sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" } }, "node_modules/@inquirer/checkbox": { - "version": "4.3.2", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-4.3.2.tgz", - "integrity": "sha512-VXukHf0RR1doGe6Sm4F0Em7SWYLTHSsbGfJdS9Ja2bX5/D5uwVOEjr07cncLROdBvmnvCATYEWlHqYmXv2IlQA==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.1.tgz", + "integrity": "sha512-b6xmA/VlTe0ZgDQHDui+Nav470u7u49nRd8/iuhOcQPO9Ch7lGuogydhi2VOmNlZ+zXcM8IcPuNSwQcdJaF/kw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/core": "^10.3.2", - "@inquirer/figures": "^1.0.15", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -2752,17 +3787,17 @@ } }, "node_modules/@inquirer/confirm": { - "version": "5.1.21", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-5.1.21.tgz", - "integrity": "sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==", + "version": "6.0.12", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.0.12.tgz", + "integrity": "sha512-h9FgGun3QwVYNj5TWIZZ+slii73bMoBFjPfVIGtnFuL4t8gBiNDV9PcSfIzkuxvgquJKt9nr1QzszpBzTbH8Og==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" + "@inquirer/core": "^11.1.9", + "@inquirer/type": "^4.0.5" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -2774,23 +3809,22 @@ } }, "node_modules/@inquirer/core": { - "version": "10.3.2", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-10.3.2.tgz", - "integrity": "sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==", + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.2.1.tgz", + "integrity": "sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/figures": "^1.0.15", - "@inquirer/type": "^3.0.10", + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7", "cli-width": "^4.1.0", - "mute-stream": "^2.0.0", - "signal-exit": "^4.1.0", - "wrap-ansi": "^6.2.0", - "yoctocolors-cjs": "^2.1.3" + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -2802,18 +3836,18 @@ } }, "node_modules/@inquirer/editor": { - "version": "4.2.23", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-4.2.23.tgz", - "integrity": "sha512-aLSROkEwirotxZ1pBaP8tugXRFCxW94gwrQLxXfrZsKkfjOYC1aRvAZuhpJOb5cu4IBTJdsCigUlf2iCOu4ZDQ==", + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.2.2.tgz", + "integrity": "sha512-ZRVd/oD+sYsUd5zVm0NflqEzlqfYCyHNsqkHl2oWXEUHs12tCbcSFi+wVFEvD8+LGRaMUsVrE7qeo6lSG/S1Vg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/external-editor": "^1.0.3", - "@inquirer/type": "^3.0.10" + "@inquirer/core": "^11.2.1", + "@inquirer/external-editor": "^3.0.3", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -2825,18 +3859,17 @@ } }, "node_modules/@inquirer/expand": { - "version": "4.0.23", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-4.0.23.tgz", - "integrity": "sha512-nRzdOyFYnpeYTTR2qFwEVmIWypzdAx/sIkCMeTNTcflFOovfqUk+HcFhQQVBftAh9gmGrpFj6QcGEqrDMDOiew==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.1.tgz", + "integrity": "sha512-YmQpenjbFSHAK3sOd44puHh3V1KXXr+JiNpUztoSQ4drLh2rTVzTap/YtlAVu/5xavifIlBfNEzJ/neZJ1a/1g==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -2848,17 +3881,17 @@ } }, "node_modules/@inquirer/external-editor": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-1.0.3.tgz", - "integrity": "sha512-RWbSrDiYmO4LbejWY7ttpxczuwQyZLBUyygsA9Nsv95hpzUWwnNTVQmAq3xuh7vNwCp07UTmE5i11XAEExx4RA==", + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha512-6thf5I8q7lZwzGLAxPaaGEREEkZ3nyePPDQ1oyobblxmEE8mqTLguScP7pDjUTAibiyb4hfXl+qjUEJ+di/aNA==", "dev": true, "license": "MIT", "dependencies": { "chardet": "^2.1.1", - "iconv-lite": "^0.7.0" + "iconv-lite": "^0.7.2" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -2870,27 +3903,27 @@ } }, "node_modules/@inquirer/figures": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.15.tgz", - "integrity": "sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==", + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.7.tgz", + "integrity": "sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" } }, "node_modules/@inquirer/input": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-4.3.1.tgz", - "integrity": "sha512-kN0pAM4yPrLjJ1XJBjDxyfDduXOuQHrBB8aLDMueuwUGn+vNpF7Gq7TvyVxx8u4SHlFFj4trmj+a2cbpG4Jn1g==", + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.2.tgz", + "integrity": "sha512-9K/DDBSQpOyZSkt6sOVP9Vo0TR7atX2kuILsUu0x3wVcVbe97lJwIJKMLdMw25tDYuXl/qp6erT0Xs1rfmcfZg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -2902,17 +3935,17 @@ } }, "node_modules/@inquirer/number": { - "version": "3.0.23", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-3.0.23.tgz", - "integrity": "sha512-5Smv0OK7K0KUzUfYUXDXQc9jrf8OHo4ktlEayFlelCjwMXz0299Y8OrI+lj7i4gCBY15UObk76q0QtxjzFcFcg==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.1.1.tgz", + "integrity": "sha512-XF4IXAbPnGPgw0wsbC/i2tPcyfdZgDpUlhsqU0SfT4IRIGWha6Xm9VRgN5yYxJq+jnyXlfXI/nQ3ulfk0iEICA==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -2924,18 +3957,18 @@ } }, "node_modules/@inquirer/password": { - "version": "4.0.23", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-4.0.23.tgz", - "integrity": "sha512-zREJHjhT5vJBMZX/IUbyI9zVtVfOLiTO66MrF/3GFZYZ7T4YILW5MSkEYHceSii/KtRk+4i3RE7E1CUXA2jHcA==", + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.1.1.tgz", + "integrity": "sha512-3XBfF7DAsp5qeDsvN5Rd1HmbNokVvEQoUM0QLrRcybC9nX96w3Pbmu7qUsb3IT3J3jBvs2+mTXaKHOUsgHMLzg==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10" + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -2947,25 +3980,25 @@ } }, "node_modules/@inquirer/prompts": { - "version": "7.10.1", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-7.10.1.tgz", - "integrity": "sha512-Dx/y9bCQcXLI5ooQ5KyvA4FTgeo2jYj/7plWfV5Ak5wDPKQZgudKez2ixyfz7tKXzcJciTxqLeK7R9HItwiByg==", + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.4.2.tgz", + "integrity": "sha512-XJmn/wY4AX56l1BRU+ZjDrFtg9+2uBEi4JvJQj82kwJDQKiPgSn4CEsbfGGygS4Gw6rkL4W18oATjfVfaqub2Q==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/checkbox": "^4.3.2", - "@inquirer/confirm": "^5.1.21", - "@inquirer/editor": "^4.2.23", - "@inquirer/expand": "^4.0.23", - "@inquirer/input": "^4.3.1", - "@inquirer/number": "^3.0.23", - "@inquirer/password": "^4.0.23", - "@inquirer/rawlist": "^4.1.11", - "@inquirer/search": "^3.2.2", - "@inquirer/select": "^4.4.2" + "@inquirer/checkbox": "^5.1.4", + "@inquirer/confirm": "^6.0.12", + "@inquirer/editor": "^5.1.1", + "@inquirer/expand": "^5.0.13", + "@inquirer/input": "^5.0.12", + "@inquirer/number": "^4.0.12", + "@inquirer/password": "^5.0.12", + "@inquirer/rawlist": "^5.2.8", + "@inquirer/search": "^4.1.8", + "@inquirer/select": "^5.1.4" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^21.7.0 || ^20.12.0" }, "peerDependencies": { "@types/node": ">=18" @@ -2977,18 +4010,17 @@ } }, "node_modules/@inquirer/rawlist": { - "version": "4.1.11", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-4.1.11.tgz", - "integrity": "sha512-+LLQB8XGr3I5LZN/GuAHo+GpDJegQwuPARLChlMICNdwW7OwV2izlCSCxN6cqpL0sMXmbKbFcItJgdQq5EBXTw==", + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.1.tgz", + "integrity": "sha512-QqdTqQddL3qPX/PPrjobpsO25NZ4dWXgTLenrR445L2ptLEYE6Z+PD5c5CNDJNx4ugRgELAIpSIJxZaO2jJ2Og==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -3000,19 +4032,18 @@ } }, "node_modules/@inquirer/search": { - "version": "3.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-3.2.2.tgz", - "integrity": "sha512-p2bvRfENXCZdWF/U2BXvnSI9h+tuA8iNqtUKb9UWbmLYCRQxd8WkvwWvYn+3NgYaNwdUkHytJMGG4MMLucI1kA==", + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.2.1.tgz", + "integrity": "sha512-xJj8QWKRSrfKoBIITLZK61dD3zwo0Rz11fgDImku30/Oe81zMdIdGgrLY2h6RkJ+KZ/GhNYIRMKnH/62qBTA5g==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/core": "^10.3.2", - "@inquirer/figures": "^1.0.15", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -3024,20 +4055,19 @@ } }, "node_modules/@inquirer/select": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-4.4.2.tgz", - "integrity": "sha512-l4xMuJo55MAe+N7Qr4rX90vypFwCajSakx59qe/tMaC1aEHWLyw68wF4o0A4SLAY4E0nd+Vt+EyskeDIqu1M6w==", + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.1.tgz", + "integrity": "sha512-FlDndEUww8m7BfukO2nJa25vhD+H5jxxCv4oGioKqzyWz3nPHhhw4LKdYRSlXuAx7DsdWia7iyaBPKKS95Evfw==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/ansi": "^1.0.2", - "@inquirer/core": "^10.3.2", - "@inquirer/figures": "^1.0.15", - "@inquirer/type": "^3.0.10", - "yoctocolors-cjs": "^2.1.3" + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" }, "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -3049,13 +4079,13 @@ } }, "node_modules/@inquirer/type": { - "version": "3.0.10", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-3.0.10.tgz", - "integrity": "sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==", + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.7.tgz", + "integrity": "sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" }, "peerDependencies": { "@types/node": ">=18" @@ -3085,6 +4115,8 @@ "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -3140,26 +4172,26 @@ } }, "node_modules/@listr2/prompt-adapter-inquirer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-3.0.5.tgz", - "integrity": "sha512-WELs+hj6xcilkloBXYf9XXK8tYEnKsgLj01Xl5ONUJpKjmT5hGVUzNUS5tooUxs7pGMrw+jFD/41WpqW4V3LDA==", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@listr2/prompt-adapter-inquirer/-/prompt-adapter-inquirer-4.2.3.tgz", + "integrity": "sha512-Co9U3AJ3LW0J8XBHjVoNKA79dMAyFt8EZH3OaKTMcDTj8r+6kG3vSUPq/eGLHT7P0iK3uLaFfhdFYd3033P24g==", "dev": true, "license": "MIT", "dependencies": { - "@inquirer/type": "^3.0.8" + "@inquirer/type": "^4.0.5" }, "engines": { - "node": ">=20.0.0" + "node": ">=22.13.0" }, "peerDependencies": { - "@inquirer/prompts": ">= 3 < 8", - "listr2": "9.0.5" + "@inquirer/prompts": ">= 3 < 9", + "listr2": "10.2.1" } }, "node_modules/@lmdb/lmdb-darwin-arm64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.5.1.tgz", - "integrity": "sha512-tpfN4kKrrMpQ+If1l8bhmoNkECJi0iOu6AEdrTJvWVC+32sLxTARX5Rsu579mPImRP9YFWfWgeRQ5oav7zApQQ==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-arm64/-/lmdb-darwin-arm64-3.5.4.tgz", + "integrity": "sha512-Kk4Kz3iyu1QiLsLZBS9Af1eSKUC8VR2T+/jyE2iAyuGw2VwK08pp5iTbZnXn6sWu0LogO/RFktMxOjiDA2sS3w==", "cpu": [ "arm64" ], @@ -3171,9 +4203,9 @@ ] }, "node_modules/@lmdb/lmdb-darwin-x64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.5.1.tgz", - "integrity": "sha512-+a2tTfc3rmWhLAolFUWRgJtpSuu+Fw/yjn4rF406NMxhfjbMuiOUTDRvRlMFV+DzyjkwnokisskHbCWkS3Ly5w==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-darwin-x64/-/lmdb-darwin-x64-3.5.4.tgz", + "integrity": "sha512-BEe5Rp3trn26oxoXOVL5HVDoiYmjUDwr8NRPkBOdUdCSBEorKI+7JrZLRKAdxO+G6cGQLgseXk0gR7qIQa7aGw==", "cpu": [ "x64" ], @@ -3185,9 +4217,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.5.1.tgz", - "integrity": "sha512-0EgcE6reYr8InjD7V37EgXcYrloqpxVPINy3ig1MwDSbl6LF/vXTYRH9OE1Ti1D8YZnB35ZH9aTcdfSb5lql2A==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm/-/lmdb-linux-arm-3.5.4.tgz", + "integrity": "sha512-SGbFR7816uBcTHc2ZY4S6WyOkl9bICnzqTQd2Mv4V/j24cfds88xx2nC6cm/y8zGQL7Ds31YF/5NGxjgcdM5Hw==", "cpu": [ "arm" ], @@ -3199,9 +4231,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-arm64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.1.tgz", - "integrity": "sha512-aoERa5B6ywXdyFeYGQ1gbQpkMkDbEo45qVoXE5QpIRavqjnyPwjOulMkmkypkmsbJ5z4Wi0TBztON8agCTG0Vg==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-arm64/-/lmdb-linux-arm64-3.5.4.tgz", + "integrity": "sha512-cUXEengO8o60v1SWerJTH4/RH4U3+9jC0/4njp2Z9NdmvaGzhKsbRM2wpXuRYrN8tytsoJCg0SvWEWwHAwLbCA==", "cpu": [ "arm64" ], @@ -3213,9 +4245,9 @@ ] }, "node_modules/@lmdb/lmdb-linux-x64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.5.1.tgz", - "integrity": "sha512-SqNDY1+vpji7bh0sFH5wlWyFTOzjbDOl0/kB5RLLYDAFyd/uw3n7wyrmas3rYPpAW7z18lMOi1yKlTPv967E3g==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-linux-x64/-/lmdb-linux-x64-3.5.4.tgz", + "integrity": "sha512-Gxq8jpgOWXwd0PUR+c9R2Ik1/uBnGd5GMIIzRRDqABCkvmjtC3KWcyhesV9jSPCz759isl0NlbsstZ2oyvk8lA==", "cpu": [ "x64" ], @@ -3227,9 +4259,9 @@ ] }, "node_modules/@lmdb/lmdb-win32-arm64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.5.1.tgz", - "integrity": "sha512-50v0O1Lt37cwrmR9vWZK5hRW0Aw+KEmxJJ75fge/zIYdvNKB/0bSMSVR5Uc2OV9JhosIUyklOmrEvavwNJ8D6w==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-arm64/-/lmdb-win32-arm64-3.5.4.tgz", + "integrity": "sha512-pKv1DJ1bPZAaHkdFsSz5IDfUG8x9vntgquXF9/Dm2xuupcIe/EkLzylpoBxppFVK5vzbV561Dq26jNY2fIMA7g==", "cpu": [ "arm64" ], @@ -3241,9 +4273,9 @@ ] }, "node_modules/@lmdb/lmdb-win32-x64": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.5.1.tgz", - "integrity": "sha512-qwosvPyl+zpUlp3gRb7UcJ3H8S28XHCzkv0Y0EgQToXjQP91ZD67EHSCDmaLjtKhe+GVIW5om1KUpzVLA0l6pg==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/@lmdb/lmdb-win32-x64/-/lmdb-win32-x64-3.5.4.tgz", + "integrity": "sha512-JF1BmLCm9kGEVZgYmJq43zeQVdHVgAJnTi/NURWEsy6L1ZrrlSmdltS+D17QN4LODwf+1LMXAA9auIZVXtWwzw==", "cpu": [ "x64" ], @@ -3470,9 +4502,9 @@ "license": "MIT" }, "node_modules/@modelcontextprotocol/sdk": { - "version": "1.26.0", - "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.26.0.tgz", - "integrity": "sha512-Y5RmPncpiDtTXDbLKswIJzTqu2hyBKxTNsgKqKclDbhIgg1wgtf1fRuvxgTnRfcnxtvvgbIEcqUOzZrJ6iSReg==", + "version": "1.29.0", + "resolved": "https://registry.npmjs.org/@modelcontextprotocol/sdk/-/sdk-1.29.0.tgz", + "integrity": "sha512-zo37mZA9hJWpULgkRpowewez1y6ML5GsXJPY8FI0tBBCd77HEvza4jDqRKOXgHNn867PVGCyTdzqpz0izu5ZjQ==", "dev": true, "license": "MIT", "dependencies": { @@ -3914,26 +4946,7 @@ "win32" ], "engines": { - "node": ">= 10" - } - }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", - "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.1" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1", - "@emnapi/runtime": "^1.7.1" + "node": ">= 10" } }, "node_modules/@ngneat/hotkeys": { @@ -4013,6 +5026,30 @@ "node": "^20.17.0 || >=22.9.0" } }, + "node_modules/@npmcli/agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/@npmcli/agent/node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/@npmcli/agent/node_modules/lru-cache": { "version": "11.5.1", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.1.tgz", @@ -4341,16 +5378,6 @@ "node": ">= 10" } }, - "node_modules/@oxc-project/types": { - "version": "0.113.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.113.0.tgz", - "integrity": "sha512-Tp3XmgxwNQ9pEN9vxgJBAqdRamHibi76iowQ38O2I4PMpcvNRQNVsU2n1x1nv9yh0XoTrGFzf7cZSGxmixxrhA==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/Boshen" - } - }, "node_modules/@parcel/watcher": { "version": "2.5.6", "resolved": "https://registry.npmjs.org/@parcel/watcher/-/watcher-2.5.6.tgz", @@ -4682,234 +5709,6 @@ "url": "https://opencollective.com/pkgr" } }, - "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.4.tgz", - "integrity": "sha512-vRq9f4NzvbdZavhQbjkJBx7rRebDKYR9zHfO/Wg486+I7bSecdUapzCm5cyXoK+LHokTxgSq7A5baAXUZkIz0w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.4.tgz", - "integrity": "sha512-kFgEvkWLqt3YCgKB5re9RlIrx9bRsvyVUnaTakEpOPuLGzLpLapYxE9BufJNvPg8GjT6mB1alN4yN1NjzoeM8Q==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.4.tgz", - "integrity": "sha512-JXmaOJGsL/+rsmMfutcDjxWM2fTaVgCHGoXS7nE8Z3c9NAYjGqHvXrAhMUZvMpHS/k7Mg+X7n/MVKb7NYWKKww==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.4.tgz", - "integrity": "sha512-ep3Catd6sPnHTM0P4hNEvIv5arnDvk01PfyJIJ+J3wVCG1eEaPo09tvFqdtcaTrkwQy0VWR24uz+cb4IsK53Qw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.4.tgz", - "integrity": "sha512-LwA5ayKIpnsgXJEwWc3h8wPiS33NMIHd9BhsV92T8VetVAbGe2qXlJwNVDGHN5cOQ22R9uYvbrQir2AB+ntT2w==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.4.tgz", - "integrity": "sha512-AC1WsGdlV1MtGay/OQ4J9T7GRadVnpYRzTcygV1hKnypbYN20Yh4t6O1Sa2qRBMqv1etulUknqXjc3CTIsBu6A==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.4.tgz", - "integrity": "sha512-lU+6rgXXViO61B4EudxtVMXSOfiZONR29Sys5VGSetUY7X8mg9FCKIIjcPPj8xNDeYzKl+H8F/qSKOBVFJChCQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.4.tgz", - "integrity": "sha512-DZaN1f0PGp/bSvKhtw50pPsnln4T13ycDq1FrDWRiHmWt1JeW+UtYg9touPFf8yt993p8tS2QjybpzKNTxYEwg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.4.tgz", - "integrity": "sha512-RnGxwZLN7fhMMAItnD6dZ7lvy+TI7ba+2V54UF4dhaWa/p8I/ys1E73KO6HmPmgz92ZkfD8TXS1IMV8+uhbR9g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.4.tgz", - "integrity": "sha512-6lcI79+X8klGiGd8yHuTgQRjuuJYNggmEml+RsyN596P23l/zf9FVmJ7K0KVKkFAeYEdg0iMUKyIxiV5vebDNQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.4.tgz", - "integrity": "sha512-wz7ohsKCAIWy91blZ/1FlpPdqrsm1xpcEOQVveWoL6+aSPKL4VUcoYmmzuLTssyZxRpEwzuIxL/GDsvpjaBtOw==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@napi-rs/wasm-runtime": "^1.1.1" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.4.tgz", - "integrity": "sha512-cfiMrfuWCIgsFmcVG0IPuO6qTRHvF7NuG3wngX1RZzc6dU8FuBFb+J3MIR5WrdTNozlumfgL4cvz+R4ozBCvsQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.4.tgz", - "integrity": "sha512-p6UeR9y7ht82AH57qwGuFYn69S6CZ7LLKdCKy/8T3zS9VTrJei2/CGsTUV45Da4Z9Rbhc7G4gyWQ/Ioamqn09g==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.4.tgz", - "integrity": "sha512-1BrrmTu0TWfOP1riA8uakjFc9bpIUGzVKETsOtzY39pPga8zELGDl8eu1Dx7/gjM5CAz14UknsUMpBO8L+YntQ==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.61.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.61.1.tgz", @@ -5239,47 +6038,148 @@ ], "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.61.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.1.tgz", + "integrity": "sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@scarf/scarf": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", + "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", + "hasInstallScript": true, + "license": "Apache-2.0" + }, + "node_modules/@schematics/angular": { + "version": "22.0.3", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-22.0.3.tgz", + "integrity": "sha512-iAUqIoRcK1CCHDm5E4Q1SI7rpVtsHJ+0qv5ll72wV3C1eCNdeDuGV0lX7PXEEkwd4y//s6yqI9o7f6VZZd6Fbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "22.0.3", + "@angular-devkit/schematics": "22.0.3", + "jsonc-parser": "3.3.1", + "typescript": "6.0.3" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@schematics/angular/node_modules/@angular-devkit/core": { + "version": "22.0.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-22.0.3.tgz", + "integrity": "sha512-pBjo1JKwI8GbNdTo/Z0g+ZekqlTBCJWmzIC5fgGW9q5eRjl1y+5N5jlX8UAyyMCeUTTwsfpQdkAM2jyi/jcvjA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "8.20.0", + "ajv-formats": "3.0.1", + "jsonc-parser": "3.3.1", + "picomatch": "4.0.4", + "rxjs": "7.8.2", + "source-map": "0.7.6" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^5.0.0" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@schematics/angular/node_modules/@angular-devkit/schematics": { + "version": "22.0.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-22.0.3.tgz", + "integrity": "sha512-aIp5sQDHdhyLbeVJF/k3w079XhW91mNAo2OliZllBCjoYhkIXNnWECOx5y2nXtCChyFJA2+ZgNST7NIDvtz1/w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@angular-devkit/core": "22.0.3", + "jsonc-parser": "3.3.1", + "magic-string": "0.30.21", + "ora": "9.4.0", + "rxjs": "7.8.2" + }, + "engines": { + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } }, - "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.61.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.61.1.tgz", - "integrity": "sha512-X+zaP2x+j4RXGfbp/seSoRHWnPxzApilDszisZxbYH5C/jTxFhCtDNdPGZb9lJyYPs24wGxruPF7Y+sIXt9Gzw==", - "cpu": [ - "x64" - ], + "node_modules/@schematics/angular/node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", - "optional": true, - "os": [ - "win32" - ] + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } }, - "node_modules/@scarf/scarf": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/@scarf/scarf/-/scarf-1.4.0.tgz", - "integrity": "sha512-xxeapPiUXdZAE3che6f3xogoJPeZgig6omHEy1rIY5WVsB3H2BHNnZH+gHG6x91SCWyQCzWGsuL2Hh3ClO5/qQ==", - "hasInstallScript": true, - "license": "Apache-2.0" + "node_modules/@schematics/angular/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } }, - "node_modules/@schematics/angular": { - "version": "21.2.15", - "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-21.2.15.tgz", - "integrity": "sha512-xdTirIUUegMXtyEDsYabCRcAnlVatVYb6S8v77fgK2eqUhGalI2e/3+L51N3XF1+6K2vEhyDpmmhFZLsdhLYbw==", + "node_modules/@schematics/angular/node_modules/ora": { + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-9.4.0.tgz", + "integrity": "sha512-84cglkRILFxdtA8hAvLNdMrtBpPNBTrQ9/ulg0FA7xLMnD6mifv+enAIeRmvtv+WgdCE+LPGOfQmtJRrVaIVhQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.15", - "@angular-devkit/schematics": "21.2.15", - "jsonc-parser": "3.3.1" + "chalk": "^5.6.2", + "cli-cursor": "^5.0.0", + "cli-spinners": "^3.2.0", + "is-interactive": "^2.0.0", + "is-unicode-supported": "^2.1.0", + "log-symbols": "^7.0.1", + "stdin-discarder": "^0.3.2", + "string-width": "^8.1.0" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/@sigstore/bundle": { @@ -5571,17 +6471,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.2", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.2.tgz", - "integrity": "sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@types/angular": { "version": "1.5.11", "resolved": "https://registry.npmjs.org/@types/angular/-/angular-1.5.11.tgz", @@ -5963,16 +6852,16 @@ } }, "node_modules/@vitejs/plugin-basic-ssl": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.1.4.tgz", - "integrity": "sha512-HXciTXN/sDBYWgeAD4V4s0DN0g72x5mlxQhHxtYu3Tt8BLa6MzcJZUyDVFCdtjNs3bfENVHVzOsmooTVuNgAAw==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-2.3.0.tgz", + "integrity": "sha512-bdyo8rB3NnQbikdMpHaML9Z1OZPBu6fFOBo+OtxsBlvMJtysWskmBcnbIDhUqgC8tcxNv/a+BcV5U+2nQMm1OQ==", "dev": true, "license": "MIT", "engines": { "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "peerDependencies": { - "vite": "^6.0.0 || ^7.0.0" + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, "node_modules/@vitest/expect": { @@ -6178,13 +7067,13 @@ } }, "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-9.0.0.tgz", + "integrity": "sha512-TQf59BsZnytt8GdJKLPfUZ54g/iaUL2OWDSFCCvMOhsHduDQxO8xC4PNeyIkVcA5KwL2phPSv0douC0fgWzmnA==", "dev": true, "license": "MIT", "engines": { - "node": ">= 14" + "node": ">= 20" } }, "node_modules/ajv": { @@ -6223,26 +7112,26 @@ } }, "node_modules/algoliasearch": { - "version": "5.48.1", - "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.48.1.tgz", - "integrity": "sha512-Rf7xmeuIo7nb6S4mp4abW2faW8DauZyE2faBIKFaUfP3wnpOvNSbiI5AwVhqBNj0jPgBWEvhyCu0sLjN2q77Rg==", + "version": "5.52.0", + "resolved": "https://registry.npmjs.org/algoliasearch/-/algoliasearch-5.52.0.tgz", + "integrity": "sha512-0ZzY9mjqV7gop/AH8pIBiAS8giXP7WcSiUfoFYIzYAK9QC5c37E4SIVtJVBMwlURc0/uNt2o4RcNRvdHa4CJ5w==", "dev": true, "license": "MIT", "dependencies": { - "@algolia/abtesting": "1.14.1", - "@algolia/client-abtesting": "5.48.1", - "@algolia/client-analytics": "5.48.1", - "@algolia/client-common": "5.48.1", - "@algolia/client-insights": "5.48.1", - "@algolia/client-personalization": "5.48.1", - "@algolia/client-query-suggestions": "5.48.1", - "@algolia/client-search": "5.48.1", - "@algolia/ingestion": "1.48.1", - "@algolia/monitoring": "1.48.1", - "@algolia/recommend": "5.48.1", - "@algolia/requester-browser-xhr": "5.48.1", - "@algolia/requester-fetch": "5.48.1", - "@algolia/requester-node-http": "5.48.1" + "@algolia/abtesting": "1.18.0", + "@algolia/client-abtesting": "5.52.0", + "@algolia/client-analytics": "5.52.0", + "@algolia/client-common": "5.52.0", + "@algolia/client-insights": "5.52.0", + "@algolia/client-personalization": "5.52.0", + "@algolia/client-query-suggestions": "5.52.0", + "@algolia/client-search": "5.52.0", + "@algolia/ingestion": "1.52.0", + "@algolia/monitoring": "1.52.0", + "@algolia/recommend": "5.52.0", + "@algolia/requester-browser-xhr": "5.52.0", + "@algolia/requester-fetch": "5.52.0", + "@algolia/requester-node-http": "5.52.0" }, "engines": { "node": ">= 14.0.0" @@ -6705,9 +7594,9 @@ } }, "node_modules/beasties": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.4.1.tgz", - "integrity": "sha512-2Imdcw3LznDuxAbJM26RHniOLAzE6WgrK8OuvVXCQtNBS8rsnD9zsSEa3fHl4hHpUY7BYTlrpvtPVbvu9G6neg==", + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/beasties/-/beasties-0.4.2.tgz", + "integrity": "sha512-NvcGjG/7AVUAfRbvrJmHunDQS9uHnE6Q/7AkaPr8oKE8HjOlpjRG5075z/th2Tmlezk3VlaaS8+X9I1RwHJMQw==", "dev": true, "license": "Apache-2.0", "dependencies": { @@ -6780,22 +7669,36 @@ } }, "node_modules/body-parser": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", - "integrity": "sha512-oP5VkATKlNwcgvxi0vM0p/D3n2C3EReYVX+DNYs5TjZFn/oQt2j+4sVJtSMr18pdRr8wjTcBl6LoV+FUwzPmNA==", + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.3.0.tgz", + "integrity": "sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==", "dev": true, "license": "MIT", "dependencies": { "bytes": "^3.1.2", - "content-type": "^1.0.5", + "content-type": "^2.0.0", "debug": "^4.4.3", - "http-errors": "^2.0.0", - "iconv-lite": "^0.7.0", + "http-errors": "^2.0.1", + "iconv-lite": "^0.7.2", "on-finished": "^2.4.1", - "qs": "^6.14.1", - "raw-body": "^3.0.1", - "type-is": "^2.0.1" + "qs": "^6.15.2", + "raw-body": "^3.0.2", + "type-is": "^2.1.0" + }, + "engines": { + "node": ">=18" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/body-parser/node_modules/content-type": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-2.0.0.tgz", + "integrity": "sha512-j/O/d7GcZCyNl7/hwZAb606rzqkyvaDctLmckbxLzHvFBzTJHuGEdodATcP3yIRoDrLHkIATJuvzbFlp/ki2cQ==", + "dev": true, + "license": "MIT", "engines": { "node": ">=18" }, @@ -7371,13 +8274,6 @@ "color-support": "bin.js" } }, - "node_modules/colorette": { - "version": "2.0.20", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", - "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==", - "dev": true, - "license": "MIT" - }, "node_modules/commander": { "version": "2.6.0", "resolved": "https://registry.npmjs.org/commander/-/commander-2.6.0.tgz", @@ -8580,13 +9476,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/err-code": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", - "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==", - "dev": true, - "license": "MIT" - }, "node_modules/error-ex": { "version": "1.3.4", "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.4.tgz", @@ -9257,6 +10146,23 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "license": "MIT" }, + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-truncated-width": "^3.0.2" + } + }, "node_modules/fast-uri": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.2.tgz", @@ -9274,6 +10180,16 @@ ], "license": "BSD-3-Clause" }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-string-width": "^3.0.2" + } + }, "node_modules/fastq": { "version": "1.20.1", "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.20.1.tgz", @@ -9872,9 +10788,9 @@ } }, "node_modules/hono": { - "version": "4.12.25", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.25.tgz", - "integrity": "sha512-2NFaIyNVgJmBs/ecmtGzlmluTFs5cHEWGTdu0t1HBwYzoGXOL5nUQBRMXsXWla5i4KkG//QMzVP88m1+I3fdAQ==", + "version": "4.12.26", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.26.tgz", + "integrity": "sha512-uyZtpnYxM9CmQ7QsQknM4zN8EftNqhON1qYeIKM0Se67CCEe2c44xyGURwB0axX2fBDu1dqHrHAc1hmNT8ITkw==", "dev": true, "license": "MIT", "engines": { @@ -10027,18 +10943,28 @@ "node": ">= 14" } }, + "node_modules/http-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-9.0.0.tgz", + "integrity": "sha512-/MVmHp58WkOypgFhCLk4fzpPcFQvTJ/e6LBI7irpIO2HfxUbpmYoHF+KzipzJpxxzJu7aJNWQ0xojJ/dzV2G5g==", "dev": true, "license": "MIT", "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" + "agent-base": "9.0.0", + "debug": "^4.3.4" }, "engines": { - "node": ">= 14" + "node": ">= 20" } }, "node_modules/husky": { @@ -10482,6 +11408,8 @@ "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", "dev": true, "license": "BSD-3-Clause", + "optional": true, + "peer": true, "engines": { "node": ">=8" } @@ -10492,6 +11420,8 @@ "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", "dev": true, "license": "BSD-3-Clause", + "optional": true, + "peer": true, "dependencies": { "@babel/core": "^7.23.9", "@babel/parser": "^7.23.9", @@ -11263,21 +12193,20 @@ "license": "MIT" }, "node_modules/listr2": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-9.0.5.tgz", - "integrity": "sha512-ME4Fb83LgEgwNw96RKNvKV4VTLuXfoKudAmm2lP8Kk87KaMK0/Xrx/aAkMWmT8mDb+3MlFDspfbCs7adjRxA2g==", + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-10.2.1.tgz", + "integrity": "sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q==", "dev": true, "license": "MIT", "dependencies": { - "cli-truncate": "^5.0.0", - "colorette": "^2.0.20", - "eventemitter3": "^5.0.1", + "cli-truncate": "^5.2.0", + "eventemitter3": "^5.0.4", "log-update": "^6.1.0", "rfdc": "^1.4.1", - "wrap-ansi": "^9.0.0" + "wrap-ansi": "^10.0.0" }, "engines": { - "node": ">=20.0.0" + "node": ">=22.13.0" } }, "node_modules/listr2/node_modules/ansi-styles": { @@ -11293,13 +12222,6 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/listr2/node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", - "dev": true, - "license": "MIT" - }, "node_modules/listr2/node_modules/eventemitter3": { "version": "5.0.4", "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", @@ -11307,46 +12229,28 @@ "dev": true, "license": "MIT" }, - "node_modules/listr2/node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" - }, - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/listr2/node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-10.0.0.tgz", + "integrity": "sha512-SGcvg80f0wUy2/fXES19feHMz8E0JoXv2uNgHOu4Dgi2OrCy1lqwFYEJz1BLbDI0exjPMe/ZdzZ/YpGECBG/aQ==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" + "ansi-styles": "^6.2.3", + "string-width": "^8.2.0", + "strip-ansi": "^7.1.2" }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, "node_modules/lmdb": { - "version": "3.5.1", - "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.5.1.tgz", - "integrity": "sha512-NYHA0MRPjvNX+vSw8Xxg6FLKxzAG+e7Pt8RqAQA/EehzHVXq9SxDqJIN3JL1hK0dweb884y8kIh6rkWvPyg9Wg==", + "version": "3.5.4", + "resolved": "https://registry.npmjs.org/lmdb/-/lmdb-3.5.4.tgz", + "integrity": "sha512-9FKQA6G1MMtqNxfxvSBNXD/axeG2QRjYbNh0/ykRL5xYcRbCm2vXq7B9bhc7nSuKdHzr8/BHIwfPuYYH1UsXXw==", "dev": true, "hasInstallScript": true, "license": "MIT", @@ -11363,13 +12267,13 @@ "download-lmdb-prebuilds": "bin/download-prebuilds.js" }, "optionalDependencies": { - "@lmdb/lmdb-darwin-arm64": "3.5.1", - "@lmdb/lmdb-darwin-x64": "3.5.1", - "@lmdb/lmdb-linux-arm": "3.5.1", - "@lmdb/lmdb-linux-arm64": "3.5.1", - "@lmdb/lmdb-linux-x64": "3.5.1", - "@lmdb/lmdb-win32-arm64": "3.5.1", - "@lmdb/lmdb-win32-x64": "3.5.1" + "@lmdb/lmdb-darwin-arm64": "3.5.4", + "@lmdb/lmdb-darwin-x64": "3.5.4", + "@lmdb/lmdb-linux-arm": "3.5.4", + "@lmdb/lmdb-linux-arm64": "3.5.4", + "@lmdb/lmdb-linux-x64": "3.5.4", + "@lmdb/lmdb-win32-arm64": "3.5.4", + "@lmdb/lmdb-win32-x64": "3.5.4" } }, "node_modules/load-json-file": { @@ -12112,13 +13016,13 @@ } }, "node_modules/mute-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-2.0.0.tgz", - "integrity": "sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==", + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", "dev": true, "license": "ISC", "engines": { - "node": "^18.17.0 || >=20.5.0" + "node": "^20.17.0 || >=22.9.0" } }, "node_modules/mz": { @@ -12397,16 +13301,6 @@ "node": ">=20" } }, - "node_modules/node-gyp/node_modules/undici": { - "version": "6.26.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-6.26.0.tgz", - "integrity": "sha512-4yqz8a3n5HmGTlsbADNtr/dJlhkh/55Rq798G6ibiULcXbDtaLpTl1pvdqcbFfeoj3iSi52lePFM7h9H21cw/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18.17" - } - }, "node_modules/node-gyp/node_modules/which": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/which/-/which-6.0.1.tgz", @@ -12910,12 +13804,13 @@ } }, "node_modules/pacote": { - "version": "21.3.1", - "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.3.1.tgz", - "integrity": "sha512-O0EDXi85LF4AzdjG74GUwEArhdvawi/YOHcsW6IijKNj7wm8IvEWNF5GnfuxNpQ/ZpO3L37+v8hqdVh8GgWYhg==", + "version": "21.5.1", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-21.5.1.tgz", + "integrity": "sha512-KvcJ9iy3crysCsgqc4+PknH/w6jkrp8JN36mpZBPwNaDRwTfMZD37YzRazNstiZUOhuF5pno9f78n9mEJBavwg==", "dev": true, "license": "ISC", "dependencies": { + "@gar/promise-retry": "^1.0.0", "@npmcli/git": "^7.0.0", "@npmcli/installed-package-contents": "^4.0.0", "@npmcli/package-json": "^7.0.0", @@ -12929,7 +13824,6 @@ "npm-pick-manifest": "^11.0.1", "npm-registry-fetch": "^19.0.0", "proc-log": "^6.0.0", - "promise-retry": "^2.0.1", "sigstore": "^4.0.0", "ssri": "^13.0.0", "tar": "^7.4.3" @@ -13016,13 +13910,13 @@ } }, "node_modules/parse5-html-rewriting-stream": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-8.0.0.tgz", - "integrity": "sha512-wzh11mj8KKkno1pZEu+l2EVeWsuKDfR5KNWZOTsslfUX8lPDZx77m9T0kIoAVkFtD1nx6YF8oh4BnPHvxMtNMw==", + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-8.0.1.tgz", + "integrity": "sha512-NaRku2aMpUN1Sh1Gyk1KWUh2A7EJx2c6qYzvwsPtqhoHoaURshdrceYK3LunVCm3WHhm6FS7Vcczbvdh3/UIVw==", "dev": true, "license": "MIT", "dependencies": { - "entities": "^6.0.0", + "entities": "^8.0.0", "parse5": "^8.0.0", "parse5-sax-parser": "^8.0.0" }, @@ -13031,13 +13925,13 @@ } }, "node_modules/parse5-html-rewriting-stream/node_modules/entities": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", - "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", "dev": true, "license": "BSD-2-Clause", "engines": { - "node": ">=0.12" + "node": ">=20.19.0" }, "funding": { "url": "https://github.com/fb55/entities?sponsor=1" @@ -13734,20 +14628,6 @@ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", "license": "MIT" }, - "node_modules/promise-retry": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", - "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", - "dev": true, - "license": "MIT", - "dependencies": { - "err-code": "^2.0.2", - "retry": "^0.12.0" - }, - "engines": { - "node": ">=10" - } - }, "node_modules/proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -14268,16 +15148,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4" - } - }, "node_modules/reusify": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", @@ -14312,38 +15182,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/rolldown": { - "version": "1.0.0-rc.4", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.4.tgz", - "integrity": "sha512-V2tPDUrY3WSevrvU2E41ijZlpF+5PbZu4giH+VpNraaadsJGHa4fR6IFwsocVwEXDoAdIv5qgPPxgrvKAOIPtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@oxc-project/types": "=0.113.0", - "@rolldown/pluginutils": "1.0.0-rc.4" - }, - "bin": { - "rolldown": "bin/cli.mjs" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.4", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.4", - "@rolldown/binding-darwin-x64": "1.0.0-rc.4", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.4", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.4", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.4", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.4", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.4", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.4", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.4", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.4", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.4", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.4" - } - }, "node_modules/rollup": { "version": "4.61.1", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.61.1.tgz", @@ -15146,6 +15984,16 @@ "node": ">= 14" } }, + "node_modules/socks-proxy-agent/node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/source-map": { "version": "0.7.6", "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", @@ -15726,13 +16574,13 @@ } }, "node_modules/tinyglobby": { - "version": "0.2.15", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.15.tgz", - "integrity": "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==", + "version": "0.2.16", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", + "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", "license": "MIT", "dependencies": { "fdir": "^6.5.0", - "picomatch": "^4.0.3" + "picomatch": "^4.0.4" }, "engines": { "node": ">=12.0.0" @@ -16000,9 +16848,9 @@ } }, "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -16087,13 +16935,13 @@ } }, "node_modules/undici": { - "version": "7.24.4", - "resolved": "https://registry.npmjs.org/undici/-/undici-7.24.4.tgz", - "integrity": "sha512-BM/JzwwaRXxrLdElV2Uo6cTLEjhSb3WXboncJamZ15NgUURmvlXvxa6xkwIOILIjPNo9i8ku136ZvWV0Uly8+w==", + "version": "6.27.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.27.0.tgz", + "integrity": "sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==", "dev": true, "license": "MIT", "engines": { - "node": ">=20.18.1" + "node": ">=18.17" } }, "node_modules/undici-types": { @@ -16242,9 +17090,9 @@ } }, "node_modules/vite": { - "version": "7.3.2", - "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.2.tgz", - "integrity": "sha512-Bby3NOsna2jsjfLVOHKes8sGwgl4TT0E6vvpYgnAYDIF/tie7MRaFthmKuHx1NSXjiTueXH3do80FMQgvEktRg==", + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.5.tgz", + "integrity": "sha512-KuOaNhcnGFN2zIPGA7wRmzF+lJA1sea7rHq17aiJ++9lzY1WWG6Jpwqwe1KNbRVPIqHmr8GLYx7jbrQcN/7/ww==", "dev": true, "license": "MIT", "dependencies": { @@ -16837,24 +17685,10 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/yoctocolors-cjs": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.3.tgz", - "integrity": "sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/zod": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.3.6.tgz", - "integrity": "sha512-rftlrkhHZOcjDwkGlnUtZZkvaPHCsDATp4pGpuOOMDaTdDDXF91wuVDJoWoPsKX/3YPQ5fHuF3STjcYyKr+Qhg==", - "dev": true, + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.2.tgz", + "integrity": "sha512-IynmDyxsEsb9RKzO3J9+4SxXnl2FTFSzNBaKKaMV6tsSk0rw9gYw9gs+JFCq/qk2LCZ78KDwyj+Z289TijSkUw==", "license": "MIT", "funding": { "url": "https://github.com/sponsors/colinhacks" diff --git a/package.json b/package.json index f7646cab11..3d849a4a55 100644 --- a/package.json +++ b/package.json @@ -25,19 +25,19 @@ "keywords": [], "author": "", "dependencies": { - "@angular/animations": "^21.2.17", + "@angular/animations": "^22.0.2", "@angular/cdk": "^21.2.9", - "@angular/common": "^21.2.17", - "@angular/compiler": "^21.2.17", - "@angular/core": "^21.2.17", - "@angular/forms": "^21.2.17", + "@angular/common": "^22.0.2", + "@angular/compiler": "^22.0.2", + "@angular/core": "^22.0.2", + "@angular/forms": "^22.0.2", "@angular/material": "^21.2.9", "@angular/material-date-fns-adapter": "^21.2.9", - "@angular/platform-browser": "^21.2.17", - "@angular/platform-browser-dynamic": "^21.2.17", - "@angular/router": "^21.2.17", - "@angular/service-worker": "^21.2.17", - "@angular/upgrade": "^21.2.17", + "@angular/platform-browser": "^22.0.2", + "@angular/platform-browser-dynamic": "^22.0.2", + "@angular/router": "^22.0.2", + "@angular/service-worker": "^22.0.2", + "@angular/upgrade": "^22.0.2", "@ctrl/ngx-emoji-mart": "^9.3.0", "@eslint/js": "^10.0.1", "@ngneat/hotkeys": "^4.0.0", @@ -89,10 +89,10 @@ "@angular-eslint/eslint-plugin-template": "^21.4.0", "@angular-eslint/schematics": "^21.4.0", "@angular-eslint/template-parser": "^21.4.0", - "@angular/build": "^21.2.15", - "@angular/cli": "^21.2.15", - "@angular/compiler-cli": "^21.2.17", - "@angular/language-service": "^21.2.17", + "@angular/build": "^22.0.3", + "@angular/cli": "^22.0.3", + "@angular/compiler-cli": "^22.0.2", + "@angular/language-service": "^22.0.2", "@commitlint/cli": "^20.5.0", "@commitlint/config-conventional": "^21", "@trivago/prettier-plugin-sort-imports": "^6.0.2", @@ -122,7 +122,7 @@ "sass": "^1.48.0", "tailwindcss": "~3.4.17", "ts-node": "~10.9", - "typescript": "~5.9.3", + "typescript": "~6.0.3", "underscore": "^1.8.3", "vitest": "^4.1.8" }, diff --git a/src/app/account/edit-profile/edit-profile.component.ts b/src/app/account/edit-profile/edit-profile.component.ts index 3dc37b0c12..91e2c95b78 100644 --- a/src/app/account/edit-profile/edit-profile.component.ts +++ b/src/app/account/edit-profile/edit-profile.component.ts @@ -1,4 +1,4 @@ -import {Component, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, OnInit} from '@angular/core'; import {Router} from '@angular/router'; import {AuthenticationService} from 'src/app/api/services/authentication.service'; @@ -6,6 +6,7 @@ import {AuthenticationService} from 'src/app/api/services/authentication.service selector: 'f-edit-profile', templateUrl: './edit-profile.component.html', styleUrls: ['./edit-profile.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class EditProfileComponent implements OnInit { diff --git a/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.ts b/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.ts index 47fb5c6210..b9899b934d 100644 --- a/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.ts +++ b/src/app/admin/institution-settings/activity-type-list/activity-type-list.component.ts @@ -1,4 +1,4 @@ -import {AfterViewInit, Component, ViewChild} from '@angular/core'; +import {AfterViewInit, ChangeDetectionStrategy, Component, ViewChild} from '@angular/core'; import {UntypedFormControl, Validators} from '@angular/forms'; import {MatSort, Sort} from '@angular/material/sort'; import {MatTable, MatTableDataSource} from '@angular/material/table'; @@ -10,6 +10,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'activity-type-list', templateUrl: 'activity-type-list.component.html', styleUrls: ['activity-type-list.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ActivityTypeListComponent diff --git a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts index a83d640a5f..0ba7c27ad8 100644 --- a/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts +++ b/src/app/admin/institution-settings/campuses/campus-list/campus-list.component.ts @@ -1,4 +1,4 @@ -import {AfterViewInit, Component, ViewChild} from '@angular/core'; +import {AfterViewInit, ChangeDetectionStrategy, Component, ViewChild} from '@angular/core'; import {UntypedFormControl, Validators} from '@angular/forms'; import {MatSort, Sort} from '@angular/material/sort'; import {MatTable, MatTableDataSource} from '@angular/material/table'; @@ -10,6 +10,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'campus-list', templateUrl: 'campus-list.component.html', styleUrls: ['campus-list.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class CampusListComponent extends EntityFormComponent implements AfterViewInit { diff --git a/src/app/admin/institution-settings/institution-settings.component.ts b/src/app/admin/institution-settings/institution-settings.component.ts index 5d859282f8..2914c7606c 100644 --- a/src/app/admin/institution-settings/institution-settings.component.ts +++ b/src/app/admin/institution-settings/institution-settings.component.ts @@ -1,10 +1,11 @@ -import {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; @Component({ selector: 'institution-settings', templateUrl: 'institution-settings.component.html', styleUrls: ['institution-settings.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class InstitutionSettingsComponent { diff --git a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts index 14f3a20f0c..fc427c320a 100644 --- a/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts +++ b/src/app/admin/institution-settings/overseer-images/overseer-image-list.component.ts @@ -1,5 +1,11 @@ import {HttpClient} from '@angular/common/http'; -import {AfterViewInit, Component, TemplateRef, ViewChild} from '@angular/core'; +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + TemplateRef, + ViewChild, +} from '@angular/core'; import {UntypedFormControl, Validators} from '@angular/forms'; import {MatDialog} from '@angular/material/dialog'; import {MatSort, Sort} from '@angular/material/sort'; @@ -13,6 +19,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'overseer-image-list', templateUrl: 'overseer-image-list.component.html', styleUrls: ['overseer-image-list.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class OverseerImageListComponent diff --git a/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal-content.component.ts b/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal-content.component.ts index b9e6da9451..e844877f73 100644 --- a/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal-content.component.ts +++ b/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal-content.component.ts @@ -1,4 +1,4 @@ -import {Component, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, OnInit} from '@angular/core'; import {MatDialogRef} from '@angular/material/dialog'; import {TeachingPeriod} from 'src/app/api/models/teaching-period'; import {TeachingPeriodService} from 'src/app/api/services/teaching-period.service'; @@ -8,6 +8,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; @Component({ selector: 'create-new-unit-modal-content', templateUrl: 'create-new-unit-modal-content.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class CreateNewUnitModalContentComponent implements OnInit { diff --git a/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal.component.ts b/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal.component.ts index 6096f86bcc..d3e7dde8f5 100644 --- a/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal.component.ts +++ b/src/app/admin/modals/create-new-unit-modal/create-new-unit-modal.component.ts @@ -1,10 +1,11 @@ -import {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; import {CreateNewUnitModalContentComponent} from './create-new-unit-modal-content.component'; @Component({ selector: 'create-new-unit-modal', templateUrl: './create-new-unit-modal.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class CreateNewUnitModal { diff --git a/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.ts b/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.ts index 12415b42da..b61aeeb53c 100644 --- a/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.ts +++ b/src/app/admin/states/teaching-periods/teaching-period-list/teaching-period-list.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, OnInit, ViewChild} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnInit, ViewChild} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; import {MatPaginator} from '@angular/material/paginator'; import {MatSort, Sort} from '@angular/material/sort'; @@ -14,6 +14,7 @@ import {TeachingPeriodUnitImportService} from '../teaching-period-unit-import/te selector: 'f-teaching-period-list', templateUrl: './teaching-period-list.component.html', styleUrls: ['./teaching-period-list.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TeachingPeriodListComponent implements OnInit { @@ -95,6 +96,7 @@ export class TeachingPeriodListComponent implements OnInit { @Component({ selector: 'f-new-teaching-period-dialog', templateUrl: 'new-teaching-period-dialog.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class NewTeachingPeriodDialogComponent { diff --git a/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts b/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts index 8b01596437..8dfefa5cb5 100644 --- a/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts +++ b/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.ts @@ -1,4 +1,11 @@ -import {Component, Inject, Injectable, OnInit, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Inject, + Injectable, + OnInit, + ViewChild, +} from '@angular/core'; import {FormControl} from '@angular/forms'; import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; import {MatTable, MatTableDataSource} from '@angular/material/table'; @@ -50,6 +57,7 @@ export class TeachingPeriodUnitImportService { selector: 'f-teaching-period-unit-import', templateUrl: 'teaching-period-unit-import.dialog.html', styleUrls: ['teaching-period-unit-import.dialog.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TeachingPeriodUnitImportDialogComponent implements OnInit { diff --git a/src/app/admin/states/units/units.component.ts b/src/app/admin/states/units/units.component.ts index 7b224e13fe..86f03ab90d 100644 --- a/src/app/admin/states/units/units.component.ts +++ b/src/app/admin/states/units/units.component.ts @@ -1,4 +1,11 @@ -import {AfterViewInit, Component, Input, OnInit, ViewChild} from '@angular/core'; +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + Input, + OnInit, + ViewChild, +} from '@angular/core'; import {MatPaginator} from '@angular/material/paginator'; import {MatSort, Sort} from '@angular/material/sort'; import {MatTable, MatTableDataSource} from '@angular/material/table'; @@ -33,6 +40,7 @@ interface IUnitOrProject { selector: 'f-units', templateUrl: './units.component.html', styleUrls: ['./units.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class FUnitsComponent implements OnInit, AfterViewInit { diff --git a/src/app/admin/states/users/users.component.ts b/src/app/admin/states/users/users.component.ts index 6e3461172b..b75d603d61 100644 --- a/src/app/admin/states/users/users.component.ts +++ b/src/app/admin/states/users/users.component.ts @@ -1,4 +1,11 @@ -import {AfterViewInit, Component, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + OnDestroy, + OnInit, + ViewChild, +} from '@angular/core'; import {MatPaginator} from '@angular/material/paginator'; import {MatSort, Sort} from '@angular/material/sort'; import {MatTable, MatTableDataSource} from '@angular/material/table'; @@ -14,6 +21,7 @@ import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; selector: 'f-users', templateUrl: './users.component.html', styleUrls: ['./users.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class FUsersComponent implements OnInit, AfterViewInit, OnDestroy { diff --git a/src/app/admin/tii-action-log/tii-action-log.component.ts b/src/app/admin/tii-action-log/tii-action-log.component.ts index 545bbd177d..ae492f6773 100644 --- a/src/app/admin/tii-action-log/tii-action-log.component.ts +++ b/src/app/admin/tii-action-log/tii-action-log.component.ts @@ -1,4 +1,4 @@ -import {AfterViewInit, Component, ViewChild} from '@angular/core'; +import {AfterViewInit, ChangeDetectionStrategy, Component, ViewChild} from '@angular/core'; import {MatPaginator} from '@angular/material/paginator'; import {MatSort, Sort} from '@angular/material/sort'; import {MatTable, MatTableDataSource} from '@angular/material/table'; @@ -10,6 +10,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-tii-action-log', templateUrl: './tii-action-log.component.html', styleUrls: ['./tii-action-log.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TiiActionLogComponent implements AfterViewInit { diff --git a/src/app/api/services/spec/campus.service.spec.ts b/src/app/api/services/spec/campus.service.spec.ts index d96c869e4c..3373d5b15d 100644 --- a/src/app/api/services/spec/campus.service.spec.ts +++ b/src/app/api/services/spec/campus.service.spec.ts @@ -1,5 +1,10 @@ import {afterEach, beforeEach, describe, expect, it} from 'vitest'; -import {HttpRequest, provideHttpClient, withInterceptorsFromDi} from '@angular/common/http'; +import { + HttpRequest, + provideHttpClient, + withInterceptorsFromDi, + withXhr, +} from '@angular/common/http'; import {HttpTestingController, provideHttpClientTesting} from '@angular/common/http/testing'; import {TestBed} from '@angular/core/testing'; import {Campus} from 'src/app/api/models/doubtfire-model'; @@ -14,7 +19,7 @@ describe('CampusService', () => { imports: [], providers: [ CampusService, - provideHttpClient(withInterceptorsFromDi()), + provideHttpClient(withXhr(), withInterceptorsFromDi()), provideHttpClientTesting(), ], }); diff --git a/src/app/api/services/spec/user.service.spec.ts b/src/app/api/services/spec/user.service.spec.ts index 6f39dc81eb..2e03e7e9c4 100644 --- a/src/app/api/services/spec/user.service.spec.ts +++ b/src/app/api/services/spec/user.service.spec.ts @@ -1,5 +1,10 @@ import {afterEach, beforeEach, describe, expect, it} from 'vitest'; -import {HttpRequest, provideHttpClient, withInterceptorsFromDi} from '@angular/common/http'; +import { + HttpRequest, + provideHttpClient, + withInterceptorsFromDi, + withXhr, +} from '@angular/common/http'; import {HttpTestingController, provideHttpClientTesting} from '@angular/common/http/testing'; import {TestBed} from '@angular/core/testing'; import {User, UserService} from 'src/app/api/models/doubtfire-model'; @@ -13,7 +18,7 @@ describe('UserService', () => { imports: [], providers: [ UserService, - provideHttpClient(withInterceptorsFromDi()), + provideHttpClient(withXhr(), withInterceptorsFromDi()), provideHttpClientTesting(), ], }); diff --git a/src/app/app.component.ts b/src/app/app.component.ts index adc62064a8..b5d35f7f32 100644 --- a/src/app/app.component.ts +++ b/src/app/app.component.ts @@ -1,10 +1,11 @@ -import {Component, OnDestroy, OnInit, Renderer2} from '@angular/core'; +import {ChangeDetectionStrategy, Component, OnDestroy, OnInit, Renderer2} from '@angular/core'; import {NavigationEnd, Router} from '@angular/router'; import {Subscription, filter} from 'rxjs'; @Component({ selector: 'app-root', templateUrl: './app.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class AppComponent implements OnInit, OnDestroy { diff --git a/src/app/common/archive-viewer/archive-viewer.component.ts b/src/app/common/archive-viewer/archive-viewer.component.ts index 6ea01d9949..ef08675259 100644 --- a/src/app/common/archive-viewer/archive-viewer.component.ts +++ b/src/app/common/archive-viewer/archive-viewer.component.ts @@ -1,6 +1,7 @@ import JSZip from 'jszip'; import {HttpClient, HttpResponse} from '@angular/common/http'; import { + ChangeDetectionStrategy, Component, EventEmitter, Input, @@ -39,6 +40,7 @@ interface ArchiveFileTreeNode { selector: 'f-archive-viewer', templateUrl: './archive-viewer.component.html', styleUrls: ['./archive-viewer.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ArchiveViewerComponent implements OnChanges, OnDestroy { diff --git a/src/app/common/audio-player/audio-player.component.ts b/src/app/common/audio-player/audio-player.component.ts index d72d61ae11..e1f14e8b4f 100644 --- a/src/app/common/audio-player/audio-player.component.ts +++ b/src/app/common/audio-player/audio-player.component.ts @@ -1,5 +1,13 @@ import {HttpResponse} from '@angular/common/http'; -import {Component, ElementRef, Inject, Input, OnDestroy, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + ElementRef, + Inject, + Input, + OnDestroy, + ViewChild, +} from '@angular/core'; import {Project, Task, TaskComment} from 'src/app/api/models/doubtfire-model'; import {FileDownloaderService} from '../file-downloader/file-downloader.service'; import {AlertService} from '../services/alert.service'; @@ -8,6 +16,7 @@ import {AlertService} from '../services/alert.service'; selector: 'audio-player', templateUrl: './audio-player.component.html', styleUrls: ['./audio-player.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class AudioPlayerComponent implements OnDestroy { diff --git a/src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.ts b/src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.ts index b326da25f9..cf6fbf25aa 100644 --- a/src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.ts +++ b/src/app/common/audio-recorder/audio/audio-comment-recorder/audio-comment-recorder.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {Task, TaskComment, TaskCommentService} from 'src/app/api/models/doubtfire-model'; import {AlertService} from 'src/app/common/services/alert.service'; import {MediaRecorderService} from 'src/app/common/services/recorder-service'; @@ -8,6 +8,7 @@ import {BaseAudioRecorderComponent} from '../base-audio-recorder'; selector: 'audio-comment-recorder', templateUrl: './audio-comment-recorder.html', providers: [MediaRecorderService], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class AudioCommentRecorderComponent extends BaseAudioRecorderComponent implements OnInit { diff --git a/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester.component.ts b/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester.component.ts index 07a5559d16..ddbdba7851 100644 --- a/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester.component.ts +++ b/src/app/common/audio-recorder/audio/microphone-tester/microphone-tester.component.ts @@ -1,4 +1,4 @@ -import {AfterViewInit, Component, Input} from '@angular/core'; +import {AfterViewInit, ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Task} from 'src/app/api/models/doubtfire-model'; import {MediaRecorderService} from 'src/app/common/services/recorder-service'; import {BaseAudioRecorderComponent} from '../base-audio-recorder'; @@ -7,6 +7,7 @@ import {BaseAudioRecorderComponent} from '../base-audio-recorder'; selector: 'microphone-tester', templateUrl: './microphone-tester-component.html', providers: [MediaRecorderService], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class MicrophoneTesterComponent extends BaseAudioRecorderComponent implements AfterViewInit { diff --git a/src/app/common/chart-base/chart-base-component/chart-base-component.component.ts b/src/app/common/chart-base/chart-base-component/chart-base-component.component.ts index 58e2cc25c6..e54f546dcc 100644 --- a/src/app/common/chart-base/chart-base-component/chart-base-component.component.ts +++ b/src/app/common/chart-base/chart-base-component/chart-base-component.component.ts @@ -1,5 +1,5 @@ import {TooltipService} from '@swimlane/ngx-charts'; -import {Component, ViewContainerRef} from '@angular/core'; +import {ChangeDetectionStrategy, Component, ViewContainerRef} from '@angular/core'; import {AppInjector} from 'src/app/app-injector'; /** @@ -10,6 +10,7 @@ import {AppInjector} from 'src/app/app-injector'; */ @Component({ templateUrl: './chart-base-component.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ChartBaseComponent { diff --git a/src/app/common/edit-profile-form/edit-profile-form.component.ts b/src/app/common/edit-profile-form/edit-profile-form.component.ts index 0e9605f118..fbc51a92d6 100644 --- a/src/app/common/edit-profile-form/edit-profile-form.component.ts +++ b/src/app/common/edit-profile-form/edit-profile-form.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, Input, OnInit, Optional} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, Input, OnInit, Optional} from '@angular/core'; import {MAT_DIALOG_DATA} from '@angular/material/dialog'; import {MatSnackBar} from '@angular/material/snack-bar'; import {Router} from '@angular/router'; @@ -11,6 +11,7 @@ import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; selector: 'f-edit-profile-form', templateUrl: './edit-profile-form.component.html', styleUrls: ['./edit-profile-form.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class EditProfileFormComponent implements OnInit { diff --git a/src/app/common/f-chip/chip.component.ts b/src/app/common/f-chip/chip.component.ts index ff926f0556..6aa6222a72 100644 --- a/src/app/common/f-chip/chip.component.ts +++ b/src/app/common/f-chip/chip.component.ts @@ -1,9 +1,10 @@ -import {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; @Component({ selector: 'f-chip', templateUrl: './chip.component.html', styleUrls: ['./chip.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class FChipComponent {} diff --git a/src/app/common/feedback-template-editor/feedback-template-editor.component.ts b/src/app/common/feedback-template-editor/feedback-template-editor.component.ts index 69b1f24ed1..82e3dcb16c 100644 --- a/src/app/common/feedback-template-editor/feedback-template-editor.component.ts +++ b/src/app/common/feedback-template-editor/feedback-template-editor.component.ts @@ -1,4 +1,12 @@ -import {AfterViewInit, Component, Input, OnChanges, SimpleChanges, ViewChild} from '@angular/core'; +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + SimpleChanges, + ViewChild, +} from '@angular/core'; import {MatPaginator} from '@angular/material/paginator'; import {MatSelectChange} from '@angular/material/select'; import {MatSort, Sort} from '@angular/material/sort'; @@ -23,6 +31,7 @@ import {CsvUploadModalService} from '../modals/csv-upload-modal/csv-upload-modal @Component({ selector: 'f-feedback-template-editor', templateUrl: 'feedback-template-editor.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class FeedbackTemplateEditorComponent implements OnChanges, AfterViewInit { diff --git a/src/app/common/file-drop/file-drop.component.html b/src/app/common/file-drop/file-drop.component.html index d4615a73f4..fe4f73c8a9 100644 --- a/src/app/common/file-drop/file-drop.component.html +++ b/src/app/common/file-drop/file-drop.component.html @@ -37,7 +37,9 @@ (click)="uploadProgress ? cancelUpload() : upload()" > @if (!uploadProgress) { - upload + upload } @if (uploadProgress) { cancel diff --git a/src/app/common/file-drop/file-drop.component.ts b/src/app/common/file-drop/file-drop.component.ts index ea4e8ec7cd..610dc4cbe3 100644 --- a/src/app/common/file-drop/file-drop.component.ts +++ b/src/app/common/file-drop/file-drop.component.ts @@ -1,5 +1,5 @@ import {HttpClient, HttpErrorResponse, HttpEventType, HttpResponse} from '@angular/common/http'; -import {Component, EventEmitter, Input, Output} from '@angular/core'; +import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core'; import {Subscription, throwError} from 'rxjs'; import {AlertService} from '../services/alert.service'; @@ -10,6 +10,7 @@ import {AlertService} from '../services/alert.service'; selector: 'f-file-drop', templateUrl: 'file-drop.component.html', styleUrls: ['file-drop.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class FileDropComponent { diff --git a/src/app/common/file-uploader/file-uploader.component.html b/src/app/common/file-uploader/file-uploader.component.html index 900c616b27..72443ddca0 100644 --- a/src/app/common/file-uploader/file-uploader.component.html +++ b/src/app/common/file-uploader/file-uploader.component.html @@ -128,7 +128,10 @@
      Upload Summary
      - + } diff --git a/src/app/common/file-uploader/file-uploader.component.ts b/src/app/common/file-uploader/file-uploader.component.ts index c4a6653f49..a3b47f8830 100644 --- a/src/app/common/file-uploader/file-uploader.component.ts +++ b/src/app/common/file-uploader/file-uploader.component.ts @@ -1,4 +1,5 @@ import { + ChangeDetectionStrategy, Component, EventEmitter, Input, @@ -79,6 +80,7 @@ export const ACCEPTED_TYPES = { selector: 'f-file-uploader', templateUrl: './file-uploader.component.html', styleUrls: ['./file-uploader.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class FileUploaderComponent implements OnInit, OnChanges { diff --git a/src/app/common/file-viewer/file-viewer.component.ts b/src/app/common/file-viewer/file-viewer.component.ts index ae6ae795d1..c034f471d3 100644 --- a/src/app/common/file-viewer/file-viewer.component.ts +++ b/src/app/common/file-viewer/file-viewer.component.ts @@ -1,6 +1,13 @@ import {PDFProgressData} from 'ng2-pdf-viewer'; import {HttpResponse} from '@angular/common/http'; -import {Component, Input, OnChanges, OnDestroy, SimpleChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + OnDestroy, + SimpleChanges, +} from '@angular/core'; import {FileDownloaderService} from '../file-downloader/file-downloader.service'; import {AlertService} from '../services/alert.service'; @@ -11,6 +18,7 @@ import {AlertService} from '../services/alert.service'; selector: 'f-file-viewer', templateUrl: './file-viewer.component.html', styleUrls: ['./file-viewer.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class FileViewerComponent implements OnDestroy, OnChanges { diff --git a/src/app/common/footer/footer.component.ts b/src/app/common/footer/footer.component.ts index d0a0836ad1..9278ba3da7 100644 --- a/src/app/common/footer/footer.component.ts +++ b/src/app/common/footer/footer.component.ts @@ -1,4 +1,12 @@ -import {Component, ElementRef, HostListener, Input, OnInit, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + ElementRef, + HostListener, + Input, + OnInit, + ViewChild, +} from '@angular/core'; import {Observable} from 'rxjs'; import {Task} from 'src/app/api/models/task'; import {UnitRole} from 'src/app/api/models/unit-role'; @@ -16,6 +24,7 @@ import {AlertService} from '../services/alert.service'; selector: 'f-footer', templateUrl: './footer.component.html', styleUrls: ['./footer.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class FooterComponent implements OnInit { diff --git a/src/app/common/grade-icon/grade-icon.component.ts b/src/app/common/grade-icon/grade-icon.component.ts index a07bf1c238..f99a8ee817 100644 --- a/src/app/common/grade-icon/grade-icon.component.ts +++ b/src/app/common/grade-icon/grade-icon.component.ts @@ -1,11 +1,19 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + OnInit, + SimpleChanges, +} from '@angular/core'; import {GradeService} from '../services/grade.service'; @Component({ selector: 'f-grade-icon', templateUrl: './grade-icon.component.html', styleUrls: ['./grade-icon.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class GradeIconComponent implements OnInit, OnChanges { diff --git a/src/app/common/header/header.component.ts b/src/app/common/header/header.component.ts index 68ebc4dd99..a5859dc65f 100644 --- a/src/app/common/header/header.component.ts +++ b/src/app/common/header/header.component.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import {MediaObserver} from 'ng-flex-layout'; -import {Component, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, OnDestroy, OnInit} from '@angular/core'; import {Router} from '@angular/router'; import {Subscription, asapScheduler, observeOn} from 'rxjs'; import { @@ -27,6 +27,7 @@ import {IsActiveUnitRole} from '../pipes/is-active-unit-role.pipe'; selector: 'app-header', templateUrl: './header.component.html', styleUrls: ['./header.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class HeaderComponent implements OnInit, OnDestroy { diff --git a/src/app/common/header/task-dropdown/task-dropdown.component.ts b/src/app/common/header/task-dropdown/task-dropdown.component.ts index 6230c70764..08d3b0e861 100644 --- a/src/app/common/header/task-dropdown/task-dropdown.component.ts +++ b/src/app/common/header/task-dropdown/task-dropdown.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {ActivatedRoute, NavigationEnd, Router} from '@angular/router'; import {filter} from 'rxjs'; import {Project, Unit, UnitRole} from 'src/app/api/models/doubtfire-model'; @@ -9,6 +9,7 @@ import {TutorNotesModalService} from '../../modals/tutor-notes-modal/tutor-notes selector: 'task-dropdown', templateUrl: './task-dropdown.component.html', styleUrls: ['./task-dropdown.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDropdownComponent { diff --git a/src/app/common/header/unit-dropdown/unit-dropdown.component.html b/src/app/common/header/unit-dropdown/unit-dropdown.component.html index 3bf5b0c19f..8a3927d771 100644 --- a/src/app/common/header/unit-dropdown/unit-dropdown.component.html +++ b/src/app/common/header/unit-dropdown/unit-dropdown.component.html @@ -6,7 +6,7 @@ [isDropdown]="true" [matMenuTriggerFor]="menu" [shiftBetweenBadges]="false" - [unit_code]="unit?.code" + [unit_code]="$safeNavigationMigration(unit?.code)" [width]="80" > {{ menuState.menuOpen ? 'arrow_drop_up' : 'arrow_drop_down' }} diff --git a/src/app/common/header/unit-dropdown/unit-dropdown.component.ts b/src/app/common/header/unit-dropdown/unit-dropdown.component.ts index f32bb06acc..4190257424 100644 --- a/src/app/common/header/unit-dropdown/unit-dropdown.component.ts +++ b/src/app/common/header/unit-dropdown/unit-dropdown.component.ts @@ -1,11 +1,12 @@ import {MediaObserver} from 'ng-flex-layout'; -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Project, Unit, UnitRole} from 'src/app/api/models/doubtfire-model'; @Component({ selector: 'unit-dropdown', templateUrl: './unit-dropdown.component.html', styleUrls: ['./unit-dropdown.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitDropdownComponent { diff --git a/src/app/common/hero-sidebar/hero-sidebar.component.ts b/src/app/common/hero-sidebar/hero-sidebar.component.ts index 7c47c46a5e..7c54a7bd8c 100644 --- a/src/app/common/hero-sidebar/hero-sidebar.component.ts +++ b/src/app/common/hero-sidebar/hero-sidebar.component.ts @@ -1,10 +1,11 @@ -import {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; @Component({ selector: 'f-hero-sidebar', templateUrl: './hero-sidebar.component.html', styleUrls: ['./hero-sidebar.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class HeroSidebarComponent { diff --git a/src/app/common/learning-outcome-editor/learning-outcome-editor.component.ts b/src/app/common/learning-outcome-editor/learning-outcome-editor.component.ts index d5801ed011..7b141d5cbb 100644 --- a/src/app/common/learning-outcome-editor/learning-outcome-editor.component.ts +++ b/src/app/common/learning-outcome-editor/learning-outcome-editor.component.ts @@ -3,6 +3,7 @@ import {LiveAnnouncer} from '@angular/cdk/a11y'; import {COMMA, ENTER} from '@angular/cdk/keycodes'; import { AfterViewInit, + ChangeDetectionStrategy, Component, Input, OnChanges, @@ -44,6 +45,7 @@ import {NestedCsvDownloadModalService} from './nested-csv-download-modal/nested- @Component({ selector: 'f-learning-outcome-editor', templateUrl: 'learning-outcome-editor.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class LearningOutcomeEditorComponent implements OnChanges, OnInit, AfterViewInit, OnDestroy { diff --git a/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.ts b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.ts index 1c072924cf..d17b8fd895 100644 --- a/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.ts +++ b/src/app/common/learning-outcome-editor/nested-csv-download-modal/nested-csv-download-modal.component.ts @@ -1,10 +1,11 @@ -import {Component, Inject} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {FileDownloaderService} from '../../file-downloader/file-downloader.service'; @Component({ selector: 'f-nested-csv-download-modal', templateUrl: './nested-csv-download-modal.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class NestedCsvDownloadModalComponent { diff --git a/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.component.ts b/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.component.ts index df9295c025..e0cdf53f73 100644 --- a/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.component.ts +++ b/src/app/common/modals/about-doubtfire-modal/about-doubtfire-modal.component.ts @@ -1,7 +1,7 @@ // // Modal to show Doubtfire version info // -import {Component, Inject, Injectable} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, Injectable} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialog} from '@angular/material/dialog'; import {Sort} from '@angular/material/sort'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; @@ -12,6 +12,7 @@ import {GithubProfile} from './github-profile'; @Component({ selector: 'about-doubtfire-dialog', templateUrl: 'about-doubtfire-modal-content.tpl.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class AboutDoubtfireModalContent { diff --git a/src/app/common/modals/calendar-modal/calendar-modal.component.ts b/src/app/common/modals/calendar-modal/calendar-modal.component.ts index 40e5856c6e..9d464eca36 100644 --- a/src/app/common/modals/calendar-modal/calendar-modal.component.ts +++ b/src/app/common/modals/calendar-modal/calendar-modal.component.ts @@ -1,4 +1,11 @@ -import {AfterViewInit, Component, Inject, OnInit, ViewChild} from '@angular/core'; +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + Inject, + OnInit, + ViewChild, +} from '@angular/core'; import {MAT_DIALOG_DATA} from '@angular/material/dialog'; import {MatSlideToggle} from '@angular/material/slide-toggle'; import {Project, ProjectService, Webcal, WebcalService} from 'src/app/api/models/doubtfire-model'; @@ -10,6 +17,7 @@ import {ConfirmationModalService} from '../confirmation-modal/confirmation-modal selector: 'calendar-modal', templateUrl: './calendar-modal.component.html', styleUrls: ['./calendar-modal.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class CalendarModalComponent implements OnInit, AfterViewInit { diff --git a/src/app/common/modals/comments-modal/comments-modal.component.ts b/src/app/common/modals/comments-modal/comments-modal.component.ts index 197162b588..7cb5d80dc3 100644 --- a/src/app/common/modals/comments-modal/comments-modal.component.ts +++ b/src/app/common/modals/comments-modal/comments-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, Input, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA} from '@angular/material/dialog'; import {TaskComment} from 'src/app/api/models/doubtfire-model'; @@ -11,6 +11,7 @@ export interface CommentsModalData { selector: 'comments-modal', templateUrl: './comments-modal.component.html', styleUrls: ['./comments-modal.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class CommentsModalComponent implements OnInit { diff --git a/src/app/common/modals/confirmation-modal/confirmation-modal.component.ts b/src/app/common/modals/confirmation-modal/confirmation-modal.component.ts index dea3e5fad4..5427fc020c 100644 --- a/src/app/common/modals/confirmation-modal/confirmation-modal.component.ts +++ b/src/app/common/modals/confirmation-modal/confirmation-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, Input, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {AlertService} from '../../services/alert.service'; @@ -15,6 +15,7 @@ export interface ConfirmationModalData { selector: 'confirmation-modal', templateUrl: './confirmation-modal.component.html', styleUrls: ['./confirmation-modal.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ConfirmationModalComponent implements OnInit { diff --git a/src/app/common/modals/csv-result-modal/csv-result-modal.component.ts b/src/app/common/modals/csv-result-modal/csv-result-modal.component.ts index b5f3bea79a..8d1f1a6d70 100644 --- a/src/app/common/modals/csv-result-modal/csv-result-modal.component.ts +++ b/src/app/common/modals/csv-result-modal/csv-result-modal.component.ts @@ -1,4 +1,4 @@ -import {AfterViewInit, Component, Inject, ViewChild} from '@angular/core'; +import {AfterViewInit, ChangeDetectionStrategy, Component, Inject, ViewChild} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {MatPaginator} from '@angular/material/paginator'; import {MatTableDataSource} from '@angular/material/table'; @@ -16,6 +16,7 @@ interface CsvDisplayRow { selector: 'f-csv-result-modal', templateUrl: './csv-result-modal.component.html', styleUrls: ['./csv-result-modal.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class CsvResultModalComponent implements AfterViewInit { diff --git a/src/app/common/modals/csv-upload-modal/csv-upload-modal.component.ts b/src/app/common/modals/csv-upload-modal/csv-upload-modal.component.ts index 76d58e1ac6..809dd0abae 100644 --- a/src/app/common/modals/csv-upload-modal/csv-upload-modal.component.ts +++ b/src/app/common/modals/csv-upload-modal/csv-upload-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; export interface CsvUploadFileSpec { @@ -20,6 +20,7 @@ export interface CsvUploadModalData { selector: 'f-csv-upload-modal', templateUrl: './csv-upload-modal.component.html', styleUrls: ['./csv-upload-modal.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class CsvUploadModalComponent { diff --git a/src/app/common/modals/date-change-modal/task-date-slider.component.ts b/src/app/common/modals/date-change-modal/task-date-slider.component.ts index 6ffa383a0a..5947ff626a 100644 --- a/src/app/common/modals/date-change-modal/task-date-slider.component.ts +++ b/src/app/common/modals/date-change-modal/task-date-slider.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges} from '@angular/core'; import {Task} from 'src/app/api/models/doubtfire-model'; import {MappingFunctions} from 'src/app/api/services/mapping-fn'; import {AlertService} from '../../services/alert.service'; @@ -8,6 +8,7 @@ import {ConfirmationModalService} from '../confirmation-modal/confirmation-modal selector: 'f-task-date-slider', styleUrl: './task-date-slider.component.scss', templateUrl: './task-date-slider.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDateSliderComponent implements OnChanges { diff --git a/src/app/common/modals/discussed-in-class-reason-modal/discussed-in-class-reason-modal.component.ts b/src/app/common/modals/discussed-in-class-reason-modal/discussed-in-class-reason-modal.component.ts index 84206f6236..0166f2fc3d 100644 --- a/src/app/common/modals/discussed-in-class-reason-modal/discussed-in-class-reason-modal.component.ts +++ b/src/app/common/modals/discussed-in-class-reason-modal/discussed-in-class-reason-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; export interface DiscussedInClassReasonModalData { @@ -11,6 +11,7 @@ export interface DiscussedInClassReasonModalData { selector: 'f-discussed-in-class-reason-modal', templateUrl: './discussed-in-class-reason-modal.component.html', styleUrl: './discussed-in-class-reason-modal.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class DiscussedInClassReasonModalComponent { diff --git a/src/app/common/modals/extension-modal/extension-modal.component.ts b/src/app/common/modals/extension-modal/extension-modal.component.ts index 9ae3da2c81..70ff977b6b 100644 --- a/src/app/common/modals/extension-modal/extension-modal.component.ts +++ b/src/app/common/modals/extension-modal/extension-modal.component.ts @@ -1,5 +1,5 @@ import {addDays, differenceInDays, differenceInWeeks, isAfter} from 'date-fns'; -import {Component, Inject, LOCALE_ID} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, LOCALE_ID} from '@angular/core'; import {FormControl, FormGroup, FormGroupDirective, NgForm, Validators} from '@angular/forms'; import {ErrorStateMatcher} from '@angular/material/core'; import {MatDatepickerInputEvent} from '@angular/material/datepicker'; @@ -19,6 +19,7 @@ export class ReasonErrorStateMatcher implements ErrorStateMatcher { @Component({ selector: 'extension-modal', templateUrl: './extension-modal.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ExtensionModalComponent { diff --git a/src/app/common/modals/qr-modal/qr-modal.component.ts b/src/app/common/modals/qr-modal/qr-modal.component.ts index 072f319ba2..92f1784ee7 100644 --- a/src/app/common/modals/qr-modal/qr-modal.component.ts +++ b/src/app/common/modals/qr-modal/qr-modal.component.ts @@ -1,5 +1,5 @@ import QRCode from 'qrcode'; -import {Component, Inject, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA} from '@angular/material/dialog'; import {QrModalData} from './qr-modal.service'; @@ -7,6 +7,7 @@ import {QrModalData} from './qr-modal.service'; selector: 'f-qr-modal', templateUrl: './qr-modal.component.html', styleUrls: ['./qr-modal.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class QrModalComponent implements OnInit { diff --git a/src/app/common/modals/scorm-extension-modal/scorm-extension-modal.component.ts b/src/app/common/modals/scorm-extension-modal/scorm-extension-modal.component.ts index 9ebb0f1ac5..8322724d1b 100644 --- a/src/app/common/modals/scorm-extension-modal/scorm-extension-modal.component.ts +++ b/src/app/common/modals/scorm-extension-modal/scorm-extension-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, LOCALE_ID} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, LOCALE_ID} from '@angular/core'; import {FormControl, FormGroup, FormGroupDirective, NgForm, Validators} from '@angular/forms'; import {ErrorStateMatcher} from '@angular/material/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; @@ -17,6 +17,7 @@ export class ReasonErrorStateMatcher implements ErrorStateMatcher { @Component({ selector: 'f-scorm-extension-modal', templateUrl: './scorm-extension-modal.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ScormExtensionModalComponent { diff --git a/src/app/common/modals/sidekiq-jobs-modal/sidekiq-jobs-modal.component.ts b/src/app/common/modals/sidekiq-jobs-modal/sidekiq-jobs-modal.component.ts index 3cc938e9b3..dceebc3455 100644 --- a/src/app/common/modals/sidekiq-jobs-modal/sidekiq-jobs-modal.component.ts +++ b/src/app/common/modals/sidekiq-jobs-modal/sidekiq-jobs-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnInit} from '@angular/core'; import {MatDialogRef} from '@angular/material/dialog'; import {SidekiqJobEntry, SidekiqJobService} from 'src/app/api/services/sidekiq-job.service'; import {SidekiqProgressModalService} from 'src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.service'; @@ -8,6 +8,7 @@ import {AlertService} from '../../services/alert.service'; selector: 'f-sidekiq-jobs-modal', templateUrl: './sidekiq-jobs-modal.component.html', styleUrl: './sidekiq-jobs-modal.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class SidekiqJobsModalComponent implements OnInit { diff --git a/src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.component.ts b/src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.component.ts index e5fd5e5cf1..440d1ebf5d 100644 --- a/src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.component.ts +++ b/src/app/common/modals/sidekiq-progress-modal/sidekiq-progress-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnDestroy, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {MatSnackBar} from '@angular/material/snack-bar'; import {Subject} from 'rxjs'; @@ -18,6 +18,7 @@ export interface SidekiqProgressModalData { selector: 'f-sidekiq-progress-modal', templateUrl: './sidekiq-progress-modal.component.html', styleUrl: './sidekiq-progress-modal.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class SidekiqProgressModalComponent implements OnInit, OnDestroy { diff --git a/src/app/common/modals/spec-con-modal/spec-con-modal.component.ts b/src/app/common/modals/spec-con-modal/spec-con-modal.component.ts index 64eba3bf2a..ee96ac0396 100644 --- a/src/app/common/modals/spec-con-modal/spec-con-modal.component.ts +++ b/src/app/common/modals/spec-con-modal/spec-con-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {Project} from 'src/app/api/models/doubtfire-model'; import {AlertService} from '../../services/alert.service'; @@ -6,6 +6,7 @@ import {AlertService} from '../../services/alert.service'; @Component({ selector: 'f-spec-con-modal', templateUrl: './spec-con-modal.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class SpecConModalComponent { diff --git a/src/app/common/modals/task-assessment-modal/task-assessment-modal.component.ts b/src/app/common/modals/task-assessment-modal/task-assessment-modal.component.ts index c560b4b20c..c37611915f 100644 --- a/src/app/common/modals/task-assessment-modal/task-assessment-modal.component.ts +++ b/src/app/common/modals/task-assessment-modal/task-assessment-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, Input, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {Subject} from 'rxjs'; import {Task} from 'src/app/api/models/doubtfire-model'; @@ -8,6 +8,7 @@ import {TaskAssessmentModalData} from './task-assessment-modal.service'; selector: 'task-assessment-modal', templateUrl: './task-assessment-modal.component.html', styleUrls: ['./task-assessment-modal.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskAssessmentModalComponent implements OnInit { diff --git a/src/app/common/modals/tutor-notes-modal/tutor-notes-modal.component.ts b/src/app/common/modals/tutor-notes-modal/tutor-notes-modal.component.ts index 097684ace0..bb34f4495f 100644 --- a/src/app/common/modals/tutor-notes-modal/tutor-notes-modal.component.ts +++ b/src/app/common/modals/tutor-notes-modal/tutor-notes-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA} from '@angular/material/dialog'; import {Task} from 'src/app/api/models/task'; import {UnitRole} from 'src/app/api/models/unit-role'; @@ -8,6 +8,7 @@ import {TutorNotesModalData} from './tutor-notes-modal.service'; selector: 'f-tutor-notes-modal', templateUrl: './tutor-notes-modal.component.html', styleUrl: './tutor-notes-modal.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TutorNotesModalComponent implements OnInit { diff --git a/src/app/common/obect-select/object-select.component.ts b/src/app/common/obect-select/object-select.component.ts index 3be3019985..386429f338 100644 --- a/src/app/common/obect-select/object-select.component.ts +++ b/src/app/common/obect-select/object-select.component.ts @@ -1,4 +1,4 @@ -import {Component, EventEmitter, Input, Output} from '@angular/core'; +import {ChangeDetectionStrategy, Component, EventEmitter, Input, Output} from '@angular/core'; import {MatSelectChange} from '@angular/material/select'; /** @@ -9,6 +9,7 @@ import {MatSelectChange} from '@angular/material/select'; @Component({ selector: 'object-select', templateUrl: 'object-select.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ObjectSelectComponent { diff --git a/src/app/common/pdf-viewer-panel/pdf-viewer-panel.component.ts b/src/app/common/pdf-viewer-panel/pdf-viewer-panel.component.ts index c1e38cf8f5..5fa911c55a 100644 --- a/src/app/common/pdf-viewer-panel/pdf-viewer-panel.component.ts +++ b/src/app/common/pdf-viewer-panel/pdf-viewer-panel.component.ts @@ -1,10 +1,11 @@ -import {Component, Inject, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, Input} from '@angular/core'; import {FileDownloaderService} from '../file-downloader/file-downloader.service'; @Component({ selector: 'pdf-viewer-panel', templateUrl: './pdf-viewer-panel.component.html', styleUrls: ['./pdf-viewer-panel.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PdfViewerPanelComponent { diff --git a/src/app/common/pdf-viewer/pdf-viewer.component.ts b/src/app/common/pdf-viewer/pdf-viewer.component.ts index a6b1ca914c..a8a2de519f 100644 --- a/src/app/common/pdf-viewer/pdf-viewer.component.ts +++ b/src/app/common/pdf-viewer/pdf-viewer.component.ts @@ -2,6 +2,7 @@ import {PDFDocumentProxy, PdfViewerComponent} from 'ng2-pdf-viewer'; import {HttpResponse} from '@angular/common/http'; import { AfterViewInit, + ChangeDetectionStrategy, Component, Inject, Input, @@ -17,6 +18,7 @@ import {AlertService} from '../services/alert.service'; selector: 'f-pdf-viewer', templateUrl: './pdf-viewer.component.html', styleUrls: ['./pdf-viewer.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class fPdfViewerComponent implements OnDestroy, OnChanges, AfterViewInit { diff --git a/src/app/common/project-progress-bar/project-progress-bar.component.ts b/src/app/common/project-progress-bar/project-progress-bar.component.ts index 9a1db3bd5c..d1935aa561 100644 --- a/src/app/common/project-progress-bar/project-progress-bar.component.ts +++ b/src/app/common/project-progress-bar/project-progress-bar.component.ts @@ -1,9 +1,10 @@ -import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges} from '@angular/core'; @Component({ selector: 'f-project-progress-bar', templateUrl: './project-progress-bar.component.html', styleUrls: ['./project-progress-bar.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ProjectProgressBarComponent implements OnChanges { diff --git a/src/app/common/project-progress/project-progress-gauge.component.ts b/src/app/common/project-progress/project-progress-gauge.component.ts index 8ed44e122c..75a4249481 100644 --- a/src/app/common/project-progress/project-progress-gauge.component.ts +++ b/src/app/common/project-progress/project-progress-gauge.component.ts @@ -1,11 +1,19 @@ import {TooltipService} from '@swimlane/ngx-charts'; -import {Component, Injector, Input, OnInit, ViewContainerRef} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Injector, + Input, + OnInit, + ViewContainerRef, +} from '@angular/core'; import {Project} from 'src/app/api/models/project'; @Component({ selector: 'f-project-progress-gauge', templateUrl: './project-progress-gauge.component.html', styleUrl: './project-progress-gauge.component.css', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ProjectProgressGaugeComponent implements OnInit { diff --git a/src/app/common/scorm-player/scorm-player.component.ts b/src/app/common/scorm-player/scorm-player.component.ts index c4897d905a..7c33c459e9 100644 --- a/src/app/common/scorm-player/scorm-player.component.ts +++ b/src/app/common/scorm-player/scorm-player.component.ts @@ -1,4 +1,4 @@ -import {Component, HostListener, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, HostListener, Input, OnInit} from '@angular/core'; import {DomSanitizer, SafeResourceUrl} from '@angular/platform-browser'; import {ActivatedRoute} from '@angular/router'; import { @@ -30,6 +30,7 @@ declare global { selector: 'f-scorm-player', templateUrl: './scorm-player.component.html', styleUrls: ['./scorm-player.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ScormPlayerComponent implements OnInit { diff --git a/src/app/common/services/alert.service.ts b/src/app/common/services/alert.service.ts index 4b26a8ae23..bf27c6f386 100644 --- a/src/app/common/services/alert.service.ts +++ b/src/app/common/services/alert.service.ts @@ -1,4 +1,4 @@ -import {Component, Inject, Injectable, inject} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, Injectable, inject} from '@angular/core'; import {MAT_SNACK_BAR_DATA, MatSnackBar, MatSnackBarRef} from '@angular/material/snack-bar'; import {ConfettiService} from './confetti.service'; @@ -49,6 +49,7 @@ export class AlertService { @Component({ selector: 'f-alert', templateUrl: './alert.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class AlertComponent { diff --git a/src/app/common/status-icon/status-icon.component.ts b/src/app/common/status-icon/status-icon.component.ts index 56e2cf060a..7a9667694a 100644 --- a/src/app/common/status-icon/status-icon.component.ts +++ b/src/app/common/status-icon/status-icon.component.ts @@ -1,10 +1,11 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {TaskStatus, TaskStatusEnum} from 'src/app/api/models/task-status'; @Component({ selector: 'status-icon', templateUrl: './status-icon.component.html', styleUrls: ['./status-icon.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class StatusIconComponent implements OnInit { diff --git a/src/app/common/submission-files-download/submission-files-download.component.ts b/src/app/common/submission-files-download/submission-files-download.component.ts index 386000446b..5d0e75f629 100644 --- a/src/app/common/submission-files-download/submission-files-download.component.ts +++ b/src/app/common/submission-files-download/submission-files-download.component.ts @@ -1,5 +1,5 @@ import {HttpResponse} from '@angular/common/http'; -import {Component, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, OnInit} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {FileDownloaderService} from '../file-downloader/file-downloader.service'; @@ -9,6 +9,7 @@ type DownloadState = 'downloading' | 'downloaded' | 'failed'; @Component({ selector: 'f-submission-files-download', templateUrl: './submission-files-download.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class SubmissionFilesDownloadComponent implements OnInit { diff --git a/src/app/common/success-close/success-close.component.ts b/src/app/common/success-close/success-close.component.ts index b635087ff9..558e7b7ecc 100644 --- a/src/app/common/success-close/success-close.component.ts +++ b/src/app/common/success-close/success-close.component.ts @@ -1,9 +1,10 @@ -import {Component, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, OnInit} from '@angular/core'; @Component({ selector: 'f-success-close', templateUrl: 'success-close.component.html', styleUrls: ['success-close.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class SuccessCloseComponent implements OnInit { diff --git a/src/app/common/task-badge/task-badge.component.ts b/src/app/common/task-badge/task-badge.component.ts index 6fd3950704..9868e4fb80 100644 --- a/src/app/common/task-badge/task-badge.component.ts +++ b/src/app/common/task-badge/task-badge.component.ts @@ -1,10 +1,11 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {TaskDefinition} from 'src/app/api/models/task-definition'; @Component({ selector: 'f-task-badge', templateUrl: './task-badge.component.html', styleUrl: './task-badge.component.css', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class FTaskBadgeComponent { diff --git a/src/app/common/unit-code/unit-code.component.ts b/src/app/common/unit-code/unit-code.component.ts index fb28c4eba0..a01278f7dc 100644 --- a/src/app/common/unit-code/unit-code.component.ts +++ b/src/app/common/unit-code/unit-code.component.ts @@ -1,5 +1,5 @@ import {animate, state, style, transition, trigger} from '@angular/animations'; -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit} from '@angular/core'; import {Subscription} from 'rxjs'; import {UnitCodeService} from './unit-code.service'; @@ -20,6 +20,7 @@ import {UnitCodeService} from './unit-code.service'; ]), ]), ], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitCodeComponent implements OnInit, OnDestroy { diff --git a/src/app/common/user-badge/user-badge.component.html b/src/app/common/user-badge/user-badge.component.html index 4baab5ced6..8b407dcf87 100644 --- a/src/app/common/user-badge/user-badge.component.html +++ b/src/app/common/user-badge/user-badge.component.html @@ -8,7 +8,7 @@ size="40" style="margin-right: 8px" [unselected]="unselected" - [user]="selectedTask?.project.student" + [user]="$safeNavigationMigration(selectedTask?.project.student)" >
      diff --git a/src/app/common/user-badge/user-badge.component.ts b/src/app/common/user-badge/user-badge.component.ts index cd57a75e36..52f1a7b93d 100644 --- a/src/app/common/user-badge/user-badge.component.ts +++ b/src/app/common/user-badge/user-badge.component.ts @@ -1,10 +1,11 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Task} from 'src/app/api/models/doubtfire-model'; @Component({ selector: 'f-user-badge', templateUrl: './user-badge.component.html', styleUrls: ['./user-badge.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UserBadgeComponent { diff --git a/src/app/common/user-icon/user-icon.component.ts b/src/app/common/user-icon/user-icon.component.ts index 7073ba6999..dd2f25058a 100644 --- a/src/app/common/user-icon/user-icon.component.ts +++ b/src/app/common/user-icon/user-icon.component.ts @@ -1,6 +1,7 @@ import {Md5} from 'ts-md5/dist/md5'; import { AfterViewInit, + ChangeDetectionStrategy, Component, ElementRef, Input, @@ -42,6 +43,7 @@ declare const d3: { selector: 'user-icon', templateUrl: './user-icon.component.html', styleUrls: ['./user-icon.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UserIconComponent implements AfterViewInit, OnChanges { diff --git a/src/app/config/privacy-policy/privacy-policy.spec.ts b/src/app/config/privacy-policy/privacy-policy.spec.ts index 4371a4c972..634447dd0a 100644 --- a/src/app/config/privacy-policy/privacy-policy.spec.ts +++ b/src/app/config/privacy-policy/privacy-policy.spec.ts @@ -1,5 +1,5 @@ import {afterEach, beforeEach, describe, expect, it} from 'vitest'; -import {provideHttpClient} from '@angular/common/http'; +import {provideHttpClient, withXhr} from '@angular/common/http'; import {HttpTestingController, provideHttpClientTesting} from '@angular/common/http/testing'; import {TestBed} from '@angular/core/testing'; import {PrivacyPolicy} from './privacy-policy'; @@ -10,7 +10,7 @@ describe('PrivacyPolicy', () => { beforeEach(() => { TestBed.configureTestingModule({ - providers: [provideHttpClient(), provideHttpClientTesting()], + providers: [provideHttpClient(withXhr()), provideHttpClientTesting()], }); service = TestBed.inject(PrivacyPolicy); httpMock = TestBed.inject(HttpTestingController); diff --git a/src/app/errors/states/timeout/timeout.component.ts b/src/app/errors/states/timeout/timeout.component.ts index 94730d3043..b9b4094231 100644 --- a/src/app/errors/states/timeout/timeout.component.ts +++ b/src/app/errors/states/timeout/timeout.component.ts @@ -1,9 +1,10 @@ -import {Component, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, OnDestroy, OnInit} from '@angular/core'; import {AuthenticationService} from '../../../api/services/authentication.service'; @Component({ selector: 'f-timeout', templateUrl: 'timeout.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TimeoutComponent implements OnInit, OnDestroy { diff --git a/src/app/errors/states/unauthorised/unauthorised.component.ts b/src/app/errors/states/unauthorised/unauthorised.component.ts index 289a4ad067..da3f9dddb8 100644 --- a/src/app/errors/states/unauthorised/unauthorised.component.ts +++ b/src/app/errors/states/unauthorised/unauthorised.component.ts @@ -1,10 +1,11 @@ import {Location} from '@angular/common'; -import {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; @Component({ selector: 'unauthorised', templateUrl: 'unauthorised.component.html', styleUrls: ['unauthorised.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnauthorisedComponent { diff --git a/src/app/errors/unavailable-card/unavailable-card.component.ts b/src/app/errors/unavailable-card/unavailable-card.component.ts index 51709816b8..f949856e31 100644 --- a/src/app/errors/unavailable-card/unavailable-card.component.ts +++ b/src/app/errors/unavailable-card/unavailable-card.component.ts @@ -1,9 +1,10 @@ -import {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; @Component({ selector: 'f-unavailable-card', templateUrl: './unavailable-card.component.html', styleUrls: ['./unavailable-card.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnavailableCardComponent {} diff --git a/src/app/eula/accept-eula/accept-eula.component.ts b/src/app/eula/accept-eula/accept-eula.component.ts index 17d24aeec5..a8c0ede0e0 100644 --- a/src/app/eula/accept-eula/accept-eula.component.ts +++ b/src/app/eula/accept-eula/accept-eula.component.ts @@ -1,4 +1,4 @@ -import {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {Router} from '@angular/router'; import {Observable, ReplaySubject, take} from 'rxjs'; import {UserService} from 'src/app/api/models/doubtfire-model'; @@ -10,6 +10,7 @@ import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; selector: 'f-accept-eula', templateUrl: './accept-eula.component.html', styleUrls: ['./accept-eula.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class AcceptEulaComponent { diff --git a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.ts b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.ts index f96cfc1266..6f75ea24ea 100644 --- a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.ts +++ b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.component.ts @@ -1,4 +1,5 @@ import { + ChangeDetectionStrategy, Component, EventEmitter, Input, @@ -18,6 +19,7 @@ import {Task} from 'src/app/api/models/task'; selector: 'f-group-member-contribution-assigner', templateUrl: './group-member-contribution-assigner.component.html', styleUrls: ['./group-member-contribution-assigner.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class GroupMemberContributionAssignerComponent implements OnInit, OnChanges { diff --git a/src/app/groups/group-member-list/group-member-list.component.ts b/src/app/groups/group-member-list/group-member-list.component.ts index 6d752d67d8..162c552139 100644 --- a/src/app/groups/group-member-list/group-member-list.component.ts +++ b/src/app/groups/group-member-list/group-member-list.component.ts @@ -1,4 +1,11 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + OnInit, + SimpleChanges, +} from '@angular/core'; import {MatTableDataSource} from '@angular/material/table'; import {Subscription} from 'rxjs'; import {Group, UnitRole} from 'src/app/api/models/doubtfire-model'; @@ -10,6 +17,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-group-member-list', templateUrl: './group-member-list.component.html', styleUrls: ['./group-member-list.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class GroupMemberListComponent implements OnInit, OnChanges { diff --git a/src/app/groups/group-selector/group-selector.component.ts b/src/app/groups/group-selector/group-selector.component.ts index 4dd8ed7de3..0a9b475738 100644 --- a/src/app/groups/group-selector/group-selector.component.ts +++ b/src/app/groups/group-selector/group-selector.component.ts @@ -1,5 +1,6 @@ import { AfterViewInit, + ChangeDetectionStrategy, Component, Input, OnChanges, @@ -23,6 +24,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-group-selector', templateUrl: './group-selector.component.html', styleUrls: ['./group-selector.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class GroupSelectorComponent diff --git a/src/app/groups/group-set-manager/group-set-manager.component.ts b/src/app/groups/group-set-manager/group-set-manager.component.ts index 6a214c6ee8..5d986592e6 100644 --- a/src/app/groups/group-set-manager/group-set-manager.component.ts +++ b/src/app/groups/group-set-manager/group-set-manager.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {FormControl} from '@angular/forms'; import {Observable, map, startWith} from 'rxjs'; import {Group, GroupSet, Project, Unit, UnitRole} from 'src/app/api/models/doubtfire-model'; @@ -9,6 +9,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-group-set-manager', templateUrl: './group-set-manager.component.html', styleUrls: ['./group-set-manager.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class GroupSetManagerComponent implements OnInit { diff --git a/src/app/groups/group-set-selector/group-set-selector.component.ts b/src/app/groups/group-set-selector/group-set-selector.component.ts index 10430346cd..b6b7103d67 100644 --- a/src/app/groups/group-set-selector/group-set-selector.component.ts +++ b/src/app/groups/group-set-selector/group-set-selector.component.ts @@ -1,10 +1,18 @@ -import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + OnInit, + Output, +} from '@angular/core'; import {GroupSet, Unit} from 'src/app/api/models/doubtfire-model'; @Component({ selector: 'group-set-selector', templateUrl: './group-set-selector.component.html', styleUrls: ['./group-set-selector.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class GroupSetSelectorComponent implements OnInit { diff --git a/src/app/home/splash-screen/splash-screen.component.ts b/src/app/home/splash-screen/splash-screen.component.ts index 18b1ca48b8..f53ae1d1ad 100644 --- a/src/app/home/splash-screen/splash-screen.component.ts +++ b/src/app/home/splash-screen/splash-screen.component.ts @@ -1,5 +1,5 @@ import {AnimationOptions} from 'ngx-lottie'; -import {Component, ContentChild, OnInit, TemplateRef} from '@angular/core'; +import {ChangeDetectionStrategy, Component, ContentChild, OnInit, TemplateRef} from '@angular/core'; import {Observable} from 'rxjs'; import {GlobalStateService} from 'src/app/projects/states/index/global-state.service'; import {LoadingService} from './LoadingService.service'; @@ -8,6 +8,7 @@ import {LoadingService} from './LoadingService.service'; selector: 'splash-screen', templateUrl: './splash-screen.component.html', styleUrls: ['./splash-screen.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class SplashScreenComponent implements OnInit { diff --git a/src/app/home/states/home/home.component.html b/src/app/home/states/home/home.component.html index cdeeb9af4e..2ae5a92d86 100644 --- a/src/app/home/states/home/home.component.html +++ b/src/app/home/states/home/home.component.html @@ -19,7 +19,15 @@

      Units you teach

      @for (unitRole of unitRoles | isActiveUnitRole; track unitRole) {
      @if (!unitRole.unit.teachingPeriod || unitRole.unit.teachingPeriod?.active) { -
      +
      {{ unitRole.unit?.name }} @@ -55,7 +63,7 @@

      Units you teach

      You do not teach any active units

      diff --git a/src/app/home/states/home/home.component.ts b/src/app/home/states/home/home.component.ts index fe4f807fc9..a384d1ff64 100644 --- a/src/app/home/states/home/home.component.ts +++ b/src/app/home/states/home/home.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnDestroy, OnInit} from '@angular/core'; import {Router} from '@angular/router'; import {Subscription} from 'rxjs'; import {Project, UnitRole, User, UserService} from 'src/app/api/models/doubtfire-model'; @@ -10,6 +10,7 @@ import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global selector: 'home', templateUrl: 'home.component.html', styleUrls: ['home.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class HomeComponent implements OnInit, OnDestroy { diff --git a/src/app/home/states/lti-dashboard/lti-dashboard.component.ts b/src/app/home/states/lti-dashboard/lti-dashboard.component.ts index 8b821f3612..dd775f824d 100644 --- a/src/app/home/states/lti-dashboard/lti-dashboard.component.ts +++ b/src/app/home/states/lti-dashboard/lti-dashboard.component.ts @@ -1,4 +1,4 @@ -import {AfterViewInit, Component, Input} from '@angular/core'; +import {AfterViewInit, ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {ProjectService, User} from 'src/app/api/models/doubtfire-model'; import {Unit} from 'src/app/api/models/unit'; @@ -15,6 +15,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-lti-dashboard', templateUrl: 'lti-dashboard.component.html', styleUrls: ['lti-dashboard.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class LtiDashboardComponent implements AfterViewInit { diff --git a/src/app/home/states/lti-unit-link/lti-unit-link.component.ts b/src/app/home/states/lti-unit-link/lti-unit-link.component.ts index 9319ce2067..74f4c8bbb3 100644 --- a/src/app/home/states/lti-unit-link/lti-unit-link.component.ts +++ b/src/app/home/states/lti-unit-link/lti-unit-link.component.ts @@ -1,4 +1,4 @@ -import {AfterViewInit, Component, Input} from '@angular/core'; +import {AfterViewInit, ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {CreateNewUnitModal} from 'src/app/admin/modals/create-new-unit-modal/create-new-unit-modal.component'; import {Unit} from 'src/app/api/models/unit'; @@ -13,6 +13,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-lti-unit-link', templateUrl: 'lti-unit-link.component.html', styleUrls: ['lti-unit-link.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class LtiUnitLinkComponent implements AfterViewInit { diff --git a/src/app/legacy-route-placeholder.component.ts b/src/app/legacy-route-placeholder.component.ts index a08dfc603c..dc364e55dc 100644 --- a/src/app/legacy-route-placeholder.component.ts +++ b/src/app/legacy-route-placeholder.component.ts @@ -1,9 +1,10 @@ -import {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; @Component({ selector: 'legacy-route-placeholder', templateUrl: './legacy-route-placeholder.component.html', styleUrl: './legacy-route-placeholder.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class LegacyRoutePlaceholderComponent {} diff --git a/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.ts b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.ts index bc26d55292..c08e4f6934 100644 --- a/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.ts +++ b/src/app/projects/project-progress-dashboard/project-progress-dashboard.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, type OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, type OnInit} from '@angular/core'; import {Observable} from 'rxjs'; import {Project} from 'src/app/api/models/project'; import {ProjectService} from 'src/app/api/services/project.service'; @@ -9,6 +9,7 @@ import {GradeService} from 'src/app/common/services/grade.service'; selector: 'f-project-progress-dashboard', templateUrl: './project-progress-dashboard.component.html', styleUrl: './project-progress-dashboard.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ProjectProgressDashboardComponent implements OnInit { diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.ts b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.ts index f3e3019c7a..3ceeff6ff8 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.ts +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/add-engagement-dialog/add-engagement-dialog.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject} from '@angular/core'; import {FormControl, FormGroup, Validators} from '@angular/forms'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {Engagement, EngagementService, Project} from 'src/app/api/models/doubtfire-model'; @@ -19,6 +19,7 @@ interface AddEngagementForm { selector: 'f-add-engagement-dialog', templateUrl: './add-engagement-dialog.component.html', styleUrl: './add-engagement-dialog.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class AddEngagementDialogComponent { diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.ts b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.ts index d86b756544..e64a8007d5 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.ts +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-detail-dialog/engagement-detail-dialog.component.ts @@ -1,4 +1,12 @@ -import {Component, ElementRef, Inject, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + ElementRef, + Inject, + OnDestroy, + OnInit, + ViewChild, +} from '@angular/core'; import {MAT_DIALOG_DATA} from '@angular/material/dialog'; import { Engagement, @@ -14,6 +22,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-engagement-detail-dialog', templateUrl: './engagement-detail-dialog.component.html', styleUrl: './engagement-detail-dialog.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class EngagementDetailDialogComponent implements OnInit, OnDestroy { diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.ts b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.ts index 8ef0cc2706..560e609555 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.ts +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/engagement-passport-card/engagement-passport-card.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnChanges} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnChanges} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; import { Engagement, @@ -36,6 +36,7 @@ interface EngagementLegendItem extends EngagementPresentation { selector: 'f-engagement-passport-card', templateUrl: './engagement-passport-card.component.html', styleUrl: './engagement-passport-card.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class EngagementPassportCardComponent implements OnChanges { diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.ts b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.ts index 621544ee18..f840db6819 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.ts +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/progress-dashboard.component.ts @@ -1,4 +1,11 @@ -import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + OnInit, + Output, +} from '@angular/core'; import {Project} from 'src/app/api/models/project'; import {ProjectService} from 'src/app/api/services/project.service'; import {UserService} from 'src/app/api/services/user.service'; @@ -9,6 +16,7 @@ import {GradeService} from 'src/app/common/services/grade.service'; selector: 'f-progress-dashboard', templateUrl: './progress-dashboard.component.html', styleUrls: ['./progress-dashboard.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ProgressDashboardComponent implements OnInit { diff --git a/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts index 8f10cc0c38..c3d77da113 100644 --- a/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts +++ b/src/app/projects/states/dashboard/directives/progress-dashboard/task-planner-card/task-planner-card.component.ts @@ -1,10 +1,11 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Project} from 'src/app/api/models/project'; @Component({ selector: 'f-task-planner-card', templateUrl: './task-planner-card.component.html', styleUrl: './task-planner-card.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskPlannerCardComponent { diff --git a/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.ts b/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.ts index 47792337ab..3c8b138d06 100644 --- a/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.ts +++ b/src/app/projects/states/dashboard/directives/student-task-list/create-portfolio-task-list-item/create-portfolio-task-list-item.component.ts @@ -1,10 +1,11 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Project, Task} from 'src/app/api/models/doubtfire-model'; @Component({ selector: 'create-portfolio-task-list-item', templateUrl: 'create-portfolio-task-list-item.component.html', styleUrls: ['create-portfolio-task-list-item.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class CreatePortfolioTaskListItemComponent { diff --git a/src/app/projects/states/dashboard/directives/student-task-list/task-list-item/task-list-item.component.ts b/src/app/projects/states/dashboard/directives/student-task-list/task-list-item/task-list-item.component.ts index a8612c44ba..2f2351cc40 100644 --- a/src/app/projects/states/dashboard/directives/student-task-list/task-list-item/task-list-item.component.ts +++ b/src/app/projects/states/dashboard/directives/student-task-list/task-list-item/task-list-item.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {Task} from 'src/app/api/models/doubtfire-model'; import {GradeService} from 'src/app/common/services/grade.service'; @@ -6,6 +6,7 @@ import {GradeService} from 'src/app/common/services/grade.service'; selector: 'task-list-item', templateUrl: 'task-list-item.component.html', styleUrls: ['task-list-item.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskListItemComponent implements OnInit { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts index 43ae248427..864f64226f 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/discussion-prompts-view/discussion-prompts-view.component.ts @@ -1,9 +1,10 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; @Component({ selector: 'f-discussion-prompts-view', templateUrl: './discussion-prompts-view.component.html', styleUrls: ['./discussion-prompts-view.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class DiscussionPromptsViewComponent { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.ts index 7f7d38039d..e61a9d1a43 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/staff-notes-view/staff-notes-view.component.ts @@ -1,9 +1,10 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; @Component({ selector: 'f-staff-notes-view', templateUrl: './staff-notes-view.component.html', styleUrls: ['./staff-notes-view.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class StaffNotesViewComponent { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.ts index 8047e45479..0b04db98a9 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-assessment-card/task-assessment-card.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Task} from 'src/app/api/models/task'; import {TaskService} from 'src/app/api/services/task.service'; import {GradeService} from 'src/app/common/services/grade.service'; @@ -7,6 +7,7 @@ import {GradeService} from 'src/app/common/services/grade.service'; selector: 'f-task-assessment-card', templateUrl: './task-assessment-card.component.html', styleUrls: ['./task-assessment-card.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskAssessmentCardComponent { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html index 4269449855..b13dee8ab3 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.html @@ -6,7 +6,10 @@
      -
      +
      @if (task) { } diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.ts index bb41a679a3..eaf85a0273 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-description-card/task-description-card.component.ts @@ -1,4 +1,11 @@ -import {Component, EventEmitter, Inject, Input, Output} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Inject, + Input, + Output, +} from '@angular/core'; import {Task, TaskDefinition, Unit} from 'src/app/api/models/doubtfire-model'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; import {GradeService} from 'src/app/common/services/grade.service'; @@ -7,6 +14,7 @@ import {GradeService} from 'src/app/common/services/grade.service'; selector: 'f-task-description-card', templateUrl: 'task-description-card.component.html', styleUrls: ['task-description-card.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDescriptionCardComponent { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html index 1bd23719a9..0e308f0ffa 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.html @@ -15,13 +15,13 @@ @if (flexibleDatesEnabled) { -

      +

      Your target due date for this task is {{ task?.localDueDateString() }}. You should aim to complete this task before then to keep your progress on track.

      } @else { -

      +

      This task's due date is {{ task?.localDueDateString() }}. You should aim to complete this task before then to keep your progress on track.

      @@ -68,7 +68,10 @@ - + @if (flexibleDatesEnabled) {

      @@ -125,7 +128,10 @@ > - +

      @if (task?.definition?.unit.markLateSubmissionsAsAssessInPortfolio) { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.ts index 1e100f72b8..4cba264c1b 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-due-card/task-due-card.component.ts @@ -1,10 +1,11 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Task} from 'src/app/api/models/task'; @Component({ selector: 'f-task-due-card', templateUrl: './task-due-card.component.html', styleUrls: ['./task-due-card.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDueCardComponent { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-ilos-card/task-ilos-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-ilos-card/task-ilos-card.component.ts index 5033a187b2..033e5d5b6a 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-ilos-card/task-ilos-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-ilos-card/task-ilos-card.component.ts @@ -1,4 +1,11 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + OnInit, + SimpleChanges, +} from '@angular/core'; import {LearningOutcome} from 'src/app/api/models/learning-outcome'; import {Project} from 'src/app/api/models/project'; import {TaskDefinition} from 'src/app/api/models/task-definition'; @@ -8,6 +15,7 @@ import {Unit} from 'src/app/api/models/unit'; selector: 'f-task-ilos-card', templateUrl: './task-ilos-card.component.html', styleUrls: ['./task-ilos-card.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskIlosCardComponent implements OnInit, OnChanges { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html index a5cf691e16..92a1481c32 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.html @@ -56,7 +56,7 @@

      [ngTemplateOutletContext]="{ number: data.comparedWithNumber, isMostRecent: data.comparedWithIsMostRecent, - timestamp: data.comparedWith?.timestamp, + timestamp: $safeNavigationMigration(data.comparedWith?.timestamp), }" > @if (primaryArchiveParsed) { @@ -193,8 +193,8 @@

      } @else { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts index 47d19f2a7e..5a1cce8f98 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/submission-files-modal/submission-files-modal.component.ts @@ -1,6 +1,6 @@ import * as monaco from 'monaco-editor'; import {HttpResponse} from '@angular/common/http'; -import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnDestroy, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {SubmissionArchive} from 'src/app/api/models/submission-history'; import { @@ -25,6 +25,7 @@ export interface SubmissionFilesModalData { selector: 'f-submission-files-modal', templateUrl: './submission-files-modal.component.html', styleUrls: ['./submission-files-modal.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class SubmissionFilesModalComponent implements OnInit, OnDestroy { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts index d9868ab3ef..8906c1de07 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-overseer-report/task-overseer-report.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; import {MatMenuTrigger} from '@angular/material/menu'; import {forkJoin} from 'rxjs'; @@ -15,6 +15,7 @@ import {SubmissionFilesModalComponent} from './submission-files-modal/submission selector: 'f-task-overseer-report', templateUrl: './task-overseer-report.component.html', styleUrl: './task-overseer-report.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskOverseerReportComponent implements OnInit { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.ts index 490847af90..659232c1c8 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-prerequisites-card/task-prerequisites-card.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Task} from 'src/app/api/models/task'; import {TaskDefinition} from 'src/app/api/models/task-definition'; @@ -6,6 +6,7 @@ import {TaskDefinition} from 'src/app/api/models/task-definition'; selector: 'f-task-prerequisites-card', templateUrl: './task-prerequisites-card.component.html', styleUrls: ['./task-prerequisites-card.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskPrerequisitesCardComponent { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts index bbf0af2fb4..9839c23679 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-scorm-card/task-scorm-card.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges} from '@angular/core'; import {Task, User, UserService} from 'src/app/api/models/doubtfire-model'; import {ScormExtensionModalService} from 'src/app/common/modals/scorm-extension-modal/scorm-extension-modal.service'; @@ -6,6 +6,7 @@ import {ScormExtensionModalService} from 'src/app/common/modals/scorm-extension- selector: 'f-task-scorm-card', templateUrl: './task-scorm-card.component.html', styleUrls: ['./task-scorm-card.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskScormCardComponent implements OnChanges { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html index 4893c99cb4..c96b1d69bc 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-similarity-view/task-similarity-view.component.html @@ -17,7 +17,10 @@

      Similarities

      @if (!jplagOpenState) { - @for (similarity of task?.similarityCache.values | async; track similarity) { + @for ( + similarity of $safeNavigationMigration(task?.similarityCache.values) | async; + track similarity + ) {
      @for (part of similarity.parts; track part; let i = $index) { - +

      {{ task?.statusLabel() }}

      @@ -26,7 +29,10 @@
      {{ trigger.label }}
      @if (triggers?.length < 0) { - +
      {{ task?.statusLabel() }}
      diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts index 75e00023fb..a66b5f81fe 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-status-card/task-status-card.component.ts @@ -1,5 +1,13 @@ import * as _ from 'lodash'; -import {AfterViewInit, Component, Input, OnChanges, OnDestroy, SimpleChanges} from '@angular/core'; +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + OnDestroy, + SimpleChanges, +} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {Subscription} from 'rxjs'; import {Project} from 'src/app/api/models/project'; @@ -18,6 +26,7 @@ import {SubmissionTypeModalService} from 'src/app/tasks/modals/submission-type-m selector: 'f-task-status-card', templateUrl: './task-status-card.component.html', styleUrls: ['./task-status-card.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskStatusCardComponent implements OnChanges, AfterViewInit, OnDestroy { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.ts index 1b9c53bd75..1af683d9ad 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/task-submission-card/task-submission-card.component.ts @@ -1,4 +1,11 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + OnInit, + SimpleChanges, +} from '@angular/core'; import {Task} from 'src/app/api/models/task'; import {TaskService} from 'src/app/api/services/task.service'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; @@ -8,6 +15,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-task-submission-card', templateUrl: './task-submission-card.component.html', styleUrls: ['./task-submission-card.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskSubmissionCardComponent implements OnChanges, OnInit { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.ts index 3e58ce563c..6b44ee689b 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/directives/tutor-notes-view/tutor-notes-view.component.ts @@ -1,10 +1,11 @@ -import {Component, Input, OnChanges, SimpleChanges} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnChanges, SimpleChanges} from '@angular/core'; import {UnitRole} from 'src/app/api/models/unit-role'; @Component({ selector: 'f-tutor-notes-view', templateUrl: './tutor-notes-view.component.html', styleUrls: ['./tutor-notes-view.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TutorNotesViewComponent implements OnChanges { diff --git a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.ts b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.ts index 7aecf1173d..cc98b75399 100644 --- a/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.ts +++ b/src/app/projects/states/dashboard/directives/task-dashboard/task-dashboard.component.ts @@ -1,4 +1,11 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + OnInit, + SimpleChanges, +} from '@angular/core'; import {MatTabChangeEvent} from '@angular/material/tabs'; import {ActivatedRoute} from '@angular/router'; import {UnitRole} from 'src/app/api/models/doubtfire-model'; @@ -13,6 +20,7 @@ import {DashboardViews} from '../../selected-task.service'; selector: 'f-task-dashboard', templateUrl: './task-dashboard.component.html', styleUrls: ['./task-dashboard.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDashboardComponent implements OnInit, OnChanges { diff --git a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.ts b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.ts index 189b177e34..fc38e38e41 100644 --- a/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.ts +++ b/src/app/projects/states/dashboard/project-dashboard/project-dashboard.component.ts @@ -1,6 +1,6 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ import {CdkDragEnd, CdkDragMove, CdkDragStart} from '@angular/cdk/drag-drop'; -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import { BehaviorSubject, @@ -23,6 +23,7 @@ import {GlobalStateService, ViewType} from '../../index/global-state.service'; selector: 'f-project-dashboard', templateUrl: './project-dashboard.component.html', styleUrl: './project-dashboard.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ProjectDashboardComponent implements OnInit { diff --git a/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts b/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts index be33473189..cc81e95a94 100644 --- a/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts +++ b/src/app/projects/states/discussion-prompts/discussion-prompts.component.ts @@ -1,4 +1,11 @@ -import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + ElementRef, + Input, + OnInit, + ViewChild, +} from '@angular/core'; import {DiscussionPrompt} from 'src/app/api/models/discussion-prompt'; import {Project, TaskDefinition, UserService} from 'src/app/api/models/doubtfire-model'; import {StaffNote} from 'src/app/api/models/staff-note'; @@ -10,6 +17,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-discussion-prompts', templateUrl: './discussion-prompts.component.html', styleUrl: './discussion-prompts.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class DiscussionPromptsComponent implements OnInit { diff --git a/src/app/projects/states/groups/project-groups-state.component.ts b/src/app/projects/states/groups/project-groups-state.component.ts index afe151bbf1..5d46a7c7c4 100644 --- a/src/app/projects/states/groups/project-groups-state.component.ts +++ b/src/app/projects/states/groups/project-groups-state.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {Observable, Subscription, of} from 'rxjs'; import {GroupSet, Project} from 'src/app/api/models/doubtfire-model'; @@ -8,6 +8,7 @@ import {GlobalStateService} from '../index/global-state.service'; selector: 'f-project-groups-state', templateUrl: './project-groups-state.component.html', styleUrls: ['./project-groups-state.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ProjectGroupsStateComponent implements OnInit, OnDestroy { diff --git a/src/app/projects/states/groups/project-groups/project-groups.component.ts b/src/app/projects/states/groups/project-groups/project-groups.component.ts index 21f88722ec..6e64ae5f43 100644 --- a/src/app/projects/states/groups/project-groups/project-groups.component.ts +++ b/src/app/projects/states/groups/project-groups/project-groups.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {GroupSet, Project} from 'src/app/api/models/doubtfire-model'; import {Unit} from 'src/app/api/models/unit'; @@ -7,6 +7,7 @@ import {Unit} from 'src/app/api/models/unit'; selector: 'f-project-groups', templateUrl: './project-groups.component.html', styleUrl: './project-groups.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ProjectGroupsComponent { diff --git a/src/app/projects/states/jplag/jplag-report-viewer.component.ts b/src/app/projects/states/jplag/jplag-report-viewer.component.ts index 28da488d6b..09f9bff4db 100644 --- a/src/app/projects/states/jplag/jplag-report-viewer.component.ts +++ b/src/app/projects/states/jplag/jplag-report-viewer.component.ts @@ -1,9 +1,10 @@ -import {Component, ElementRef, Input, ViewChild} from '@angular/core'; +import {ChangeDetectionStrategy, Component, ElementRef, Input, ViewChild} from '@angular/core'; import {AlertService} from 'src/app/common/services/alert.service'; @Component({ selector: 'f-jplag-report-viewer', templateUrl: './jplag-report-viewer.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class JplagReportViewerComponent { diff --git a/src/app/projects/states/plan/project-plan.component.ts b/src/app/projects/states/plan/project-plan.component.ts index 8a2a591ea9..42ae46547f 100644 --- a/src/app/projects/states/plan/project-plan.component.ts +++ b/src/app/projects/states/plan/project-plan.component.ts @@ -1,4 +1,11 @@ -import {Component, Input, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnDestroy, + OnInit, + ViewChild, +} from '@angular/core'; import {MatSelectChange} from '@angular/material/select'; import {ActivatedRoute} from '@angular/router'; import {Observable, Subscription, of} from 'rxjs'; @@ -12,6 +19,7 @@ import {TaskPlannerComponent} from './task-planner/task-planner.component'; selector: 'f-project-plan', templateUrl: 'project-plan.component.html', styleUrls: ['project-plan.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ProjectPlanComponent implements OnInit, OnDestroy { diff --git a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts index 0a6cf37de1..7af70513b0 100644 --- a/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts +++ b/src/app/projects/states/plan/task-planner/task-planner-prerequisites-modal/task-planner-prerequisites-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, Input, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA} from '@angular/material/dialog'; import {MatTableDataSource} from '@angular/material/table'; import {Project} from 'src/app/api/models/project'; @@ -15,6 +15,7 @@ export interface TaskPlannerPrerequisitesModalData { selector: 'f-task-planner-prerequisites-modal', templateUrl: './task-planner-prerequisites-modal.component.html', styleUrl: './task-planner-prerequisites-modal.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskPlannerPrerequisitesModalComponent implements OnInit { diff --git a/src/app/projects/states/plan/task-planner/task-planner.component.ts b/src/app/projects/states/plan/task-planner/task-planner.component.ts index fa36cd35c6..fc78bb6dcb 100644 --- a/src/app/projects/states/plan/task-planner/task-planner.component.ts +++ b/src/app/projects/states/plan/task-planner/task-planner.component.ts @@ -11,6 +11,7 @@ import { } from '@worktile/gantt'; import { AfterViewInit, + ChangeDetectionStrategy, Component, ElementRef, Input, @@ -43,6 +44,7 @@ interface TaskGanttItem extends GanttItem { templateUrl: './task-planner.component.html', styleUrl: './task-planner.component.scss', providers: [GanttPrintService], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskPlannerComponent implements OnInit, AfterViewInit, OnDestroy { diff --git a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts index efc4bd9432..2d2316b633 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts +++ b/src/app/projects/states/portfolio/directives/portfolio-add-extra-files-step/portfolio-add-extra-files-step.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {MatSelectChange} from '@angular/material/select'; import {Project} from 'src/app/api/models/project'; import {AlertService} from 'src/app/common/services/alert.service'; @@ -7,6 +7,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-portfolio-add-extra-files-step', templateUrl: 'portfolio-add-extra-files-step.component.html', styleUrls: ['portfolio-add-extra-files-step.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PortfolioAddExtraFilesStepComponent implements OnInit { diff --git a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts index 910e02daa8..747a9f5fd4 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts +++ b/src/app/projects/states/portfolio/directives/portfolio-grade-select-step/portfolio-grade-select-step.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Project, Unit} from 'src/app/api/models/doubtfire-model'; import {ProjectService} from 'src/app/api/services/project.service'; import {AlertService} from 'src/app/common/services/alert.service'; @@ -8,6 +8,7 @@ import {GradeService} from 'src/app/common/services/grade.service'; selector: 'f-portfolio-grade-select-step', templateUrl: 'portfolio-grade-select-step.component.html', styleUrls: ['portfolio-grade-select-step.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PortfolioGradeSelectStepComponent { diff --git a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.ts index 2d162c1f7f..66843a5bae 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.ts +++ b/src/app/projects/states/portfolio/directives/portfolio-learning-summary-report-step/portfolio-learning-summary-report-step.component.ts @@ -1,4 +1,4 @@ -import {Component, Injector, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Injector, Input} from '@angular/core'; import {Project} from 'src/app/api/models/project'; import {Unit} from 'src/app/api/models/unit'; import {GradeService} from 'src/app/common/services/grade.service'; @@ -7,6 +7,7 @@ import {GradeService} from 'src/app/common/services/grade.service'; selector: 'f-portfolio-learning-summary-report-step', templateUrl: 'portfolio-learning-summary-report-step.component.html', styleUrls: ['portfolio-learning-summary-report-step.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PortfolioLearningSummaryReportStepComponent { diff --git a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.ts b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.ts index 1bd988ead0..3be9d74844 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.ts +++ b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-included-tasks/portfolio-included-tasks.component.ts @@ -1,4 +1,12 @@ -import {Component, EventEmitter, Input, OnDestroy, OnInit, Output} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + OnDestroy, + OnInit, + Output, +} from '@angular/core'; import {Subscription, interval} from 'rxjs'; import {Project} from 'src/app/api/models/project'; import {Task} from 'src/app/api/models/task'; @@ -8,6 +16,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-portfolio-included-tasks', templateUrl: 'portfolio-included-tasks.component.html', styleUrls: ['portfolio-included-tasks.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PortfolioIncludedTasksComponent implements OnInit, OnDestroy { diff --git a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.component.ts index 3af5d2a896..865e9449c0 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.component.ts +++ b/src/app/projects/states/portfolio/directives/portfolio-review-step/portfolio-review-step.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {Project} from 'src/app/api/models/project'; import {Task} from 'src/app/api/models/task'; import {Unit} from 'src/app/api/models/unit'; @@ -13,6 +13,7 @@ import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; selector: 'f-portfolio-review-step', templateUrl: 'portfolio-review-step.component.html', styleUrls: ['portfolio-review-step.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PortfolioReviewStepComponent implements OnInit { diff --git a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.ts b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.ts index c20eb3f23b..e2c9bda66c 100644 --- a/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.ts +++ b/src/app/projects/states/portfolio/directives/portfolio-welcome-step/portfolio-welcome-step.component.ts @@ -1,10 +1,11 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; @Component({ selector: 'f-portfolio-welcome-step', templateUrl: 'portfolio-welcome-step.component.html', styleUrls: ['portfolio-welcome-step.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PortfolioWelcomeStepComponent implements OnInit { diff --git a/src/app/projects/states/portfolio/portfolio-state.component.ts b/src/app/projects/states/portfolio/portfolio-state.component.ts index fc270d92d0..e96f5d2eec 100644 --- a/src/app/projects/states/portfolio/portfolio-state.component.ts +++ b/src/app/projects/states/portfolio/portfolio-state.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {Observable, Subscription, of} from 'rxjs'; import {Project} from 'src/app/api/models/project'; @@ -14,6 +14,7 @@ interface PortfolioStepTab { selector: 'f-portfolio-state', templateUrl: './portfolio-state.component.html', styleUrls: ['./portfolio-state.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PortfolioStateComponent implements OnInit, OnDestroy { diff --git a/src/app/projects/states/project-root-state.component.ts b/src/app/projects/states/project-root-state.component.ts index bfdaee850c..355f9f641f 100644 --- a/src/app/projects/states/project-root-state.component.ts +++ b/src/app/projects/states/project-root-state.component.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {Observable, of} from 'rxjs'; import {Project} from 'src/app/api/models/doubtfire-model'; @@ -8,6 +8,7 @@ import {Project} from 'src/app/api/models/doubtfire-model'; selector: 'f-project-root-state', templateUrl: './project-root-state.component.html', styleUrl: './project-root-state.component.css', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ProjectRootStateComponent { diff --git a/src/app/projects/states/staff-notes/staff-notes.component.ts b/src/app/projects/states/staff-notes/staff-notes.component.ts index 1d943bcb56..6ca071e75e 100644 --- a/src/app/projects/states/staff-notes/staff-notes.component.ts +++ b/src/app/projects/states/staff-notes/staff-notes.component.ts @@ -1,4 +1,11 @@ -import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + ElementRef, + Input, + OnInit, + ViewChild, +} from '@angular/core'; import {Project, UserService} from 'src/app/api/models/doubtfire-model'; import {StaffNote} from 'src/app/api/models/staff-note'; import {StaffNoteService} from 'src/app/api/services/staff-note.service'; @@ -9,6 +16,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-staff-notes', templateUrl: './staff-notes.component.html', styleUrl: './staff-notes.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class StaffNotesComponent implements OnInit { diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html index d41f5095af..02fe4fac65 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.html +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.html @@ -36,7 +36,10 @@ [disabled]="selectedTaskDefinition" [(ngModel)]="selectedTaskDefinition" > - @for (td of unit?.taskDefinitionCache.values | async; track td) { + @for ( + td of $safeNavigationMigration(unit?.taskDefinitionCache.values) | async; + track td + ) { {{ td.abbreviation }} - {{ td.name }} }
      @@ -67,7 +70,7 @@ }
      - Target Grade: {{ getTargetTradeString(project?.targetGrade) }} + Target Grade: {{ getTargetTradeString($safeNavigationMigration(project?.targetGrade)) }}
      } @else { @@ -110,7 +113,12 @@ similarities: task.similaritiesDetected, }" > - + +

      {{ task.definition.name }}

      @@ -225,7 +233,7 @@

      {{ task.definition.name }}

      diff --git a/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts index bc6819ee40..56384bd286 100644 --- a/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts +++ b/src/app/projects/states/tutor-discussion/tutor-discussion.component.ts @@ -2,6 +2,7 @@ import {Html5QrcodeScanner, Html5QrcodeScannerState} from 'html5-qrcode'; import {DOCUMENT} from '@angular/common'; import { AfterViewInit, + ChangeDetectionStrategy, Component, Inject, Input, @@ -43,6 +44,7 @@ enum TutorDiscussionTabView { templateUrl: './tutor-discussion.component.html', styleUrl: './tutor-discussion.component.scss', encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TutorDiscussionComponent implements AfterViewInit, OnDestroy { diff --git a/src/app/projects/states/tutor-notes/tutor-notes.component.ts b/src/app/projects/states/tutor-notes/tutor-notes.component.ts index 81f3b0da7c..e595818ab0 100644 --- a/src/app/projects/states/tutor-notes/tutor-notes.component.ts +++ b/src/app/projects/states/tutor-notes/tutor-notes.component.ts @@ -1,4 +1,11 @@ -import {Component, ElementRef, Input, OnInit, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + ElementRef, + Input, + OnInit, + ViewChild, +} from '@angular/core'; import {Task, UnitRole, UserService} from 'src/app/api/models/doubtfire-model'; import {TutorNote} from 'src/app/api/models/tutor-note'; import {TutorNoteService} from 'src/app/api/services/tutor-note.service'; @@ -9,6 +16,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-tutor-notes', templateUrl: './tutor-notes.component.html', styleUrl: './tutor-notes.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TutorNotesComponent implements OnInit { diff --git a/src/app/projects/states/tutorials/tutorials.component.ts b/src/app/projects/states/tutorials/tutorials.component.ts index 47963b0d05..07f4879f06 100644 --- a/src/app/projects/states/tutorials/tutorials.component.ts +++ b/src/app/projects/states/tutorials/tutorials.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit} from '@angular/core'; import {Sort} from '@angular/material/sort'; import {MatTableDataSource} from '@angular/material/table'; import {ActivatedRoute} from '@angular/router'; @@ -9,6 +9,7 @@ import {Project, Tutorial, Unit} from 'src/app/api/models/doubtfire-model'; selector: 'f-tutorials', templateUrl: './tutorials.component.html', styleUrls: ['./tutorials.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TutorialsComponent implements OnInit, OnDestroy { diff --git a/src/app/sessions/states/sign-in/sign-in.component.ts b/src/app/sessions/states/sign-in/sign-in.component.ts index 59fab3a6cd..02cd5a197f 100644 --- a/src/app/sessions/states/sign-in/sign-in.component.ts +++ b/src/app/sessions/states/sign-in/sign-in.component.ts @@ -1,5 +1,5 @@ import {HttpClient} from '@angular/common/http'; -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {BehaviorSubject} from 'rxjs'; import {AuthenticationService} from 'src/app/api/services/authentication.service'; @@ -39,6 +39,7 @@ type signInData = selector: 'f-sign-in', templateUrl: './sign-in.component.html', styleUrls: ['./sign-in.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class SignInComponent implements OnInit { diff --git a/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.ts b/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.ts index feffeefeb8..271630413a 100644 --- a/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.ts +++ b/src/app/tasks/modals/feedback-appeal-modal/feedback-appeal-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {Task} from 'src/app/api/models/task'; import {TaskService} from 'src/app/api/services/task.service'; @@ -9,6 +9,7 @@ import {FeedbackAppealModalData} from './feedback-appeal-modal.service'; selector: 'f-feedback-appeal-modal', templateUrl: './feedback-appeal-modal.component.html', styleUrl: './feedback-appeal-modal.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class FeedbackAppealModalComponent implements OnInit { diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.ts b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.ts index 10a77aea68..5a21b0c6e3 100644 --- a/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.ts +++ b/src/app/tasks/modals/grade-task-modal/grade-task-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {GradeService, Task} from 'src/app/api/models/doubtfire-model'; @@ -6,6 +6,7 @@ import {GradeService, Task} from 'src/app/api/models/doubtfire-model'; selector: 'grade-task-modal', templateUrl: './grade-task-modal.component.html', styleUrls: ['./grade-task-modal.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class GradeTaskModalComponent implements OnInit { diff --git a/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.ts b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.ts index 93ac4ca259..ef90da6a05 100644 --- a/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.ts +++ b/src/app/tasks/modals/submission-type-modal/submission-type-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {Task} from 'src/app/api/models/task'; import {TaskStatusEnum} from 'src/app/api/models/task-status'; @@ -11,6 +11,7 @@ export interface SubmissionTypeModalData { selector: 'f-submission-type-modal', templateUrl: './submission-type-modal.component.html', styleUrls: ['./submission-type-modal.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class SubmissionTypeModalComponent { diff --git a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.component.ts b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.component.ts index d9709369de..5107f3f584 100644 --- a/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.component.ts +++ b/src/app/tasks/modals/upload-submission-modal/upload-submission-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, OnInit, ViewChild} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnInit, ViewChild} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {MemberContribution} from 'src/app/api/models/groups/group'; import {Task} from 'src/app/api/models/task'; @@ -57,6 +57,7 @@ export type UploadSubmissionModalResult = @Component({ selector: 'f-upload-submission-modal', templateUrl: './upload-submission-modal.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UploadSubmissionModalComponent implements OnInit { diff --git a/src/app/tasks/project-tasks-list/project-tasks-list.component.ts b/src/app/tasks/project-tasks-list/project-tasks-list.component.ts index a5fa15a6a5..b1ea1f3f72 100644 --- a/src/app/tasks/project-tasks-list/project-tasks-list.component.ts +++ b/src/app/tasks/project-tasks-list/project-tasks-list.component.ts @@ -1,4 +1,11 @@ -import {Component, EventEmitter, Input, OnInit, Output} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + OnInit, + Output, +} from '@angular/core'; import { GradeService, Project, @@ -12,6 +19,7 @@ import { selector: 'f-project-tasks-list', templateUrl: './project-tasks-list.component.html', styleUrls: ['./project-tasks-list.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ProjectTasksListComponent implements OnInit { diff --git a/src/app/tasks/task-comment-composer/attachment-confirmation-dialog/attachment-confirmation-dialog.component.ts b/src/app/tasks/task-comment-composer/attachment-confirmation-dialog/attachment-confirmation-dialog.component.ts index 60d4644fed..644281e04e 100644 --- a/src/app/tasks/task-comment-composer/attachment-confirmation-dialog/attachment-confirmation-dialog.component.ts +++ b/src/app/tasks/task-comment-composer/attachment-confirmation-dialog/attachment-confirmation-dialog.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnDestroy, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; export interface AttachmentConfirmationDialogData { @@ -8,6 +8,7 @@ export interface AttachmentConfirmationDialogData { @Component({ selector: 'f-attachment-confirmation-dialog', templateUrl: './attachment-confirmation-dialog.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class AttachmentConfirmationDialogComponent implements OnInit, OnDestroy { diff --git a/src/app/tasks/task-comment-composer/discussion-prompt-composer/discussion-prompt-composer.component.ts b/src/app/tasks/task-comment-composer/discussion-prompt-composer/discussion-prompt-composer.component.ts index df50dd71d5..8beb8baaa8 100644 --- a/src/app/tasks/task-comment-composer/discussion-prompt-composer/discussion-prompt-composer.component.ts +++ b/src/app/tasks/task-comment-composer/discussion-prompt-composer/discussion-prompt-composer.component.ts @@ -1,4 +1,12 @@ -import {AfterViewInit, Component, ElementRef, Inject, Input, ViewChild} from '@angular/core'; +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + ElementRef, + Inject, + Input, + ViewChild, +} from '@angular/core'; import {Task, TaskComment, TaskCommentService} from 'src/app/api/models/doubtfire-model'; import {BaseAudioRecorderComponent} from 'src/app/common/audio-recorder/audio/base-audio-recorder'; import {AlertService} from 'src/app/common/services/alert.service'; @@ -9,6 +17,7 @@ import {MediaRecorderService} from 'src/app/common/services/recorder-service'; templateUrl: './discussion-prompt-composer.component.html', styleUrls: ['./discussion-prompt-composer.component.scss'], providers: [MediaRecorderService], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class DiscussionPromptComposerComponent diff --git a/src/app/tasks/task-comment-composer/task-comment-composer.component.ts b/src/app/tasks/task-comment-composer/task-comment-composer.component.ts index 2c1850cbbf..ab994a0d57 100644 --- a/src/app/tasks/task-comment-composer/task-comment-composer.component.ts +++ b/src/app/tasks/task-comment-composer/task-comment-composer.component.ts @@ -3,6 +3,7 @@ import {EmojiData} from '@ctrl/ngx-emoji-mart/ngx-emoji'; import {animate, style, transition, trigger} from '@angular/animations'; import { AfterViewInit, + ChangeDetectionStrategy, ChangeDetectorRef, Component, DoCheck, @@ -76,6 +77,7 @@ const ACCEPTED_FILE_TYPES = [ transition('false => true', [style({width: 80}), animate('150ms 0ms ease-in-out')]), ]), ], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskCommentComposerComponent implements AfterViewInit, DoCheck, OnChanges { @@ -791,6 +793,7 @@ export class TaskCommentComposerComponent implements AfterViewInit, DoCheck, OnC selector: 'discussion-prompt-composer-dialog.html', templateUrl: 'discussion-prompt-composer-dialog.html', styleUrls: ['./discussion-prompt-composer/discussion-prompt-composer.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class DiscussionComposerDialog { diff --git a/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts index 6f6b2bf886..c873efd7a1 100644 --- a/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts +++ b/src/app/tasks/task-comment-composer/task-feedback-templates/task-feedback-templates.component.ts @@ -1,4 +1,5 @@ import { + ChangeDetectionStrategy, Component, ElementRef, EventEmitter, @@ -26,6 +27,7 @@ import { styleUrl: './task-feedback-templates.component.scss', templateUrl: './task-feedback-templates.component.html', encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskFeedbackTemplatesComponent implements OnInit, OnChanges { diff --git a/src/app/tasks/task-comments-viewer/comment-bubble-action/comment-bubble-action.component.ts b/src/app/tasks/task-comments-viewer/comment-bubble-action/comment-bubble-action.component.ts index 9177e395e2..dc68053e56 100644 --- a/src/app/tasks/task-comments-viewer/comment-bubble-action/comment-bubble-action.component.ts +++ b/src/app/tasks/task-comments-viewer/comment-bubble-action/comment-bubble-action.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {TaskComment} from 'src/app/api/models/doubtfire-model'; import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; import {TaskCommentComposerData} from '../../task-comment-composer/task-comment-composer.component'; @@ -7,6 +7,7 @@ import {TaskCommentComposerData} from '../../task-comment-composer/task-comment- selector: 'comment-bubble-action', templateUrl: './comment-bubble-action.component.html', styleUrls: ['./comment-bubble-action.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class CommentBubbleActionComponent { diff --git a/src/app/tasks/task-comments-viewer/extension-comment/extension-comment.component.ts b/src/app/tasks/task-comments-viewer/extension-comment/extension-comment.component.ts index b3784c20f3..4db00f9864 100644 --- a/src/app/tasks/task-comments-viewer/extension-comment/extension-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/extension-comment/extension-comment.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Task, TaskComment} from 'src/app/api/models/doubtfire-model'; import {ExtensionComment} from 'src/app/api/models/task-comment/extension-comment'; import {AlertService} from 'src/app/common/services/alert.service'; @@ -7,6 +7,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'extension-comment', templateUrl: './extension-comment.component.html', styleUrls: ['./extension-comment.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ExtensionCommentComponent { diff --git a/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-player.component.ts b/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-player.component.ts index ec03752589..5947922893 100644 --- a/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-player.component.ts +++ b/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-player.component.ts @@ -1,5 +1,12 @@ import moment from 'moment'; -import {AfterViewInit, Component, Inject, Input, ViewChild} from '@angular/core'; +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + Inject, + Input, + ViewChild, +} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; import {Subscription, timer} from 'rxjs'; import {DiscussionComment, Task} from 'src/app/api/models/doubtfire-model'; @@ -13,6 +20,7 @@ import {IntelligentDiscussionRecorderComponent} from './intelligent-discussion-r templateUrl: './intelligent-discussion-player.component.html', styleUrls: ['./intelligent-discussion-player.component.scss'], providers: [IntelligentDiscussionPlayerService], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class IntelligentDiscussionPlayerComponent implements AfterViewInit { @@ -77,6 +85,7 @@ export class IntelligentDiscussionPlayerComponent implements AfterViewInit { templateUrl: 'intelligent-discussion-dialog.html', styleUrls: ['./intelligent-discussion-player.component.scss'], providers: [IntelligentDiscussionPlayerService], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class IntelligentDiscussionDialog { diff --git a/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-recorder/intelligent-discussion-recorder.component.ts b/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-recorder/intelligent-discussion-recorder.component.ts index a87039ef51..bc988c98a5 100644 --- a/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-recorder/intelligent-discussion-recorder.component.ts +++ b/src/app/tasks/task-comments-viewer/intelligent-discussion-player/intelligent-discussion-recorder/intelligent-discussion-recorder.component.ts @@ -1,4 +1,4 @@ -import {AfterViewInit, Component, Inject, Input} from '@angular/core'; +import {AfterViewInit, ChangeDetectionStrategy, Component, Inject, Input} from '@angular/core'; import {DiscussionComment, Task} from 'src/app/api/models/doubtfire-model'; import { BaseAudioRecorderComponent, @@ -22,6 +22,7 @@ interface DiscussionReplyService { templateUrl: './intelligent-discussion-recorder.component.html', styleUrls: ['./intelligent-discussion-recorder.component.css'], providers: [MediaRecorderService], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class IntelligentDiscussionRecorderComponent diff --git a/src/app/tasks/task-comments-viewer/pdf-image-comment/pdf-image-comment.component.ts b/src/app/tasks/task-comments-viewer/pdf-image-comment/pdf-image-comment.component.ts index 7bc04435e1..32fee56dff 100644 --- a/src/app/tasks/task-comments-viewer/pdf-image-comment/pdf-image-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/pdf-image-comment/pdf-image-comment.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit} from '@angular/core'; import {Project, Task, TaskComment} from 'src/app/api/models/doubtfire-model'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; import {CommentsModalService} from 'src/app/common/modals/comments-modal/comments-modal.service'; @@ -8,6 +8,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'pdf-image-comment', templateUrl: './pdf-image-comment.component.html', styleUrls: [], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PdfImageCommentComponent implements OnInit, OnDestroy { diff --git a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts index 485c951a51..5cf6e6845c 100644 --- a/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/scorm-comment/scorm-comment.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import { ScormComment, Task, @@ -12,6 +12,7 @@ import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal selector: 'f-scorm-comment', templateUrl: './scorm-comment.component.html', styleUrls: ['./scorm-comment.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ScormCommentComponent { diff --git a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts index b1f93de747..ea963d9b00 100644 --- a/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/scorm-extension-comment/scorm-extension-comment.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {ScormExtensionComment, Task, TaskComment} from 'src/app/api/models/doubtfire-model'; import {AlertService} from 'src/app/common/services/alert.service'; @@ -6,6 +6,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-scorm-extension-comment', templateUrl: './scorm-extension-comment.component.html', styleUrls: ['./scorm-extension-comment.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ScormExtensionCommentComponent { diff --git a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts index 39eac04240..2c4e842f98 100644 --- a/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts +++ b/src/app/tasks/task-comments-viewer/task-assessment-comment/task-assessment-comment.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, Input} from '@angular/core'; import {Task} from 'src/app/api/models/doubtfire-model'; import {TaskAssessmentModalService} from 'src/app/common/modals/task-assessment-modal/task-assessment-modal.service'; import {AlertService} from 'src/app/common/services/alert.service'; @@ -37,6 +37,7 @@ export interface TaskAssessmentComment { selector: 'app-task-assessment-comment', templateUrl: './task-assessment-comment.component.html', styleUrls: ['./task-assessment-comment.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskAssessmentCommentComponent { diff --git a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts index 7f5e1d4af4..3233a9850b 100644 --- a/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts +++ b/src/app/tasks/task-comments-viewer/task-comments-viewer.component.ts @@ -1,4 +1,5 @@ import { + ChangeDetectionStrategy, Component, ElementRef, Input, @@ -26,6 +27,7 @@ import {TaskCommentComposerData} from '../task-comment-composer/task-comment-com selector: 'task-comments-viewer', templateUrl: './task-comments-viewer.component.html', styleUrls: ['./task-comments-viewer.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskCommentsViewerComponent implements OnChanges, OnDestroy { diff --git a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts index 4772d837fd..21460b7484 100644 --- a/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts +++ b/src/app/units/modals/unit-student-enrolment-modal/unit-student-enrolment-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {Campus, Project, Unit} from 'src/app/api/models/doubtfire-model'; import {CampusService} from 'src/app/api/services/campus.service'; @@ -8,6 +8,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-unit-student-enrolment-modal', templateUrl: 'unit-student-enrolment-modal.component.html', styleUrls: ['unit-student-enrolment-modal.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitStudentEnrolmentModalComponent implements OnInit { diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts index e8e655690d..99712feab4 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit, ViewEncapsulation} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit, ViewEncapsulation} from '@angular/core'; import {MatDatepickerInputEvent} from '@angular/material/datepicker'; import {Observable} from 'rxjs'; import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; @@ -32,6 +32,7 @@ interface SessionEvent { templateUrl: 'analytics-tutor-times.component.html', styleUrls: ['analytics-tutor-times.component.scss'], encapsulation: ViewEncapsulation.None, + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class AnalyticsTutorTimesComponent implements OnInit { diff --git a/src/app/units/states/analytics/unit-analytics-route.component.ts b/src/app/units/states/analytics/unit-analytics-route.component.ts index f7a63585d9..b05fa7187b 100644 --- a/src/app/units/states/analytics/unit-analytics-route.component.ts +++ b/src/app/units/states/analytics/unit-analytics-route.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {Observable, first, of} from 'rxjs'; import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; @@ -12,6 +12,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-unit-analytics', templateUrl: 'unit-analytics-route.component.html', styleUrls: ['unit-analytics-route.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitAnalyticsComponent implements OnInit { diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/change-target-grade-action/change-target-grade-action.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/actions/change-target-grade-action/change-target-grade-action.component.ts index fd47ca76af..5be3b69259 100644 --- a/src/app/units/states/edit/directives/unit-communications-editor/actions/change-target-grade-action/change-target-grade-action.component.ts +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/change-target-grade-action/change-target-grade-action.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {CommunicationRule} from 'src/app/api/models/doubtfire-model'; import type {UnitCommunicationsEditorComponent} from '../../unit-communications-editor.component'; @@ -6,6 +6,7 @@ import type {UnitCommunicationsEditorComponent} from '../../unit-communications- selector: 'f-change-target-grade-action', standalone: false, templateUrl: './change-target-grade-action.component.html', + changeDetection: ChangeDetectionStrategy.Eager, host: {class: 'flex w-full flex-col items-center'}, }) export class ChangeTargetGradeActionComponent { diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/communication-actions.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/actions/communication-actions.component.ts index 5a3b083c9d..254e5ccf50 100644 --- a/src/app/units/states/edit/directives/unit-communications-editor/actions/communication-actions.component.ts +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/communication-actions.component.ts @@ -1,10 +1,11 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {CommunicationRule} from 'src/app/api/models/doubtfire-model'; import type {UnitCommunicationsEditorComponent} from '../unit-communications-editor.component'; @Component({ selector: 'f-communication-actions', standalone: false, + changeDetection: ChangeDetectionStrategy.Eager, templateUrl: './communication-actions.component.html', }) export class CommunicationActionsComponent { diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/email-staff-action/email-staff-action.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/actions/email-staff-action/email-staff-action.component.ts index f795a326a1..91f2a22c79 100644 --- a/src/app/units/states/edit/directives/unit-communications-editor/actions/email-staff-action/email-staff-action.component.ts +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/email-staff-action/email-staff-action.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {CommunicationRule} from 'src/app/api/models/doubtfire-model'; import type {UnitCommunicationsEditorComponent} from '../../unit-communications-editor.component'; @@ -6,6 +6,7 @@ import type {UnitCommunicationsEditorComponent} from '../../unit-communications- selector: 'f-email-staff-action', standalone: false, templateUrl: './email-staff-action.component.html', + changeDetection: ChangeDetectionStrategy.Eager, host: {class: 'block w-full'}, }) export class EmailStaffActionComponent { diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/email-student-action/email-student-action.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/actions/email-student-action/email-student-action.component.ts index 09cd6fc64a..100e890c66 100644 --- a/src/app/units/states/edit/directives/unit-communications-editor/actions/email-student-action/email-student-action.component.ts +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/email-student-action/email-student-action.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {CommunicationRule} from 'src/app/api/models/doubtfire-model'; import type {UnitCommunicationsEditorComponent} from '../../unit-communications-editor.component'; @@ -6,6 +6,7 @@ import type {UnitCommunicationsEditorComponent} from '../../unit-communications- selector: 'f-email-student-action', standalone: false, templateUrl: './email-student-action.component.html', + changeDetection: ChangeDetectionStrategy.Eager, host: {class: 'block w-full'}, }) export class EmailStudentActionComponent { diff --git a/src/app/units/states/edit/directives/unit-communications-editor/actions/task-comment-action/task-comment-action.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/actions/task-comment-action/task-comment-action.component.ts index f7f2fb5b4b..6c459e3d26 100644 --- a/src/app/units/states/edit/directives/unit-communications-editor/actions/task-comment-action/task-comment-action.component.ts +++ b/src/app/units/states/edit/directives/unit-communications-editor/actions/task-comment-action/task-comment-action.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {CommunicationRule} from 'src/app/api/models/doubtfire-model'; import type {UnitCommunicationsEditorComponent} from '../../unit-communications-editor.component'; @@ -6,6 +6,7 @@ import type {UnitCommunicationsEditorComponent} from '../../unit-communications- selector: 'f-task-comment-action', standalone: false, templateUrl: './task-comment-action.component.html', + changeDetection: ChangeDetectionStrategy.Eager, host: {class: 'block w-full'}, }) export class TaskCommentActionComponent { diff --git a/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedule-modal.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedule-modal.component.ts index eb241004d0..674e156d72 100644 --- a/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedule-modal.component.ts +++ b/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedule-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import { Campus, @@ -25,6 +25,7 @@ export const SCHEDULE_WEEKDAYS = [ @Component({ selector: 'f-communication-schedule-modal', standalone: false, + changeDetection: ChangeDetectionStrategy.Eager, templateUrl: './communication-schedule-modal.component.html', }) export class CommunicationScheduleModalComponent implements OnInit { diff --git a/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedules.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedules.component.ts index e902eca099..aa1156619e 100644 --- a/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedules.component.ts +++ b/src/app/units/states/edit/directives/unit-communications-editor/communication-schedule-modal/communication-schedules.component.ts @@ -1,10 +1,11 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {CommunicationSet} from 'src/app/api/models/doubtfire-model'; import type {UnitCommunicationsEditorComponent} from '../unit-communications-editor.component'; @Component({ selector: 'f-communication-schedules', standalone: false, + changeDetection: ChangeDetectionStrategy.Eager, templateUrl: './communication-schedules.component.html', }) export class CommunicationSchedulesComponent { diff --git a/src/app/units/states/edit/directives/unit-communications-editor/conditions/communication-conditions.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/conditions/communication-conditions.component.ts index abab204e98..a4167c217a 100644 --- a/src/app/units/states/edit/directives/unit-communications-editor/conditions/communication-conditions.component.ts +++ b/src/app/units/states/edit/directives/unit-communications-editor/conditions/communication-conditions.component.ts @@ -1,10 +1,11 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {CommunicationRule} from 'src/app/api/models/doubtfire-model'; import type {UnitCommunicationsEditorComponent} from '../unit-communications-editor.component'; @Component({ selector: 'f-communication-conditions', standalone: false, + changeDetection: ChangeDetectionStrategy.Eager, templateUrl: './communication-conditions.component.html', }) export class CommunicationConditionsComponent { diff --git a/src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.ts b/src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.ts index 5b83236047..cfe6bf4191 100644 --- a/src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-communications-editor/unit-communications-editor.component.ts @@ -1,5 +1,13 @@ import {NestedTreeControl} from '@angular/cdk/tree'; -import {Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + OnDestroy, + OnInit, + SimpleChanges, +} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; import {MatTreeNestedDataSource} from '@angular/material/tree'; import {Subscription} from 'rxjs'; @@ -47,6 +55,7 @@ interface CommunicationTreeNode { selector: 'f-unit-communications-editor', standalone: false, templateUrl: './unit-communications-editor.component.html', + changeDetection: ChangeDetectionStrategy.Eager, styleUrl: './unit-communications-editor.component.scss', }) export class UnitCommunicationsEditorComponent implements OnInit, OnChanges, OnDestroy { diff --git a/src/app/units/states/edit/directives/unit-details-editor/d2l-details-form/d2l-unit-details-form.component.ts b/src/app/units/states/edit/directives/unit-details-editor/d2l-details-form/d2l-unit-details-form.component.ts index 4b66e6c644..cd19b0b701 100644 --- a/src/app/units/states/edit/directives/unit-details-editor/d2l-details-form/d2l-unit-details-form.component.ts +++ b/src/app/units/states/edit/directives/unit-details-editor/d2l-details-form/d2l-unit-details-form.component.ts @@ -1,7 +1,7 @@ // // Modal to show Doubtfire version info // -import {Component, Inject, Injectable, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, Injectable, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; import {Observable} from 'rxjs'; import {D2lAssessmentMapping} from 'src/app/api/models/d2l/d2l_assessment_mapping'; @@ -13,6 +13,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-d2l-unit-details-form', templateUrl: 'd2l-unit-details-form.component.html', styleUrl: 'd2l-unit-details-form.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class D2lUnitDetailsFormComponent implements OnInit { diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html index 93e858b13f..ce5030841c 100644 --- a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html +++ b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.html @@ -48,11 +48,21 @@

      Unit Details

      } @else { {{ unit.teachingPeriod.name }} Start Date - + {{ unit.teachingPeriod.name }} End Date - + }
      diff --git a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts index 8b6448915b..961ea8def8 100644 --- a/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-details-editor/unit-details-editor.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {MatSlideToggleChange} from '@angular/material/slide-toggle'; import {OverseerImage, UnitService} from 'src/app/api/models/doubtfire-model'; import {TaskDefinition} from 'src/app/api/models/task-definition'; @@ -16,6 +16,7 @@ import {D2lUnitDetailsModal} from './d2l-details-form/d2l-unit-details-form.comp selector: 'f-unit-details-editor', templateUrl: 'unit-details-editor.component.html', styleUrls: ['unit-details-editor.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitDetailsEditorComponent implements OnInit { diff --git a/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.component.ts b/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.component.ts index dc95919d08..f35f861698 100644 --- a/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-group-set-editor/unit-group-set-editor.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {GroupSet, Unit, UnitRole} from 'src/app/api/models/doubtfire-model'; import {GroupSetService} from 'src/app/api/services/group-set.service'; import {FileDownloaderService} from 'src/app/common/file-downloader/file-downloader.service'; @@ -20,6 +20,7 @@ interface GroupSetEditModel { selector: 'f-unit-group-set-editor', templateUrl: './unit-group-set-editor.component.html', styleUrls: ['./unit-group-set-editor.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitGroupSetEditorComponent implements OnInit { diff --git a/src/app/units/states/edit/directives/unit-staff-editor/bulk-import-staff-modal/bulk-import-staff-modal.component.ts b/src/app/units/states/edit/directives/unit-staff-editor/bulk-import-staff-modal/bulk-import-staff-modal.component.ts index e3d7a8a295..0456d484ed 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/bulk-import-staff-modal/bulk-import-staff-modal.component.ts +++ b/src/app/units/states/edit/directives/unit-staff-editor/bulk-import-staff-modal/bulk-import-staff-modal.component.ts @@ -1,9 +1,10 @@ -import {Component} from '@angular/core'; +import {ChangeDetectionStrategy, Component} from '@angular/core'; import {MatDialogRef} from '@angular/material/dialog'; @Component({ selector: 'bulk-import-staff-modal', templateUrl: './bulk-import-staff-modal.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class BulkImportStaffModalComponent { diff --git a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts index f549cd09b8..af051c8f14 100644 --- a/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-staff-editor/unit-staff-editor.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {MatButtonToggleChange} from '@angular/material/button-toggle'; import {MatSelectChange} from '@angular/material/select'; import {MatTableDataSource} from '@angular/material/table'; @@ -20,6 +20,7 @@ import {BulkImportStaffModalService} from './bulk-import-staff-modal/bulk-import @Component({ selector: 'unit-staff-editor', templateUrl: 'unit-staff-editor.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitStaffEditorComponent implements OnInit { diff --git a/src/app/units/states/edit/directives/unit-students-editor/student-campus-select/student-campus-select.component.ts b/src/app/units/states/edit/directives/unit-students-editor/student-campus-select/student-campus-select.component.ts index 001758c768..bb80001e70 100644 --- a/src/app/units/states/edit/directives/unit-students-editor/student-campus-select/student-campus-select.component.ts +++ b/src/app/units/states/edit/directives/unit-students-editor/student-campus-select/student-campus-select.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnChanges, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnChanges, OnInit} from '@angular/core'; import {MatSelectChange} from '@angular/material/select'; import {Campus, CampusService, Project, Unit} from 'src/app/api/models/doubtfire-model'; import {AlertService} from 'src/app/common/services/alert.service'; @@ -7,6 +7,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'student-campus-select', templateUrl: 'student-campus-select.component.html', styleUrls: ['student-campus-select.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class StudentCampusSelectComponent implements OnChanges, OnInit { diff --git a/src/app/units/states/edit/directives/unit-students-editor/student-tutorial-select/student-tutorial-select.component.ts b/src/app/units/states/edit/directives/unit-students-editor/student-tutorial-select/student-tutorial-select.component.ts index 1ca41cdb12..ce5b9b1e58 100644 --- a/src/app/units/states/edit/directives/unit-students-editor/student-tutorial-select/student-tutorial-select.component.ts +++ b/src/app/units/states/edit/directives/unit-students-editor/student-tutorial-select/student-tutorial-select.component.ts @@ -1,10 +1,11 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Project, Tutorial, TutorialStream, Unit} from 'src/app/api/models/doubtfire-model'; @Component({ selector: 'student-tutorial-select', templateUrl: 'student-tutorial-select.component.html', styleUrls: ['student-tutorial-select.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class StudentTutorialSelectComponent { diff --git a/src/app/units/states/edit/directives/unit-students-editor/unit-students-editor.component.ts b/src/app/units/states/edit/directives/unit-students-editor/unit-students-editor.component.ts index 9033952a22..fd20d9cdf8 100644 --- a/src/app/units/states/edit/directives/unit-students-editor/unit-students-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-students-editor/unit-students-editor.component.ts @@ -1,5 +1,13 @@ import {HttpClient} from '@angular/common/http'; -import {AfterViewInit, Component, Input, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + Input, + OnDestroy, + OnInit, + ViewChild, +} from '@angular/core'; import {MatPaginator} from '@angular/material/paginator'; import {MatSort, Sort} from '@angular/material/sort'; import {MatTable, MatTableDataSource} from '@angular/material/table'; @@ -22,6 +30,7 @@ import {UnitStudentEnrolmentModalService} from 'src/app/units/modals/unit-studen selector: 'unit-students-editor', templateUrl: 'unit-students-editor.component.html', styleUrls: ['unit-students-editor.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitStudentsEditorComponent implements OnInit, AfterViewInit, OnDestroy { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.ts index 2846c38f2c..40d0f325c5 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-dates/task-definition-dates.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Unit} from 'src/app/api/models/unit'; @@ -6,6 +6,7 @@ import {Unit} from 'src/app/api/models/unit'; selector: 'f-task-definition-dates', templateUrl: 'task-definition-dates.component.html', styleUrls: ['task-definition-dates.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDefinitionDatesComponent { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts index 1de5e5f142..7f9de46ef7 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-discussion-prompts/task-definition-discussion-prompts.component.ts @@ -1,4 +1,11 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + OnInit, + SimpleChanges, +} from '@angular/core'; import {UntypedFormControl, Validators} from '@angular/forms'; import {MatTableDataSource} from '@angular/material/table'; import {Observable, Subscription} from 'rxjs'; @@ -17,6 +24,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-task-definition-discussion-prompts', templateUrl: 'task-definition-discussion-prompts.component.html', styleUrls: ['task-definition-discussion-prompts.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDefinitionDiscussionPromptsComponent diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts index 1e24f9cc96..6c48f141f8 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-editor.component.ts @@ -1,5 +1,6 @@ import { AfterViewInit, + ChangeDetectionStrategy, Component, ElementRef, HostListener, @@ -41,6 +42,7 @@ interface TaskDefinitionSection { selector: 'f-task-definition-editor', templateUrl: 'task-definition-editor.component.html', styleUrls: ['task-definition-editor.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDefinitionEditorComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.ts index 5683af008a..3203ea0eaa 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-general/task-definition-general.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Unit} from 'src/app/api/models/unit'; import {GradeService} from 'src/app/common/services/grade.service'; @@ -7,6 +7,7 @@ import {GradeService} from 'src/app/common/services/grade.service'; selector: 'f-task-definition-general', templateUrl: 'task-definition-general.component.html', styleUrls: ['task-definition-general.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDefinitionGeneralComponent { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts index f41aac39bb..29037633b7 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-options/task-definition-options.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Unit} from 'src/app/api/models/unit'; import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal/confirmation-modal.service'; @@ -7,6 +7,7 @@ import {ConfirmationModalService} from 'src/app/common/modals/confirmation-modal selector: 'f-task-definition-options', templateUrl: 'task-definition-options.component.html', styleUrls: ['task-definition-options.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDefinitionOptionsComponent { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts index ab124ad2da..c2bc724c2e 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/overseer-script-editor-modal/overseer-script-editor-modal.component.ts @@ -1,6 +1,6 @@ import {CodeModel} from '@ngstack/code-editor'; import {HttpClient} from '@angular/common/http'; -import {Component, Inject, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {AlertService} from 'src/app/common/services/alert.service'; import {OverseerScriptEditorModalData} from './overseer-script-editor-modal.service'; @@ -9,6 +9,7 @@ import {OverseerScriptEditorModalData} from './overseer-script-editor-modal.serv selector: 'f-overseer-script-editor-modal', templateUrl: './overseer-script-editor-modal.component.html', styleUrls: ['./overseer-script-editor-modal.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class OverseerScriptEditorModalComponent implements OnInit { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts index feb75b8fbc..17df2de59c 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-overseer/task-definition-overseer.component.ts @@ -1,7 +1,15 @@ import * as monaco from 'monaco-editor'; import {CdkDragDrop, moveItemInArray} from '@angular/cdk/drag-drop'; import {HttpClient, HttpResponse} from '@angular/common/http'; -import {Component, Input, OnChanges, OnInit, SimpleChanges, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + OnInit, + SimpleChanges, + ViewChild, +} from '@angular/core'; import {MatSelectChange} from '@angular/material/select'; import {Observable} from 'rxjs'; import { @@ -28,6 +36,7 @@ import {OverseerScriptEditorModalService} from './overseer-script-editor-modal/o selector: 'f-task-definition-overseer', templateUrl: 'task-definition-overseer.component.html', styleUrls: ['task-definition-overseer.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDefinitionOverseerComponent implements OnChanges, OnInit { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html index 530d31da43..5f9bb9acd6 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.html @@ -6,7 +6,7 @@
      @@ -23,12 +23,15 @@
      + Username + Username {{ project.student.username || 'N/A' }} Name + Name {{ project.student.name }} Stats + Stats
      @for (bar of project.taskStats; track bar.key) {
      @if (bar.key === 'not_started') { {{ bar.value }}% @@ -132,15 +132,15 @@

      Students

      -
      Target Grade + Target Grade Portfolio + Portfolio @if (project.hasPortfolio) { menu_book } @@ -148,8 +148,8 @@

      Students

      -
      Similarity + Similarity @if (project.similarityFlag) { visibility } @@ -157,12 +157,12 @@

      Students

      -
      Campus + Campus
      @@ -170,23 +170,23 @@

      Students

      -
      Tutorial + Tutorial
      - +
      No students were found using the filters specified. {{ link.prerequisite?.abbreviation }} {{ link.prerequisite?.name }} @if (!staffView) { } @else { @if (link.taskStatus) { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts index bc19d15057..7870470c2c 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-prerequisites/task-definition-prerequisites.component.ts @@ -1,4 +1,11 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + OnInit, + SimpleChanges, +} from '@angular/core'; import {FormControl} from '@angular/forms'; import {MatTableDataSource} from '@angular/material/table'; import {Observable, Subscription} from 'rxjs'; @@ -15,6 +22,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-task-definition-prerequisites', templateUrl: 'task-definition-prerequisites.component.html', styleUrls: ['task-definition-prerequisites.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDefinitionPrerequisitesComponent implements OnInit, OnChanges { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.ts index 0973e21805..991202f359 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-resources/task-definition-resources.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Unit} from 'src/app/api/models/unit'; import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; @@ -9,6 +9,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-task-definition-resources', templateUrl: 'task-definition-resources.component.html', styleUrls: ['task-definition-resources.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDefinitionResourcesComponent { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts index ec01b60b09..93ceb71852 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-scorm/task-definition-scorm.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Unit} from 'src/app/api/models/unit'; import {TaskDefinitionService} from 'src/app/api/services/task-definition.service'; @@ -9,6 +9,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-task-definition-scorm', templateUrl: 'task-definition-scorm.component.html', styleUrls: ['task-definition-scorm.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDefinitionScormComponent { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts index 3cbb9a03ed..0cb7e0b0d7 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-upload/task-definition-upload.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, ViewChild} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, ViewChild} from '@angular/core'; import {MatTable} from '@angular/material/table'; import {TaskDefinition, UploadRequirement} from 'src/app/api/models/task-definition'; import {Unit} from 'src/app/api/models/unit'; @@ -8,6 +8,7 @@ import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; selector: 'f-task-definition-upload', templateUrl: 'task-definition-upload.component.html', styleUrls: ['task-definition-upload.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDefinitionUploadComponent { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html index 65dee44436..e857fed00c 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.html @@ -28,7 +28,7 @@ Related tutorials
        @for ( - tutorial of taskDefinition.tutorialStream?.tutorialsIn(unit) + tutorial of $safeNavigationMigration(taskDefinition.tutorialStream?.tutorialsIn(unit)) | slice: 0 : (showAllTutorials ? undefined : 3); track tutorial ) { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts index 4ca19148ce..7ef4f65c5a 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/task-definition-editor/task-definition-who/task-definition-who.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Unit} from 'src/app/api/models/unit'; @@ -6,6 +6,7 @@ import {Unit} from 'src/app/api/models/unit'; selector: 'f-task-definition-who', templateUrl: 'task-definition-who.component.html', styleUrls: ['task-definition-who.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskDefinitionWhoComponent { diff --git a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts index ddb32c6635..f12139cd37 100644 --- a/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts +++ b/src/app/units/states/edit/directives/unit-tasks-editor/unit-task-editor.component.ts @@ -1,5 +1,5 @@ import {addWeeks} from 'date-fns'; -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit} from '@angular/core'; import {MatTableDataSource} from '@angular/material/table'; import {Subscription} from 'rxjs'; import {Grade} from 'src/app/api/models/grade'; @@ -21,6 +21,7 @@ type GradeCol = 'p' | 'c' | 'd' | 'hd'; selector: 'f-unit-task-editor', templateUrl: 'unit-task-editor.component.html', styleUrls: ['unit-task-editor.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitTaskEditorComponent implements OnInit, OnDestroy { diff --git a/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.ts b/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.ts index e2a351c8da..4db0b6c297 100644 --- a/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.ts +++ b/src/app/units/states/edit/directives/unit-tutorials-list/unit-tutorials-list.component.ts @@ -1,6 +1,6 @@ import {RequestOptions} from 'ngx-entity-service'; import {HttpErrorResponse} from '@angular/common/http'; -import {AfterViewInit, Component, Input, ViewChild} from '@angular/core'; +import {AfterViewInit, ChangeDetectionStrategy, Component, Input, ViewChild} from '@angular/core'; import {UntypedFormControl, Validators} from '@angular/forms'; import {MatSort, Sort} from '@angular/material/sort'; import {MatTable, MatTableDataSource} from '@angular/material/table'; @@ -22,6 +22,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'df-unit-tutorials-list', templateUrl: 'unit-tutorials-list.component.html', styleUrls: ['unit-tutorials-list.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitTutorialsListComponent diff --git a/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.ts b/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.ts index cdc7bacc90..2a71c1c6c7 100644 --- a/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.ts +++ b/src/app/units/states/edit/directives/unit-tutorials-manager/unit-tutorials-manager.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import { ActivityType, ActivityTypeService, @@ -11,6 +11,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'unit-tutorials-manager', templateUrl: 'unit-tutorials-manager.component.html', styleUrls: ['unit-tutorials-manager.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitTutorialsManagerComponent implements OnInit { diff --git a/src/app/units/states/edit/unit-admin-state.component.ts b/src/app/units/states/edit/unit-admin-state.component.ts index a9e02c4753..9550f29044 100644 --- a/src/app/units/states/edit/unit-admin-state.component.ts +++ b/src/app/units/states/edit/unit-admin-state.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit} from '@angular/core'; import {MatTabChangeEvent} from '@angular/material/tabs'; import {ActivatedRoute, Router} from '@angular/router'; import {Observable, Subscription, first, of} from 'rxjs'; @@ -23,6 +23,7 @@ interface UnitAdminTab { @Component({ selector: 'f-unit-admin-state', templateUrl: './unit-admin-state.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitAdminStateComponent implements OnInit, OnDestroy { diff --git a/src/app/units/states/groups/unit-groups/unit-groups.component.ts b/src/app/units/states/groups/unit-groups/unit-groups.component.ts index ee40e83f08..16d8612a5c 100644 --- a/src/app/units/states/groups/unit-groups/unit-groups.component.ts +++ b/src/app/units/states/groups/unit-groups/unit-groups.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {Observable, Subscription, of} from 'rxjs'; import {GroupSet, Unit, UnitRole, UserService} from 'src/app/api/models/doubtfire-model'; @@ -10,6 +10,7 @@ import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global selector: 'f-unit-groups', templateUrl: './unit-groups.component.html', styleUrl: './unit-groups.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitGroupsComponent implements OnInit, OnDestroy { diff --git a/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.ts b/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.ts index d262360101..c965168641 100644 --- a/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.ts +++ b/src/app/units/states/portfolios/d2l-transfer-modal/d2l-transfer.component.ts @@ -2,7 +2,7 @@ // Modal to show Doubtfire version info // import {HttpClient} from '@angular/common/http'; -import {Component, Inject, Injectable, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, Injectable, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialog, MatDialogRef} from '@angular/material/dialog'; import {D2lAssessmentMapping} from 'src/app/api/models/d2l/d2l_assessment_mapping'; import {D2lAssessmentMappingService} from 'src/app/api/models/doubtfire-model'; @@ -15,6 +15,7 @@ import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; selector: 'f-d2l-transfer', templateUrl: 'd2l-transfer.component.html', styleUrl: 'd2l-transfer.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class D2lTransferComponent implements OnInit { diff --git a/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.ts b/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.ts index 48a9bed310..54f33d479e 100644 --- a/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.ts +++ b/src/app/units/states/portfolios/directives/portfolios-assessment/portfolios-assessment.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Project} from 'src/app/api/models/project'; import {Unit} from 'src/app/api/models/unit'; @@ -6,6 +6,7 @@ import {Unit} from 'src/app/api/models/unit'; selector: 'f-portfolios-assessment', templateUrl: './portfolios-assessment.component.html', styleUrl: './portfolios-assessment.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PortfoliosAssessmentComponent { diff --git a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts index 36b7a1dc0b..a07840e7ba 100644 --- a/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts +++ b/src/app/units/states/portfolios/directives/portfolios-list/portfolios-list.component.ts @@ -1,5 +1,6 @@ import { AfterViewInit, + ChangeDetectionStrategy, Component, EventEmitter, Input, @@ -28,6 +29,7 @@ import {D2lTransferModal} from '../../d2l-transfer-modal/d2l-transfer.component' selector: 'f-portfolios-list', templateUrl: './portfolios-list.component.html', styleUrl: './portfolios-list.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PortfoliosListComponent implements OnChanges, AfterViewInit { diff --git a/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.ts b/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.ts index c7d0f4d066..53efce9faa 100644 --- a/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.ts +++ b/src/app/units/states/portfolios/directives/portfolios-portfolio-view/portfolios-portfolio-view.component.ts @@ -1,10 +1,11 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Project} from 'src/app/api/models/project'; @Component({ selector: 'f-portfolios-portfolio-view', templateUrl: './portfolios-portfolio-view.component.html', styleUrl: './portfolios-portfolio-view.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PortfoliosPortfolioViewComponent { diff --git a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts index 044245349b..b608d8937a 100644 --- a/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts +++ b/src/app/units/states/portfolios/directives/portfolios-project-progress/portfolios-project-progress.component.ts @@ -1,4 +1,11 @@ -import {Component, ElementRef, HostListener, Input, OnChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + ElementRef, + HostListener, + Input, + OnChanges, +} from '@angular/core'; import {BehaviorSubject} from 'rxjs'; import {Project} from 'src/app/api/models/project'; import {Unit} from 'src/app/api/models/unit'; @@ -11,6 +18,7 @@ import {GradeService} from 'src/app/common/services/grade.service'; selector: 'f-portfolios-project-progress', templateUrl: './portfolios-project-progress.component.html', styleUrl: './portfolios-project-progress.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PortfoliosProjectProgressComponent implements OnChanges { diff --git a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts index 93b802e44b..6c102ef91c 100644 --- a/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts +++ b/src/app/units/states/portfolios/download-staff-notes/download-staff-notes.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {Unit} from 'src/app/api/models/unit'; import {AlertService} from 'src/app/common/services/alert.service'; @@ -6,6 +6,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-download-staff-notes', templateUrl: 'download-staff-notes.component.html', styleUrl: 'download-staff-notes.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class DownloadStaffNotesComponent implements OnInit { diff --git a/src/app/units/states/portfolios/portfolios.component.ts b/src/app/units/states/portfolios/portfolios.component.ts index 7144b754d5..2f8ad67b63 100644 --- a/src/app/units/states/portfolios/portfolios.component.ts +++ b/src/app/units/states/portfolios/portfolios.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit} from '@angular/core'; import {MatTabChangeEvent} from '@angular/material/tabs'; import {ActivatedRoute, Router} from '@angular/router'; import {BehaviorSubject, Observable, Subscription, first, of} from 'rxjs'; @@ -19,6 +19,7 @@ interface PortfolioTab { selector: 'f-portfolios', templateUrl: './portfolios.component.html', styleUrl: './portfolios.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class PortfoliosComponent implements OnInit, OnDestroy { diff --git a/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts b/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts index d8d246cbb9..fe302d5415 100644 --- a/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts +++ b/src/app/units/states/portfolios/upload-grades/upload-grades.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; import {Unit} from 'src/app/api/models/unit'; import {CsvResultModalService} from 'src/app/common/modals/csv-result-modal/csv-result-modal.service'; @@ -10,6 +10,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-upload-grades', templateUrl: 'upload-grades.component.html', styleUrl: 'upload-grades.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UploadGradesComponent implements OnInit { diff --git a/src/app/units/states/rollover/rollover.component.html b/src/app/units/states/rollover/rollover.component.html index a6f4ed56f2..1ad9d9c595 100644 --- a/src/app/units/states/rollover/rollover.component.html +++ b/src/app/units/states/rollover/rollover.component.html @@ -40,11 +40,21 @@ } @else { {{ teachingPeriod.name }} Start Date - + {{ teachingPeriod.name }} End Date - + } diff --git a/src/app/units/states/rollover/rollover.component.ts b/src/app/units/states/rollover/rollover.component.ts index 80d2a6e69e..a9c255c5bd 100644 --- a/src/app/units/states/rollover/rollover.component.ts +++ b/src/app/units/states/rollover/rollover.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {TeachingPeriod} from 'src/app/api/models/teaching-period'; import {Unit} from 'src/app/api/models/unit'; @@ -11,6 +11,7 @@ import {GlobalStateService, ViewType} from 'src/app/projects/states/index/global selector: 'f-rollover', templateUrl: './rollover.component.html', styleUrl: './rollover.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class RolloverComponent implements OnInit { diff --git a/src/app/units/states/students-list/students-list.component.ts b/src/app/units/states/students-list/students-list.component.ts index 21a2345e2c..46b36bcde5 100644 --- a/src/app/units/states/students-list/students-list.component.ts +++ b/src/app/units/states/students-list/students-list.component.ts @@ -1,4 +1,12 @@ -import {AfterViewInit, Component, Input, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import { + AfterViewInit, + ChangeDetectionStrategy, + Component, + Input, + OnDestroy, + OnInit, + ViewChild, +} from '@angular/core'; import {MatPaginator} from '@angular/material/paginator'; import {MatSort, Sort} from '@angular/material/sort'; import {MatTableDataSource} from '@angular/material/table'; @@ -18,6 +26,7 @@ import {UnitStudentEnrolmentModalService} from '../../modals/unit-student-enrolm @Component({ selector: 'f-students-list', templateUrl: './students-list.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class StudentsListComponent implements OnInit, AfterViewInit, OnDestroy { diff --git a/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.html b/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.html index f7c4f017c9..756361487e 100644 --- a/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.html +++ b/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.html @@ -92,7 +92,9 @@ } @case (InboxDashboardTab.staffNotes) {
        - +
        } @case (InboxDashboardTab.tutorNotes) { diff --git a/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.ts b/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.ts index 6f81bf8311..701396d9f3 100644 --- a/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.ts +++ b/src/app/units/states/tasks/inbox/directives/inbox-dashboard/inbox-dashboard.component.ts @@ -1,4 +1,12 @@ -import {Component, EventEmitter, Input, OnChanges, Output, SimpleChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + EventEmitter, + Input, + OnChanges, + Output, + SimpleChanges, +} from '@angular/core'; import {MatTabChangeEvent} from '@angular/material/tabs'; import {UnitRole} from 'src/app/api/models/doubtfire-model'; import {Task} from 'src/app/api/models/task'; @@ -18,6 +26,7 @@ enum InboxDashboardTab { selector: 'f-inbox-dashboard', templateUrl: './inbox-dashboard.component.html', host: {'class': 'block h-full'}, + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class InboxDashboardComponent implements OnChanges { diff --git a/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.ts b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.ts index f1d562d4cd..abfd42c886 100644 --- a/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.ts +++ b/src/app/units/states/tasks/inbox/directives/moderation/confirm-moderation-modal/confirm-moderation-modal.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject, OnInit} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {FeedbackModerationActionType} from 'src/app/api/models/task'; import {Task} from 'src/app/api/models/task'; @@ -10,6 +10,7 @@ import {ConfirmModerationModalData} from './confirm-moderation-modal.service'; selector: 'f-confirm-moderation-modal', templateUrl: './confirm-moderation-modal.component.html', styleUrl: './confirm-moderation-modal.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ConfirmModerationModalComponent implements OnInit { diff --git a/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.ts b/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.ts index 761c0e4010..c1ae2b0225 100644 --- a/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.ts +++ b/src/app/units/states/tasks/inbox/directives/moderation/moderation.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Router} from '@angular/router'; import {FeedbackModerationActionType, Task} from 'src/app/api/models/task'; import {AlertService} from 'src/app/common/services/alert.service'; @@ -8,6 +8,7 @@ import {ConfirmModerationModalService} from './confirm-moderation-modal/confirm- selector: 'f-moderation', templateUrl: './moderation.component.html', styleUrl: './moderation.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ModerationComponent { diff --git a/src/app/units/states/tasks/inbox/directives/staff-task-list/batch-feedback-workflow-dialog/batch-feedback-workflow-dialog.component.ts b/src/app/units/states/tasks/inbox/directives/staff-task-list/batch-feedback-workflow-dialog/batch-feedback-workflow-dialog.component.ts index ae95e7e203..3ff4d4f302 100644 --- a/src/app/units/states/tasks/inbox/directives/staff-task-list/batch-feedback-workflow-dialog/batch-feedback-workflow-dialog.component.ts +++ b/src/app/units/states/tasks/inbox/directives/staff-task-list/batch-feedback-workflow-dialog/batch-feedback-workflow-dialog.component.ts @@ -1,4 +1,4 @@ -import {Component, Inject} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Inject} from '@angular/core'; import {MAT_DIALOG_DATA, MatDialogRef} from '@angular/material/dialog'; import {TaskDefinition, Unit} from 'src/app/api/models/doubtfire-model'; @@ -11,6 +11,7 @@ export interface BatchFeedbackWorkflowDialogData { @Component({ selector: 'f-batch-feedback-workflow-dialog', templateUrl: './batch-feedback-workflow-dialog.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class BatchFeedbackWorkflowDialogComponent { diff --git a/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.ts b/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.ts index d5fc369806..d27857003b 100644 --- a/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.ts +++ b/src/app/units/states/tasks/inbox/directives/staff-task-list/staff-task-list.component.ts @@ -1,6 +1,7 @@ /* eslint-disable no-shadow, @typescript-eslint/no-shadow */ import {HotkeysService} from '@ngneat/hotkeys'; import { + ChangeDetectionStrategy, Component, Input, OnChanges, @@ -42,6 +43,7 @@ import {BatchFeedbackWorkflowDialogComponent} from './batch-feedback-workflow-di selector: 'df-staff-task-list', templateUrl: './staff-task-list.component.html', styleUrls: ['./staff-task-list.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class StaffTaskListComponent implements OnInit, OnChanges, OnDestroy { diff --git a/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.ts b/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.ts index 2ef59dd69b..e79654c560 100644 --- a/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.ts +++ b/src/app/units/states/tasks/inbox/directives/task-claim/task-claim.component.ts @@ -1,4 +1,4 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {MatSnackBar} from '@angular/material/snack-bar'; import {Task} from 'src/app/api/models/task'; import {UnitRole} from 'src/app/api/models/unit-role'; @@ -10,6 +10,7 @@ import {AlertService} from 'src/app/common/services/alert.service'; selector: 'f-task-claim', templateUrl: './task-claim.component.html', styleUrl: './task-claim.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskClaimComponent { diff --git a/src/app/units/states/tasks/inbox/inbox.component.html b/src/app/units/states/tasks/inbox/inbox.component.html index 7dfe9338b0..1ad317db4e 100644 --- a/src/app/units/states/tasks/inbox/inbox.component.html +++ b/src/app/units/states/tasks/inbox/inbox.component.html @@ -73,7 +73,7 @@ } @else { } @@ -156,7 +156,7 @@

        {{ taskData?.selectedTask?.project.student.nickname }}

        } @else { } diff --git a/src/app/units/states/tasks/inbox/inbox.component.ts b/src/app/units/states/tasks/inbox/inbox.component.ts index 0964f06543..71924db971 100644 --- a/src/app/units/states/tasks/inbox/inbox.component.ts +++ b/src/app/units/states/tasks/inbox/inbox.component.ts @@ -1,7 +1,15 @@ import {HotkeysHelpComponent, HotkeysService} from '@ngneat/hotkeys'; import {MediaObserver} from 'ng-flex-layout'; import {CdkDragEnd, CdkDragMove, CdkDragStart} from '@angular/cdk/drag-drop'; -import {Component, ElementRef, Input, OnDestroy, OnInit, ViewChild} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + ElementRef, + Input, + OnDestroy, + OnInit, + ViewChild, +} from '@angular/core'; import {MatDialog} from '@angular/material/dialog'; import {Router} from '@angular/router'; import {Observable, Subject, auditTime, merge, of, tap, withLatestFrom} from 'rxjs'; @@ -19,6 +27,7 @@ import {SelectedTaskService} from 'src/app/projects/states/dashboard/selected-ta selector: 'f-inbox', templateUrl: './inbox.component.html', styleUrls: ['./inbox.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class InboxComponent implements OnInit, OnDestroy { diff --git a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts index 032fdcf4fc..05f22ae741 100644 --- a/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts +++ b/src/app/units/states/tasks/inbox/unit-task-inbox-state.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, OnDestroy, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnDestroy, OnInit} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {Observable, first, of, tap} from 'rxjs'; import { @@ -42,6 +42,7 @@ type TaskSource = ( @Component({ selector: 'f-unit-task-inbox-state', templateUrl: './unit-task-inbox-state.component.html', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitTaskInboxStateComponent implements OnInit, OnDestroy { diff --git a/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.ts b/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.ts index d593c2ad68..5360b13f58 100644 --- a/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.ts +++ b/src/app/units/task-viewer/directives/task-details-view/task-details-view.component.ts @@ -1,4 +1,4 @@ -import {Component, Input, signal} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, signal} from '@angular/core'; import {TaskDefinition} from 'src/app/api/models/task-definition'; import {Unit} from 'src/app/api/models/unit'; @@ -6,6 +6,7 @@ import {Unit} from 'src/app/api/models/unit'; selector: 'f-task-details-view', templateUrl: './task-details-view.component.html', styleUrls: ['./task-details-view.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class FTaskDetailsViewComponent { diff --git a/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.ts b/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.ts index 256db4968e..7f027aab91 100644 --- a/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.ts +++ b/src/app/units/task-viewer/directives/task-sheet-view/task-sheet-view.component.ts @@ -1,10 +1,11 @@ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {TaskDefinition} from 'src/app/api/models/task-definition'; @Component({ selector: 'f-task-sheet-view', templateUrl: './task-sheet-view.component.html', styleUrls: ['./task-sheet-view.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class FTaskSheetViewComponent { diff --git a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts index 19b0e9c736..0cb2ba0562 100644 --- a/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts +++ b/src/app/units/task-viewer/directives/unit-task-list/unit-task-list.component.ts @@ -1,4 +1,12 @@ -import {Component, HostBinding, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + HostBinding, + Input, + OnChanges, + OnInit, + SimpleChanges, +} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {BehaviorSubject} from 'rxjs'; import {Project, Task, TaskDefinition} from 'src/app/api/models/doubtfire-model'; @@ -9,6 +17,7 @@ import {TaskDefinitionNamePipe} from 'src/app/common/filters/task-definition-nam selector: 'f-unit-task-list', templateUrl: './unit-task-list.component.html', styleUrls: ['./unit-task-list.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class FUnitTaskListComponent implements OnChanges, OnInit { diff --git a/src/app/units/task-viewer/task-viewer-state.component.ts b/src/app/units/task-viewer/task-viewer-state.component.ts index edc089dfbc..36c6635f83 100644 --- a/src/app/units/task-viewer/task-viewer-state.component.ts +++ b/src/app/units/task-viewer/task-viewer-state.component.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import {Component, Input} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {ActivatedRoute, Router} from '@angular/router'; import {BehaviorSubject, Observable} from 'rxjs'; import {of} from 'rxjs'; @@ -9,6 +9,7 @@ import {TaskDefinition, Unit} from 'src/app/api/models/doubtfire-model'; selector: 'f-task-viewer-state', templateUrl: './task-viewer-state.component.html', styleUrl: './task-viewer-state.component.scss', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskViewerStateComponent { diff --git a/src/app/units/unit-root-state.component.ts b/src/app/units/unit-root-state.component.ts index f66a6d3bee..55feeecb27 100644 --- a/src/app/units/unit-root-state.component.ts +++ b/src/app/units/unit-root-state.component.ts @@ -1,5 +1,5 @@ /* eslint-disable @typescript-eslint/no-explicit-any */ -import {Component, Input, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {Observable} from 'rxjs'; import {Unit} from 'src/app/api/models/doubtfire-model'; @@ -8,6 +8,7 @@ import {Unit} from 'src/app/api/models/doubtfire-model'; selector: 'f-unit-root-state', templateUrl: './unit-root-state.component.html', styleUrl: './unit-root-state.component.css', + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class UnitRootStateComponent implements OnInit { diff --git a/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.ts b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.ts index b6e4835462..fd874e7c19 100644 --- a/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.ts +++ b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.ts @@ -1,5 +1,6 @@ import {formatDate} from '@angular/common'; import { + ChangeDetectionStrategy, Component, Input, LOCALE_ID, @@ -26,6 +27,7 @@ interface BurndownSeries { selector: 'f-progress-burndown-chart', templateUrl: './progress-burndown-chart.component.html', styleUrls: ['./progress-burndown-chart.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class ProgressBurndownChartComponent diff --git a/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.ts b/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.ts index c7fc6c6a1b..f2028a452b 100644 --- a/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.ts +++ b/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.ts @@ -1,4 +1,11 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + OnInit, + SimpleChanges, +} from '@angular/core'; import {Project, TaskStatus} from 'src/app/api/models/doubtfire-model'; import {ChartBaseComponent} from 'src/app/common/chart-base/chart-base-component/chart-base-component.component'; @@ -6,6 +13,7 @@ import {ChartBaseComponent} from 'src/app/common/chart-base/chart-base-component selector: 'f-task-status-pie-chart', templateUrl: './task-status-pie-chart.component.html', styleUrls: ['./task-status-pie-chart.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskStatusPieChartComponent extends ChartBaseComponent implements OnChanges, OnInit { diff --git a/src/app/visualisations/task-visualisation/task-visualisation.component.ts b/src/app/visualisations/task-visualisation/task-visualisation.component.ts index 74a6d92898..ba1dc1a54e 100644 --- a/src/app/visualisations/task-visualisation/task-visualisation.component.ts +++ b/src/app/visualisations/task-visualisation/task-visualisation.component.ts @@ -1,10 +1,18 @@ -import {Component, Input, OnChanges, OnInit, SimpleChanges} from '@angular/core'; +import { + ChangeDetectionStrategy, + Component, + Input, + OnChanges, + OnInit, + SimpleChanges, +} from '@angular/core'; import {Project, TaskStatus} from 'src/app/api/models/doubtfire-model'; @Component({ selector: 'f-task-visualisation', templateUrl: './task-visualisation.component.html', styleUrls: ['./task-visualisation.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class TaskVisualisationComponent implements OnChanges, OnInit { diff --git a/src/app/welcome/welcome.component.ts b/src/app/welcome/welcome.component.ts index 5abc2b4439..afa619b690 100644 --- a/src/app/welcome/welcome.component.ts +++ b/src/app/welcome/welcome.component.ts @@ -1,4 +1,4 @@ -import {Component, OnInit} from '@angular/core'; +import {ChangeDetectionStrategy, Component, OnInit} from '@angular/core'; import {Router} from '@angular/router'; import {AuthenticationService} from 'src/app/api/services/authentication.service'; import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; @@ -9,6 +9,7 @@ import {GlobalStateService} from '../projects/states/index/global-state.service' selector: 'f-welcome', templateUrl: './welcome.component.html', styleUrls: ['./welcome.component.scss'], + changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) export class WelcomeComponent implements OnInit { diff --git a/src/tsconfig.app.json b/src/tsconfig.app.json index 4e165072c4..c15174ae8c 100644 --- a/src/tsconfig.app.json +++ b/src/tsconfig.app.json @@ -5,5 +5,14 @@ "types": [] }, "files": ["main.ts", "polyfills.ts"], - "include": ["src/**/*.d.ts", "src/**/*.ts"] + "include": ["src/**/*.d.ts", "src/**/*.ts"], + "angularCompilerOptions": { + // TODO: Re-enable extendedDiagnostics after strictTempaltes is enabled + // "extendedDiagnostics": { + // "checks": { + // "nullishCoalescingNotNullable": "suppress", + // "optionalChainNotNullable": "suppress" + // } + // } + } } diff --git a/src/tsconfig.spec.json b/src/tsconfig.spec.json index 5fa6abff5f..8d291fc904 100644 --- a/src/tsconfig.spec.json +++ b/src/tsconfig.spec.json @@ -5,5 +5,13 @@ "typeRoots": ["../node_modules/@types", "../node_modules"], "types": ["vitest/globals", "node"] }, - "include": ["**/*.spec.ts", "**/*.d.ts", "vitest-setup.ts"] + "include": ["**/*.spec.ts", "**/*.d.ts", "vitest-setup.ts"], + "angularCompilerOptions": { + "extendedDiagnostics": { + "checks": { + "nullishCoalescingNotNullable": "suppress", + "optionalChainNotNullable": "suppress" + } + } + } } diff --git a/tsconfig.json b/tsconfig.json index 84230f0709..5a5fc3099e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,11 @@ { "compileOnSave": false, "compilerOptions": { + "ignoreDeprecations": "6.0", "baseUrl": "./", "importHelpers": true, "module": "es2020", + "rootDir": ".", "outDir": "./build", "sourceMap": true, "esModuleInterop": true, From e300ac043f199442e361235e5ba2affafe90decc Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:40:39 +1000 Subject: [PATCH 1133/1280] chore: upgrade material ui to 22 --- package-lock.json | 44 ++++++++++++++++++++++---------------------- package.json | 6 +++--- 2 files changed, 25 insertions(+), 25 deletions(-) diff --git a/package-lock.json b/package-lock.json index cf8a3ab19e..fc17ee8128 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,13 +10,13 @@ "license": "AGPL-3.0", "dependencies": { "@angular/animations": "^22.0.2", - "@angular/cdk": "^21.2.9", + "@angular/cdk": "^22.0.2", "@angular/common": "^22.0.2", "@angular/compiler": "^22.0.2", "@angular/core": "^22.0.2", "@angular/forms": "^22.0.2", - "@angular/material": "^21.2.9", - "@angular/material-date-fns-adapter": "^21.2.9", + "@angular/material": "^22.0.2", + "@angular/material-date-fns-adapter": "^22.0.2", "@angular/platform-browser": "^22.0.2", "@angular/platform-browser-dynamic": "^22.0.2", "@angular/router": "^22.0.2", @@ -1654,18 +1654,18 @@ } }, "node_modules/@angular/cdk": { - "version": "21.2.14", - "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-21.2.14.tgz", - "integrity": "sha512-806REq/CLf37nEhmmd8Q+ILN8z/RVG2vk2n8YZ/4TdHpcBCi5ux4AxLbpMmduLwGPOzPagJ6ggRzE5fnX0rmcQ==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/cdk/-/cdk-22.0.2.tgz", + "integrity": "sha512-3AOyLNIpvXkxbiCeUc4R5ubwCBpY83ZPe2I6Q/cTUW53SnFapEBNYZ2spSY+jPVY4IVPnQN1Tvjlzq6R9K4M3w==", "license": "MIT", "dependencies": { "parse5": "^8.0.0", "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/common": "^21.0.0 || ^22.0.0", - "@angular/core": "^21.0.0 || ^22.0.0", - "@angular/platform-browser": "^21.0.0 || ^22.0.0", + "@angular/common": "^22.0.0 || ^23.0.0", + "@angular/core": "^22.0.0 || ^23.0.0", + "@angular/platform-browser": "^22.0.0 || ^23.0.0", "rxjs": "^6.5.3 || ^7.4.0" } }, @@ -1940,33 +1940,33 @@ } }, "node_modules/@angular/material": { - "version": "21.2.14", - "resolved": "https://registry.npmjs.org/@angular/material/-/material-21.2.14.tgz", - "integrity": "sha512-fMQca8VRtei93JRRG9qQ+u08DCb0nga59Esoakq5yx3+A1NfdpFeUS1tBns56U04o8KAaIAwZK3NBqXz8ZKNqg==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/material/-/material-22.0.2.tgz", + "integrity": "sha512-a2sp9ipozR4THqu5A3ff3VXBpbQHpfTmH+Oqb0+RD47fJ+/kvyBUZQ5JK2Yh6eUXVceAOW4s+sL0ev8tS1EfuQ==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/cdk": "21.2.14", - "@angular/common": "^21.0.0 || ^22.0.0", - "@angular/core": "^21.0.0 || ^22.0.0", - "@angular/forms": "^21.0.0 || ^22.0.0", - "@angular/platform-browser": "^21.0.0 || ^22.0.0", + "@angular/cdk": "22.0.2", + "@angular/common": "^22.0.0 || ^23.0.0", + "@angular/core": "^22.0.0 || ^23.0.0", + "@angular/forms": "^22.0.0 || ^23.0.0", + "@angular/platform-browser": "^22.0.0 || ^23.0.0", "rxjs": "^6.5.3 || ^7.4.0" } }, "node_modules/@angular/material-date-fns-adapter": { - "version": "21.2.14", - "resolved": "https://registry.npmjs.org/@angular/material-date-fns-adapter/-/material-date-fns-adapter-21.2.14.tgz", - "integrity": "sha512-PvfX/Y+6ml8G+Zacgmp52nerI4fQmPtCKPDweUVA5Drm8Ygoo3zdVS9UnB+74KuH56I+AS5IZ8usJSwdV+z1UQ==", + "version": "22.0.2", + "resolved": "https://registry.npmjs.org/@angular/material-date-fns-adapter/-/material-date-fns-adapter-22.0.2.tgz", + "integrity": "sha512-xoxECE2NowCIT3GlKIfxFh8tvuaS4g7wV9wN9rbMH284SRITC1TavvhtFdLcCDrMafUvSxY/du441SBcBmOoKg==", "license": "MIT", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/core": "^21.0.0 || ^22.0.0", - "@angular/material": "21.2.14", + "@angular/core": "^22.0.0 || ^23.0.0", + "@angular/material": "22.0.2", "date-fns": ">2.20.0 <5.0" } }, diff --git a/package.json b/package.json index 3d849a4a55..452ebf402e 100644 --- a/package.json +++ b/package.json @@ -26,13 +26,13 @@ "author": "", "dependencies": { "@angular/animations": "^22.0.2", - "@angular/cdk": "^21.2.9", + "@angular/cdk": "^22.0.2", "@angular/common": "^22.0.2", "@angular/compiler": "^22.0.2", "@angular/core": "^22.0.2", "@angular/forms": "^22.0.2", - "@angular/material": "^21.2.9", - "@angular/material-date-fns-adapter": "^21.2.9", + "@angular/material": "^22.0.2", + "@angular/material-date-fns-adapter": "^22.0.2", "@angular/platform-browser": "^22.0.2", "@angular/platform-browser-dynamic": "^22.0.2", "@angular/router": "^22.0.2", From 886d9b7be89707c10e62f63b1f534b48dc832b8a Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:41:26 +1000 Subject: [PATCH 1134/1280] chore: upgrade angular eslint to 22 --- package-lock.json | 470 ++++++++++------------------------------------ package.json | 12 +- 2 files changed, 106 insertions(+), 376 deletions(-) diff --git a/package-lock.json b/package-lock.json index fc17ee8128..ec43a6471f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -68,11 +68,11 @@ "zone.js": "~0.16.2" }, "devDependencies": { - "@angular-eslint/builder": "^21.4.0", - "@angular-eslint/eslint-plugin": "^21.4.0", - "@angular-eslint/eslint-plugin-template": "^21.4.0", - "@angular-eslint/schematics": "^21.4.0", - "@angular-eslint/template-parser": "^21.4.0", + "@angular-eslint/builder": "^22.0.0", + "@angular-eslint/eslint-plugin": "^22.0.0", + "@angular-eslint/eslint-plugin-template": "^22.0.0", + "@angular-eslint/schematics": "^22.0.0", + "@angular-eslint/template-parser": "^22.0.0", "@angular/build": "^22.0.3", "@angular/cli": "^22.0.3", "@angular/compiler-cli": "^22.0.2", @@ -88,7 +88,7 @@ "@types/node": "^20.9.0", "@typescript-eslint/eslint-plugin": "^8.60.1", "@typescript-eslint/parser": "^8.60.1", - "angular-eslint": "^21.4.0", + "angular-eslint": "^22.0.0", "autoprefixer": "~6", "canonical-path": "0.0.2", "concurrently": "^3.2.0", @@ -360,32 +360,32 @@ } }, "node_modules/@angular-devkit/architect": { - "version": "0.2102.15", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2102.15.tgz", - "integrity": "sha512-EZQXu6j7J7OUxmpxIO2mxd58NTlCb7HOAOfLLGdk7lRcwZeCxnjGRzb72tXlJgIEi3IoOYwcW0ft2cg7r/d6qA==", + "version": "0.2200.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2200.3.tgz", + "integrity": "sha512-Ru+ucNkTZr98gmeaBYjq3zZwh32yGofAeB8+GJL/ZNy0x+7NzK6b+OatdzwT4l7mCWFC5vL8iYu0B4++M66Jpg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.15", + "@angular-devkit/core": "22.0.3", "rxjs": "7.8.2" }, "bin": { "architect": "bin/cli.js" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" } }, "node_modules/@angular-devkit/core": { - "version": "21.2.15", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-21.2.15.tgz", - "integrity": "sha512-x7EwuQtMGHANVznHpwyEi/3lMo/kRoaxV2w7lXbRGjTezwv4SPaOBwhrIGCbAVFs5B1ziff4jZzors4owlCTgg==", + "version": "22.0.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-22.0.3.tgz", + "integrity": "sha512-pBjo1JKwI8GbNdTo/Z0g+ZekqlTBCJWmzIC5fgGW9q5eRjl1y+5N5jlX8UAyyMCeUTTwsfpQdkAM2jyi/jcvjA==", "dev": true, "license": "MIT", "dependencies": { - "ajv": "8.18.0", + "ajv": "8.20.0", "ajv-formats": "3.0.1", "jsonc-parser": "3.3.1", "picomatch": "4.0.4", @@ -393,7 +393,7 @@ "source-map": "0.7.6" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" }, @@ -407,130 +407,143 @@ } }, "node_modules/@angular-devkit/schematics": { - "version": "21.2.15", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-21.2.15.tgz", - "integrity": "sha512-kHHV694KUPuXlItjvnxUspn+KYjlTKu8KINX/kT1qlogzLYojpnRwcUtZyRPUz1f/M1d3TUHVFeBKx+h5HoNcA==", + "version": "22.0.3", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-22.0.3.tgz", + "integrity": "sha512-aIp5sQDHdhyLbeVJF/k3w079XhW91mNAo2OliZllBCjoYhkIXNnWECOx5y2nXtCChyFJA2+ZgNST7NIDvtz1/w==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": "21.2.15", + "@angular-devkit/core": "22.0.3", "jsonc-parser": "3.3.1", "magic-string": "0.30.21", - "ora": "9.3.0", + "ora": "9.4.0", "rxjs": "7.8.2" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0", + "node": "^22.22.3 || ^24.15.0 || >=26.0.0", "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", "yarn": ">= 1.13.0" } }, "node_modules/@angular-eslint/builder": { - "version": "21.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-21.4.0.tgz", - "integrity": "sha512-3kgGmrVaCYbLtDjC8g4BmMBbdz4thsOB8/NYly8JtXM8EuDZEk5Pz6VTRpJR02ARprwayraTTmhyvq6OGBlQ9w==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/builder/-/builder-22.0.0.tgz", + "integrity": "sha512-T2vWQYUhJs6iUlgocHV12OgoxbmN63f17a+tgW+3sYrKN0KAB3xuHsPOoYpRYoWqkVVC44HD441Ju4IDvo8vKg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/architect": ">= 0.2100.0 < 0.2200.0", - "@angular-devkit/core": ">= 21.0.0 < 22.0.0" + "@angular-devkit/architect": ">= 0.2200.0 < 0.2300.0", + "@angular-devkit/core": ">= 22.0.0 < 23.0.0" }, "peerDependencies": { - "@angular/cli": ">= 21.0.0 < 22.0.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "@angular/cli": ">= 22.0.0 < 23.0.0", + "eslint": "^9.0.0 || ^10.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/bundled-angular-compiler": { - "version": "21.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-21.4.0.tgz", - "integrity": "sha512-/3H4BPbQ1BHJkkrUsfusZtmHc+qiFWBBZ9UDPWah4xZMjflexOK9U4GYeH7nMjcuyqFnIlMMeJJNwNLGt/hmdg==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/bundled-angular-compiler/-/bundled-angular-compiler-22.0.0.tgz", + "integrity": "sha512-rv15vGDpGW8zZFaLdhQ+iIO1f0bZds/xvuxoX277hFisXp5Kt6FumJNNIb4g/qxq3xsY46a7fD6R7KvGY3smHg==", "dev": true, "license": "MIT" }, "node_modules/@angular-eslint/eslint-plugin": { - "version": "21.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-21.4.0.tgz", - "integrity": "sha512-mow2DMj+xBvGl5t7jzC34R8YfbHbaGNyCNFzpovtl9qc0JbuqLyg6htmt8xb05f8ZjATOr4nz0ESt6HV4c51hw==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin/-/eslint-plugin-22.0.0.tgz", + "integrity": "sha512-mKLScPZhqG64ic0KIQoxqSqCdkPwtEZuTOuunvc9lYTw05MJSHRUM2yVFODlCGq97c6BN1F6KBk2I+a+KFnr1g==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "21.4.0", - "@angular-eslint/utils": "21.4.0", + "@angular-eslint/bundled-angular-compiler": "22.0.0", + "@angular-eslint/utils": "22.0.0", "ts-api-utils": "^2.1.0" }, "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "@typescript-eslint/utils": "^8.0.0", + "eslint": "^9.0.0 || ^10.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/eslint-plugin-template": { - "version": "21.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-21.4.0.tgz", - "integrity": "sha512-sJEHx2WYnvOgPpzP1eHnUdRS06zgKmRxbiIR0JiCcaSen5iv1HlsMieXy//FS9TtNW+abHOy4UtDuGuSPflPFA==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/eslint-plugin-template/-/eslint-plugin-template-22.0.0.tgz", + "integrity": "sha512-y6XL5HJ8C31NpBvkVHpU3bWc+Rk9g1zRtHrs39omhuT29eEUcS3zu47HMFV6tf8rHOI97B2Mstg6qYS5XL9ATg==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "21.4.0", - "@angular-eslint/utils": "21.4.0", + "@angular-eslint/bundled-angular-compiler": "22.0.0", + "@angular-eslint/utils": "22.0.0", "aria-query": "5.3.2", "axobject-query": "4.1.0" }, "peerDependencies": { - "@angular-eslint/template-parser": "21.4.0", - "@typescript-eslint/types": "^7.11.0 || ^8.0.0", - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "@angular-eslint/template-parser": "22.0.0", + "@typescript-eslint/types": "^8.0.0", + "@typescript-eslint/utils": "^8.0.0", + "eslint": "^9.0.0 || ^10.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/schematics": { - "version": "21.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-21.4.0.tgz", - "integrity": "sha512-crD6Hfxs7x5bN9FCqTZI7uVSiGvprfCS3MCPOpyIQl87bRr/9aNhnicJ3ROUHv+2A713BgPHIgiCII/bxzrfPw==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/schematics/-/schematics-22.0.0.tgz", + "integrity": "sha512-gsJQx6c+WIWC5d+NAqn4rRdUzwhinUCTNmCM9x4wygV9DrbAfVG+6OFPEbaDMryNvf0HYDcnGclbIbXjukGCaw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": ">= 21.0.0 < 22.0.0", - "@angular-devkit/schematics": ">= 21.0.0 < 22.0.0", - "@angular-eslint/eslint-plugin": "21.4.0", - "@angular-eslint/eslint-plugin-template": "21.4.0", + "@angular-devkit/core": ">= 22.0.0 < 23.0.0", + "@angular-devkit/schematics": ">= 22.0.0 < 23.0.0", + "@angular-eslint/eslint-plugin": "22.0.0", + "@angular-eslint/eslint-plugin-template": "22.0.0", "ignore": "7.0.5", - "semver": "7.7.4", + "semver": "7.8.0", "strip-json-comments": "3.1.1" }, "peerDependencies": { - "@angular/cli": ">= 21.0.0 < 22.0.0" + "@angular/cli": ">= 22.0.0 < 23.0.0" + } + }, + "node_modules/@angular-eslint/schematics/node_modules/semver": { + "version": "7.8.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.0.tgz", + "integrity": "sha512-AcM7dV/5ul4EekoQ29Agm5vri8JNqRyj39o0qpX6vDF2GZrtutZl5RwgD1XnZjiTAfncsJhMI48QQH3sN87YNA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" } }, "node_modules/@angular-eslint/template-parser": { - "version": "21.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-21.4.0.tgz", - "integrity": "sha512-BaUSLSyS+43fzDoJkTMkGqNdCXq3fGnUZsfXTmrlZPJf5AYFbgAlAPGZXDJyoNWw43fux+DafdlrlKcYUSgSIw==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-22.0.0.tgz", + "integrity": "sha512-jU5MKQ24bBB4J99gSSexmUrLm2LvTJZCuCHhNTQ1LavWX4e1lrIxhm+6pJILOm6Cixf8jyNXnHMty6nljX8J+Q==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "21.4.0", + "@angular-eslint/bundled-angular-compiler": "22.0.0", "eslint-scope": "9.1.2" }, "peerDependencies": { - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "eslint": "^9.0.0 || ^10.0.0", "typescript": "*" } }, "node_modules/@angular-eslint/utils": { - "version": "21.4.0", - "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-21.4.0.tgz", - "integrity": "sha512-7pi+Ga7QmdH5Ig/diau6fR5L4yubgKr9TOjdCg7OeuE/zo0O3osTCNT6JOodzS/iQM1kSCJFDoIBKFeUOttiNw==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/@angular-eslint/utils/-/utils-22.0.0.tgz", + "integrity": "sha512-VFodMojghnPYm+B3U+HRYrqebPMj8NyobNjVzDdY8V5XIBW+4ivOSEINIz81G48rmm/NZKwj56+bJ88bVX4KIw==", "dev": true, "license": "MIT", "dependencies": { - "@angular-eslint/bundled-angular-compiler": "21.4.0" + "@angular-eslint/bundled-angular-compiler": "22.0.0" }, "peerDependencies": { - "@typescript-eslint/utils": "^7.11.0 || ^8.0.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "@typescript-eslint/utils": "^8.0.0", + "eslint": "^9.0.0 || ^10.0.0", "typescript": "*" } }, @@ -652,53 +665,6 @@ } } }, - "node_modules/@angular/build/node_modules/@angular-devkit/architect": { - "version": "0.2200.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2200.3.tgz", - "integrity": "sha512-Ru+ucNkTZr98gmeaBYjq3zZwh32yGofAeB8+GJL/ZNy0x+7NzK6b+OatdzwT4l7mCWFC5vL8iYu0B4++M66Jpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "22.0.3", - "rxjs": "7.8.2" - }, - "bin": { - "architect": "bin/cli.js" - }, - "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular/build/node_modules/@angular-devkit/core": { - "version": "22.0.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-22.0.3.tgz", - "integrity": "sha512-pBjo1JKwI8GbNdTo/Z0g+ZekqlTBCJWmzIC5fgGW9q5eRjl1y+5N5jlX8UAyyMCeUTTwsfpQdkAM2jyi/jcvjA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.20.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.4", - "rxjs": "7.8.2", - "source-map": "0.7.6" - }, - "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^5.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, "node_modules/@angular/build/node_modules/@esbuild/aix-ppc64": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.1.tgz", @@ -1498,23 +1464,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@angular/build/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, "node_modules/@angular/build/node_modules/esbuild": { "version": "0.28.1", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.1.tgz", @@ -1704,125 +1653,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@angular/cli/node_modules/@angular-devkit/architect": { - "version": "0.2200.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.2200.3.tgz", - "integrity": "sha512-Ru+ucNkTZr98gmeaBYjq3zZwh32yGofAeB8+GJL/ZNy0x+7NzK6b+OatdzwT4l7mCWFC5vL8iYu0B4++M66Jpg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "22.0.3", - "rxjs": "7.8.2" - }, - "bin": { - "architect": "bin/cli.js" - }, - "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular/cli/node_modules/@angular-devkit/core": { - "version": "22.0.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-22.0.3.tgz", - "integrity": "sha512-pBjo1JKwI8GbNdTo/Z0g+ZekqlTBCJWmzIC5fgGW9q5eRjl1y+5N5jlX8UAyyMCeUTTwsfpQdkAM2jyi/jcvjA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.20.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.4", - "rxjs": "7.8.2", - "source-map": "0.7.6" - }, - "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^5.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@angular/cli/node_modules/@angular-devkit/schematics": { - "version": "22.0.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-22.0.3.tgz", - "integrity": "sha512-aIp5sQDHdhyLbeVJF/k3w079XhW91mNAo2OliZllBCjoYhkIXNnWECOx5y2nXtCChyFJA2+ZgNST7NIDvtz1/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "22.0.3", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.21", - "ora": "9.4.0", - "rxjs": "7.8.2" - }, - "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@angular/cli/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@angular/cli/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@angular/cli/node_modules/ora": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-9.4.0.tgz", - "integrity": "sha512-84cglkRILFxdtA8hAvLNdMrtBpPNBTrQ9/ulg0FA7xLMnD6mifv+enAIeRmvtv+WgdCE+LPGOfQmtJRrVaIVhQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^5.6.2", - "cli-cursor": "^5.0.0", - "cli-spinners": "^3.2.0", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.1.0", - "log-symbols": "^7.0.1", - "stdin-discarder": "^0.3.2", - "string-width": "^8.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@angular/common": { "version": "22.0.2", "resolved": "https://registry.npmjs.org/@angular/common/-/common-22.0.2.tgz", @@ -6082,106 +5912,6 @@ "yarn": ">= 1.13.0" } }, - "node_modules/@schematics/angular/node_modules/@angular-devkit/core": { - "version": "22.0.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-22.0.3.tgz", - "integrity": "sha512-pBjo1JKwI8GbNdTo/Z0g+ZekqlTBCJWmzIC5fgGW9q5eRjl1y+5N5jlX8UAyyMCeUTTwsfpQdkAM2jyi/jcvjA==", - "dev": true, - "license": "MIT", - "dependencies": { - "ajv": "8.20.0", - "ajv-formats": "3.0.1", - "jsonc-parser": "3.3.1", - "picomatch": "4.0.4", - "rxjs": "7.8.2", - "source-map": "0.7.6" - }, - "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - }, - "peerDependencies": { - "chokidar": "^5.0.0" - }, - "peerDependenciesMeta": { - "chokidar": { - "optional": true - } - } - }, - "node_modules/@schematics/angular/node_modules/@angular-devkit/schematics": { - "version": "22.0.3", - "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-22.0.3.tgz", - "integrity": "sha512-aIp5sQDHdhyLbeVJF/k3w079XhW91mNAo2OliZllBCjoYhkIXNnWECOx5y2nXtCChyFJA2+ZgNST7NIDvtz1/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "@angular-devkit/core": "22.0.3", - "jsonc-parser": "3.3.1", - "magic-string": "0.30.21", - "ora": "9.4.0", - "rxjs": "7.8.2" - }, - "engines": { - "node": "^22.22.3 || ^24.15.0 || >=26.0.0", - "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", - "yarn": ">= 1.13.0" - } - }, - "node_modules/@schematics/angular/node_modules/ajv": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", - "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", - "dev": true, - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@schematics/angular/node_modules/chalk": { - "version": "5.6.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", - "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "^12.17.0 || ^14.13 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/@schematics/angular/node_modules/ora": { - "version": "9.4.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-9.4.0.tgz", - "integrity": "sha512-84cglkRILFxdtA8hAvLNdMrtBpPNBTrQ9/ulg0FA7xLMnD6mifv+enAIeRmvtv+WgdCE+LPGOfQmtJRrVaIVhQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^5.6.2", - "cli-cursor": "^5.0.0", - "cli-spinners": "^3.2.0", - "is-interactive": "^2.0.0", - "is-unicode-supported": "^2.1.0", - "log-symbols": "^7.0.1", - "stdin-discarder": "^0.3.2", - "string-width": "^8.1.0" - }, - "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/@sigstore/bundle": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-4.0.0.tgz", @@ -7077,9 +6807,9 @@ } }, "node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", "dev": true, "license": "MIT", "dependencies": { @@ -7185,25 +6915,25 @@ } }, "node_modules/angular-eslint": { - "version": "21.4.0", - "resolved": "https://registry.npmjs.org/angular-eslint/-/angular-eslint-21.4.0.tgz", - "integrity": "sha512-LH7bWmtJvsubzwPoztnl1pWgI5X0VrfGTUITGSYcwn2J+SXuN/avzrKrxJmhUiIrNvLtfV+18GG6xZS1IGZdKg==", + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/angular-eslint/-/angular-eslint-22.0.0.tgz", + "integrity": "sha512-6tHLndzM6rU+2iuICakJS/hD1scK5sWLkcD7828zStT1ViA9zX8z9g/V1IlBiKEdZeMsl+m7K2DlNc34AkYyoQ==", "dev": true, "license": "MIT", "dependencies": { - "@angular-devkit/core": ">= 21.0.0 < 22.0.0", - "@angular-devkit/schematics": ">= 21.0.0 < 22.0.0", - "@angular-eslint/builder": "21.4.0", - "@angular-eslint/eslint-plugin": "21.4.0", - "@angular-eslint/eslint-plugin-template": "21.4.0", - "@angular-eslint/schematics": "21.4.0", - "@angular-eslint/template-parser": "21.4.0", + "@angular-devkit/core": ">= 22.0.0 < 23.0.0", + "@angular-devkit/schematics": ">= 22.0.0 < 23.0.0", + "@angular-eslint/builder": "22.0.0", + "@angular-eslint/eslint-plugin": "22.0.0", + "@angular-eslint/eslint-plugin-template": "22.0.0", + "@angular-eslint/schematics": "22.0.0", + "@angular-eslint/template-parser": "22.0.0", "@typescript-eslint/types": "^8.0.0", "@typescript-eslint/utils": "^8.0.0" }, "peerDependencies": { - "@angular/cli": ">= 21.0.0 < 22.0.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", + "@angular/cli": ">= 22.0.0 < 23.0.0", + "eslint": "^9.0.0 || ^10.0.0", "typescript": "*", "typescript-eslint": "^8.0.0" } @@ -13708,9 +13438,9 @@ } }, "node_modules/ora": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/ora/-/ora-9.3.0.tgz", - "integrity": "sha512-lBX72MWFduWEf7v7uWf5DHp9Jn5BI8bNPGuFgtXMmr2uDz2Gz2749y3am3agSDdkhHPHYmmxEGSKH85ZLGzgXw==", + "version": "9.4.0", + "resolved": "https://registry.npmjs.org/ora/-/ora-9.4.0.tgz", + "integrity": "sha512-84cglkRILFxdtA8hAvLNdMrtBpPNBTrQ9/ulg0FA7xLMnD6mifv+enAIeRmvtv+WgdCE+LPGOfQmtJRrVaIVhQ==", "dev": true, "license": "MIT", "dependencies": { @@ -13720,7 +13450,7 @@ "is-interactive": "^2.0.0", "is-unicode-supported": "^2.1.0", "log-symbols": "^7.0.1", - "stdin-discarder": "^0.3.1", + "stdin-discarder": "^0.3.2", "string-width": "^8.1.0" }, "engines": { diff --git a/package.json b/package.json index 452ebf402e..5add687337 100644 --- a/package.json +++ b/package.json @@ -84,11 +84,11 @@ "zone.js": "~0.16.2" }, "devDependencies": { - "@angular-eslint/builder": "^21.4.0", - "@angular-eslint/eslint-plugin": "^21.4.0", - "@angular-eslint/eslint-plugin-template": "^21.4.0", - "@angular-eslint/schematics": "^21.4.0", - "@angular-eslint/template-parser": "^21.4.0", + "@angular-eslint/builder": "^22.0.0", + "@angular-eslint/eslint-plugin": "^22.0.0", + "@angular-eslint/eslint-plugin-template": "^22.0.0", + "@angular-eslint/schematics": "^22.0.0", + "@angular-eslint/template-parser": "^22.0.0", "@angular/build": "^22.0.3", "@angular/cli": "^22.0.3", "@angular/compiler-cli": "^22.0.2", @@ -104,7 +104,7 @@ "@types/node": "^20.9.0", "@typescript-eslint/eslint-plugin": "^8.60.1", "@typescript-eslint/parser": "^8.60.1", - "angular-eslint": "^21.4.0", + "angular-eslint": "^22.0.0", "autoprefixer": "~6", "canonical-path": "0.0.2", "concurrently": "^3.2.0", From e2b718c1aed4f8ea3746a6f0f0622ebc7af6f8b4 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 12:54:51 +1000 Subject: [PATCH 1135/1280] chore: suppress change detection eager warnings --- eslint.config.js | 1 + .../directives/student-task-list/student-task-list.component.ts | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/eslint.config.js b/eslint.config.js index f724f8a890..c30806bfe0 100644 --- a/eslint.config.js +++ b/eslint.config.js @@ -61,6 +61,7 @@ module.exports = tseslint.config( '@angular-eslint/prefer-standalone': 'off', '@typescript-eslint/consistent-generic-constructors': ['error', 'type-annotation'], '@typescript-eslint/no-inferrable-types': 'off', + '@angular-eslint/prefer-on-push-component-change-detection': 'off', '@typescript-eslint/no-unused-vars': [ 'error', { diff --git a/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.component.ts b/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.component.ts index fae6805595..a4bd5296cd 100644 --- a/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.component.ts +++ b/src/app/projects/states/dashboard/directives/student-task-list/student-task-list.component.ts @@ -6,6 +6,6 @@ import {ChangeDetectionStrategy, Component} from '@angular/core'; imports: [], templateUrl: './student-task-list.component.html', styleUrl: './student-task-list.component.css', - changeDetection: ChangeDetectionStrategy.OnPush, + changeDetection: ChangeDetectionStrategy.Eager, }) export class StudentTaskListComponent {} From ec4bab9719e12e5ceffb74f4b2f9f44713c70ff0 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:19:03 +1000 Subject: [PATCH 1136/1280] chore: update packages --- package-lock.json | 28 ++++++++++++++-------------- package.json | 4 ++-- src/app/doubtfire-angular.module.ts | 3 ++- 3 files changed, 18 insertions(+), 17 deletions(-) diff --git a/package-lock.json b/package-lock.json index ec43a6471f..c4272051da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -54,9 +54,9 @@ "ng-file-upload": "~5.0.9", "ng-flex-layout": "^17.3.7-beta.1", "ng2-pdf-viewer": "10.2.2", - "ngx-entity-service": "^0.0.43", + "ngx-entity-service": "^0.0.44", "ngx-lottie": "^21.2.0", - "ngx-monaco-editor-v2": "^21", + "ngx-monaco-editor-v2-alternative": "^22.0.0", "ngx-skeleton-loader": "^12.0.0", "nvd3": "1.8.6", "qrcode": "^1.5.4", @@ -12859,15 +12859,15 @@ } }, "node_modules/ngx-entity-service": { - "version": "0.0.43", - "resolved": "https://registry.npmjs.org/ngx-entity-service/-/ngx-entity-service-0.0.43.tgz", - "integrity": "sha512-O77ZIu3822bKsiL8nBpj+4DW5q6V53URO5iiAojYVwITdd2zFmsiOZjgrYUEjEAIT7B+o5sDKvpzROZ1CS33OQ==", + "version": "0.0.44", + "resolved": "https://registry.npmjs.org/ngx-entity-service/-/ngx-entity-service-0.0.44.tgz", + "integrity": "sha512-FmSYKulHJxILKzLkBhXjNJsMdd55Slu11/TLg89GJZq3guBBD8RDsxHtbN1mKku5+Dp8i8H6vNSqJ3bwsyYwVw==", "dependencies": { "tslib": "^2.3.0" }, "peerDependencies": { - "@angular/common": "^13.0 || ^14.0 || ^15.0 || ^16.0 || ^17 || ^18 || ^19 || ^20 || ^21", - "@angular/core": "^13.0 || ^14.0 || ^15.0 || ^16.0 || ^17 || ^18 || ^19 || ^20 || ^21" + "@angular/common": "^13.0 || ^14.0 || ^15.0 || ^16.0 || ^17 || ^18 || ^19 || ^20 || ^21 || ^22", + "@angular/core": "^13.0 || ^14.0 || ^15.0 || ^16.0 || ^17 || ^18 || ^19 || ^20 || ^21 || ^22" } }, "node_modules/ngx-lottie": { @@ -12884,17 +12884,17 @@ "lottie-web": ">=5.9.2" } }, - "node_modules/ngx-monaco-editor-v2": { - "version": "21.1.4", - "resolved": "https://registry.npmjs.org/ngx-monaco-editor-v2/-/ngx-monaco-editor-v2-21.1.4.tgz", - "integrity": "sha512-dZu3dY3D1YXPTIDRn9zOERdtDtGy1SOztpWG6gJlaj6NMSV59kNR/hfzaP+L3BukP6Ve07f3bIyvsx6Pz7uOaA==", + "node_modules/ngx-monaco-editor-v2-alternative": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/ngx-monaco-editor-v2-alternative/-/ngx-monaco-editor-v2-alternative-22.0.0.tgz", + "integrity": "sha512-JB5eSWdtDhJF5hhuDUQQyABfx+1JHHWFwvhdn/R74twxE2NcCODWqgPFNKYLZhWKiPIG/w6TlpsyfS68wRNw0g==", "license": "MIT", "dependencies": { - "tslib": "^2.8.1" + "tslib": "^2.4.0" }, "peerDependencies": { - "@angular/common": "^21.1.4", - "@angular/core": "^21.1.4", + "@angular/common": "^22.0.0", + "@angular/core": "^22.0.0", "monaco-editor": "^0.55.1" } }, diff --git a/package.json b/package.json index 5add687337..21049bd0a4 100644 --- a/package.json +++ b/package.json @@ -70,9 +70,9 @@ "ng-file-upload": "~5.0.9", "ng-flex-layout": "^17.3.7-beta.1", "ng2-pdf-viewer": "10.2.2", - "ngx-entity-service": "^0.0.43", + "ngx-entity-service": "^0.0.44", "ngx-lottie": "^21.2.0", - "ngx-monaco-editor-v2": "^21", + "ngx-monaco-editor-v2-alternative": "^22.0.0", "ngx-skeleton-loader": "^12.0.0", "nvd3": "1.8.6", "qrcode": "^1.5.4", diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index f64afd172d..27c6b54932 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -19,7 +19,8 @@ import player from 'lottie-web'; import {PdfViewerModule} from 'ng2-pdf-viewer'; import {FlexLayoutModule} from 'ng-flex-layout'; import {LottieComponent, provideLottieOptions} from 'ngx-lottie'; -import {MonacoEditorModule} from 'ngx-monaco-editor-v2'; +// TODO: replace back to original ngx-monaco-editor-v2 once it supports angular 22 +import {MonacoEditorModule} from 'ngx-monaco-editor-v2-alternative'; import {NgxSkeletonLoaderModule} from 'ngx-skeleton-loader'; import {environment} from 'src/environments/environment'; // import {GradeTaskModalComponent} from './tasks/modals/grade-task-modal/grade-task-modal.component'; From 1d228d5f01ec712761dafbafb6d6bbfa2aa5be75 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:20:19 +1000 Subject: [PATCH 1137/1280] ci: use node 22 --- .github/workflows/lint.yml | 2 +- .github/workflows/nodejs-ci.yml | 2 +- .github/workflows/test.yml | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 42e81cb2d1..953c8b8fa9 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -10,7 +10,7 @@ jobs: strategy: matrix: - node-version: [20] + node-version: [22] steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/nodejs-ci.yml b/.github/workflows/nodejs-ci.yml index ea2b1cd81c..c2f9f1a4ef 100644 --- a/.github/workflows/nodejs-ci.yml +++ b/.github/workflows/nodejs-ci.yml @@ -13,7 +13,7 @@ jobs: strategy: matrix: - node-version: [20] + node-version: [22] steps: - uses: actions/checkout@v4 - uses: browser-actions/setup-chrome@latest diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 5a5dc93556..a8da82c7e4 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -10,10 +10,10 @@ jobs: steps: - uses: actions/checkout@v4 - - name: Use Node.js 20 + - name: Use Node.js 22 uses: actions/setup-node@v4 with: - node-version: 20 + node-version: 22 cache: npm - run: npm ci - run: npm run test:ci From f9357bbb5646f4ce57007dd1b4d139775badb02f Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:20:50 +1000 Subject: [PATCH 1138/1280] build: use node 22 --- Dockerfile | 2 +- deploy.Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 18590c09e9..0a0b3f0c7c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20 +FROM node:22 ENV DEBIAN_FRONTEND noninteractive ENV USER=node diff --git a/deploy.Dockerfile b/deploy.Dockerfile index 9aa69355e3..f39e326af0 100644 --- a/deploy.Dockerfile +++ b/deploy.Dockerfile @@ -1,5 +1,5 @@ ### STAGE 1: Build ### -FROM node:20 AS build +FROM node:22 AS build USER node From 6790339fcbef96f4bc9664998fa2f2b9b8fcdb61 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:23:29 +1000 Subject: [PATCH 1139/1280] chore: update deps --- .tool-versions | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.tool-versions b/.tool-versions index c2ca3d3d25..42bb250e67 100644 --- a/.tool-versions +++ b/.tool-versions @@ -1 +1 @@ -nodejs 20.9.0 +nodejs 22.22.3 From 4d02701447bf68b78d3c05631bf92a94ec0d2c92 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:25:51 +1000 Subject: [PATCH 1140/1280] ci: update packages to support node 22 --- .github/workflows/deployment.yml | 10 +++++----- .github/workflows/lint.yml | 4 ++-- .github/workflows/nodejs-ci.yml | 6 +++--- .github/workflows/test.yml | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/.github/workflows/deployment.yml b/.github/workflows/deployment.yml index 40d35b9eee..6c986fcff7 100644 --- a/.github/workflows/deployment.yml +++ b/.github/workflows/deployment.yml @@ -50,20 +50,20 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: submodules: recursive - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@v4 - name: Login to DockerHub - uses: docker/login-action@v3 + uses: docker/login-action@v4 if: github.event_name != 'pull_request' with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - name: Setup meta for web server id: docker_meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@v6 with: images: lmsdoubtfire/doubtfire-web tags: | @@ -74,7 +74,7 @@ jobs: type=semver,pattern=prod-{{major}} - name: Build and push web server id: docker_build - uses: docker/build-push-action@v5 + uses: docker/build-push-action@v7 with: file: deploy.Dockerfile context: . diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 953c8b8fa9..a6e94362b6 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -13,9 +13,9 @@ jobs: node-version: [22] steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: ${{ matrix.node-version }} - run: npm ci diff --git a/.github/workflows/nodejs-ci.yml b/.github/workflows/nodejs-ci.yml index c2f9f1a4ef..df3f516514 100644 --- a/.github/workflows/nodejs-ci.yml +++ b/.github/workflows/nodejs-ci.yml @@ -15,10 +15,10 @@ jobs: matrix: node-version: [22] steps: - - uses: actions/checkout@v4 - - uses: browser-actions/setup-chrome@latest + - uses: actions/checkout@v6 + - uses: browser-actions/setup-chrome@v2 - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: ${{ matrix.node-version }} - run: npm ci diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index a8da82c7e4..0254469205 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,9 +9,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v6 - name: Use Node.js 22 - uses: actions/setup-node@v4 + uses: actions/setup-node@v5 with: node-version: 22 cache: npm From 20d610e16c2cf106abc713ade05cb69432cfbc50 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:43:10 +1000 Subject: [PATCH 1141/1280] chore: hotfix tooltip errors --- .../chart-base-component.component.ts | 7 +---- .../project-progress-gauge.component.html | 1 + .../project-progress-gauge.component.ts | 25 ++-------------- .../analytics-tutor-times.component.html | 30 +++++++++++++++---- .../analytics-tutor-times.component.scss | 15 ++++++++++ .../analytics-tutor-times.component.ts | 11 +++++++ .../progress-burndown-chart.component.html | 1 + .../task-status-pie-chart.component.html | 1 + 8 files changed, 56 insertions(+), 35 deletions(-) diff --git a/src/app/common/chart-base/chart-base-component/chart-base-component.component.ts b/src/app/common/chart-base/chart-base-component/chart-base-component.component.ts index e54f546dcc..326b8cd75c 100644 --- a/src/app/common/chart-base/chart-base-component/chart-base-component.component.ts +++ b/src/app/common/chart-base/chart-base-component/chart-base-component.component.ts @@ -1,6 +1,4 @@ -import {TooltipService} from '@swimlane/ngx-charts'; import {ChangeDetectionStrategy, Component, ViewContainerRef} from '@angular/core'; -import {AppInjector} from 'src/app/app-injector'; /** * @title chart-base-component @@ -14,8 +12,5 @@ import {AppInjector} from 'src/app/app-injector'; standalone: false, }) export class ChartBaseComponent { - constructor(public viewContainerRef: ViewContainerRef) { - const chartToolTipService = AppInjector.get(TooltipService); - chartToolTipService.injectionService.setRootViewContainer(this.viewContainerRef); - } + constructor(public viewContainerRef: ViewContainerRef) {} } diff --git a/src/app/common/project-progress/project-progress-gauge.component.html b/src/app/common/project-progress/project-progress-gauge.component.html index c1a7ba8dca..c3fada1231 100644 --- a/src/app/common/project-progress/project-progress-gauge.component.html +++ b/src/app/common/project-progress/project-progress-gauge.component.html @@ -12,6 +12,7 @@ [showAxis]="false" [showText]="true" [textValue]="gaugeData[0].value" + [tooltipDisabled]="true" [view]="view" > diff --git a/src/app/common/project-progress/project-progress-gauge.component.ts b/src/app/common/project-progress/project-progress-gauge.component.ts index 75a4249481..07b5f0d265 100644 --- a/src/app/common/project-progress/project-progress-gauge.component.ts +++ b/src/app/common/project-progress/project-progress-gauge.component.ts @@ -1,12 +1,4 @@ -import {TooltipService} from '@swimlane/ngx-charts'; -import { - ChangeDetectionStrategy, - Component, - Injector, - Input, - OnInit, - ViewContainerRef, -} from '@angular/core'; +import {ChangeDetectionStrategy, Component, Input} from '@angular/core'; import {Project} from 'src/app/api/models/project'; @Component({ @@ -16,7 +8,7 @@ import {Project} from 'src/app/api/models/project'; changeDetection: ChangeDetectionStrategy.Eager, standalone: false, }) -export class ProjectProgressGaugeComponent implements OnInit { +export class ProjectProgressGaugeComponent { @Input() project: Project; protected gaugeData = [ @@ -38,19 +30,6 @@ export class ProjectProgressGaugeComponent implements OnInit { }, ]; - ngOnInit(): void { - this.chartToolTipService.injectionService.setRootViewContainer(this.viewContainerRef); - - console.log(this.project.taskStats); - } - - constructor(private injectorObj: Injector) { - this.chartToolTipService = this.injectorObj.get(TooltipService); - this.viewContainerRef = this.injectorObj.get(ViewContainerRef); - } - private chartToolTipService: TooltipService; - readonly viewContainerRef: ViewContainerRef; - smallView = [90, 90]; view = [500, 500]; legend: boolean = true; diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html index 6298d27683..449c726ca2 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.html +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.html @@ -90,25 +90,43 @@

        Tutor Times Session Summary

        @if (isLoading) { - - +
        } + + +
        + {{ weekEvent.event.title }} +
        +
        diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.scss b/src/app/units/states/analytics/directives/analytics-tutor-times.component.scss index 2ce45fc98d..298a078abc 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.scss +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.scss @@ -14,3 +14,18 @@ width: 100%; min-height: 35px; } + +.analytics-loading-spinner { + width: 48px; + height: 48px; + border: 4px solid rgb(0 0 0 / 12%); + border-top-color: var(--mat-sys-primary, #3f51b5); + border-radius: 50%; + animation: analytics-spinner-rotate 800ms linear infinite; +} + +@keyframes analytics-spinner-rotate { + to { + transform: rotate(360deg); + } +} diff --git a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts index 99712feab4..8d6db18fde 100644 --- a/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts +++ b/src/app/units/states/analytics/directives/analytics-tutor-times.component.ts @@ -269,6 +269,17 @@ export class AnalyticsTutorTimesComponent implements OnInit { } } + sessionEventTitle(event: SessionEvent): string { + return [ + `${event.tutorName} (${event.duration} minutes)${event.duringTutorial ? ' T' : ''}`, + `${event.startHour} - ${event.endHour}`, + `Assessments: ${event.assessments || 0}`, + `Comments: ${event.commentsAdded || 0}`, + `Submissions opened: ${event.submissionsOpened || 0}`, + `During Tutorial?: ${event.duringTutorial ? 'yes' : 'no'}`, + ].join('\n'); + } + private stringToHexColor( name: string, opts?: {hue?: [number, number]; sat?: [number, number]; lit?: [number, number]}, diff --git a/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html index d4406f7937..e2b819eaed 100644 --- a/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html +++ b/src/app/visualisations/progress-burndown-chart/progress-burndown-chart.component.html @@ -8,6 +8,7 @@ [scheme]="colorScheme" [showXAxisLabel]="showXAxisLabel" [showYAxisLabel]="showYAxisLabel" + [tooltipDisabled]="true" [view]="" [xAxis]="xAxis" [xAxisLabel]="xAxisLabel" diff --git a/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.html b/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.html index b4c56c857b..0f477cb78d 100644 --- a/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.html +++ b/src/app/visualisations/task-status-pie-chart/task-status-pie-chart.component.html @@ -6,6 +6,7 @@ [legend]="true" [legendTitle]="''" [results]="data" + [tooltipDisabled]="true" [view]="" > From e1f9baa6b3a87247694a81ae45355212cb071e32 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:45:39 +1000 Subject: [PATCH 1142/1280] test: fix ci --- .../common/hero-sidebar/hero-sidebar.component.spec.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/app/common/hero-sidebar/hero-sidebar.component.spec.ts b/src/app/common/hero-sidebar/hero-sidebar.component.spec.ts index 19ed7c2b1a..96247b980e 100644 --- a/src/app/common/hero-sidebar/hero-sidebar.component.spec.ts +++ b/src/app/common/hero-sidebar/hero-sidebar.component.spec.ts @@ -1,5 +1,7 @@ import {beforeEach, describe, expect, it} from 'vitest'; import {ComponentFixture, TestBed} from '@angular/core/testing'; +import {BehaviorSubject} from 'rxjs'; +import {DoubtfireConstants} from 'src/app/config/constants/doubtfire-constants'; import {HeroSidebarComponent} from './hero-sidebar.component'; describe('HeroSidebarComponent', () => { @@ -9,6 +11,12 @@ describe('HeroSidebarComponent', () => { beforeEach(async () => { await TestBed.configureTestingModule({ declarations: [HeroSidebarComponent], + providers: [ + { + provide: DoubtfireConstants, + useValue: {ExternalName: new BehaviorSubject('Doubtfire')}, + }, + ], }).compileComponents(); }); From 7bcc4460c22226af58d0a41e6eb21bd027168365 Mon Sep 17 00:00:00 2001 From: b0ink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 13:51:04 +1000 Subject: [PATCH 1143/1280] chore: bump node requirement --- package-lock.json | 2 +- package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index c4272051da..f9018de1ba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -111,7 +111,7 @@ "vitest": "^4.1.8" }, "engines": { - "node": ">=20.9.0" + "node": ">=22.22.3" }, "optionalDependencies": { "@nx/nx-darwin-arm64": "^18.0", diff --git a/package.json b/package.json index 21049bd0a4..284eb2f421 100644 --- a/package.json +++ b/package.json @@ -6,7 +6,7 @@ "license": "AGPL-3.0", "repository": {}, "engines": { - "node": ">=20.9.0" + "node": ">=22.22.3" }, "scripts": { "build": "ng build", From 4583569390e686f7aca3ee4bebcda4be630274a5 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 15:00:58 +1000 Subject: [PATCH 1144/1280] Merge pull request #1201 from b0ink/feat/overflow-task-claim-analytics feat: download overflow task claim analytics --- src/app/api/models/unit.ts | 6 ++++++ .../analytics/unit-analytics-route.component.html | 3 +++ .../analytics/unit-analytics-route.component.ts | 14 +++++++++++++- 3 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/app/api/models/unit.ts b/src/app/api/models/unit.ts index 37f11595cc..9a00a22d11 100644 --- a/src/app/api/models/unit.ts +++ b/src/app/api/models/unit.ts @@ -673,6 +673,12 @@ export class Unit extends Entity { ); } + public downloadOverflowTaskClaimsCsv(): Observable { + return AppInjector.get(HttpClient).get( + `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/overflow_task_claims`, + ); + } + public downloadTutorAssessmentCsv(): Observable { return AppInjector.get(HttpClient).get( `${AppInjector.get(DoubtfireConstants).API_URL}/csv/units/${this.id}/tutor_assessments`, diff --git a/src/app/units/states/analytics/unit-analytics-route.component.html b/src/app/units/states/analytics/unit-analytics-route.component.html index 39b3461d24..9a554016c3 100644 --- a/src/app/units/states/analytics/unit-analytics-route.component.html +++ b/src/app/units/states/analytics/unit-analytics-route.component.html @@ -16,6 +16,9 @@

        Unit Statistics

        + diff --git a/src/app/units/states/analytics/unit-analytics-route.component.ts b/src/app/units/states/analytics/unit-analytics-route.component.ts index b05fa7187b..c8f2cabaf9 100644 --- a/src/app/units/states/analytics/unit-analytics-route.component.ts +++ b/src/app/units/states/analytics/unit-analytics-route.component.ts @@ -1,4 +1,5 @@ -import {ChangeDetectionStrategy, Component, Input, OnInit} from '@angular/core'; +import {formatDate} from '@angular/common'; +import {ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit} from '@angular/core'; import {ActivatedRoute} from '@angular/router'; import {Observable, first, of} from 'rxjs'; import {SidekiqJob} from 'src/app/api/models/sidekiq-job'; @@ -27,6 +28,7 @@ export class UnitAnalyticsComponent implements OnInit { private userService: UserService, private alertService: AlertService, private route: ActivatedRoute, + @Inject(LOCALE_ID) private locale: string, ) {} ngOnInit(): void { @@ -72,6 +74,16 @@ export class UnitAnalyticsComponent implements OnInit { ); } + public getOverflowTaskClaimsCsv() { + const timestamp = formatDate(new Date(), 'd-MMMM-y-HHmm', this.locale).toLowerCase(); + + this.downloadCsv( + this.unit.downloadOverflowTaskClaimsCsv(), + 'Overflow Task Claims CSV', + `${this.unit.code}-overflow-task-claims-${timestamp}.csv`, + ); + } + public downloadCsv(newJob: Observable, title: string, filename: string) { newJob.subscribe({ next: (job) => { From fc75fcb2f61eacaee6620bd2362bff50d386d801 Mon Sep 17 00:00:00 2001 From: Boink <40929320+b0ink@users.noreply.github.com> Date: Fri, 19 Jun 2026 16:43:36 +1000 Subject: [PATCH 1145/1280] chore: upgrade to tailwindcss 4 (#1292) * chore: upgrade to tailwindcss 4 * fix: restore intellisense * chore: format --- .postcssrc.json | 6 + package-lock.json | 1126 +++++++++-------- package.json | 9 +- .../teaching-period-unit-import.dialog.html | 2 +- .../admin/states/units/units.component.html | 2 +- .../archive-viewer.component.html | 8 +- .../audio-comment-recorder.html | 2 +- .../file-uploader.component.html | 2 +- .../nested-csv-download-modal.component.html | 2 +- .../about-doubtfire-modal-content.tpl.html | 8 +- .../csv-result-modal.component.html | 18 +- .../sidekiq-progress-modal.component.html | 2 +- .../status-icon/status-icon.component.html | 2 +- .../unavailable-card.component.html | 2 +- .../group-member-list.component.html | 2 +- .../group-set-manager.component.html | 2 +- .../lti-dashboard.component.html | 4 +- .../project-progress-dashboard.component.html | 2 +- .../engagement-detail-dialog.component.html | 12 +- .../student-task-list.tpl.html | 2 +- .../task-ilos-card.component.html | 2 +- .../submission-files-modal.component.html | 6 +- .../task-overseer-report.component.html | 6 +- .../task-scorm-card.component.html | 2 +- .../task-dashboard.component.html | 2 +- .../task-dashboard/task-dashboard.tpl.html | 4 +- .../staff-notes/staff-notes.component.html | 12 +- .../tutor-discussion.component.html | 14 +- .../tutor-discussion.component.scss | 27 +- .../tutor-notes/tutor-notes.component.html | 14 +- .../submission-type-modal.component.html | 2 +- .../upload-submission-modal.component.html | 2 +- ...achment-confirmation-dialog.component.html | 2 +- .../task-feedback-templates.component.html | 2 +- .../task-assessment-comment.component.html | 2 +- .../analytics-tutor-times.component.html | 2 +- .../communication-schedules.component.html | 8 +- .../task-definition-editor.component.html | 8 +- ...sk-definition-prerequisites.component.html | 2 +- .../task-definition-scorm.component.html | 2 +- .../unit-task-editor.component.html | 2 +- .../unit-tutorials-list.component.html | 2 +- .../inbox-dashboard.component.html | 2 +- .../staff-task-list.component.html | 2 +- .../unit-task-list.component.html | 12 +- src/styles.scss | 6 +- src/tailwind-intellisense.css | 2 + 47 files changed, 715 insertions(+), 649 deletions(-) create mode 100644 .postcssrc.json create mode 100644 src/tailwind-intellisense.css diff --git a/.postcssrc.json b/.postcssrc.json new file mode 100644 index 0000000000..865e00b364 --- /dev/null +++ b/.postcssrc.json @@ -0,0 +1,6 @@ +{ + "syntax": "postcss-scss", + "plugins": { + "@tailwindcss/postcss": {} + } +} diff --git a/package-lock.json b/package-lock.json index f9018de1ba..c53b176b2a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "@ngneat/hotkeys": "^4.0.0", "@ngstack/code-editor": "^9.0.0", "@swimlane/ngx-charts": "^20.5.0", + "@tailwindcss/postcss": "^4.3.1", "@worktile/gantt": "^21.0.0", "angular-calendar": "^0.31.1", "angular-cookies": "1.5.11", @@ -100,11 +101,11 @@ "ip": "^2.0.1", "jsdom": "^29.1.1", "npm-run-all2": "^7.0", - "postcss": "^8.5.10", - "postcss-scss": "^0.1.7", + "postcss": "^8.5.15", + "postcss-scss": "^4.0.9", "prettier": "^3.8.3", - "sass": "^1.48.0", - "tailwindcss": "~3.4.17", + "sass": "^1.101.0", + "tailwindcss": "^4.3.1", "ts-node": "~10.9", "typescript": "~6.0.3", "underscore": "^1.8.3", @@ -336,7 +337,6 @@ "version": "5.2.0", "resolved": "https://registry.npmjs.org/@alloc/quick-lru/-/quick-lru-5.2.0.tgz", "integrity": "sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -3955,7 +3955,6 @@ "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.0", @@ -3966,7 +3965,6 @@ "version": "2.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/gen-mapping": "^0.3.5", @@ -3977,7 +3975,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.0.0" @@ -3987,14 +3984,12 @@ "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", - "dev": true, "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.31", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", @@ -6069,6 +6064,284 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, + "node_modules/@tailwindcss/node": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.1.tgz", + "integrity": "sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==", + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "5.21.6", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.1" + } + }, + "node_modules/@tailwindcss/node/node_modules/enhanced-resolve": { + "version": "5.21.6", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.21.6.tgz", + "integrity": "sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/@tailwindcss/node/node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.1.tgz", + "integrity": "sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==", + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-arm64": "4.3.1", + "@tailwindcss/oxide-darwin-x64": "4.3.1", + "@tailwindcss/oxide-freebsd-x64": "4.3.1", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.1", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.1", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.1", + "@tailwindcss/oxide-linux-x64-musl": "4.3.1", + "@tailwindcss/oxide-wasm32-wasi": "4.3.1", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.1", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.1" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.1.tgz", + "integrity": "sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.1.tgz", + "integrity": "sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.1.tgz", + "integrity": "sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.1.tgz", + "integrity": "sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.1.tgz", + "integrity": "sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.1.tgz", + "integrity": "sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.1.tgz", + "integrity": "sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.1.tgz", + "integrity": "sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.1.tgz", + "integrity": "sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.1.tgz", + "integrity": "sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" + ], + "cpu": [ + "wasm32" + ], + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "^1.10.0", + "@emnapi/runtime": "^1.10.0", + "@emnapi/wasi-threads": "^1.2.1", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.1.tgz", + "integrity": "sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.1.tgz", + "integrity": "sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 20" + } + }, + "node_modules/@tailwindcss/postcss": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.1.tgz", + "integrity": "sha512-dNJuNbdEJT/SWRuXTYP1WSamelsz3ztkUsdtWQPjrexysrTpaEPM40P/71knXiXLYEojqPOEGitVLLpPMS5T6A==", + "license": "MIT", + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.1", + "@tailwindcss/oxide": "4.3.1", + "postcss": "8.5.15", + "tailwindcss": "4.3.1" + } + }, "node_modules/@trivago/prettier-plugin-sort-imports": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/@trivago/prettier-plugin-sort-imports/-/prettier-plugin-sort-imports-6.0.2.tgz", @@ -7022,19 +7295,14 @@ "node": ">=4" } }, - "node_modules/any-promise": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz", - "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==", - "dev": true, - "license": "MIT" - }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", "dev": true, "license": "ISC", + "optional": true, + "peer": true, "dependencies": { "normalize-path": "^3.0.0", "picomatch": "^2.0.4" @@ -7049,6 +7317,8 @@ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=8.6" }, @@ -7093,13 +7363,6 @@ "node": ">= 6" } }, - "node_modules/arg": { - "version": "5.0.2", - "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", - "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", - "dev": true, - "license": "MIT" - }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -7360,6 +7623,8 @@ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=8" }, @@ -7690,16 +7955,6 @@ "node": ">=6" } }, - "node_modules/camelcase-css": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz", - "integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/caniuse-db": { "version": "1.0.30001797", "resolved": "https://registry.npmjs.org/caniuse-db/-/caniuse-db-1.0.30001797.tgz", @@ -8425,19 +8680,6 @@ "url": "https://github.com/sponsors/fb55" } }, - "node_modules/cssesc": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", - "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", - "dev": true, - "license": "MIT", - "bin": { - "cssesc": "bin/cssesc" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/custom-event": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", @@ -8850,7 +9092,6 @@ "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", "license": "Apache-2.0", - "optional": true, "engines": { "node": ">=8" } @@ -8864,13 +9105,6 @@ "optional": true, "peer": true }, - "node_modules/didyoumean": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz", - "integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/diff": { "version": "4.0.4", "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.4.tgz", @@ -8887,13 +9121,6 @@ "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", "license": "MIT" }, - "node_modules/dlv": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz", - "integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==", - "dev": true, - "license": "MIT" - }, "node_modules/dom-serialize": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", @@ -10430,7 +10657,6 @@ "version": "4.2.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "dev": true, "license": "ISC" }, "node_modules/has-ansi": { @@ -10951,6 +11177,8 @@ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "dependencies": { "binary-extensions": "^2.0.0" }, @@ -11902,30 +12130,266 @@ "immediate": "~3.0.5" } }, - "node_modules/lilconfig": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz", - "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==", - "dev": true, - "license": "MIT", + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, "engines": { - "node": ">=14" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/antonk52" - } - }, - "node_modules/lines-and-columns": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", - "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", - "dev": true, - "license": "MIT" - }, - "node_modules/listr2": { - "version": "10.2.1", - "resolved": "https://registry.npmjs.org/listr2/-/listr2-10.2.1.tgz", - "integrity": "sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q==", + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" + } + }, + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/listr2": { + "version": "10.2.1", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-10.2.1.tgz", + "integrity": "sha512-7I5knELsJKTUjXG+A6BkKAiGkW1i25fNa/xlUl9hFtk15WbE9jndA89xu5FzQKrY5llajE1hfZZFMILXkDHk/Q==", "dev": true, "license": "MIT", "dependencies": { @@ -12231,7 +12695,6 @@ "version": "0.30.21", "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", - "dev": true, "license": "MIT", "dependencies": { "@jridgewell/sourcemap-codec": "^1.5.5" @@ -12755,18 +13218,6 @@ "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" - } - }, "node_modules/nan": { "version": "2.27.0", "resolved": "https://registry.npmjs.org/nan/-/nan-2.27.0.tgz", @@ -12778,7 +13229,6 @@ "version": "3.3.12", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.12.tgz", "integrity": "sha512-ZB9RH/39qpq5Vu6Y+NmUaFhQR6pp+M2Xt76XBnEwDaGcVAqhlvxrl3B2bKS5D3NH3QR76v3aSrKaF/Kiy7lEtQ==", - "dev": true, "funding": [ { "type": "github", @@ -13109,6 +13559,8 @@ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", "dev": true, "license": "MIT", + "optional": true, + "peer": true, "engines": { "node": ">=0.10.0" } @@ -13344,16 +13796,6 @@ "node": ">=0.10.0" } }, - "node_modules/object-hash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", - "integrity": "sha512-RSn9F68PjH9HqtltsSnqYC1XXoWe9Bju5+213R98cNGttag9q9yAOTzdbsqvIa7aNm5WffBZFpWYr2aWrklWAw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -13876,7 +14318,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "dev": true, "license": "ISC" }, "node_modules/picomatch": { @@ -13914,16 +14355,6 @@ "node": ">=4" } }, - "node_modules/pirates": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.7.tgz", - "integrity": "sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/piscina": { "version": "5.1.4", "resolved": "https://registry.npmjs.org/piscina/-/piscina-5.1.4.tgz", @@ -13978,7 +14409,6 @@ "version": "8.5.15", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.15.tgz", "integrity": "sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==", - "dev": true, "funding": [ { "type": "opencollective", @@ -14003,268 +14433,65 @@ "node": "^10 || ^12 || >=14" } }, - "node_modules/postcss-import": { - "version": "15.1.0", - "resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-15.1.0.tgz", - "integrity": "sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss-value-parser": "^4.0.0", - "read-cache": "^1.0.0", - "resolve": "^1.1.7" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "postcss": "^8.0.0" - } - }, - "node_modules/postcss-import/node_modules/postcss-value-parser": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", - "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==", + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", "dev": true, "license": "MIT" }, - "node_modules/postcss-js": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.1.0.tgz", - "integrity": "sha512-oIAOTqgIo7q2EOwbhb8UalYePMvYoIeRY2YKntdpFQXNosSu3vLrniGgmH9OKs/qAkfoj5oB3le/7mINW1LCfw==", + "node_modules/postcss-safe-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", "dev": true, "funding": [ { "type": "opencollective", "url": "https://opencollective.com/postcss/" }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, { "type": "github", "url": "https://github.com/sponsors/ai" } ], "license": "MIT", - "dependencies": { - "camelcase-css": "^2.0.1" - }, "engines": { - "node": "^12 || ^14 || >= 16" + "node": ">=18.0" }, "peerDependencies": { - "postcss": "^8.4.21" + "postcss": "^8.4.31" } }, - "node_modules/postcss-load-config": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-6.0.1.tgz", - "integrity": "sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==", + "node_modules/postcss-scss": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", + "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", "dev": true, "funding": [ { "type": "opencollective", "url": "https://opencollective.com/postcss/" }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-scss" + }, { "type": "github", "url": "https://github.com/sponsors/ai" } ], "license": "MIT", - "dependencies": { - "lilconfig": "^3.1.1" - }, "engines": { - "node": ">= 18" + "node": ">=12.0" }, "peerDependencies": { - "jiti": ">=1.21.0", - "postcss": ">=8.0.9", - "tsx": "^4.8.1", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "jiti": { - "optional": true - }, - "postcss": { - "optional": true - }, - "tsx": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/postcss-media-query-parser": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", - "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==", - "dev": true, - "license": "MIT" - }, - "node_modules/postcss-nested": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-6.2.0.tgz", - "integrity": "sha512-HQbt28KulC5AJzG+cZtj9kvKB93CFCdLvog1WFLf1D+xmMvPGlBstkpTEZfK5+AN9hfJocyBFCNiqyS48bpgzQ==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "dependencies": { - "postcss-selector-parser": "^6.1.1" - }, - "engines": { - "node": ">=12.0" - }, - "peerDependencies": { - "postcss": "^8.2.14" - } - }, - "node_modules/postcss-safe-parser": { - "version": "7.0.1", - "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", - "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", - "dev": true, - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "MIT", - "engines": { - "node": ">=18.0" - }, - "peerDependencies": { - "postcss": "^8.4.31" - } - }, - "node_modules/postcss-scss": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-0.1.9.tgz", - "integrity": "sha512-FkLd8Pxci394edesXqewjAd6eMnYGUPK5bgkYbYHX7YPeJDcuaKMuHnXsd0i3tnXJOLTuX+L+m3edda1IKMrbQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "postcss": "^5.1.0" - } - }, - "node_modules/postcss-scss/node_modules/ansi-regex": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", - "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-scss/node_modules/ansi-styles": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", - "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-scss/node_modules/chalk": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", - "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-styles": "^2.2.1", - "escape-string-regexp": "^1.0.2", - "has-ansi": "^2.0.0", - "strip-ansi": "^3.0.0", - "supports-color": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-scss/node_modules/chalk/node_modules/supports-color": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", - "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.8.0" - } - }, - "node_modules/postcss-scss/node_modules/postcss": { - "version": "5.2.18", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-5.2.18.tgz", - "integrity": "sha512-zrUjRRe1bpXKsX1qAJNJjqZViErVuyEkMTRrwu4ud4sbTtIBRmtaYDrHmcGgmrbsW3MHfmtIf+vJumgQn+PrXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "chalk": "^1.1.3", - "js-base64": "^2.1.9", - "source-map": "^0.5.6", - "supports-color": "^3.2.3" - }, - "engines": { - "node": ">=0.12" - } - }, - "node_modules/postcss-scss/node_modules/source-map": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", - "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", - "dev": true, - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-scss/node_modules/strip-ansi": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", - "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==", - "dev": true, - "license": "MIT", - "dependencies": { - "ansi-regex": "^2.0.0" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/postcss-selector-parser": { - "version": "6.1.2", - "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.1.2.tgz", - "integrity": "sha512-Q8qQfPiZ+THO/3ZrOrO0cJJKfpYCagtMUkXbnEfmgUjwXg6z/WBeOyS9APBBPCTSiDV+s4SwQGu8yFsiMRIudg==", - "dev": true, - "license": "MIT", - "dependencies": { - "cssesc": "^3.0.0", - "util-deprecate": "^1.0.2" - }, - "engines": { - "node": ">=4" + "postcss": "^8.4.29" } }, "node_modules/postcss-value-parser": { @@ -14690,26 +14917,6 @@ "node": ">=0.10.0" } }, - "node_modules/read-cache": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/read-cache/-/read-cache-1.0.0.tgz", - "integrity": "sha512-Owdv/Ft7IjOgm/i0xvNDZ1LrRANRfew4b2prF3OWMQLxLfu3bS8FVhCsrSCMK4lR56Y9ya+AThoTpDCTxCmpRA==", - "dev": true, - "license": "MIT", - "dependencies": { - "pify": "^2.3.0" - } - }, - "node_modules/read-cache/node_modules/pify": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", - "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/read-package-json-fast": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-4.0.0.tgz", @@ -15047,9 +15254,9 @@ "license": "MIT" }, "node_modules/sass": { - "version": "1.100.0", - "resolved": "https://registry.npmjs.org/sass/-/sass-1.100.0.tgz", - "integrity": "sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ==", + "version": "1.101.0", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.101.0.tgz", + "integrity": "sha512-OL3GoQyoUdDt843DpVmDO6y2k1sc5IhUDSpu8XucEI+35neq5QivZ1iuegnpraEVTJXlQGK1gl27zKcTLEPbQw==", "dev": true, "license": "MIT", "dependencies": { @@ -15738,7 +15945,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "dev": true, "license": "BSD-3-Clause", "engines": { "node": ">=0.10.0" @@ -15950,39 +16156,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/sucrase": { - "version": "3.35.1", - "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.1.tgz", - "integrity": "sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/gen-mapping": "^0.3.2", - "commander": "^4.0.0", - "lines-and-columns": "^1.1.6", - "mz": "^2.7.0", - "pirates": "^4.0.1", - "tinyglobby": "^0.2.11", - "ts-interface-checker": "^0.1.9" - }, - "bin": { - "sucrase": "bin/sucrase", - "sucrase-node": "bin/sucrase-node" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "node_modules/sucrase/node_modules/commander": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", - "integrity": "sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 6" - } - }, "node_modules/supports-color": { "version": "3.2.3", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-3.2.3.tgz", @@ -16051,122 +16224,15 @@ } }, "node_modules/tailwindcss": { - "version": "3.4.19", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.19.tgz", - "integrity": "sha512-3ofp+LL8E+pK/JuPLPggVAIaEuhvIz4qNcf3nA1Xn2o/7fb7s/TYpHhwGDv1ZU3PkBluUVaF8PyCHcm48cKLWQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "arg": "^5.0.2", - "chokidar": "^3.6.0", - "didyoumean": "^1.2.2", - "dlv": "^1.1.3", - "fast-glob": "^3.3.2", - "glob-parent": "^6.0.2", - "is-glob": "^4.0.3", - "jiti": "^1.21.7", - "lilconfig": "^3.1.3", - "micromatch": "^4.0.8", - "normalize-path": "^3.0.0", - "object-hash": "^3.0.0", - "picocolors": "^1.1.1", - "postcss": "^8.4.47", - "postcss-import": "^15.1.0", - "postcss-js": "^4.0.1", - "postcss-load-config": "^4.0.2 || ^5.0 || ^6.0", - "postcss-nested": "^6.2.0", - "postcss-selector-parser": "^6.1.2", - "resolve": "^1.22.8", - "sucrase": "^3.35.0" - }, - "bin": { - "tailwind": "lib/cli.js", - "tailwindcss": "lib/cli.js" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tailwindcss/node_modules/chokidar": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", - "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", - "dev": true, - "license": "MIT", - "dependencies": { - "anymatch": "~3.1.2", - "braces": "~3.0.2", - "glob-parent": "~5.1.2", - "is-binary-path": "~2.1.0", - "is-glob": "~4.0.1", - "normalize-path": "~3.0.0", - "readdirp": "~3.6.0" - }, - "engines": { - "node": ">= 8.10.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "node_modules/tailwindcss/node_modules/chokidar/node_modules/glob-parent": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", - "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", - "dev": true, - "license": "ISC", - "dependencies": { - "is-glob": "^4.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/tailwindcss/node_modules/jiti": { - "version": "1.21.7", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.7.tgz", - "integrity": "sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==", - "dev": true, - "license": "MIT", - "bin": { - "jiti": "bin/jiti.js" - } - }, - "node_modules/tailwindcss/node_modules/picomatch": { - "version": "2.3.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz", - "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8.6" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, - "node_modules/tailwindcss/node_modules/readdirp": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", - "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", - "dev": true, - "license": "MIT", - "dependencies": { - "picomatch": "^2.2.1" - }, - "engines": { - "node": ">=8.10.0" - } + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.1.tgz", + "integrity": "sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==", + "license": "MIT" }, "node_modules/tapable": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -16263,29 +16329,6 @@ "node": ">=18" } }, - "node_modules/thenify": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/thenify/-/thenify-3.3.1.tgz", - "integrity": "sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==", - "dev": true, - "license": "MIT", - "dependencies": { - "any-promise": "^1.0.0" - } - }, - "node_modules/thenify-all": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/thenify-all/-/thenify-all-1.6.0.tgz", - "integrity": "sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==", - "dev": true, - "license": "MIT", - "dependencies": { - "thenify": ">= 3.1.0 < 4" - }, - "engines": { - "node": ">=0.8" - } - }, "node_modules/tinybench": { "version": "2.9.0", "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", @@ -16429,13 +16472,6 @@ "typescript": ">=4.8.4" } }, - "node_modules/ts-interface-checker": { - "version": "0.1.13", - "resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz", - "integrity": "sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==", - "dev": true, - "license": "Apache-2.0" - }, "node_modules/ts-md5": { "version": "1.3.1", "resolved": "https://registry.npmjs.org/ts-md5/-/ts-md5-1.3.1.tgz", diff --git a/package.json b/package.json index 284eb2f421..e6356cdb59 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "@ngneat/hotkeys": "^4.0.0", "@ngstack/code-editor": "^9.0.0", "@swimlane/ngx-charts": "^20.5.0", + "@tailwindcss/postcss": "^4.3.1", "@worktile/gantt": "^21.0.0", "angular-calendar": "^0.31.1", "angular-cookies": "1.5.11", @@ -116,11 +117,11 @@ "ip": "^2.0.1", "jsdom": "^29.1.1", "npm-run-all2": "^7.0", - "postcss": "^8.5.10", - "postcss-scss": "^0.1.7", + "postcss": "^8.5.15", + "postcss-scss": "^4.0.9", "prettier": "^3.8.3", - "sass": "^1.48.0", - "tailwindcss": "~3.4.17", + "sass": "^1.101.0", + "tailwindcss": "^4.3.1", "ts-node": "~10.9", "typescript": "~6.0.3", "underscore": "^1.8.3", diff --git a/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.html b/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.html index 275098a43d..28ea364d2e 100644 --- a/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.html +++ b/src/app/admin/states/teaching-periods/teaching-period-unit-import/teaching-period-unit-import.dialog.html @@ -78,7 +78,7 @@

        Import Units Into {{ data.teachingPeriod.name }}

      -
      +
      Unit Code(s) diff --git a/src/app/admin/states/units/units.component.html b/src/app/admin/states/units/units.component.html index d334c47c1c..b7ef11e74c 100644 --- a/src/app/admin/states/units/units.component.html +++ b/src/app/admin/states/units/units.component.html @@ -5,7 +5,7 @@

      {{ title }}

      - + Search search diff --git a/src/app/common/archive-viewer/archive-viewer.component.html b/src/app/common/archive-viewer/archive-viewer.component.html index 2b081b24ec..51331b3e4f 100644 --- a/src/app/common/archive-viewer/archive-viewer.component.html +++ b/src/app/common/archive-viewer/archive-viewer.component.html @@ -1,4 +1,4 @@ -
      +
      @if (isLoading) {
      @@ -43,7 +43,7 @@ @if (navigationMode === 'tree') {
    - +

    {{privacyPolicy.privacy}} - +

    Plagiarism and collusion

    Plagiarism and Collusion

    diff --git a/src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/task-ilo-alignment-modal.tpl.html b/src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/task-ilo-alignment-modal.tpl.html index 91fdabc350..a89b929a99 100644 --- a/src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/task-ilo-alignment-modal.tpl.html +++ b/src/app/tasks/task-ilo-alignment/modals/task-ilo-alignment-modal/task-ilo-alignment-modal.tpl.html @@ -14,7 +14,7 @@

    -
    +
    Click to add one

    diff --git a/src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.tpl.html b/src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.tpl.html index 2032d7bf1d..79fc40a50b 100644 --- a/src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.tpl.html +++ b/src/app/tasks/task-ilo-alignment/task-ilo-alignment-viewer/task-ilo-alignment-viewer.tpl.html @@ -34,7 +34,7 @@

    Description
    -
    +
    {{ilo.description}}
    Visualisation
    @@ -50,7 +50,7 @@
    Visualisation
    Rationale
    -
    +
    Related Tasks
    From ce7e69f2aa43b409bbf91eec29273e9cd19cd973 Mon Sep 17 00:00:00 2001 From: ShounakB <65479699+Shounaks@users.noreply.github.com> Date: Wed, 13 Nov 2024 17:29:57 +1100 Subject: [PATCH 0219/1280] rebase migration:grade-icon onto origin/8.0.x --- src/app/common/common.coffee | 1 - src/app/common/grade-icon/grade-icon.coffee | 16 - .../grade-icon/grade-icon.component.html | 16 + .../grade-icon/grade-icon.component.scss | 20 + .../common/grade-icon/grade-icon.component.ts | 35 ++ src/app/common/grade-icon/grade-icon.scss | 48 --- src/app/common/grade-icon/grade-icon.tpl.html | 8 - src/app/doubtfire-angular.module.ts | 2 + src/app/doubtfire-angularjs.module.ts | 3 +- ...roup-member-contribution-assigner.tpl.html | 82 ++-- .../project-progress-dashboard.tpl.html | 2 +- .../grade-task-modal.tpl.html | 54 +-- .../states/portfolios/portfolios.tpl.html | 6 +- .../students-list/students-list.tpl.html | 364 +++++++++--------- 14 files changed, 329 insertions(+), 328 deletions(-) delete mode 100644 src/app/common/grade-icon/grade-icon.coffee create mode 100644 src/app/common/grade-icon/grade-icon.component.html create mode 100644 src/app/common/grade-icon/grade-icon.component.scss create mode 100644 src/app/common/grade-icon/grade-icon.component.ts delete mode 100644 src/app/common/grade-icon/grade-icon.scss delete mode 100644 src/app/common/grade-icon/grade-icon.tpl.html diff --git a/src/app/common/common.coffee b/src/app/common/common.coffee index e5bbea48a2..f330d8f6ac 100644 --- a/src/app/common/common.coffee +++ b/src/app/common/common.coffee @@ -3,6 +3,5 @@ angular.module("doubtfire.common", [ 'doubtfire.common.filters' 'doubtfire.common.modals' 'doubtfire.common.file-uploader' - 'doubtfire.common.grade-icon' 'doubtfire.common.content-editable' ]) diff --git a/src/app/common/grade-icon/grade-icon.coffee b/src/app/common/grade-icon/grade-icon.coffee deleted file mode 100644 index f35f7fbfa4..0000000000 --- a/src/app/common/grade-icon/grade-icon.coffee +++ /dev/null @@ -1,16 +0,0 @@ -angular.module('doubtfire.common.grade-icon', []) - -.directive 'gradeIcon', -> - restrict: 'E' - replace: true - templateUrl: 'common/grade-icon/grade-icon.tpl.html' - scope: - inputGrade: '=?grade' - colorful: '=?' - controller: ($scope, gradeService) -> - $scope.$watch 'inputGrade', (newGrade) -> - $scope.grade = if _.isString($scope.inputGrade) then gradeService.stringToGrade($scope.inputGrade) else $scope.inputGrade - $scope.gradeText = (grade) -> - if grade? then gradeService.grades[grade] or "Grade" - $scope.gradeLetter = (grade) -> - gradeService.gradeAcronyms[grade] or 'G' diff --git a/src/app/common/grade-icon/grade-icon.component.html b/src/app/common/grade-icon/grade-icon.component.html new file mode 100644 index 0000000000..2cb10af9d8 --- /dev/null +++ b/src/app/common/grade-icon/grade-icon.component.html @@ -0,0 +1,16 @@ +
    + + {{ gradeLetter }} + +
    diff --git a/src/app/common/grade-icon/grade-icon.component.scss b/src/app/common/grade-icon/grade-icon.component.scss new file mode 100644 index 0000000000..76ea15e629 --- /dev/null +++ b/src/app/common/grade-icon/grade-icon.component.scss @@ -0,0 +1,20 @@ +.grade-icon { + color: #fff; + font-size: 1em; + background-color: #333333; + border-radius: 100%; + width: 2.25em; + height: 2.25em; + font-weight: 100; + font-size: 1em; + margin: 0 auto; + display: flex; + align-items: center; + justify-content: center; +} +.text-left .grade-icon { + margin-left: 0; +} +.text-right .grade-icon { + margin-right: 0; +} diff --git a/src/app/common/grade-icon/grade-icon.component.ts b/src/app/common/grade-icon/grade-icon.component.ts new file mode 100644 index 0000000000..5c539d5ead --- /dev/null +++ b/src/app/common/grade-icon/grade-icon.component.ts @@ -0,0 +1,35 @@ +/* eslint-disable @typescript-eslint/no-unused-vars */ +import { Component, Inject, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; +import { GradeService } from '../services/grade.service'; +import { Project } from 'src/app/api/models/project'; + +@Component({ + selector: 'grade-icon', + templateUrl: './grade-icon.component.html', + styleUrls: ['./grade-icon.component.scss'], +}) +export class GradeIconComponent implements OnInit, OnChanges { + @Input() grade?: number; + @Input() colorful: boolean = false; + + InputGrade?: number; + gradeText: string = 'Grade'; + gradeLetter: string = 'G'; + + constructor(private gradeService: GradeService) {} + + ngOnInit(): void { + this.updateGrade(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes['grade']) { + this.updateGrade(); + } + } + + private updateGrade(): void { + this.gradeText = this.gradeService.grades[this.grade] || 'Grade'; + this.gradeLetter = this.gradeService.gradeAcronyms[this.grade] || 'G'; + } +} diff --git a/src/app/common/grade-icon/grade-icon.scss b/src/app/common/grade-icon/grade-icon.scss deleted file mode 100644 index 08db661a8b..0000000000 --- a/src/app/common/grade-icon/grade-icon.scss +++ /dev/null @@ -1,48 +0,0 @@ -.grade-icon.text-muted { - background-color: $text-muted; -} -.grade-icon.text-primary { - background-color: $brand-primary; -} -.grade-icon.text-success { - background-color: $brand-success; -} -.grade-icon.text-danger { - background-color: $brand-danger; -} -.grade-icon.text-info { - background-color: $brand-info; -} -.grade-icon.text-warning { - background-color: $brand-warning; -} -a .grade-icon:hover { - background-color: $link-hover-color; -} -.grade-icon { - color: #fff; - font-size: 1em; - background-color: $text-color; - border-radius: 100%; - width: 2.25em; - height: 2.25em; - font-weight: 100; - font-size: 1em; - @include no-select; - margin: 0 auto; - display: flex; - align-items: center; - justify-content: center; -} -.grade-icon.colorful { - &.grade-0 { background-color: $grade-color-p; } - &.grade-1 { background-color: $grade-color-c; } - &.grade-2 { background-color: $grade-color-d; } - &.grade-3 { background-color: $grade-color-hd; } -} -.text-left .grade-icon { - margin-left: 0; -} -.text-right .grade-icon { - margin-right: 0; -} diff --git a/src/app/common/grade-icon/grade-icon.tpl.html b/src/app/common/grade-icon/grade-icon.tpl.html deleted file mode 100644 index 1939b21361..0000000000 --- a/src/app/common/grade-icon/grade-icon.tpl.html +++ /dev/null @@ -1,8 +0,0 @@ -
    - - {{gradeLetter(grade)}} - -
    diff --git a/src/app/doubtfire-angular.module.ts b/src/app/doubtfire-angular.module.ts index 991ac397b4..4b06266dc1 100644 --- a/src/app/doubtfire-angular.module.ts +++ b/src/app/doubtfire-angular.module.ts @@ -170,6 +170,7 @@ import {TaskAssessmentModalComponent} from './common/modals/task-assessment-moda import {TaskSubmissionHistoryComponent} from './tasks/task-submission-history/task-submission-history.component'; import {HomeComponent} from './home/states/home/home.component'; import {IsActiveUnitRole} from './common/pipes/is-active-unit-role.pipe'; +import {GradeIconComponent} from './common/grade-icon/grade-icon.component'; import {HeaderComponent} from './common/header/header.component'; import {UnitDropdownComponent} from './common/header/unit-dropdown/unit-dropdown.component'; import {TaskDropdownComponent} from './common/header/task-dropdown/task-dropdown.component'; @@ -316,6 +317,7 @@ const MY_DATE_FORMAT = { TaskAssessmentCommentComponent, TaskAssessmentModalComponent, TaskSubmissionHistoryComponent, + GradeIconComponent, HeaderComponent, UnitDropdownComponent, TaskDropdownComponent, diff --git a/src/app/doubtfire-angularjs.module.ts b/src/app/doubtfire-angularjs.module.ts index e14fdbb545..1f42ca4907 100644 --- a/src/app/doubtfire-angularjs.module.ts +++ b/src/app/doubtfire-angularjs.module.ts @@ -122,7 +122,6 @@ import 'build/src/app/common/modals/confirmation-modal/confirmation-modal.js'; import 'build/src/app/common/modals/comments-modal/comments-modal.js'; import 'build/src/app/common/modals/csv-result-modal/csv-result-modal.js'; import 'build/src/app/common/modals/modals.js'; -import 'build/src/app/common/grade-icon/grade-icon.js'; import 'build/src/app/common/file-uploader/file-uploader.js'; import 'build/src/app/common/common.js'; import 'build/src/app/common/services/listener-service.js'; @@ -193,6 +192,7 @@ import {CheckForUpdateService} from './sessions/service-worker-updater/check-for import {TaskSubmissionService} from './common/services/task-submission.service'; import {TaskAssessmentModalService} from './common/modals/task-assessment-modal/task-assessment-modal.service'; import {TaskSubmissionHistoryComponent} from './tasks/task-submission-history/task-submission-history.component'; +import {GradeIconComponent} from './common/grade-icon/grade-icon.component'; import {HeaderComponent} from './common/header/header.component'; import {SplashScreenComponent} from './home/splash-screen/splash-screen.component'; import {GlobalStateService} from './projects/states/index/global-state.service'; @@ -313,6 +313,7 @@ DoubtfireAngularJSModule.directive( 'objectSelect', downgradeComponent({component: ObjectSelectComponent}), ); +DoubtfireAngularJSModule.directive('gradeIcon', downgradeComponent({component: GradeIconComponent})); DoubtfireAngularJSModule.directive('appHeader', downgradeComponent({component: HeaderComponent})); DoubtfireAngularJSModule.directive( 'splashScreen', diff --git a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.tpl.html b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.tpl.html index 4caab308f5..149ebb8a13 100644 --- a/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.tpl.html +++ b/src/app/groups/group-member-contribution-assigner/group-member-contribution-assigner.tpl.html @@ -1,41 +1,41 @@ -
    - - - - - - - - - - - - - - - -
    Team MemberTarget GradeContribution
    {{contrib.project.student.name}} - - - - - - - {{contrib.percent}} % effort - - - No effort - - -
    -
    +
    + + + + + + + + + + + + + + + +
    Team MemberTarget GradeContribution
    {{contrib.project.student.name}} + + + + + + + {{contrib.percent}} % effort + + + No effort + + +
    +
    diff --git a/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html b/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html index 5dc40dc5b0..7e59cac17b 100644 --- a/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html +++ b/src/app/projects/project-progress-dashboard/project-progress-dashboard.tpl.html @@ -22,7 +22,7 @@

    Target Grade

    diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html b/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html index 0906d7b593..4d02cce31f 100644 --- a/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html +++ b/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html @@ -1,27 +1,27 @@ -
    - - - -
    +
    + + + +
    diff --git a/src/app/units/states/portfolios/portfolios.tpl.html b/src/app/units/states/portfolios/portfolios.tpl.html index 2b8a2277eb..800d4f4cbe 100644 --- a/src/app/units/states/portfolios/portfolios.tpl.html +++ b/src/app/units/states/portfolios/portfolios.tpl.html @@ -65,7 +65,7 @@

    Mark Portfolios

    btn-radio="{{$index}}" > Mark Portfolios

    {{student.tutorNames()}} {{student.shortTutorialDescription()}} - + - + diff --git a/src/app/units/states/students-list/students-list.tpl.html b/src/app/units/states/students-list/students-list.tpl.html index 929cefe386..d81fdb4cd6 100644 --- a/src/app/units/states/students-list/students-list.tpl.html +++ b/src/app/units/states/students-list/students-list.tpl.html @@ -1,182 +1,182 @@ -
    -
    -
    -
    - - - - -
    - -
    -
    -
    - -
    -
    - - -
    -
    -
    -
    - -
    -
    - - - -
    -
    -

    - Click the button twice to reverse the sort ordering. -

    -
    -
    -
    -
    -

    No students found

    -

    - No students were found using the filters specified. -

    -
    -
    - - - - - - - - - - - - - - - - - - - - - - - -
    - - Username - - - - Name - - - - Stats - - - - Flags - - - - - Campus - - - - Tutorial - -
    - - - {{project.student.username || "N/A"}} - - {{project.student.name}} - - - - {{bar.value !== bar.value ? 'No Interaction' : (bar.value + '%')}} - - - - - - - - - - - - - - - - - - -
    - -
    -
    +
    +
    +
    +
    + + + + +
    + +
    +
    +
    + +
    +
    + + +
    +
    +
    +
    + +
    +
    + + + +
    +
    +

    + Click the button twice to reverse the sort ordering. +

    +
    +
    +
    +
    +

    No students found

    +

    + No students were found using the filters specified. +

    +
    +
    + + + + + + + + + + + + + + + + + + + + + + + +
    + + Username + + + + Name + + + + Stats + + + + Flags + + + + + Campus + + + + Tutorial + +
    + + + {{project.student.username || "N/A"}} + + {{project.student.name}} + + + + {{bar.value !== bar.value ? 'No Interaction' : (bar.value + '%')}} + + + + + + + + + + + + + + + + + + +
    + +
    +
    From 91b42988188a2e9ebfdfbcca338382da656a7e32 Mon Sep 17 00:00:00 2001 From: ShounakB <65479699+Shounaks@users.noreply.github.com> Date: Mon, 18 Nov 2024 21:21:41 +1100 Subject: [PATCH 0220/1280] Fixing All components and CSS Cleanup --- .../common/grade-icon/grade-icon.component.html | 14 +++++++------- .../common/grade-icon/grade-icon.component.scss | 14 -------------- .../common/grade-icon/grade-icon.component.ts | 17 +++++++++-------- src/app/doubtfire-angularjs.module.ts | 2 +- .../group-member-contribution-assigner.tpl.html | 2 +- .../group-member-list.tpl.html | 2 +- .../project-progress-dashboard.tpl.html | 2 +- .../portfolio-grade-select-step.tpl.html | 6 +++--- .../grade-task-modal/grade-task-modal.tpl.html | 2 +- .../units/states/portfolios/portfolios.tpl.html | 8 ++++---- .../states/students-list/students-list.tpl.html | 2 +- 11 files changed, 29 insertions(+), 42 deletions(-) diff --git a/src/app/common/grade-icon/grade-icon.component.html b/src/app/common/grade-icon/grade-icon.component.html index 2cb10af9d8..7af15c0ba3 100644 --- a/src/app/common/grade-icon/grade-icon.component.html +++ b/src/app/common/grade-icon/grade-icon.component.html @@ -1,12 +1,12 @@ -
    +
    {{contrib.project.student.name}} - + No members in group {{member.student.username || "N/A"}} {{member.student.name}} - +

    diff --git a/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html b/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html index 4d02cce31f..7fa8e7055e 100644 --- a/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html +++ b/src/app/tasks/modals/grade-task-modal/grade-task-modal.tpl.html @@ -7,7 +7,7 @@

    Assess Task Quality

    Please provide a grade to change the student's status for task .

    diff --git a/src/app/units/states/portfolios/portfolios.tpl.html b/src/app/units/states/portfolios/portfolios.tpl.html index 800d4f4cbe..c67b13e400 100644 --- a/src/app/units/states/portfolios/portfolios.tpl.html +++ b/src/app/units/states/portfolios/portfolios.tpl.html @@ -64,12 +64,12 @@

    Mark Portfolios

    ng-model="filterOptions.selectedGrade" btn-radio="{{$index}}" > - + >