From 152d129204f620a713f990aa7e61369845f6d70b Mon Sep 17 00:00:00 2001
From: Irv Katz <60225276+exidy80@users.noreply.github.com>
Date: Sat, 7 Dec 2024 18:59:34 -0500
Subject: [PATCH 01/35] upgrade user-list and user-info
---
README.md | 9 +-
UPGRADE_NOTES.md | 23 +-
app/components/ui/form-field.hbs | 44 ++-
app/components/ui/form-field.js | 12 +-
...ble-list.hbs => user-collapsible-list.hbs} | 0
...sible-list.js => user-collapsible-list.js} | 0
app/components/user-info.hbs | 299 +++++++++---------
app/components/user-info.js | 236 +++++++-------
app/components/user-list.hbs | 24 +-
app/components/user-list.js | 182 +++++------
app/routes/users/user.js | 16 +-
app/services/error-handling.js | 5 +-
12 files changed, 452 insertions(+), 398 deletions(-)
rename app/components/{collapsible-list.hbs => user-collapsible-list.hbs} (100%)
rename app/components/{collapsible-list.js => user-collapsible-list.js} (100%)
diff --git a/README.md b/README.md
index 9292f9a1b..45ecc9700 100644
--- a/README.md
+++ b/README.md
@@ -76,7 +76,7 @@ If you run into the following error while running tests:
## Client `/app`
-EnCOMPASS uses Ember for the client and was recently migrated to Ember Octane from v2.14. Portions are not fully migrated.
+EnCOMPASS uses Ember for the client and was recently migrated to Ember Octane from v2.14. Portions are not fully migrated. See [UPGRADE_NOTES](./UPGRADE_NOTES.md) for more information.
### workflow
@@ -90,9 +90,6 @@ EnCOMPASS uses Ember for the client and was recently migrated to Ember Octane fr
Ember is switching to Glimmer for its component engine. Components that have their templates (.hbs files) in `app/components` have been migrated. Their classes (.js files) will look like native JS classes. Components with templates in `app/templates/components` have not been migrated and still use Classic Ember component classes. I tried to combine similar components when possible.
-- `admin-problem-filter` and `admin-workspace-filter` could be comined
-- `problem-filter` and `workspace-filter` could be combined
-
### mixins
usage of mixins (found in `app/mixins`) are deprecated - they still work for classic components but should be refactored away
@@ -122,9 +119,7 @@ Each route has a corresponding template that gets rendered. It should be in the
Libraries that are not managed by npm are added in the `/vendor` directory and configured into the bundle in `/ember-cli-build.js` including:
-1. selectize input library (see `app/components/selectize-input.js`)
-2. typeahead library (see `app/components/twitter-typeahead.js`)
-3. selection libraries (`vendor/image-tagging.js` and `vendor/selection-highlighting.js`) that are used in `app/components/workspace-submission.js`
+- selection libraries (`vendor/image-tagging.js` and `vendor/selection-highlighting.js`) that are used in `app/components/workspace-submission.js`
### `/helpers`
diff --git a/UPGRADE_NOTES.md b/UPGRADE_NOTES.md
index 989b7a25b..50f7261e4 100644
--- a/UPGRADE_NOTES.md
+++ b/UPGRADE_NOTES.md
@@ -6,6 +6,19 @@ There has been various attempts to upgrade this app to modern Ember (Octane, Emb
This file is an attempt to document what has and has not been done, as well as suggestions for future developers if I (like all others) leave an incomplete upgrade process.
+# Notes about the current state
+
+Enc-test has been updated with the latest version of the work that I've done over the last couple of months, as represented in this file. Of course, there is plenty that does not work; mostly parts of the system that have not yet been upgraded, upgrades that have not been adequately tested, and a few items that I document below that represent my current work when this contracted ended. To help the next developer, there are two files beyond this one:
+
+1. component audit.xls -- contains notes about all components in the Encompass system, including which have been upgraded or deleted.
+2. componentFinder.js -- script (run with "node componentFinder") that produces a report of all the components used in the different routes, all the components used by other components, etc. This should help the next developer in understanding how the Encompass app is organized.
+
+## Items in progress
+
+1. user-info component -- mostly works except for a few of the updates: seen tour, authorized, etc.
+2. problem-list-container and related components -- trashed problems might not be showing up correctly. Deleting and some actions might not be working.
+3. workspace-list-container and related components -- trashed and hidden workspaces might not be showing up correctly. Many of the actions in the three-dot (more) menu are not working.
+
# Upgrades needed globally
## Removal of Mixins
@@ -60,6 +73,10 @@ In Ember 4.5, helpers can now be regular functions rather than wrapped in a mana
11/14/2024: Upgraded to 4.5 and simplified all helpers.
+## Controllers
+
+Controllers are slated to be deprecated. Best practices are to replace them with the use of components -- the idea is that route templates reference components that contain work that had been done by controllers.
+
## EmberTable
There are other packages that are more aligned with Glimmer and Octane approaches to Ember. However, depending on the needs, perhaps the 5 uses of EmberTable could be replaced with vanilla JS.
@@ -87,6 +104,10 @@ Instead, we could leverage the {timestamps: true} option when defining all the M
There is now the folder app/components/ui that contains the form-field and expandable-cell components. The purpose of this folder is a place for generic UI components. Other generic UI components include: my-select, selectize-input, twitter-typeahead, radio-group (and radio-group-item), toggle-control, checkbox-list (and checkbox-list-item), collapsible-list, and quill-container. Once these get moved into that folder, every usage must reference the "Ui" namespace, such as or .
+# Other components
+
+Similar to the Ui example above, usage of Namespaces is encouraged in Ember moving forward. Thus, we should reorganize the app/components folder with subfolders representing the distinct subsystems of Encompass. The components in the folders would then be referenced in templates via namespaces, such as which refers to app/components/users/user-list.js and user-list.hbs.
+
## New Workspaces
The components workspace-new, workspace-new-enc, and workspace-new-pows are currently not used. They seem to reflect some type of new functionality (rather than template/workspaces/new.hbs and workspace-new-container, which are used) that Pedro was working on but never finished. I'm leaving these files in the codebase with the hope that someday someone will use them to figure out what was being done and to finish the work. Likely the intent was to have tempalte/workspaces/new.hbs use the workspace-new component.
@@ -184,7 +205,7 @@ If this.removeMessages is undefined, Ember might **not** show an error in the co
- **Components** - most of the discussion in this file focuses on the upgrading of components from classic to modern (Glimmer, Octane, Ember 4.5).
- **Adapters** - Upgraded
-- **Controllers** - Seem to have already been upgraded. I've not tested these.
+- **Controllers** - Controllers are slated to be deprecated in favor of using components. That is, the template for a route would simply contain invocations of one or ore components. Thus, working through the controllers and refactoring to remove them all is another goal of the upgrade.
- **Helpers** - as document elsewhere in this document, all upgraded.
- **Initializers** - only one and I believe it's not needed for production. I upgraded it, however.
- **Mixins** - as documented elsewhere, I'm in the process of eliminating these and double-checking others' work on removing these from components, etc.
diff --git a/app/components/ui/form-field.hbs b/app/components/ui/form-field.hbs
index 64f96545e..978cdf05a 100644
--- a/app/components/ui/form-field.hbs
+++ b/app/components/ui/form-field.hbs
@@ -1,21 +1,45 @@
-
+
{{! If isEditing is true, render an input/checkbox/other editable UI }}
{{#if @isEditing}}
{{#if (is-equal @type 'checkbox')}}
+ {{#if @label}}
+
+ {{/if}}
{{else if (is-equal @type 'textarea')}}
+ {{#if @label}}
+
+ {{/if}}
+ {{else if (is-equal @type 'button')}}
+
{{else}}
+ {{#if @label}}
+
+ {{/if}}
{{/if}}
- {{! Render a button if provided }}
+ {{! Render a post-field button if provided }}
{{#if @buttonLabel}}
-
+ {{#if @isEditing}}
+
+ {{/if}}
{{/if}}
\ No newline at end of file
diff --git a/app/components/ui/form-field.js b/app/components/ui/form-field.js
index e4ed262eb..62ccc7a38 100644
--- a/app/components/ui/form-field.js
+++ b/app/components/ui/form-field.js
@@ -3,7 +3,12 @@ import { action } from '@ember/object';
import { tracked } from '@glimmer/tracking';
export default class UiFormFieldComponent extends Component {
- @tracked currentValue = this.args.value; // Track the value for inline editing
+ // @tracked currentValue = this.args.value; // Track the value for inline editing
+ @tracked currentValue = this.args.value;
+
+ get id() {
+ return this.args.id || this.args.name || 'xyzzy';
+ }
@action
handleInput(event) {
@@ -27,4 +32,9 @@ export default class UiFormFieldComponent extends Component {
this.args.onClick();
}
}
+
+ @action
+ resetEditingValue() {
+ this.currentValue = this.args.value;
+ }
}
diff --git a/app/components/collapsible-list.hbs b/app/components/user-collapsible-list.hbs
similarity index 100%
rename from app/components/collapsible-list.hbs
rename to app/components/user-collapsible-list.hbs
diff --git a/app/components/collapsible-list.js b/app/components/user-collapsible-list.js
similarity index 100%
rename from app/components/collapsible-list.js
rename to app/components/user-collapsible-list.js
diff --git a/app/components/user-info.hbs b/app/components/user-info.hbs
index 830c615b4..ce684e3ee 100644
--- a/app/components/user-info.hbs
+++ b/app/components/user-info.hbs
@@ -1,5 +1,7 @@
-
{{@user.username}}'s Account Details
-{{#each this.errorHandling.loadOrgsErrors as |error|}}
+
\ No newline at end of file
diff --git a/app/templates/users/user.hbs b/app/templates/users/user.hbs
index be06db807..d6aa3082f 100644
--- a/app/templates/users/user.hbs
+++ b/app/templates/users/user.hbs
@@ -1,4 +1,10 @@
{{page-title this.model.user.username}}
-
-
+
+
\ No newline at end of file
From d1110931e7b05b9da30e76353ce2eec5a726705a Mon Sep 17 00:00:00 2001
From: Irv Katz <60225276+exidy80@users.noreply.github.com>
Date: Sat, 7 Dec 2024 19:27:17 -0500
Subject: [PATCH 04/35] used router service instead of deprecated
this.transitionTo
---
app/components/assignment-info-teacher.js | 10 +++++-----
app/components/problem-info.js | 10 +++++-----
app/routes/application.js | 15 ++++++++-------
app/routes/assignments/assignment.js | 3 ++-
app/routes/assignments/new.js | 7 ++++---
app/routes/folders_index.js | 4 +++-
app/routes/problems/new.js | 5 +++--
app/routes/responses.js | 7 ++++---
app/routes/responses/new/submission.js | 7 ++++---
app/routes/responses/submission.js | 11 ++++++-----
app/routes/sections/new.js | 3 ++-
app/routes/sections/section.js | 5 +++--
app/routes/submission/response.js | 13 +++++++------
app/routes/submissions/first.js | 5 +++--
app/routes/submissions/submission.js | 11 ++++++++---
app/routes/unauthorized.js | 7 ++++---
app/routes/unconfirmed.js | 7 ++++---
app/routes/users.js | 3 ++-
app/routes/vmt/import.js | 4 +++-
app/routes/workspace/submissions/submission.js | 12 ++++++++----
app/routes/workspaces.js | 4 +++-
app/routes/workspaces/copy.js | 3 ++-
app/routes/workspaces/new.js | 7 ++++---
23 files changed, 97 insertions(+), 66 deletions(-)
diff --git a/app/components/assignment-info-teacher.js b/app/components/assignment-info-teacher.js
index 4c07e8edc..a92d6b76c 100644
--- a/app/components/assignment-info-teacher.js
+++ b/app/components/assignment-info-teacher.js
@@ -6,6 +6,11 @@ import $ from 'jquery';
import moment from 'moment';
export default class AssignmentInfoTeacherComponent extends ErrorHandlingComponent {
+ @service store;
+ @service router;
+ @service('sweet-alert') alert;
+ @service('assignment-permissions') permissions;
+ @service('utility-methods') utils;
@tracked formattedDueDate = null;
@tracked formattedAssignedDate = null;
@tracked isEditing = false;
@@ -45,11 +50,6 @@ export default class AssignmentInfoTeacherComponent extends ErrorHandlingCompone
get allGroupsHaveWs() {
return this.groupsWithoutWorkspaces.length === 0;
}
- @service store;
- @service router;
- @service('sweet-alert') alert;
- @service('assignment-permissions') permissions;
- @service('utility-methods') utils;
get hasLinkedWorkspaces() {
return this.args.assignment.linkedWorkspaces.length > 0;
diff --git a/app/components/problem-info.js b/app/components/problem-info.js
index 0825aee79..c830052c1 100644
--- a/app/components/problem-info.js
+++ b/app/components/problem-info.js
@@ -6,6 +6,11 @@ import { inject as service } from '@ember/service';
import $ from 'jquery';
export default class ProblemInfoComponent extends ErrorHandlingComponent {
+ @service('sweet-alert') alert;
+ @service('problem-permissions') permissions;
+ @service('utility-methods') utils;
+ @service store;
+ @service router;
@tracked isEditing = false;
@tracked showGeneral = true;
@tracked problemName = null;
@@ -32,11 +37,6 @@ export default class ProblemInfoComponent extends ErrorHandlingComponent {
@tracked showAdditional = false;
@tracked showLegal = false;
@tracked categoryTree = {};
- @service('sweet-alert') alert;
- @service('problem-permissions') permissions;
- @service('utility-methods') utils;
- @service store;
- @service router;
@tracked copyrightNotice = '';
@tracked sharingAuth = '';
@tracked author = '';
diff --git a/app/routes/application.js b/app/routes/application.js
index 6bb87f802..912c79ffa 100644
--- a/app/routes/application.js
+++ b/app/routes/application.js
@@ -13,11 +13,12 @@ import { action } from '@ember/object';
export default class Application extends Route {
//the application route can't require authentication since it's getting the user
- @service('user-ntfs') userNtfs;
+ @service userNtfs;
@service store;
- @service('workspace-permissions') workspacePermissions;
- @service('edit-permissions') editPermissions;
- @service('current-user') currentUser;
+ @service router;
+ @service workspacePermissions;
+ @service editPermissions;
+ @service currentUser;
beforeModel() {
let that = this;
window.addEventListener(
@@ -62,11 +63,11 @@ export default class Application extends Route {
// should be extending AuthenticatedRoute.
if (!user.get('isAuthenticated')) {
this.store.unloadAll();
- this.transitionTo('welcome');
+ this.router.transitionTo('welcome');
} else if (!user.get('isEmailConfirmed') && !user.get('isStudent')) {
- this.transitionTo('unconfirmed');
+ this.router.transitionTo('unconfirmed');
} else if (!user.get('isAuthz')) {
- this.transitionTo('unauthorized');
+ this.router.transitionTo('unauthorized');
}
}
diff --git a/app/routes/assignments/assignment.js b/app/routes/assignments/assignment.js
index 4e0336d04..82ec09bce 100644
--- a/app/routes/assignments/assignment.js
+++ b/app/routes/assignments/assignment.js
@@ -4,6 +4,7 @@ import { hash } from 'rsvp';
import { inject as service } from '@ember/service';
export default class AssignmentsAssignmentRoute extends AuthenticatedRoute {
@service store;
+ @service router;
async model(params) {
let currentUser = this.modelFor('application');
const assignment = await this.store.findRecord(
@@ -27,6 +28,6 @@ export default class AssignmentsAssignmentRoute extends AuthenticatedRoute {
});
}
@action toAssignments() {
- this.transitionTo('assignments');
+ this.router.transitionTo('assignments');
}
}
diff --git a/app/routes/assignments/new.js b/app/routes/assignments/new.js
index eb8ad1d41..8a148f7a8 100644
--- a/app/routes/assignments/new.js
+++ b/app/routes/assignments/new.js
@@ -4,12 +4,13 @@ import AuthenticatedRoute from '../_authenticated_route';
import { inject as service } from '@ember/service';
export default class AssignmentsNewRoute extends AuthenticatedRoute {
@service store;
+ @service router;
beforeModel() {
const user = this.modelFor('application');
const isStudent = user.get('isStudent');
if (isStudent) {
- this.transitionTo('assignments');
+ this.router.transitionTo('assignments');
}
}
async model() {
@@ -22,9 +23,9 @@ export default class AssignmentsNewRoute extends AuthenticatedRoute {
});
}
@action toAssignmentInfo(model) {
- this.transitionTo('assignment', model);
+ this.router.transitionTo('assignment', model);
}
@action toAssignmentsHome() {
- this.transitionTo('assignments');
+ this.router.transitionTo('assignments');
}
}
diff --git a/app/routes/folders_index.js b/app/routes/folders_index.js
index a17c88c26..024c757f1 100644
--- a/app/routes/folders_index.js
+++ b/app/routes/folders_index.js
@@ -4,15 +4,17 @@
* @since 1.0.0
*/
import Route from '@ember/routing/route';
+import { inject as service } from '@ember/service';
export default class FoldersIndexRoute extends Route {
+ @service router;
model() {
return this.store.findAll('folder');
}
afterModel(folders, transition) {
if (folders.length === 1) {
- this.transitionTo('workspaceFolder', folders.firstObject);
+ this.router.transitionTo('workspaceFolder', folders.firstObject);
}
}
}
diff --git a/app/routes/problems/new.js b/app/routes/problems/new.js
index 1fbd7f8ae..289212b40 100644
--- a/app/routes/problems/new.js
+++ b/app/routes/problems/new.js
@@ -5,6 +5,7 @@ import AuthenticatedRoute from '../_authenticated_route';
export default class ProblemsNewRoute extends AuthenticatedRoute {
@service store;
+ @service router;
model() {
let currentUser = this.modelFor('application');
return hash({
@@ -15,9 +16,9 @@ export default class ProblemsNewRoute extends AuthenticatedRoute {
}
@action toProblemInfo(problem) {
- this.transitionTo('problems.problem', problem.id);
+ this.router.transitionTo('problems.problem', problem.id);
}
@action toProblemList() {
- this.transitionTo('problems');
+ this.router.transitionTo('problems');
}
}
diff --git a/app/routes/responses.js b/app/routes/responses.js
index ef0c88aa7..e4230374a 100644
--- a/app/routes/responses.js
+++ b/app/routes/responses.js
@@ -1,15 +1,16 @@
import AuthenticatedRoute from './_authenticated_route';
import { action } from '@ember/object';
-
+import { inject as service } from '@ember/service';
export default class ResponsesRoute extends AuthenticatedRoute {
+ @service router;
@action toSubmissionResponse(subId) {
- this.transitionTo('responses.submission', subId);
+ this.router.transitionTo('responses.submission', subId);
}
@action toResponses() {
this.refresh();
}
@action toResponse(submissionId, responseId) {
- this.transitionTo('responses.submission', submissionId, {
+ this.router.transitionTo('responses.submission', submissionId, {
queryParams: { responseId: responseId },
});
}
diff --git a/app/routes/responses/new/submission.js b/app/routes/responses/new/submission.js
index ed49f78e6..9cdc26645 100644
--- a/app/routes/responses/new/submission.js
+++ b/app/routes/responses/new/submission.js
@@ -9,6 +9,7 @@ export default class ResponsesNewSubmissionRoute extends Route.extend(
) {
@service('utility-methods') utils;
@service store;
+ @service router;
renderTemplate() {
this.render('responses/response');
}
@@ -130,18 +131,18 @@ export default class ResponsesNewSubmissionRoute extends Route.extend(
afterModel(model) {
if (model.isDraft) {
- this.transitionTo('responses.submission', model.submissionId, {
+ this.router.transitionTo('responses.submission', model.submissionId, {
queryParams: { responseId: model.responseId },
});
}
}
@action toResponse(submissionId, responseId) {
- this.transitionTo('responses.submission', submissionId, {
+ this.router.transitionTo('responses.submission', submissionId, {
queryParams: { responseId: responseId },
});
}
@action toResponseSubmission(subId) {
- this.transitionTo('responses.submission', subId);
+ this.router.transitionTo('responses.submission', subId);
}
}
diff --git a/app/routes/responses/submission.js b/app/routes/responses/submission.js
index 7318894d4..064246382 100644
--- a/app/routes/responses/submission.js
+++ b/app/routes/responses/submission.js
@@ -5,6 +5,7 @@ import { action } from '@ember/object';
export default class ResponsesRoute extends AuthenticatedRoute {
@service('utility-methods') utils;
@service store;
+ @service router;
queryParams = {
responseId: {
refreshModel: true,
@@ -86,26 +87,26 @@ export default class ResponsesRoute extends AuthenticatedRoute {
redirect(model, transition) {
if (!model) {
- this.transitionTo('responses');
+ this.router.transitionTo('responses');
}
}
@action toResponseSubmission(subId) {
- this.transitionTo('responses.submission', subId);
+ this.router.transitionTo('responses.submission', subId);
}
@action toResponse(submissionId, responseId) {
- this.transitionTo('responses.submission', submissionId, {
+ this.router.transitionTo('responses.submission', submissionId, {
queryParams: { responseId: responseId },
});
}
@action toResponses() {
- this.transitionTo('responses');
+ this.router.transitionTo('responses');
}
@action toNewResponse(submissionId, workspaceId) {
- this.transitionTo('responses.new.submission', submissionId, {
+ this.router.transitionTo('responses.new.submission', submissionId, {
queryParams: { workspaceId: workspaceId },
});
}
diff --git a/app/routes/sections/new.js b/app/routes/sections/new.js
index 1dff6df38..40fbc3b16 100644
--- a/app/routes/sections/new.js
+++ b/app/routes/sections/new.js
@@ -4,12 +4,13 @@ import { inject as service } from '@ember/service';
export default class SectionsNewRoute extends AuthenticatedRoute {
@service store;
+ @service router;
beforeModel() {
const user = this.modelFor('application');
const isStudent = user.get('isStudent');
if (isStudent) {
- this.transitionTo('sections');
+ this.router.transitionTo('sections');
}
}
diff --git a/app/routes/sections/section.js b/app/routes/sections/section.js
index 2fdb8a271..59d20db75 100644
--- a/app/routes/sections/section.js
+++ b/app/routes/sections/section.js
@@ -5,6 +5,7 @@ import { inject as service } from '@ember/service';
export default class SectionsSectionRoute extends AuthenticatedRoute {
@service store;
+ @service router;
async model(params) {
let section = await this.store.findRecord('section', params.section_id);
let groups = await this.store.query('group', {
@@ -23,10 +24,10 @@ export default class SectionsSectionRoute extends AuthenticatedRoute {
}
@action toSectionList() {
- this.transitionTo('sections');
+ this.router.transitionTo('sections');
}
@action toAssignmentInfo(assignment) {
- this.transitionTo('assignments.assignment', assignment);
+ this.router.transitionTo('assignments.assignment', assignment);
}
@action refreshModel() {
this.refresh();
diff --git a/app/routes/submission/response.js b/app/routes/submission/response.js
index a6fd3953d..f9659d480 100644
--- a/app/routes/submission/response.js
+++ b/app/routes/submission/response.js
@@ -4,33 +4,34 @@ import { action } from '@ember/object';
export default class ResponsesRoute extends ConfirmLeavingRoute {
@service('utility-methods') utils;
@service store;
+ @service router;
model(params) {
return this.store.findRecord('response', params.response_id);
}
redirect(model, transition) {
if (!model) {
- this.transitionTo('responses');
+ this.router.transitionTo('responses');
} else {
let submissionId = this.utils.getBelongsToId(model, 'submission');
if (this.utils.isValidMongoId(submissionId)) {
- this.transitionTo('responses.submission', submissionId, {
+ this.router.transitionTo('responses.submission', submissionId, {
queryParams: { responseId: model.get('id') },
});
} else {
- this.transitionTo('responses');
+ this.router.transitionTo('responses');
}
}
}
@action toResponseInfo(response) {
- this.transitionTo('response', response.get('id'));
+ this.router.transitionTo('response', response.get('id'));
}
@action toResponses() {
- this.transitionTo('responses');
+ this.router.transitionTo('responses');
}
@action toNewResponse(submissionId, workspaceId) {
- this.transitionTo('responses.new.submission', submissionId, {
+ this.router.transitionTo('responses.new.submission', submissionId, {
queryParams: { workspaceId: workspaceId },
});
}
diff --git a/app/routes/submissions/first.js b/app/routes/submissions/first.js
index 67c8ecf09..af73e7cbf 100644
--- a/app/routes/submissions/first.js
+++ b/app/routes/submissions/first.js
@@ -10,6 +10,7 @@ import { inject as service } from '@ember/service';
export default Route.extend({
utils: service('utility-methods'),
alert: service('sweet-alert'),
+ router: service(),
model: function () {
return this.modelFor('workspace.submissions');
@@ -22,7 +23,7 @@ export default Route.extend({
let firstStudent = sorted.get('firstObject.student');
let lastRevision = sorted.getEach('student').lastIndexOf(firstStudent);
- this.transitionTo(
+ this.router.transitionTo(
'workspace.submissions.submission',
workspace,
sorted.objectAt(lastRevision).get('id')
@@ -38,7 +39,7 @@ export default Route.extend({
null
);
- this.transitionTo('workspace.info');
+ this.router.transitionTo('workspace.info');
}
},
});
diff --git a/app/routes/submissions/submission.js b/app/routes/submissions/submission.js
index 72a70d21e..3858769c5 100644
--- a/app/routes/submissions/submission.js
+++ b/app/routes/submissions/submission.js
@@ -18,6 +18,7 @@ import VmtHostMixin from '../mixins/vmt-host';
export default Route.extend(CurrentUserMixin, VmtHostMixin, {
alert: service('sweet-alert'),
utils: service('utility-methods'),
+ router: service(),
queryParams: 'vmtRoomId',
@@ -39,9 +40,13 @@ export default Route.extend(CurrentUserMixin, VmtHostMixin, {
// so links to selections still work
if (transition.intent.name === 'workspace.submissions.submission') {
- this.transitionTo('workspace.submissions.submission', submission, {
- queryParams: { vmtRoomId },
- });
+ this.router.transitionTo(
+ 'workspace.submissions.submission',
+ submission,
+ {
+ queryParams: { vmtRoomId },
+ }
+ );
}
});
},
diff --git a/app/routes/unauthorized.js b/app/routes/unauthorized.js
index 96857a9a5..3a49aa925 100644
--- a/app/routes/unauthorized.js
+++ b/app/routes/unauthorized.js
@@ -4,12 +4,13 @@ import { action } from '@ember/object';
export default class UnauthorizedRoute extends Route {
@service store;
+ @service router;
beforeModel() {
// redirect to login if no user logged in
const user = this.modelFor('application');
if (!user || !user.get('isAuthenticated')) {
- return this.transitionTo('auth.login');
+ return this.router.transitionTo('auth.login');
}
// redirect to confirm email info page if
// email still needs confirming
@@ -19,12 +20,12 @@ export default class UnauthorizedRoute extends Route {
!user.get('isStudent');
if (doesEmailNeedConfirming) {
- return this.transitionTo('unconfirmed');
+ return this.router.transitionTo('unconfirmed');
}
// redirect to home page if already authorized
if (user.get('isAuthz')) {
- this.transitionTo('/');
+ this.router.transitionTo('/');
}
}
diff --git a/app/routes/unconfirmed.js b/app/routes/unconfirmed.js
index 21ef0706e..5f443a839 100644
--- a/app/routes/unconfirmed.js
+++ b/app/routes/unconfirmed.js
@@ -1,17 +1,18 @@
import Route from '@ember/routing/route';
-
+import { inject as service } from '@ember/service';
export default class UnconfirmedRoute extends Route {
+ @service router;
beforeModel() {
// redirect to login if no user logged in
const user = this.modelFor('application');
if (!user || !user.get('isAuthenticated')) {
- return this.transitionTo('auth.login');
+ return this.router.transitionTo('auth.login');
}
// redirect to home page if email is already confirmed or user does not have an email
if (user.get('isEmailConfirmed') || !user.get('email')) {
- this.transitionTo('/');
+ this.router.transitionTo('/');
}
}
}
diff --git a/app/routes/users.js b/app/routes/users.js
index 1e7e6b152..10b203f1c 100644
--- a/app/routes/users.js
+++ b/app/routes/users.js
@@ -11,12 +11,13 @@ import { inject as service } from '@ember/service';
export default class UsersRoute extends Route {
@service store;
+ @service router;
beforeModel() {
const user = this.modelFor('application');
const isStudent = user.get('isStudent');
if (isStudent) {
- this.transitionTo('/');
+ this.router.transitionTo('/');
}
}
async model() {
diff --git a/app/routes/vmt/import.js b/app/routes/vmt/import.js
index 63f472f7b..856467191 100644
--- a/app/routes/vmt/import.js
+++ b/app/routes/vmt/import.js
@@ -1,8 +1,10 @@
import { hash } from 'rsvp';
import AuthenticatedRoute from '../_authenticated_route';
+import { inject as service } from '@ember/service';
export default AuthenticatedRoute.extend({
controllerName: 'vmt-import',
+ router: service(),
model() {
return hash({
@@ -13,7 +15,7 @@ export default AuthenticatedRoute.extend({
actions: {
toWorkspaces: function (workspaceId) {
- this.transitionTo('workspace.work', workspaceId);
+ this.router.transitionTo('workspace.work', workspaceId);
// window.location.href = `#/workspaces/${workspace._id}/submissions/${workspace.submissions[0]}`;
},
},
diff --git a/app/routes/workspace/submissions/submission.js b/app/routes/workspace/submissions/submission.js
index 4ee987996..76702ce60 100644
--- a/app/routes/workspace/submissions/submission.js
+++ b/app/routes/workspace/submissions/submission.js
@@ -11,12 +11,12 @@ import Route from '@ember/routing/route';
import { schedule } from '@ember/runloop';
import { hash, resolve } from 'rsvp';
import { inject as service } from '@ember/service';
-import $ from 'jquery';
import { action } from '@ember/object';
export default class WorkspaceSubmissionRoute extends Route {
@service sweetAlert;
@service('utility-methods') utils;
@service currentUser;
+ @service router;
queryParams = {
vmtRoomId: {
@@ -44,9 +44,13 @@ export default class WorkspaceSubmissionRoute extends Route {
// so links to selections still work
if (transition.intent.name === 'workspace.submissions.submission') {
- this.transitionTo('workspace.submissions.submission', submission, {
- queryParams: { vmtRoomId },
- });
+ this.router.transitionTo(
+ 'workspace.submissions.submission',
+ submission,
+ {
+ queryParams: { vmtRoomId },
+ }
+ );
}
});
}
diff --git a/app/routes/workspaces.js b/app/routes/workspaces.js
index 1182eb171..5ec6ed47a 100644
--- a/app/routes/workspaces.js
+++ b/app/routes/workspaces.js
@@ -7,11 +7,13 @@
import AuthenticatedRoute from './_authenticated_route';
import { action } from '@ember/object';
+import { inject as service } from '@ember/service';
export default class WorkspacesRoute extends AuthenticatedRoute {
+ @service router;
@action toCopyWorkspace(workspace) {
let workspaceId = workspace.get('id');
- this.transitionTo('workspaces.copy', {
+ this.router.transitionTo('workspaces.copy', {
queryParams: { workspace: workspaceId },
});
}
diff --git a/app/routes/workspaces/copy.js b/app/routes/workspaces/copy.js
index 6d6bf9e5f..f00117477 100644
--- a/app/routes/workspaces/copy.js
+++ b/app/routes/workspaces/copy.js
@@ -5,6 +5,7 @@ import AuthenticatedRoute from '../_authenticated_route';
export default class WorkspacesCopyRoute extends AuthenticatedRoute {
@service store;
+ @service router;
workspaceToCopy = null;
workspaceId = null;
beforeModel(transition) {
@@ -23,6 +24,6 @@ export default class WorkspacesCopyRoute extends AuthenticatedRoute {
}
@action toWorkspace(id) {
- this.transitionTo('workspace.work', id);
+ this.router.transitionTo('workspace.work', id);
}
}
diff --git a/app/routes/workspaces/new.js b/app/routes/workspaces/new.js
index 65838ccd7..519ac56f5 100644
--- a/app/routes/workspaces/new.js
+++ b/app/routes/workspaces/new.js
@@ -5,12 +5,13 @@ import AuthenticatedRoute from '../_authenticated_route';
export default class WorkspacesNewRoute extends AuthenticatedRoute {
@service store;
+ @service router;
beforeModel() {
const user = this.modelFor('application');
const isStudent = user.get('isStudent');
if (isStudent) {
- this.transitionTo('/');
+ this.router.transitionTo('/');
}
}
model() {
@@ -27,10 +28,10 @@ export default class WorkspacesNewRoute extends AuthenticatedRoute {
}
// Created workspaceId and is passed from component to redirect
@action toWorkspaces(id) {
- this.transitionTo('workspace.work', id);
+ this.router.transitionTo('workspace.work', id);
}
@action toWorkspace(id) {
- this.transitionTo('workspace/work', id);
+ this.router.transitionTo('workspace/work', id);
}
}
From a663e2e4616ade6208711403b6e09cef7d21b237 Mon Sep 17 00:00:00 2001
From: Irv Katz <60225276+exidy80@users.noreply.github.com>
Date: Sun, 8 Dec 2024 16:22:32 -0500
Subject: [PATCH 05/35] cleaned up a few more deprecations in models
---
UPGRADE_NOTES.md | 10 +++++++++-
app/models/folder.js | 2 +-
app/models/tagging.js | 6 +++---
app/models/workspace.js | 2 +-
app/routes/index.js | 30 ++++++++++++++++--------------
5 files changed, 30 insertions(+), 20 deletions(-)
diff --git a/UPGRADE_NOTES.md b/UPGRADE_NOTES.md
index 50f7261e4..dd8122c58 100644
--- a/UPGRADE_NOTES.md
+++ b/UPGRADE_NOTES.md
@@ -75,7 +75,11 @@ In Ember 4.5, helpers can now be regular functions rather than wrapped in a mana
## Controllers
-Controllers are slated to be deprecated. Best practices are to replace them with the use of components -- the idea is that route templates reference components that contain work that had been done by controllers.
+Controllers are slated to be deprecated. Best practice is to refactor the logic and properties in the controller, distributing them as appropriate to the route (for building the model), a service (for application state that will be used elsewhere), and a component (for everything else). The idea is that a route templates should be simple and reference just one or moe components that contain much of the work that had been done by the controller.
+
+## Route Templates
+
+Route templates should refer to the model via @model rather than this.model as per the Ember Octane upgrade guide.
## EmberTable
@@ -92,6 +96,10 @@ The current code includes several subsystems of components that are tightly coup
# Possible future upgrades
+## Model definitions
+
+All hasMany and belowsTo relationships should specify inverse and async options explicitly. Not doing so is deprecated.
+
## DB document timestamps
Currently, all timestamping of db documents (users, problems, workspaces, etc.) appears to be done manually primarily on the client side. This approach could cause issues because the clients clocks might be wrong. Also, because the dates are updated manually (all over the codebase), there is a higher likelihood of errors.
diff --git a/app/models/folder.js b/app/models/folder.js
index 9ad85c21f..388a62ab2 100644
--- a/app/models/folder.js
+++ b/app/models/folder.js
@@ -4,7 +4,7 @@ import AuditableModel from './auditable';
export default class FolderModel extends AuditableModel {
@attr('string') name;
@attr('number') weight;
- @hasMany('tagging', { async: true }) taggings;
+ @hasMany('tagging', { inverse: 'folder', async: true }) taggings;
@belongsTo('folder', { inverse: 'children', async: true }) parent;
@hasMany('folder', { inverse: 'parent', async: true }) children;
@belongsTo('workspace', { async: true }) workspace;
diff --git a/app/models/tagging.js b/app/models/tagging.js
index 8d4d4c259..3d265e6a4 100644
--- a/app/models/tagging.js
+++ b/app/models/tagging.js
@@ -3,9 +3,9 @@ import { belongsTo } from '@ember-data/model';
import AuditableModel from './auditable';
export default class TaggingModel extends AuditableModel {
- @belongsTo('workspace', { async: false }) workspace;
- @belongsTo('selection', { async: true }) selection;
- @belongsTo('folder', { async: true }) folder;
+ @belongsTo('workspace', { inverse: 'taggings', async: false }) workspace;
+ @belongsTo('selection', { inverse: 'taggings', async: true }) selection;
+ @belongsTo('folder', { inverse: 'taggings', async: true }) folder;
@belongsTo('tagging', { inverse: null, async: true }) originalTagging;
copy() {
diff --git a/app/models/workspace.js b/app/models/workspace.js
index bd3a06d9a..ab967673e 100644
--- a/app/models/workspace.js
+++ b/app/models/workspace.js
@@ -12,7 +12,7 @@ export default class WorkspaceModel extends AuditableModel {
@belongsTo('user', { async: true }) owner;
@hasMany('user', { async: true }) editors;
@hasMany('folder', { async: true }) folders;
- @attr() group;
+ @belongsTo('group', { inverse: null, async: true }) group;
@hasMany('submission', { async: true }) submissions;
@hasMany('response', { async: true }) responses;
@hasMany('selection', { async: true }) selections;
diff --git a/app/routes/index.js b/app/routes/index.js
index 689611b5a..d81d0eaa9 100644
--- a/app/routes/index.js
+++ b/app/routes/index.js
@@ -32,21 +32,23 @@ export default class IndexRoute extends Route {
const user = this.currentUser.user;
const sections = await this.store.findAll('section');
- const teacherSections = sections.filter((section) =>
- section.teachers.includes(user)
- );
-
- const studentSections = sections.filter((section) =>
- section.students.includes(user)
- );
-
- const teacherAssignments = teacherSections.flatMap((section) =>
- section.assignments.toArray()
- );
+ const teacherAssignments = (
+ await Promise.all(
+ sections.map(async (section) => {
+ const teachers = await section.teachers;
+ return teachers.includes(user) ? section.assignments.toArray() : [];
+ })
+ )
+ ).flat();
- const studentAssignments = studentSections.flatMap((section) =>
- section.assignments.toArray()
- );
+ const studentAssignments = (
+ await Promise.all(
+ sections.map(async (section) => {
+ const students = await section.students;
+ return students.includes(user) ? section.assignments.toArray() : [];
+ })
+ )
+ ).flat();
const teacherClasses = user.sections.map((section) => section.sectionId);
From 186e946a893a346b05b627551ddd33e1f185f318 Mon Sep 17 00:00:00 2001
From: Irv Katz <60225276+exidy80@users.noreply.github.com>
Date: Mon, 9 Dec 2024 10:39:00 -0500
Subject: [PATCH 06/35] move radiogroup to ui folder
---
app/components/assignment-new.hbs | 8 +-
app/components/parent-ws-collab-new.hbs | 4 +-
app/components/{ => ui}/radio-group-item.hbs | 0
app/components/{ => ui}/radio-group.hbs | 2 +-
app/components/{ => ui}/radio-group.js | 0
.../workspace-info-collaborators-new.hbs | 2 +-
.../workspace-info-collaborators.hbs | 18 +-
.../components/import-work-step2.hbs | 2 +-
.../components/import-work-step5.hbs | 257 ++++++++++++------
.../components/new-folderset-form.hbs | 52 +++-
.../components/workspace-new-settings.hbs | 4 +-
app/templates/components/ws-copy-config.hbs | 49 +++-
.../components/ws-copy-owner-settings.hbs | 2 +-
.../ws-new-settings-permissions.hbs | 2 +-
.../components/ws-permissions-new.hbs | 105 +++++--
15 files changed, 352 insertions(+), 155 deletions(-)
rename app/components/{ => ui}/radio-group-item.hbs (100%)
rename app/components/{ => ui}/radio-group.hbs (96%)
rename app/components/{ => ui}/radio-group.js (100%)
diff --git a/app/components/assignment-new.hbs b/app/components/assignment-new.hbs
index bcc3cb5db..2ae0094ab 100644
--- a/app/components/assignment-new.hbs
+++ b/app/components/assignment-new.hbs
@@ -200,7 +200,7 @@
\ No newline at end of file
diff --git a/app/templates/components/new-folderset-form.hbs b/app/templates/components/new-folderset-form.hbs
index f477ce371..c97fa08b5 100644
--- a/app/templates/components/new-folderset-form.hbs
+++ b/app/templates/components/new-folderset-form.hbs
@@ -1,27 +1,51 @@
-
-
+
+
Folder Set Name
-
-
+
+
-
-
+
+
{{#each nameErrors as |error|}}
-
+
{{/each}}
-
-
+
+
Folder Set Privacy Setting
-
-
+
+
-
+
{{#each privacyErrors as |error|}}
-
+
{{/each}}
-
+
\ No newline at end of file
diff --git a/app/templates/components/workspace-new-settings.hbs b/app/templates/components/workspace-new-settings.hbs
index 70bbdbb0a..a6239ce5d 100644
--- a/app/templates/components/workspace-new-settings.hbs
+++ b/app/templates/components/workspace-new-settings.hbs
@@ -75,7 +75,7 @@
-
-
+
\ No newline at end of file
diff --git a/app/templates/components/import-work-step5.hbs b/app/templates/components/import-work-step5.hbs
index 09c665927..dc1823c51 100644
--- a/app/templates/components/import-work-step5.hbs
+++ b/app/templates/components/import-work-step5.hbs
@@ -37,7 +37,7 @@
{{#if missingNameError}}
-
{{#if missingOwnerError}}
-
{{#if missingAssignmentError}}
-
{{#each nameErrors as |error|}}
-
{{#each privacyErrors as |error|}}
- Approver Panel
+
Approver Panel
{{#if showApproverActions}}
-
-
Manage Mentor Reply
+
+
Manage Mentor Reply
-
- {{#if showNoActionsMessage}}
-
- This Mentor Reply has already been approved by {{responseToApprove.approvedBy.username}} and sent to {{responseToApprove.recipient.username}}. There are no further approval actions to take at this time.
-
+ This Mentor Reply has already been approved by
+ {{responseToApprove.approvedBy.username}}
+ and sent to
+ {{responseToApprove.recipient.username}}. There are no further
+ approval actions to take at this time.
+
\ No newline at end of file
diff --git a/app/templates/components/response-mentor-reply.hbs b/app/templates/components/response-mentor-reply.hbs
index 61dd5a280..8fd3a375b 100644
--- a/app/templates/components/response-mentor-reply.hbs
+++ b/app/templates/components/response-mentor-reply.hbs
@@ -129,14 +129,14 @@
{{/each}}
{{#if this.emptyReplyError}}
-
{{/if}}
{{#if this.quillTooLongError}}
-
{{#if isEditing}}
Cancel
- Save
+ Save
{{/if}}
{{#if isRevising}}
Cancel
- Save as
- DraftSave as Draft
+ {{sendButtonText}}
{{/if}}
{{#if isFinishingDraft}}
Cancel
- Save as
- DraftSave as Draft
+ {{sendButtonText}}
{{/if}}
@@ -194,7 +214,11 @@
{{#if this.canSendNew}}
Click 'New Response' to begin composing a new Mentor Reply.
\ No newline at end of file
diff --git a/app/templates/components/workspace-new-settings.hbs b/app/templates/components/workspace-new-settings.hbs
index a6239ce5d..31b0310bb 100644
--- a/app/templates/components/workspace-new-settings.hbs
+++ b/app/templates/components/workspace-new-settings.hbs
@@ -23,7 +23,7 @@
/>
{{#each workspaceNameErrors as |error|}}
-
{{#each ownerErrors as |error|}}
-
{{#each privacySettingErrors as |error|}}
-
{{#each folderSetErrors as |error|}}
-
{{#if createWorkspaceError}}
-
{{#if insufficientSubmissions}}
-
{{#each nameErrors as |error|}}
-
{{#each ownerErrors as |error|}}
-
{{#each modeErrors as |error|}}
-
{{#if duplicateFolderSetName}}
-
{{#if missingWorkspace}}
-
{{#if saveError}}
-
{{#if saveError}}
-
Date: Mon, 9 Dec 2024 10:48:51 -0500
Subject: [PATCH 09/35] move wordcloudContainer to ui folder
---
app/components/{ => ui}/wordcloud-container.hbs | 0
app/components/{ => ui}/wordcloud-container.js | 0
app/templates/metrics/workspace.hbs | 13 ++++++++-----
3 files changed, 8 insertions(+), 5 deletions(-)
rename app/components/{ => ui}/wordcloud-container.hbs (100%)
rename app/components/{ => ui}/wordcloud-container.js (100%)
diff --git a/app/components/wordcloud-container.hbs b/app/components/ui/wordcloud-container.hbs
similarity index 100%
rename from app/components/wordcloud-container.hbs
rename to app/components/ui/wordcloud-container.hbs
diff --git a/app/components/wordcloud-container.js b/app/components/ui/wordcloud-container.js
similarity index 100%
rename from app/components/wordcloud-container.js
rename to app/components/ui/wordcloud-container.js
diff --git a/app/templates/metrics/workspace.hbs b/app/templates/metrics/workspace.hbs
index caafb1bcd..d186b4b6e 100644
--- a/app/templates/metrics/workspace.hbs
+++ b/app/templates/metrics/workspace.hbs
@@ -9,7 +9,7 @@
this.model.workspace.lastModifiedDate
'MM/DD/YYYY'
}}
-
+
-
Date: Thu, 12 Dec 2024 14:46:17 -0500
Subject: [PATCH 12/35] fixed some models and some bad syntax
---
UPGRADE_NOTES.md | 41 ++++++++++++++++++++++++--
app/models/assignment.js | 2 +-
app/models/group.js | 4 +--
app/models/import_request.js | 2 +-
app/routes/assignments/new.js | 12 ++++----
app/routes/responses/new/submission.js | 5 +---
6 files changed, 48 insertions(+), 18 deletions(-)
diff --git a/UPGRADE_NOTES.md b/UPGRADE_NOTES.md
index dd8122c58..1f19e1dc7 100644
--- a/UPGRADE_NOTES.md
+++ b/UPGRADE_NOTES.md
@@ -1,4 +1,4 @@
-This are notes taken as I attempt to upgrade Encompass to Ember 4.5. Note that there is a fair bit of redundancy in this file as these notes are being created as I do the work.
+These are notes taken as I attempt to upgrade Encompass to Ember 4.5. Note that there is a fair bit of redundancy in this file as these notes are being created as I do the work.
# Backstory
@@ -108,11 +108,11 @@ Instead, we could leverage the {timestamps: true} option when defining all the M
## Component organization
-# UI Elements
+### UI Elements
There is now the folder app/components/ui that contains the form-field and expandable-cell components. The purpose of this folder is a place for generic UI components. Other generic UI components include: my-select, selectize-input, twitter-typeahead, radio-group (and radio-group-item), toggle-control, checkbox-list (and checkbox-list-item), collapsible-list, and quill-container. Once these get moved into that folder, every usage must reference the "Ui" namespace, such as or .
-# Other components
+### Other components
Similar to the Ui example above, usage of Namespaces is encouraged in Ember moving forward. Thus, we should reorganize the app/components folder with subfolders representing the distinct subsystems of Encompass. The components in the folders would then be referenced in templates via namespaces, such as which refers to app/components/users/user-list.js and user-list.hbs.
@@ -206,6 +206,7 @@ There are several README.md files scattered through the /test folder.
If this.removeMessages is undefined, Ember might **not** show an error in the console or indicate anywhere that it failed. Subsequent lines will simply not execute but the app will continue running as if everything is fine.
- Be careful around the use of objects that are being tracked. One must be careful to update their references so that they are reactive. Just setting a property won't be enough unless you use TrackedObject from tracked-built-ins.
+- The error "Error while processing route: assignments.new Assertion Failed: Expected hash or Mixin instance, got [object Function]" was just caused by a syntax error in a model. The assertion failed because when hydrating a model, trying get all the documents from the store in that model failed.
# Current Progress
@@ -242,3 +243,37 @@ These mixins are slated to be removed:
## Upgrade of Helpers
With the upgrade to Ember 4.5 (11/14/2024), all helpers have been simplified to regular functions.
+
+## .gitkeep
+
+Removed all the unnecessary .gitkeep files that were created when the project began 6 years ago. This empty file is just a convention so that git will keep an otherwise empty folder in the history.
+
+## UI folder
+
+As of 12/9, the components/ui folder contains the following:
+
+- checkbox-list, checkbox-list-item
+- error-box
+- expandable-cell
+- form-field
+- radio-group, radio-group-item
+- twitter-typeahead
+- wordcloud-container
+
+Components potentially to include in the ui folder:
+
+- bread-crumbs, bread-crumbs-item
+- draggable-selection, DragNDrop, Droppable
+- my-select
+- pagination-control
+- quill-container
+- radio-filter
+- selectize-input
+- toggle-control
+
+The following components, included above, are actually wrappers for third-party packages, so might go into their own folder: (uiwrappers?):
+
+- quill-container
+- selectize-input
+- twitter-typeahead
+- wordcloud-container
diff --git a/app/models/assignment.js b/app/models/assignment.js
index 5eb777f33..87d99e1af 100644
--- a/app/models/assignment.js
+++ b/app/models/assignment.js
@@ -8,7 +8,7 @@ export default class AssignmentModel extends AuditableModel {
@attr('string') name;
@hasMany('answer', { inverse: 'assignment', async: true }) answers;
@hasMany('user', { inverse: null, async: true }) students;
- @belongsTo('section', { inverse: 'assignment', async: true }) section;
+ @belongsTo('section', { inverse: 'assignments', async: true }) section;
@belongsTo('problem', { inverse: null, async: true }) problem;
@attr('date') assignedDate;
@attr('date') dueDate;
diff --git a/app/models/group.js b/app/models/group.js
index e7df1ebf0..27ca1e034 100644
--- a/app/models/group.js
+++ b/app/models/group.js
@@ -1,7 +1,7 @@
-import Model, { attr, hasMany, belongsTo } from '@ember-data/model';
+import { attr, hasMany, belongsTo } from '@ember-data/model';
import AuditableModel from './auditable';
-export default class GroupModel extends Model.extend(AuditableModel) {
+export default class GroupModel extends AuditableModel {
@attr name;
@belongsTo('section', { inverse: null, async: true }) section;
@hasMany('user', { inverse: null, async: true }) students;
diff --git a/app/models/import_request.js b/app/models/import_request.js
index d035ea71b..e9de0007b 100644
--- a/app/models/import_request.js
+++ b/app/models/import_request.js
@@ -4,7 +4,7 @@
*/
import Model, { attr } from '@ember-data/model';
import Auditable from './auditable';
-export default class ImportRequestModel extends Model(Auditable) {
+export default class ImportRequestModel extends Auditable {
@attr('string') teacher;
@attr('string') submitter;
@attr('number') publication;
diff --git a/app/routes/assignments/new.js b/app/routes/assignments/new.js
index 8a148f7a8..a6ca2d38f 100644
--- a/app/routes/assignments/new.js
+++ b/app/routes/assignments/new.js
@@ -8,18 +8,16 @@ export default class AssignmentsNewRoute extends AuthenticatedRoute {
beforeModel() {
const user = this.modelFor('application');
const isStudent = user.get('isStudent');
-
if (isStudent) {
this.router.transitionTo('assignments');
}
}
- async model() {
- let currentUser = this.modelFor('application');
+ model() {
return hash({
- currentUser,
- sections: await this.store.findAll('section'),
- groups: await this.store.findAll('group'),
- cachedProblems: await this.store.findAll('problem'),
+ currentUser: this.modelFor('application'),
+ sections: this.store.findAll('section'),
+ groups: this.store.findAll('group'),
+ cachedProblems: this.store.findAll('problem'),
});
}
@action toAssignmentInfo(model) {
diff --git a/app/routes/responses/new/submission.js b/app/routes/responses/new/submission.js
index 9cdc26645..535d22dc1 100644
--- a/app/routes/responses/new/submission.js
+++ b/app/routes/responses/new/submission.js
@@ -1,12 +1,9 @@
-import Route from '@ember/routing/route';
import { inject as service } from '@ember/service';
import { hash, resolve } from 'rsvp';
import ConfirmLeavingRoute from '../../_confirm_leaving_route';
import { action } from '@ember/object';
-export default class ResponsesNewSubmissionRoute extends Route.extend(
- ConfirmLeavingRoute
-) {
+export default class ResponsesNewSubmissionRoute extends ConfirmLeavingRoute {
@service('utility-methods') utils;
@service store;
@service router;
From 168b67f471819cf4ae3fb2257d69e0a25ae2c297 Mon Sep 17 00:00:00 2001
From: Irv Katz <60225276+exidy80@users.noreply.github.com>
Date: Sat, 14 Dec 2024 13:33:30 -0500
Subject: [PATCH 13/35] upgrade some routes, route templates, and related
components (assignments)
---
UPGRADE_NOTES.md | 1 +
app/components/assignment-info-teacher.hbs | 43 +++++++++++++---------
app/components/assignment-info-teacher.js | 12 ++++--
app/components/assignment-info.hbs | 35 ++++++++++--------
app/components/assignment-info.js | 20 ++--------
app/components/assignment-list.hbs | 22 +++++------
app/components/assignment-list.js | 42 ++++++++++-----------
app/helpers/is-empty.js | 5 +++
app/helpers/not-empty.js | 5 +++
app/routes/assignments.js | 12 +-----
app/routes/assignments/assignment.js | 15 +++-----
app/templates/assignments.hbs | 6 +--
app/templates/assignments/assignment.hbs | 8 +++-
app/templates/unauthorized.hbs | 2 +-
app/templates/workspace/info.hbs | 6 +--
15 files changed, 121 insertions(+), 113 deletions(-)
create mode 100644 app/helpers/is-empty.js
create mode 100644 app/helpers/not-empty.js
diff --git a/UPGRADE_NOTES.md b/UPGRADE_NOTES.md
index 1f19e1dc7..5e9167132 100644
--- a/UPGRADE_NOTES.md
+++ b/UPGRADE_NOTES.md
@@ -207,6 +207,7 @@ If this.removeMessages is undefined, Ember might **not** show an error in the co
- Be careful around the use of objects that are being tracked. One must be careful to update their references so that they are reactive. Just setting a property won't be enough unless you use TrackedObject from tracked-built-ins.
- The error "Error while processing route: assignments.new Assertion Failed: Expected hash or Mixin instance, got [object Function]" was just caused by a syntax error in a model. The assertion failed because when hydrating a model, trying get all the documents from the store in that model failed.
+- Not really a gotcha, just something about Ember. If there is an async relationship, in the route when the model is being put together, there are cases where you'll need to `await` a property access to ensure that the value has arrived.
# Current Progress
diff --git a/app/components/assignment-info-teacher.hbs b/app/components/assignment-info-teacher.hbs
index c5c6d1386..44b3625b8 100644
--- a/app/components/assignment-info-teacher.hbs
+++ b/app/components/assignment-info-teacher.hbs
@@ -24,7 +24,8 @@
name='daterange'
id='assignedDate'
@type='date'
- @value={{(format-date @assignment.assignedDate 'YYYY-MM-DD')}} {{on "change" (action 'updateAssignedDate')}}
+ @value={{(format-date @assignment.assignedDate 'YYYY-MM-DD')}}
+ {{on 'change' (action 'updateAssignedDate')}}
/>
{{else}}