Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add Edit/Delete dropdown #3592

Merged
merged 19 commits into from
Oct 17, 2024
Merged

Feat: Add Edit/Delete dropdown #3592

merged 19 commits into from
Oct 17, 2024

Conversation

greg-adams
Copy link
Contributor

@greg-adams greg-adams commented Oct 7, 2024

Ticket #3591

Description

  • Adds support for soft-deleting a grant note for the current user
    • Adds new grants note route for note deletion (BE)
    • Adds new fields to grant_notes table to support soft-delete of notes: is_published and updated_at
    • Adds delete as dropdown on user grant note (FE)

Screenshots / Demo Video

Screenshot from 2024-10-07 16-02-49

Testing

Automated and Unit Tests

  • Added Unit tests

Manual tests for Reviewer

  • Added steps to test feature/functionality manually

Checklist

  • Provided ticket and description
  • Provided screenshots/demo
  • Provided testing information
  • Provided adequate test coverage for all new code
  • Added PR reviewers

@github-actions github-actions bot added enhancement New feature or request javascript Pull requests that update Javascript code labels Oct 7, 2024
Copy link

github-actions bot commented Oct 7, 2024

QA Summary

QA Check Result
🌐 Client Tests
🔗 Server Tests
🤝 E2E Tests
📏 ESLint
🧹 TFLint

Test Coverage

