From b73b5b0b3f20986f2618b75b6be372bd266a0f4d Mon Sep 17 00:00:00 2001 From: Gail Terman Date: Tue, 25 Jun 2024 21:59:33 -0400 Subject: [PATCH 01/31] PLAN-950 reg potential matches modal --- .../registration_sync_data_controller.rb | 1 + app/javascript/components/table_vue.vue | 15 +++++-- .../integrations/clyde_settings.vue | 32 +++++++++++---- .../integrations/reg-sync-modal.vue | 38 +++++++++++++++++ .../registrations/person_sync_table.vue | 10 +++++ app/javascript/store/model.store.js | 4 +- .../store/registration_sync_datum.store.js | 41 +++++++++++++++---- .../store/registration_sync_stats.mixin.js | 19 +++++++++ db/structure.sql | 2 + 9 files changed, 142 insertions(+), 20 deletions(-) create mode 100644 app/javascript/integrations/reg-sync-modal.vue create mode 100644 app/javascript/store/registration_sync_stats.mixin.js diff --git a/app/controllers/registration_sync_data_controller.rb b/app/controllers/registration_sync_data_controller.rb index a9f16e907..7912a07e4 100644 --- a/app/controllers/registration_sync_data_controller.rb +++ b/app/controllers/registration_sync_data_controller.rb @@ -10,6 +10,7 @@ def sync_statistics status = RegistrationSyncStatus.order('created_at desc').first result = status ? status.result : {} + result[:updated_at] = status&.updated_at; render status: :ok, json: result.to_json, content_type: 'application/json' end diff --git a/app/javascript/components/table_vue.vue b/app/javascript/components/table_vue.vue index dedd78a62..ab19bb2ce 100644 --- a/app/javascript/components/table_vue.vue +++ b/app/javascript/components/table_vue.vue @@ -55,7 +55,7 @@
- + -
+
Search Results: {{totalRows}} {{countCaption}}
-
+
@@ -201,6 +203,13 @@ export default { stateName: { type: String, default: null + }, + stickyHeader: { + default: false + }, + showBottomControls: { + type: Boolean, + default: true } }, data () { diff --git a/app/javascript/integrations/clyde_settings.vue b/app/javascript/integrations/clyde_settings.vue index 2faad60cb..5787ba8bc 100644 --- a/app/javascript/integrations/clyde_settings.vue +++ b/app/javascript/integrations/clyde_settings.vue @@ -2,11 +2,21 @@
+

Registration Sync Management

+
+ Run Registration Data Sync + +
+
    +
  • Last completed full sync: {{ lastSync }}
  • +
  • Records matched: {{ stats.matched }}
  • +
  • Records updated: {{ stats.updated }}
  • +
  • Records not found: {{ stats.not_found }}
  • +

Configuration

- + - Registration Synchronize @@ -24,8 +34,8 @@
- - This will sync with the Registration system. This will bring the server down for a short time. + + This will sync with the Registration system's data. It will bring the server down for a short time. Please double check that you wish to perform this action.
@@ -36,18 +46,26 @@ import { clydeMixin } from './clyde.mixin' import PlanoModal from '@/components/plano_modal.vue'; import { toastMixin } from '@/mixins'; import { http } from '@/http'; +import { registrationSyncStatsMixin} from '@/store/registration_sync_stats.mixin'; +import RegSyncModal from './reg-sync-modal.vue'; export default { name: "ClydeSettings", - mixins: [clydeMixin, toastMixin], + mixins: [clydeMixin, toastMixin, registrationSyncStatsMixin], components: { - PlanoModal + PlanoModal, + RegSyncModal }, methods: { synchronizeSchedule() { - this.toastPromise(http.get('/registration_sync_data/synchronize'), "Succesfully requested registration sync") + this.toastPromise(http.get('/registration_sync_data/synchronize'), "Succesfully requested registration sync").then(() => { + this.fetchStats(); + }) }, }, + mounted() { + this.fetchStats(); + } } diff --git a/app/javascript/integrations/reg-sync-modal.vue b/app/javascript/integrations/reg-sync-modal.vue new file mode 100644 index 000000000..2980abc7d --- /dev/null +++ b/app/javascript/integrations/reg-sync-modal.vue @@ -0,0 +1,38 @@ + + + + + diff --git a/app/javascript/registrations/person_sync_table.vue b/app/javascript/registrations/person_sync_table.vue index 9a6d16e35..6cf6770fb 100644 --- a/app/javascript/registrations/person_sync_table.vue +++ b/app/javascript/registrations/person_sync_table.vue @@ -6,7 +6,15 @@ ref="person-sync-table" stateName="person-sync-table-search-state" :showControls="false" + stickyHeader="450px" + :showBottomControls="false" > +
@@ -47,10 +50,14 @@ From 94aa893ab3d81c39005a2985169c8682d629b08e Mon Sep 17 00:00:00 2001 From: Gail Terman Date: Sun, 14 Jul 2024 11:37:41 -0400 Subject: [PATCH 19/31] plan-950 select person dialog --- .../integrations/reg-sync-modal.vue | 7 +- .../integrations/reg-sync-person-search.vue | 85 +++++++++++++++++++ 2 files changed, 91 insertions(+), 1 deletion(-) create mode 100644 app/javascript/integrations/reg-sync-person-search.vue diff --git a/app/javascript/integrations/reg-sync-modal.vue b/app/javascript/integrations/reg-sync-modal.vue index 0d4949aa6..fe5fd2369 100644 --- a/app/javascript/integrations/reg-sync-modal.vue +++ b/app/javascript/integrations/reg-sync-modal.vue @@ -16,6 +16,8 @@ headerBgVariant="primary" headerTextVariant="light" @hide="onHide()" + :no-close-on-backdrop="true" + :no-close-on-esc="false" >
Last completed full sync: {{ lastSync }}
@@ -28,6 +30,7 @@
{{ selected.published_name }}
+
Planorama Data
@@ -66,6 +69,7 @@ import { registrationSyncStatsMixin } from "@/store/registration_sync_stats.mixi import { mapActions, mapState } from "vuex"; import { personSyncDatumMixin } from '@/store/person_sync_datum.mixin'; import IconButton from "@/components/icon_button.vue"; +import RegSyncPersonSearch from './reg-sync-person-search.vue'; export default { name: "RegSyncModal", @@ -73,6 +77,7 @@ export default { PlanoModal, DisplaySyncData, IconButton, + RegSyncPersonSearch, }, mixins: [ modelMixinNoProp, @@ -130,7 +135,7 @@ export default { this.selectFirst(); this.modalLoading = false; }) - } + }, }, mounted() { this.loading = true; diff --git a/app/javascript/integrations/reg-sync-person-search.vue b/app/javascript/integrations/reg-sync-person-search.vue new file mode 100644 index 000000000..33a8c7ded --- /dev/null +++ b/app/javascript/integrations/reg-sync-person-search.vue @@ -0,0 +1,85 @@ + + + + + From afd3a2d031064296d9428c9005e4e2ae77ded8f0 Mon Sep 17 00:00:00 2001 From: Henry Date: Sun, 14 Jul 2024 18:43:11 -0400 Subject: [PATCH 20/31] correct view to filter out dismissed --- app/lib/migration_helpers/plano_views.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/lib/migration_helpers/plano_views.rb b/app/lib/migration_helpers/plano_views.rb index a7dedf702..11eda6f6e 100644 --- a/app/lib/migration_helpers/plano_views.rb +++ b/app/lib/migration_helpers/plano_views.rb @@ -39,7 +39,7 @@ def self.create_registration_sync_matches rsd.reg_id not in (select p2.reg_id from people p2 where p2.reg_id is not null) and concat(p.id, '-', rsd.reg_id) not in - (select concat(drsm.person_id, '-' , rsd.reg_id) from dismissed_reg_sync_matches drsm) + (select concat(drsm.person_id, '-' , drsm.reg_id) from dismissed_reg_sync_matches drsm) union select null as name, e.email, e.person_id as pid, rsd2.reg_id, rsd2.id as rid, 'email' as mtype from email_addresses e @@ -54,7 +54,7 @@ def self.create_registration_sync_matches rsd2.reg_id not in (select p2.reg_id from people p2 where p2.reg_id is not null) and concat(e.person_id, '-', rsd2.reg_id) not in - (select concat(drsm.person_id, '-' , rsd2.reg_id) from dismissed_reg_sync_matches drsm); + (select concat(drsm.person_id, '-' , drsm.reg_id) from dismissed_reg_sync_matches drsm); CREATE INDEX matches_reg_id ON registration_sync_matches (reg_id); CREATE INDEX matches_pid ON registration_sync_matches (pid); SQL From 221067988d855c8f4421d732e5f6217b16b433c6 Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 15 Jul 2024 07:28:22 -0400 Subject: [PATCH 21/31] Split view into 2 so regen only needed on dismiss filter by already matched in a regular view --- .../person_sync_data_controller.rb | 3 --- app/lib/migration_helpers/plano_views.rb | 19 +++++++++++++++---- app/models/person_sync_datum.rb | 3 --- .../registration/registration_sync_match.rb | 4 ++-- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/app/controllers/person_sync_data_controller.rb b/app/controllers/person_sync_data_controller.rb index d7814dcd9..27fad0ecb 100644 --- a/app/controllers/person_sync_data_controller.rb +++ b/app/controllers/person_sync_data_controller.rb @@ -40,9 +40,6 @@ def match IdentityService.clear_person_reg_info(person: person); IdentityService.update_reg_info(person: person, details: datum.raw_info, reg_match: reg_match) - # We need to refresh the view on match - MigrationHelpers::PlanoViews.refresh_registration_sync_matches - render status: :ok, json: { message: "Matched" }.to_json, content_type: 'application/json' diff --git a/app/lib/migration_helpers/plano_views.rb b/app/lib/migration_helpers/plano_views.rb index 11eda6f6e..0a59a8186 100644 --- a/app/lib/migration_helpers/plano_views.rb +++ b/app/lib/migration_helpers/plano_views.rb @@ -14,11 +14,22 @@ def self.create_views # view for reg matching self.create_registration_sync_matches + self.create_filtered_registration_sync_matches self.create_registration_map_counts self.create_registration_map_reg_counts self.create_registration_map_people_counts end + def self.create_filtered_registration_sync_matches + query = <<-SQL.squish + CREATE OR REPLACE VIEW filtered_registration_sync_matches AS + select * from registration_sync_matches rsm + where rsm.reg_id not in (select p2.reg_id from people p2 where p2.reg_id is not null) + SQL + + ActiveRecord::Base.connection.execute(query) + end + def self.create_registration_sync_matches query = <<-SQL.squish DROP materialized VIEW IF EXISTS registration_sync_matches; @@ -36,8 +47,6 @@ def self.create_registration_sync_matches or rsd."badge_name" ilike p.pseudonym ) where - rsd.reg_id not in (select p2.reg_id from people p2 where p2.reg_id is not null) - and concat(p.id, '-', rsd.reg_id) not in (select concat(drsm.person_id, '-' , drsm.reg_id) from dismissed_reg_sync_matches drsm) union @@ -50,8 +59,6 @@ def self.create_registration_sync_matches rsd2."alternative_email" ilike e.email ) where e.isdefault = true - and - rsd2.reg_id not in (select p2.reg_id from people p2 where p2.reg_id is not null) and concat(e.person_id, '-', rsd2.reg_id) not in (select concat(drsm.person_id, '-' , drsm.reg_id) from dismissed_reg_sync_matches drsm); @@ -661,6 +668,10 @@ def self.drop_views DROP VIEW IF EXISTS registration_map_counts; SQL + ActiveRecord::Base.connection.execute <<-SQL + DROP VIEW IF EXISTS filtered_registration_sync_matches; + SQL + if self.test_registration_sync_matches_type == 'm' ActiveRecord::Base.connection.execute <<-SQL DROP materialized VIEW IF EXISTS registration_sync_matches; diff --git a/app/models/person_sync_datum.rb b/app/models/person_sync_datum.rb index 000260020..a0864392e 100644 --- a/app/models/person_sync_datum.rb +++ b/app/models/person_sync_datum.rb @@ -104,9 +104,6 @@ # class PersonSyncDatum < Person has_many :registration_sync_matches, - -> { - where("concat(registration_sync_matches.pid, '-', registration_sync_matches.reg_id) not in (select concat(drsm.person_id, '-' , drsm.reg_id) from dismissed_reg_sync_matches drsm)") - }, class_name: 'Registration::RegistrationSyncMatch', foreign_key: 'pid' diff --git a/app/models/registration/registration_sync_match.rb b/app/models/registration/registration_sync_match.rb index 6c802072f..d98adca9a 100644 --- a/app/models/registration/registration_sync_match.rb +++ b/app/models/registration/registration_sync_match.rb @@ -1,6 +1,6 @@ # == Schema Information # -# Table name: registration_sync_matches +# Table name: filtered_registration_sync_matches # # email :string # mtype :text primary key @@ -15,7 +15,7 @@ # matches_reg_id (reg_id) # class Registration::RegistrationSyncMatch < ApplicationRecord - self.table_name = :registration_sync_matches + self.table_name = :filtered_registration_sync_matches self.primary_keys = :rid, :mtype belongs_to :person, optional: true, foreign_key: 'pid' From c9976a9ee6019e256d3e9002c86054a20d6eae11 Mon Sep 17 00:00:00 2001 From: Henry Date: Mon, 15 Jul 2024 07:45:13 -0400 Subject: [PATCH 22/31] Include not-set in the non-accepted report --- app/controllers/reports/session_reports_controller.rb | 2 +- app/javascript/reports/reports_screen.vue | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/reports/session_reports_controller.rb b/app/controllers/reports/session_reports_controller.rb index dbb73ee96..aad2fb894 100644 --- a/app/controllers/reports/session_reports_controller.rb +++ b/app/controllers/reports/session_reports_controller.rb @@ -334,7 +334,7 @@ def non_accepted_on_schedule people_sessions = SessionService.person_schedule .where("session_assignment_name in ('Moderator', 'Participant', 'Invisible')") - .where("con_state not in ('not_set', 'accepted')") + .where("con_state not in ('accepted')") .where("start_time is not null and room_id is not null") .order('name', 'start_time', 'title') diff --git a/app/javascript/reports/reports_screen.vue b/app/javascript/reports/reports_screen.vue index a58a418b6..57f2b399e 100644 --- a/app/javascript/reports/reports_screen.vue +++ b/app/javascript/reports/reports_screen.vue @@ -75,7 +75,7 @@
  • Non-Accepted Participants on Scheduled Sessions

    - Description: People with participant status other than "accepted" or "not_set" assigned to scheduled sessions, one line per person and session
    + Description: People with participant status other than "accepted" assigned to scheduled sessions, one line per person and session
    Fields: Person name, published name, participant status, session title, area(s) of session, tags, admin labels
    Session data included: all scheduled sessions
    Person data included: moderators, participants, invisible participants with a participant status that is not "accepted" or "not_set" From 0a7f056398fa02e4a7f41ab846d99224767a9665 Mon Sep 17 00:00:00 2001 From: Gail Terman Date: Mon, 15 Jul 2024 09:11:29 -0400 Subject: [PATCH 23/31] PLAN-950 larger page size and dismiss spinner --- .../integrations/reg-sync-modal.vue | 138 ++++++++++++------ app/javascript/shared/spinner-button.vue | 13 +- app/javascript/store/model.store.js | 8 +- .../store/person_sync_datum.store.js | 4 + 4 files changed, 113 insertions(+), 50 deletions(-) diff --git a/app/javascript/integrations/reg-sync-modal.vue b/app/javascript/integrations/reg-sync-modal.vue index fe5fd2369..21d17eca5 100644 --- a/app/javascript/integrations/reg-sync-modal.vue +++ b/app/javascript/integrations/reg-sync-modal.vue @@ -19,18 +19,36 @@ :no-close-on-backdrop="true" :no-close-on-esc="false" > -

    -
    Last completed full sync: {{ lastSync }}
    - -
    People with potential matches: {{ fullTotal }}
    +
    +
    Last completed full sync: {{ lastSync }}
    + +
    + People with potential matches: {{ fullTotal }}
    -
    No more people to match!
    +
    +
    + No more people to match! +
    - -
    {{ selected.published_name }}
    - - + +
    {{ selected.published_name }}
    + +
    Planorama Data
    @@ -39,22 +57,48 @@
    Name: {{ selected.name }}
    Potential Matches (from registration system)
    -
    -
      -
    1. -
      -
      -
      - -
      -
      - Match - Dismiss -
      -
      -
    2. -
    -
    There are no more potential matches.
    +
    +
      +
    1. +
      +
      +
      + +
      +
      + Match + Dismiss +
      +
      +
    2. +
    +
    +
    + There are no more potential matches. +
    @@ -64,12 +108,16 @@ import PlanoModal from "@/components/plano_modal.vue"; import { modelMixinNoProp } from "@/mixins"; import DisplaySyncData from "@/registrations/display_sync_data.vue"; -import { FETCH_MATCH_COUNT, personSyncDatumModel as model } from "@/store/person_sync_datum.store"; +import { + FETCH_MATCH_COUNT, + personSyncDatumModel as model, +} from "@/store/person_sync_datum.store"; import { registrationSyncStatsMixin } from "@/store/registration_sync_stats.mixin"; import { mapActions, mapState } from "vuex"; -import { personSyncDatumMixin } from '@/store/person_sync_datum.mixin'; +import { personSyncDatumMixin } from "@/store/person_sync_datum.mixin"; import IconButton from "@/components/icon_button.vue"; -import RegSyncPersonSearch from './reg-sync-person-search.vue'; +import RegSyncPersonSearch from "./reg-sync-person-search.vue"; +import SpinnerButton from "@/shared/spinner-button.vue"; export default { name: "RegSyncModal", @@ -78,16 +126,14 @@ export default { DisplaySyncData, IconButton, RegSyncPersonSearch, + SpinnerButton }, - mixins: [ - modelMixinNoProp, - registrationSyncStatsMixin, - personSyncDatumMixin, - ], + mixins: [modelMixinNoProp, registrationSyncStatsMixin, personSyncDatumMixin], data: () => ({ loading: false, modalLoading: false, - model + model, + dismissInProgress: false, }), computed: { ...mapState(["possibleMatchCount"]), @@ -96,14 +142,16 @@ export default { ...mapActions({ fetchMatchCount: FETCH_MATCH_COUNT, }), - dismissAndRefresh(regId, personId) { + dismissAndRefresh(regId, personId, idx) { + this.dismissInProgress = idx; this.dismissMatch(regId, personId).then(() => { + this.dismissInProgress = false; this.fetchSelected(); - }) + }); }, matchAndNext(regId, personId) { this.assistedMatch(regId, personId).then(() => { - if(this.selectedOrdinal === this.fullTotal) { + if (this.selectedOrdinal === this.fullTotal) { if (this.selectedOrdinal === 1) { // fetch everything because this was the last one // this should then display no more matches @@ -120,21 +168,21 @@ export default { this.selectNext().then(() => { // fix the ordinal this.fetch(); - }) + }); } - }) + }); }, alsoHideTooltip(target) { target(); - this.$root.$emit('bv::hide::tooltip'); + this.$root.$emit("bv::hide::tooltip"); }, onHide() { this.fetchMatchCount(); this.modalLoading = true; - this.fetch().then(() => { - this.selectFirst(); - this.modalLoading = false; - }) + this.fetch().then(() => { + this.selectFirst(); + this.modalLoading = false; + }); }, }, mounted() { @@ -146,7 +194,7 @@ export default { this.fetch().then(() => { this.selectFirst(); this.modalLoading = false; - }) + }); }, }; diff --git a/app/javascript/shared/spinner-button.vue b/app/javascript/shared/spinner-button.vue index c8d746a24..25877dd93 100644 --- a/app/javascript/shared/spinner-button.vue +++ b/app/javascript/shared/spinner-button.vue @@ -3,15 +3,22 @@ v-on="$listeners" v-bind="$attrs" > - - + + diff --git a/app/javascript/store/model.store.js b/app/javascript/store/model.store.js index fe30ee44d..46e350675 100644 --- a/app/javascript/store/model.store.js +++ b/app/javascript/store/model.store.js @@ -54,7 +54,7 @@ import { pageContentStore, pageContentEndpoints } from "@/store/page_content.sto // Registration Sync Datum/Data import { registrationSyncDatumStore, registrationSyncDatumEndpoints } from "@/store/registration_sync_datum.store"; -import { personSyncDatumStore, personSyncDatumEndpoints } from "@/store/person_sync_datum.store"; +import { personSyncDatumStore, personSyncDatumEndpoints, personSyncDatumPageSize } from "@/store/person_sync_datum.store"; // mailings import { mailingStore, mailingEndpoints } from './mailing.store'; @@ -143,6 +143,10 @@ const endpoints = { ...publicationDatesEndpoints, } +const pageSize = { + ...personSyncDatumPageSize, +} + // NOTE: this is really the store Vue.use(Vuex) export const store = new Vuex.Store({ @@ -425,7 +429,7 @@ export const store = new Vuex.Store({ current_page = state.page[model]?.currentPage ?? 1; } if (!perPage) { - perPage = state.page[model]?.perPage ?? state.perPage ?? 20 + perPage = pageSize[model] ?? state.page[model]?.perPage ?? state.perPage ?? 20 commit(SET_MODEL_PAGE_SIZE, {model, perPage}) } params = {...params, perPage, current_page} diff --git a/app/javascript/store/person_sync_datum.store.js b/app/javascript/store/person_sync_datum.store.js index 69619024d..ec2c7b1fd 100644 --- a/app/javascript/store/person_sync_datum.store.js +++ b/app/javascript/store/person_sync_datum.store.js @@ -13,6 +13,10 @@ export const personSyncDatumEndpoints = { [personSyncDatumModel]: 'person_sync_datum' } +export const personSyncDatumPageSize = { + [personSyncDatumModel]: 2000 +} + export const personSyncDatumStore = { actions: { [MATCH]({dispatch}, {regId, personId, regMatch, reload = false}) { From e849fdc0d01ea7ac6ed089652cdfbfad5ac8e183 Mon Sep 17 00:00:00 2001 From: Gail Terman Date: Mon, 15 Jul 2024 09:37:15 -0400 Subject: [PATCH 24/31] PLAN-950 small amount of refactoring --- app/javascript/components/combo_box.vue | 21 +++++-- .../integrations/reg-sync-person-search.vue | 57 ++++++++----------- 2 files changed, 41 insertions(+), 37 deletions(-) diff --git a/app/javascript/components/combo_box.vue b/app/javascript/components/combo_box.vue index d763f4b73..e5d8c93fe 100644 --- a/app/javascript/components/combo_box.vue +++ b/app/javascript/components/combo_box.vue @@ -12,8 +12,8 @@ @@ -30,18 +30,29 @@ export default { loading: { type: Boolean, default: false - } + }, + value: {} }, data: () => ({ - selectedOption: null, + selectedOptionInternal: null, term: null }), methods: { onChange(arg) { - this.$emit('change', arg) + this.$emit('change', arg); } }, computed: { + selectedOption: { + get() { + return this.value ?? this.selectedOptionInternal; + }, + set(val) { + this.selectedOptionInternal = val; + this.$emit('input', val); + } + + }, filtered_options() { return this.options.filter( obj => ((this.term == null) || (this.term === "") || obj.text.toLowerCase().includes(this.term.toLowerCase())) diff --git a/app/javascript/integrations/reg-sync-person-search.vue b/app/javascript/integrations/reg-sync-person-search.vue index 33a8c7ded..31f050003 100644 --- a/app/javascript/integrations/reg-sync-person-search.vue +++ b/app/javascript/integrations/reg-sync-person-search.vue @@ -1,10 +1,12 @@