Coverage report for `packages/client`
St File % Stmts % Branch % Funcs % Lines Uncovered Line #s
🔴 All files 35.81 34.5 32.55 37.39
🔴  src 0 100 100 0
🔴   App.vue 0 100 100 0 2-9
🔴  src/arpa_reporter 0 100 100 0
🔴   App.vue 0 100 100 0 2-13
🟡  ...ter/components 58.58 48 46.8 59.78
🟡   AlertBox.vue 80 75 50 80 13
🔴   ...oadButton.vue 20 0 0 20 2-7,38-67
🟢   ...ileButton.vue 100 100 100 100
🟢   ...ttonSmall.vue 100 100 100 100
🟢   ...mplateBtn.vue 100 100 100 100
🟡   ...avigation.vue 67.74 63.63 52.63 67.74 ...13-219,228-235
🔴   StandardForm.vue 45 50 41.66 45.45 ...24-128,135-157
🟢  ...porter/helpers 84.61 79.48 87.5 84.61
🟢   form-helpers.js 84.21 79.48 85.71 84.21 7,16,25,81-83
🟢   short-uuid.js 100 100 100 100
🔴  ...eporter/router 0 0 0 0
🔴   index.js 0 0 0 0 20-131
🔴  ...reporter/store 3.92 0 2.17 4.12
🔴   index.js 3.92 0 2.17 4.12 11-14,32-261
🔴  ...reporter/views 40.98 25.13 41.37 42.91
🟢   AgenciesView.vue 100 0 100 100 16
🔴   AgencyView.vue 40.74 36.36 50 45.83 53-62,70-96
🔴   HomeView.vue 26.66 34.14 36.36 26.66 36-66,113,137-207
🔴   LoginView.vue 29.62 36.36 20 30.76 1,4,19-34,72-100
🔴   ...plateView.vue 27.02 35.71 45.45 25 ...2,30-37,69-113
🔴   ...ploadView.vue 24.24 16.66 33.33 26.66 1,30-31,116-144
🔴   ...eriodView.vue 48 18.18 75 52.17 64-90
🟡   ...riodsView.vue 57.57 28.57 60 59.37 101,132,149-171
🔴   ...pientView.vue 40 10.52 30.76 41.02 73-93,110-152
🔴   ...ientsView.vue 48.48 8.33 46.66 53.33 ...46,165-190,203
🟡   UploadView.vue 61.53 43.75 62.5 61.36 ...41-442,448-449
🔴   UploadsView.vue 16.66 0 0 18.18 59,110-287
🔴   UserView.vue 46.34 33.33 68.75 48.64 84,97-137
🟡   UsersView.vue 60 7.69 62.5 66.66 91-92,105-107,123
🔴   ...ationView.vue 37.03 18.18 26.66 41.66 ...19,238,246-270
🟡  src/components 55.3 44.6 56.64 56.06
🔴   ...vityTable.vue 18.75 0 28.57 19.35 115-185
🟡   BaseLayout.vue 69.56 53.84 60 69.56 172,219-231
🔴   CopyButton.vue 30 33.33 40 30 5,53-62
🟢   ...tActivity.vue 80.76 62.85 83.33 80.76 ...31-136,179,201
🟢   GrantNotes.vue 90 78.26 85 89.79 ...87,207,216-217
🔴   GrantsTable.vue 45.03 38.77 45 46.85 ...51-455,463-543
🔴   ...dUploader.vue 24.24 33.33 37.5 24.24 16,25,74-111
🔴   SearchFilter.vue 40.74 28 37.5 40 ...52,64,67,72-82
🔴   ShareGrant.vue 38.7 64.28 23.07 40 ...08-112,131-152
🟢   ...ivityItem.vue 96.15 90.9 100 96.15 64
🟡   UserAvatar.vue 70 75 100 62.5 35-37
🟢   ...eaderText.vue 100 100 100 100
🔴  ...ponents/Modals 29.21 44.34 33.1 32.94
🔴   ...anization.vue 17.39 65.62 30 22.22 1-14,149-178
🔴   AddTeam.vue 45.45 55.55 61.53 57.69 ...04,210,222-245
🔴   AddUser.vue 36.66 66.66 60 37.5 ...40,145,148-176
🔴   ...anization.vue 15.38 64.28 14.28 16.66 1-15,58-78
🔴   EditTeam.vue 18.18 26.43 33.33 20.83 ...29,208,216-301
🔴   EditUser.vue 21.05 66.66 25 22.22 1,101-128
🔴   ...ilsLegacy.vue 22.03 0 0 24.07 131,177,205-369
🟢   ...Followers.vue 83.33 88.88 57.14 83.33 10,114-115
🟡   ImportTeams.vue 50 41.17 50 53.33 28,64-69,81-82
🔴   ImportUsers.vue 42.85 60 40 46.15 29,65-80
🔴   ...archPanel.vue 27.9 15.78 23.52 28.57 ...68-178,211-255
🔴   SearchPanel.vue 21.62 63.26 32 27.58 ...77-380,386-458
🔴  src/helpers 18.12 17.92 18.6 18.88
🟢   constants.js 100 100 100 100
🟢   currency.js 100 100 100 100
🟡   dates.js 66.66 100 33.33 100
🔴   fetchApi.js 6 13.79 5.26 6.12 10-12,20-132
🔴   filters.js 4 0 0 4.54 19-51
🔴   form-helpers.js 0 0 0 0 5-82
🟡   gtag.js 77.77 90 75 77.77 12,51
🟢   testHelpers.js 100 100 100 100
🔴   ...patWarning.js 0 0 0 0 39-61
🟢  ...s/featureFlags 84.61 100 71.42 84.61
🟡   index.js 60 100 60 60 8,16
🟢   utils.js 100 100 100 100
🔴  src/mixin 20 0 28.57 20
🔴   ...zableTable.js 20 0 28.57 20 16-31,36-37,42
🔴  src/router 18.91 14.28 11.11 18.91
🔴   index.js 18.91 14.28 11.11 18.91 ...76-177,181-200
🟢  src/store 100 100 100 100
🟢   index.js 100 100 100 100
🔴  src/store/modules 2.82 0 4.48 2.94
🔴   agencies.js 5.26 100 8.33 5.55 13-70
🔴   alerts.js 20 100 20 20 10-24
🔴   grants.js 0.99 0 0.97 1.03 61-456
🔴   organization.js 33.33 100 33.33 33.33 21-25
🔴   roles.js 20 100 20 25 13-22
🔴   tenants.js 11.11 100 14.28 12.5 13-32
🔴   users.js 2.43 0 4.76 2.5 17-100
🔴  src/views 44.73 37.22 33.77 46.55
🔴   ...orterView.vue 25.58 51.85 18.18 26.82 ...,62,84,109-151
🟡   ...boardView.vue 50 17.64 50 52 89-98,114-125
🔴   ...tailsView.vue 32.97 14.28 17.07 33.69 ...96-435,441-462
🟢   GrantsView.vue 100 100 100 100
🟡   LoginView.vue 56 38.88 44.44 58.33 23,137-159
🟡   MyGrantsView.vue 77.77 66.66 66.66 77.77 1,69
🟡   ...ofileView.vue 78.26 80 42.85 78.26 1,32,63,136-140
🟢   NotFoundView.vue 100 100 100 100
🔴   ...tionsView.vue 47.05 57.14 41.66 53.33 ...97-100,114-118
🔴   ...ivityView.vue 46.42 23.8 43.75 46.42 ...01,114,120-134
🔴   TeamsView.vue 44.44 88.88 41.66 53.33 1,58,142,156-163
🟡   UsersView.vue 50 66.66 36.36 53.84 ...16-121,133-139
Coverage report for `packages/server`
St File % Stmts % Branch % Funcs % Lines Uncovered Line #s
🟡 All files 59.89 53.12 55.64 59.97
🟢  src 81.63 33.33 60 81.63
🟢   configure.js 81.63 33.33 60 81.63 42,61-68,97-99
🟢  src/arpa_reporter 98.75 66.66 100 98.75
🟢   configure.js 97.36 40 100 97.36 36
🟢   environment.js 100 100 100 100
🟢   use-request.js 100 100 100 100
🟡  src/arpa_reporter/db 50.73 45.88 50 51.9
🟡   arpa-subrecipients.js 53.19 50 38.46 54.54 23-60,101,113-122
🔴   reporting-periods.js 37.2 46.87 40 38.09 46,77-156
🟢   settings.js 100 83.33 100 100 13
🟡   uploads.js 50 28.57 52.38 51.42 18-29,84,99-124,141-150
🔴  src/arpa_reporter/lib 29.57 33.08 34.56 28.46
🟢   arpa-ec-codes.js 100 100 100 100
🔴   audit-report.js 21.44 19.35 24.19 21.32 ...28-529,554-684,732-758
🟡   ensure-async-context.js 75 100 50 100
🟢   format.js 90.62 90 90 91.3 41-42
🟡   log.js 75 50 50 75 13,25
🟡   preconditions.js 66.66 33.33 100 66.66 3
🔴   spreadsheet.js 9.09 0 0 9.09 15-32
🟢   validation-error.js 85.71 100 50 85.71 16
🔴  src/arpa_reporter/routes 40 14.92 14.28 40.6
🔴   agencies.js 22.58 0 0 23.33 13-21,26-53
🟡   application_settings.js 75 100 0 75 10-11
🟡   audit-report.js 68.91 58.33 100 68.91 57-58,64-78,100-116
🟢   exports.js 81.42 83.33 100 81.42 61-75,98-99
🔴   reporting-periods.js 20 0 0 20.43 ...25-137,143-149,154-180
🔴   subrecipients.js 23.8 0 0 23.8 12-13,17-27,31-48,52-63
🔴   uploads.js 28.28 7.89 9.09 29.16 ...33-154,164-166,173-180
🔴   users.js 19.6 0 0 20 15-35,39-44,48-81
🔴  src/arpa_reporter/services 44.55 34.79 47.55 44.83
🔴   generate-arpa-report.js 36.86 2.77 50 37.24 ...-975,984-997,1071-1138
🔴   get-template.js 21.62 0 0 21.62 18-79
🟡   persist-upload.js 69.66 90 73.07 69.76 ...64-206,227-241,279-301
🔴   records.js 20.75 0 11.11 21.15 38-204,221-276
🔴   revalidate-uploads.js 37.5 100 0 37.5 5-14
🔴   validate-upload.js 43.56 58.51 37.03 44.2 ...52,371,393,411-688,703
🟢   validation-rules.js 98.18 90 90.9 100 157,173
🟡  src/db 74.26 71.42 68.42 74.29
🟢   connection.js 100 50 100 100 6
🟢   constants.js 100 100 100 100
🟡   helpers.js 75 83.33 50 75 5,21-22
🟢   index.js 82.4 78.54 82.08 82.35 ...56-1422,1604-1605,1612
🟢   saved_search_migration.js 92 88.23 71.42 93.61 5,69,134
🔴   tenant_creation.js 10.58 2.7 0 11.11 [15-40](https://github.c...*[Comment body truncated]*

Copy link

github-actions bot commented Oct 7, 2024

Terraform Summary

Step Result
🖌 Terraform Format & Style
⚙️ Terraform Initialization
🤖 Terraform Validation
📖 Terraform Plan

Hint: If "Terraform Format & Style" failed, run terraform fmt -recursive from the terraform/ directory and commit the results.

Output

Validation Output
stdout:
Success! The configuration is valid.


-------------------------------------
stderr:

Plan Summary
CHANGE RESOURCE
add module.website.aws_s3_object.origin_dist_artifact["assets/DashboardView-VsspTFBS.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/DashboardView-VsspTFBS.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantDetailsLegacy-CVlel6Ry.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantDetailsLegacy-CVlel6Ry.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantDetailsView-B_dKLKCr.css"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantDetailsView-DJGnKTa1.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantDetailsView-DJGnKTa1.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantsTable-jhzN9SPv.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantsTable-jhzN9SPv.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantsView-BrsJtfrf.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantsView-BrsJtfrf.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/MyGrantsView-BjfVdyV4.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/MyGrantsView-BjfVdyV4.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/MyProfileView-B3fT5aIb.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/MyProfileView-B3fT5aIb.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/OrganizationsView-D-fJvjQ_.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/OrganizationsView-D-fJvjQ_.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/RecentActivityView-C0M1DIV9.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/RecentActivityView-C0M1DIV9.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/TeamsView-LLkFMdO8.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/TeamsView-LLkFMdO8.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/UsersView-CQQQ-iaa.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/UsersView-CQQQ-iaa.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/main-DxZvaAMs.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/main-DxZvaAMs.js.map"]
update module.api.aws_ecs_service.default[0]
module.api.module.grant_digest_scheduled_task.aws_iam_role_policy.default[0]
module.api.module.grant_digest_scheduled_task.aws_scheduler_schedule.default[0]
module.arpa_audit_report.aws_ecs_service.default
module.arpa_treasury_report.aws_ecs_service.default
module.consume_grants.aws_ecs_service.default
module.website.aws_s3_object.deploy-config[0]
module.website.aws_s3_object.origin_dist_artifact["assets/style-Lb7S2aAW.js.map"]
module.website.aws_s3_object.origin_dist_artifact["index.html"]
recreate module.api.aws_ecs_task_definition.default[0]
module.arpa_audit_report.aws_ecs_task_definition.consumer
module.arpa_treasury_report.aws_ecs_task_definition.consumer
module.consume_grants.aws_ecs_task_definition.consume_grants
delete module.website.aws_s3_object.origin_dist_artifact["assets/DashboardView-4BqVvDxL.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/DashboardView-4BqVvDxL.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantDetailsLegacy-C6utYg3Q.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantDetailsLegacy-C6utYg3Q.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantDetailsView-Du8az7nI.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantDetailsView-Du8az7nI.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantDetailsView-wqz_lr_n.css"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantsTable-BKm8DUiu.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantsTable-BKm8DUiu.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantsView-D1-e35b5.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/GrantsView-D1-e35b5.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/MyGrantsView-DQcy8Cv2.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/MyGrantsView-DQcy8Cv2.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/MyProfileView-DbGGfjfn.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/MyProfileView-DbGGfjfn.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/OrganizationsView-BfCvQDji.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/OrganizationsView-BfCvQDji.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/RecentActivityView-YCXA_eb3.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/RecentActivityView-YCXA_eb3.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/TeamsView-D7ZwuooK.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/TeamsView-D7ZwuooK.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/UsersView-mu1qMv2H.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/UsersView-mu1qMv2H.js.map"]
module.website.aws_s3_object.origin_dist_artifact["assets/main-BMR9uZOn.js"]
module.website.aws_s3_object.origin_dist_artifact["assets/main-BMR9uZOn.js.map"]

Pusher: @greg-adams, Action: pull_request_target, Workflow: Continuous Integration

Copy link
Member

@TylerHendrickson TylerHendrickson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@greg-adams Everything looks good in testing! A couple server-side things to potentially address and/or get your take on.

Comment on lines 151 to 160
const grantNote = knex
.select('id')
.from('grant_notes')
.where({ grant_id: grantId, user_id: userId });

await knex('grant_notes_revisions')
.whereIn('grant_note_id', grantNote)
.del();

await grantNote.del();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it would be preferable to handle this on the Postgres side using ON DELETE CASCADE. Unfortunately, that doesn't currently seem to be implemented on the FK constraint, so it's probably best that we do that now since there's no data in Production just yet.

A few details that feel worth mentioning:

  • Postgres doesn't support this kind of alteration on foreign keys, so the migration will need to drop the existing FK constraint and then re-add it with the ON DELETE CASCADE specification.
  • Knex seems to have its own naming convention for foreign key constraints (it doesn't follow the Postgres standard convention of {tablename}_{columnname(s)}_{suffix}) so rather than using knex.raw(), it might be best to use the Knex schema builder functions (see table.dropForeign() and table.foreign()).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes certainly makes sense here - updated!

// sending the notes as JSON response
res.json(notes);
} catch (error) {
res.status(500).json({ error: 'Failed to retrieve notes' });
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible to re-throw error on the next line so that we can preserve the error/trace details, or will that mess with the ability to provide the Failed to retrieve notes message in the response?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, I removed the try..catch here as we aren't using this message on the FE and will still result in a 500

@github-actions github-actions bot added the database-changes Includes schema migrations or other critical changes label Oct 11, 2024
Copy link
Member

@TylerHendrickson TylerHendrickson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@greg-adams A few quick suggestions for the new Postgres function, but I think this is otherwise ready.

Comment on lines 8 to 16
const ON_UPDATE_TIMESTAMP_FUNCTION = `
CREATE OR REPLACE FUNCTION on_update_timestamp()
RETURNS trigger AS $$
BEGIN
NEW.updated_at = now();
RETURN NEW;
END;
$$ language 'plpgsql';
`;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW when you asked me about this is Slack I thought you confirming that updated_at columns should have a DEFAULT now() specification rather than ensuring that these column updates should happen automatically 😄

That said, this seems like a nice behavior to have on-hand, and is more comprehensive than a simple default. 👍 !

Comment on lines 11 to 13
BEGIN
NEW.updated_at = now();
RETURN NEW;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Slight tweak that avoids setting updated_at if the update operation isn't actually changing the row (e.g. UPDATE my_table SET my_col = 123 when my_col is already 123):

Suggested change
BEGIN
NEW.updated_at = now();
RETURN NEW;
BEGIN
IF NEW IS DISTINCT FROM OLD THEN
NEW.updated_at = now();
END IF;
RETURN NEW;
END;

*/
exports.up = async function (knex) {
const ON_UPDATE_TIMESTAMP_FUNCTION = `
CREATE OR REPLACE FUNCTION on_update_timestamp()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just making it a bit easier to locate quickly during a psql session :)

Suggested change
CREATE OR REPLACE FUNCTION on_update_timestamp()
CREATE OR REPLACE FUNCTION before_update_set_updated_at()

// Set trigger for any updated timestamps
onUpdateTrigger: (table) => `
CREATE TRIGGER ${table}_updated_at BEFORE UPDATE ON ${table}
FOR EACH ROW EXECUTE PROCEDURE on_update_timestamp();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Per my previous comment

Suggested change
FOR EACH ROW EXECUTE PROCEDURE on_update_timestamp();
FOR EACH ROW EXECUTE PROCEDURE before_update_set_updated_at();

@greg-adams
Copy link
Contributor Author

@TylerHendrickson thanks! I incorporated your changes and some small changes to another migration email_subscriptions I noticed

Copy link
Member

@TylerHendrickson TylerHendrickson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@greg-adams Looks good to me!

@@ -17,7 +17,8 @@ exports.up = function (knex) {
* @param { import("knex").Knex } knex
* @returns { Promise<void> }
*/
exports.down = function (knex) {
exports.down = async function (knex) {
await knex('email_subscriptions').where({ notification_type: 'GRANT_ACTIVITY' }).del();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch 👍

@greg-adams greg-adams merged commit 60042d3 into main Oct 17, 2024
19 checks passed
@greg-adams greg-adams deleted the feat/notes-delete branch October 17, 2024 18:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
database-changes Includes schema migrations or other critical changes enhancement New feature or request javascript Pull requests that update Javascript code
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants