diff --git a/app/assets/images/p_for_plano.png b/app/assets/images/p_for_plano.png
new file mode 100644
index 000000000..099c95d6d
Binary files /dev/null and b/app/assets/images/p_for_plano.png differ
diff --git a/app/controllers/conflicts/session_conflicts_controller.rb b/app/controllers/conflicts/session_conflicts_controller.rb
index f34c2d93d..d7b8bbd27 100644
--- a/app/controllers/conflicts/session_conflicts_controller.rb
+++ b/app/controllers/conflicts/session_conflicts_controller.rb
@@ -1,36 +1,17 @@
class Conflicts::SessionConflictsController < ApplicationController
respond_to :json
- def index
+ # Add the requested conflict id to the ignored conflicts
+ def ignore
authorize Conflicts::SessionConflict, policy_class: Conflicts::SessionConflictPolicy
- per_page = params[:perPage]&.to_i || Conflicts::SessionConflict.default_per_page
- current_page = params[:current_page]&.to_i
+ IgnoredConflict.transaction do
+ permitted = params.permit(:conflict_id, :conflict_type)
- collection = Conflicts::SessionConflict
- .includes([:session,:person,:session_assignment,:room])
- .where("session_assignment_name is null or session_assignment_name in ('Moderator', 'Participant', 'Invisible')")
- .where("conflict_session_assignment_name is null or conflict_session_assignment_name in ('Moderator', 'Participant', 'Invisible')")
- .distinct.page(current_page).per(per_page)
-
- collection_total = collection.total_count
- full_collection_total = Conflicts::SessionConflict.distinct.count
+ ignored = IgnoredConflict.create(permitted)
+ end
- meta = {}
- meta[:total] = collection_total
- meta[:full_total] = full_collection_total ? full_collection_total : collection_total
- meta[:current_page] = current_page if current_page.present?
- meta[:perPage] = per_page if per_page.present?
-
- options = {
- meta: meta,
- params: {
- domain: "#{request.base_url}",
- current_person: current_person
- }
- }
- render json: Conflicts::SessionConflictSerializer.new(collection,options).serializable_hash(),
- content_type: 'application/json'
+ render status: :ok, json: {}.to_json, content_type: 'application/json'
end
def conflicts_with
@@ -42,6 +23,7 @@ def conflicts_with
.where("conflict_session_id = ?", session_id)
.where("session_assignment_name is null or session_assignment_name in ('Moderator', 'Participant', 'Invisible')")
.where("conflict_session_assignment_name is null or conflict_session_assignment_name in ('Moderator', 'Participant', 'Invisible')")
+ .where("session_conflicts.conflict_id not in (select conflict_id from ignored_conflicts)")
.distinct
meta = {}
@@ -50,7 +32,7 @@ def conflicts_with
options = {
meta: meta,
include: [
- # :session
+ :session
],
params: {
domain: "#{request.base_url}",
@@ -70,6 +52,7 @@ def conflicts_for
.where("session_id = ?", session_id)
.where("session_assignment_name is null or session_assignment_name in ('Moderator', 'Participant', 'Invisible')")
.where("conflict_session_assignment_name is null or conflict_session_assignment_name in ('Moderator', 'Participant', 'Invisible')")
+ .where("session_conflicts.conflict_id not in (select conflict_id from ignored_conflicts)")
.distinct
meta = {}
@@ -78,7 +61,7 @@ def conflicts_for
options = {
meta: meta,
include: [
- # :conflict_session
+ :conflict_session
],
params: {
domain: "#{request.base_url}",
diff --git a/app/controllers/reports/conflict_reports_controller.rb b/app/controllers/reports/conflict_reports_controller.rb
index 14c11f895..ef7a5246a 100644
--- a/app/controllers/reports/conflict_reports_controller.rb
+++ b/app/controllers/reports/conflict_reports_controller.rb
@@ -8,6 +8,7 @@ def multiple_sessions_in_room
room_conflicts = Conflicts::RoomConflict
.includes(:room)
.references(:room)
+ .where("room_conflicts.back_to_back = false")
.order('rooms.name, start_time')
workbook = FastExcel.open(constant_memory: true)
@@ -68,6 +69,7 @@ def person_exclusion_conflicts
:person, :session, :exclusion, :excluded_session
)
.where("session_assignment_name in ('Moderator', 'Participant', 'Invisible')")
+ .order('people.published_name asc')
workbook = FastExcel.open(constant_memory: true)
worksheet = workbook.add_worksheet("Person vs Exclusion")
@@ -232,7 +234,7 @@ def back_to_back_to_back
def back_to_back
authorize SessionAssignment, policy_class: Reports::ConflictReportPolicy
- conflicts_table = ::Conflicts::PersonScheduleConflict.arel_table
+ conflicts_table = ::Conflicts::PersonBackToBack.arel_table
subquery = Session.area_list.as('areas_list')
conflict_subquery = Session.area_list.as('conflict_areas_list')
joins = [
@@ -252,8 +254,8 @@ def back_to_back
)
]
- conflicts = Conflicts::PersonScheduleConflict.select(
- Conflicts::PersonScheduleConflict.arel_table[Arel.star],
+ conflicts = Conflicts::PersonBackToBack.select(
+ Conflicts::PersonBackToBack.arel_table[Arel.star],
'areas_list.area_list as area_list',
'conflict_areas_list.area_list as conflict_area_list'
)
@@ -262,7 +264,6 @@ def back_to_back
.joins(joins)
.where("session_assignment_name is null or session_assignment_name in ('Moderator', 'Participant', 'Invisible')")
.where("conflict_session_assignment_name is null or conflict_session_assignment_name in ('Moderator', 'Participant', 'Invisible')")
- .where(back_to_back: true)
.order('published_name asc, conflict_start_time asc')
workbook = FastExcel.open(constant_memory: true)
@@ -347,8 +348,7 @@ def people_double_booked
.joins(joins)
.where("session_assignment_name is null or session_assignment_name in ('Moderator', 'Participant', 'Invisible')")
.where("conflict_session_assignment_name is null or conflict_session_assignment_name in ('Moderator', 'Participant', 'Invisible')")
- .where(back_to_back: false)
- .order('people.published_name asc, conflict_start_time asc')
+ .order('people.published_name asc, start_time asc')
workbook = FastExcel.open(constant_memory: true)
worksheet = workbook.add_worksheet("People Double Booked")
diff --git a/app/controllers/sessions_controller.rb b/app/controllers/sessions_controller.rb
index 2364eabdf..5b797e343 100644
--- a/app/controllers/sessions_controller.rb
+++ b/app/controllers/sessions_controller.rb
@@ -277,6 +277,9 @@ def allowed_params
status
environment
minors_participation
+ require_signup
+ age_restriction_id
+ room_notes
]
# Tags
# format
diff --git a/app/javascript/components/icon_button.vue b/app/javascript/components/icon_button.vue
index b7c5897ad..d909f1ea7 100644
--- a/app/javascript/components/icon_button.vue
+++ b/app/javascript/components/icon_button.vue
@@ -12,7 +12,9 @@
v-b-tooltip.bottom
v-bind="$attrs"
>
-
+
+
+
{{disabledTooltip}}
@@ -77,7 +79,7 @@ export default {
styles.pointerEvents = 'none';
}
return styles;
- }
+ },
},
}
diff --git a/app/javascript/components/table_vue.vue b/app/javascript/components/table_vue.vue
index 9cd5c72e2..30eaea3bb 100644
--- a/app/javascript/components/table_vue.vue
+++ b/app/javascript/components/table_vue.vue
@@ -188,7 +188,9 @@ export default {
data () {
return {
selected_items: [],
- editable_ids: []
+ editable_ids: [],
+ keep: false, // semaphore to catch "false" unselect
+ selecedRowNbr: -1 // keep track of selected row to keep display
}
},
computed: {
@@ -266,9 +268,21 @@ export default {
onRowSelected(items) {
this.selected_items = items
if (items[0] && (items.length == 1)) {
+ // keep the index of the row that was selected
+ this.selecedRowNbr = this.sortedCollection.indexOf(items[0])
this.select(items[0]);
} else {
- this.select(null);
+ if (this.keep) { // semaphore to keep selected from getting unselected ...
+ // This is ugly but it works !!!!
+ this.keep = false
+ if (this.selecedRowNbr > -1) {
+ this.$refs.table.selectRow(this.selecedRowNbr)
+ }
+ } else {
+ // standard unselect
+ this.select(null);
+ this.selecedRowNbr = -1;
+ }
}
},
onSortChanged(ctx) {
@@ -288,21 +302,30 @@ export default {
}
},
watch: {
+ sortedCollection(nv, ov) {
+ if (ov.length == 0 && nv.length > 0) {
+ this.keep = false
+ } else {
+ // If the length has not changed ...
+ this.keep = true
+ }
+ },
selected(val) {
if (!val && this.selected_items.length == 1) {
this.$refs.table.clearSelected()
}
},
- currentPage(ov,nv) {
+ currentPage(nv,ov) {
if (ov != nv) {
// page was changed so we clear our selected
this.selected_items = []
this.editable_ids = []
+ this.keep = false
+ this.selecedRowNbr = -1
}
}
},
mounted() {
- // ensure that there is no model selected when the table is loaded
this.editable_ids = []
this.unselect();
}
diff --git a/app/javascript/conflicts/ignore_button.vue b/app/javascript/conflicts/ignore_button.vue
new file mode 100644
index 000000000..4442e2ae8
--- /dev/null
+++ b/app/javascript/conflicts/ignore_button.vue
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/app/javascript/conflicts/session_conflicts.vue b/app/javascript/conflicts/session_conflicts.vue
index e2fb55131..47517506b 100644
--- a/app/javascript/conflicts/session_conflicts.vue
+++ b/app/javascript/conflicts/session_conflicts.vue
@@ -11,12 +11,14 @@
v-for="conflict in conflicts" :key="conflict.id"
>
+
@@ -32,6 +34,7 @@ import modelMixin from '../store/model.mixin';
import modelUtilsMixin from "@/store/model_utils.mixin"
import { sessionModel } from '@/store/session.store'
import dateTimeMixin from '../components/date_time.mixin'
+import IgnoreButton from './ignore_button.vue';
export default {
name: "SessionConflicts",
@@ -52,6 +55,9 @@ export default {
conflicts: [],
conflicts_with: []
}),
+ components: {
+ IgnoreButton
+ },
computed: {
selectedSession() {
return this.get_model(sessionModel, this.sessionId)
@@ -80,6 +86,13 @@ export default {
}
},
methods: {
+ ignore(conflict) {
+ this.ignore_conflict({conflict_id: conflict.id, conflict_type: conflict.conflict_type}).then(
+ () => {
+ this.getConflicts(this.sessionId)
+ }
+ )
+ },
getConflicts(sessionId) {
this.conflicts = []
this.conflicts_with = []
diff --git a/app/javascript/constants/strings.js b/app/javascript/constants/strings.js
index 6654f9a05..e0d47ce23 100644
--- a/app/javascript/constants/strings.js
+++ b/app/javascript/constants/strings.js
@@ -197,6 +197,9 @@ module.exports = {
ERROR_GENERIC_UNRECOVERABLE: (email) => twoLines("The server has encountered an internal error and was unable to complete your request.",
`Please contact the server administrator at ${email} and let them know the time and date the error occurred.`),
+ ADD_CONFLICT_IGNORE_SUCCESS: "Ignore Conflict Added",
+ ADD_CONFLICT_IGNORE_ERROR: "Ignore Conflict Failed",
+
// Social Links Errors
TWITTER_ID_INVALID_MSG: "Twitter ID is not in a valid format",
FACEBOOK_ID_INVALID_MSG: "Facebook ID is not in a valid format",
@@ -241,4 +244,25 @@ module.exports = {
SURVEY_REDIRECT: "Unfortunately due to the browser refreshing we have lost any answers you filled in. Please fill the survey out again.",
SURVEY_PUBLIC_NO_EDIT: "You cannot edit a published survey. Close the survey to enable editing.",
SURVEY_PUBLIC_NO_DELETE: "You cannot delete a published survey. Close the survey to enable deletion.",
+ SESSION_ENVIRONMENT: {
+ unknown: "Unknown",
+ in_person: "In Person",
+ hybrid: "Hybrid",
+ virtual: "Virtual"
+ },
+ SESSION_STATUS: {
+ draft: "Draft",
+ reviewed: "Reviewed",
+ revised: "Revised",
+ dropped: "Dropped",
+ },
+ SESSION_MUST_UNSCHEDULE: "You must unschedule a session before dropping it",
+ SESSION_MUST_UNDROP: "You must un-drop the session to be able to schedule it.",
+ SESSION_MINORS_PARTICIPATION: {
+ kids_observe: "Kids welcome to observe",
+ kids_supervision: "Kids welcome to participate with supervision",
+ kids_participate: "Kids welcome to participate",
+ geared_families: "Geared towards families",
+ geared_kids: "Geared towards kids",
+ },
}
diff --git a/app/javascript/packs/application.js b/app/javascript/packs/application.js
index 54fa32ad3..5427d3743 100644
--- a/app/javascript/packs/application.js
+++ b/app/javascript/packs/application.js
@@ -47,7 +47,9 @@ Vue.config.errorHandler = (err, vm, info) => {
}
}
-Vue.use(BootstrapVue);
+Vue.use(BootstrapVue, {
+ BSkeleton: { animation: 'fade' }
+});
Vue.use(BootstrapVueIcons);
Vue.use(CustomIconsPlugin);
Vue.use(AsyncComputed);
diff --git a/app/javascript/reports/reports_screen.vue b/app/javascript/reports/reports_screen.vue
index 38b609997..71c24882c 100644
--- a/app/javascript/reports/reports_screen.vue
+++ b/app/javascript/reports/reports_screen.vue
@@ -28,9 +28,9 @@
Participants over Con Limit
-
+
Non-Accepted Participants on Scheduled Sessions
@@ -51,9 +51,9 @@
Sessions with no Moderator
-
+
Sessions with Participants not Scheduled
diff --git a/app/javascript/schedule/schedule_screen.vue b/app/javascript/schedule/schedule_screen.vue
index 9feb24e2a..ec4a597ff 100644
--- a/app/javascript/schedule/schedule_screen.vue
+++ b/app/javascript/schedule/schedule_screen.vue
@@ -142,7 +142,8 @@ export default {
["room_id", "is null"]
]
},
- ["duration", ">", "0"]
+ ["duration", ">", "0"],
+ ["status", "!=", "dropped"]
]
}
diff --git a/app/javascript/sessions/age_restriction.mixin.js b/app/javascript/sessions/age_restriction.mixin.js
new file mode 100644
index 000000000..de84baebb
--- /dev/null
+++ b/app/javascript/sessions/age_restriction.mixin.js
@@ -0,0 +1,19 @@
+import { settingsMixin } from "@/mixins"
+
+export const ageRestrictionMixin = {
+ mixins: [ settingsMixin ],
+ computed: {
+ ageRestrictionOptions() {
+ const opts = this.currentSettings.age_restrictions?.map(ar => ({text: ar.name, value: ar.id})) || []
+ opts.push({text: 'None', value: null})
+ return opts;
+ }
+ },
+ methods: {
+ ageRestrictionName(id) {
+ return this.currentSettings.age_restrictions?.find(ar => ar.id === id)?.name || id;
+ }
+ }
+}
+
+export default ageRestrictionMixin
diff --git a/app/javascript/sessions/datetime_picker.vue b/app/javascript/sessions/datetime_picker.vue
index 7fa6a219d..91417ef3e 100644
--- a/app/javascript/sessions/datetime_picker.vue
+++ b/app/javascript/sessions/datetime_picker.vue
@@ -3,8 +3,8 @@
Time
-
-
+
+
@@ -16,7 +16,13 @@ import { settingsMixin } from '@/mixins';
export default {
name: "DatetimePicker",
- props: ['value'],
+ props: {
+ value: null,
+ disabled: {
+ type: Boolean,
+ default: false
+ }
+ },
mixins: [settingsMixin],
data: () => ({
tempDate: null
diff --git a/app/javascript/sessions/minors_participation.mixin.js b/app/javascript/sessions/minors_participation.mixin.js
new file mode 100644
index 000000000..cdaafa22f
--- /dev/null
+++ b/app/javascript/sessions/minors_participation.mixin.js
@@ -0,0 +1,30 @@
+import { SESSION_MINORS_PARTICIPATION } from "@/constants/strings";
+
+export const minorsParticipationMixin = {
+ data: () => ({
+ SESSION_MINORS_PARTICIPATION
+ }),
+ computed: {
+ minorsParticipationOptions() {
+ return Object.entries(SESSION_MINORS_PARTICIPATION).map(([value, text]) => ({value, text}))
+ },
+ minors_participation: {
+ get() {
+ const session = this.session || this.selected;
+ try {
+ const existing = JSON.parse(session.minors_participation)
+ return Array.isArray(existing) ? existing : existing ? [existing] : []
+ } catch {
+ return []
+ }
+ },
+ set(val) {
+ if(this.session) {
+ this.session.minors_participation = JSON.stringify(val);
+ }
+ }
+ }
+ }
+}
+
+export default minorsParticipationMixin;
diff --git a/app/javascript/sessions/session.js b/app/javascript/sessions/session.js
index e64b75c2f..844da4041 100644
--- a/app/javascript/sessions/session.js
+++ b/app/javascript/sessions/session.js
@@ -1,6 +1,10 @@
+import { SESSION_STATUS } from '@/constants/strings';
import AreaSelectForSearch from './area_select_for_search'
export const session_columns = [
+ // {
+ // key: 'id'
+ // },
{
key: 'title',
sortKey: 'sessions.title',
@@ -53,20 +57,29 @@ export const session_columns = [
{
key: 'status',
label: 'Status',
+ formatter: (value) => SESSION_STATUS[value] || value,
+ sortable: true,
+ sortKey: 'status',
+ choices: ['draft', 'reviewed', 'revised', 'dropped'].map(value => ({label: SESSION_STATUS[value], value})),
+ type: "select"
},
{
key: 'open_for_interest',
label: 'Open for Interest',
type: "radio",
choices: [{label: "Yes", value: "true"}, {label: "No", value: "false"}],
- formatter: (value) => value ? "Yes" : "No"
+ formatter: (value) => value ? "Yes" : "No",
+ sortable: true,
+ sortKey: 'open_for_interest'
},
{
key: 'require_signup',
label: 'Requires Signup',
type: "radio",
choices: [{label: "Yes", value: "true"}, {label: "No", value: "false"}],
- formatter: (value) => value ? "Yes" : "No"
+ formatter: (value) => value ? "Yes" : "No",
+ sortable: true,
+ sortKey: 'require_signup'
},
{
key: 'publish',
diff --git a/app/javascript/sessions/session_edit.vue b/app/javascript/sessions/session_edit.vue
index b56787cad..d6c79e5ef 100644
--- a/app/javascript/sessions/session_edit.vue
+++ b/app/javascript/sessions/session_edit.vue
@@ -60,15 +60,65 @@
-
+
+
+
+
({
editable: false,
- saving: false
+ saving: false,
+ SESSION_ENVIRONMENT,
}),
computed: {
session() {
@@ -158,7 +222,7 @@ export default {
this.session.session_areas_attributes = areasForSaving
}
- }
+ },
},
methods: {
edit() {
@@ -172,7 +236,15 @@ export default {
},
saveSession() {
this.save_model(sessionModel, this.session)
- }
+ },
+ saveValidatedSession({dirty, valid=null}) {
+ if(dirty && valid) {
+ this.save_model(sessionModel, this.session)
+ }
+ },
+ getValidationState({ dirty, validated, valid = null }) {
+ return dirty || validated ? valid : null;
+ },
}
}
diff --git a/app/javascript/sessions/session_schedule.vue b/app/javascript/sessions/session_schedule.vue
index 67fe2fac0..fd593059a 100644
--- a/app/javascript/sessions/session_schedule.vue
+++ b/app/javascript/sessions/session_schedule.vue
@@ -2,14 +2,27 @@
+
+
+ {{SESSION_MUST_UNDROP}}
+
Space
-
-
+
+
-
-
+
+
minutes
-
+ {{ validationCtx.errors[0] }}
+
@@ -20,6 +33,14 @@
import { modelMixinNoProp } from "@/mixins";
import RoomPicker from './room_picker';
import DatetimePicker from './datetime_picker';
+import { SESSION_MUST_UNDROP } from "@/constants/strings";
+import { ValidationProvider, extend } from 'vee-validate';
+import { min_value } from 'vee-validate/dist/rules'
+
+extend('min_value', {
+ ...min_value,
+ message: "Sessions can't be less than 10 minutes long"
+ })
export default {
name: "SessionSchedule",
@@ -28,12 +49,37 @@ export default {
],
components: {
RoomPicker,
- DatetimePicker
+ DatetimePicker,
+ ValidationProvider
},
data: () => ({
tempDuration: null,
- model: 'session'
+ model: 'session',
+ SESSION_MUST_UNDROP
}),
+ computed: {
+ scheduleDisabled() {
+ return this.selected.status === 'dropped'
+ },
+ duration: {
+ get() {
+ return this.tempDuration || this.selected.duration;
+ },
+ set(val) {
+ this.tempDuration = val;
+ }
+ }
+ },
+ methods: {
+ validatedPatchSelected(data, {dirty, valid=null}) {
+ if(dirty && valid) {
+ this.patchSelected(data);
+ }
+ },
+ getValidationState({ dirty, validated, valid = null }) {
+ return dirty || validated ? valid : null;
+ },
+ }
}
diff --git a/app/javascript/sessions/session_sidebar.vue b/app/javascript/sessions/session_sidebar.vue
index 15d588c7e..e81358d71 100644
--- a/app/javascript/sessions/session_sidebar.vue
+++ b/app/javascript/sessions/session_sidebar.vue
@@ -3,7 +3,7 @@
{{selected.title}}
- Last updated:
+ Last updated
on {{new Date(selected.updated_at).toLocaleString()}}
@@ -11,10 +11,14 @@
+ - Status:
+ -
+ {{SESSION_STATUS[selected.status]}}
+
-
Description:
- -
+
-
@@ -55,14 +59,25 @@
None Selected
Format
{{selected.format.name}}
-
+ None Set
+ Attendee Age Restrictions
+ {{ ageRestrictionName(selected.age_restriction_id)}}
+ None
+ Minors Participation
+ {{ SESSION_MINORS_PARTICIPATION[mp]}}
+ No Selection
Interest Instructions
No Entry
+ Required Room Features/Services
+ {{selected.room_notes}}
+ No Entry
Scheduled Participant Notes
No Entry
@@ -114,6 +129,9 @@ import { areaMixin, scheduledMixin, startTimeMixin } from './session_fields.mixi
import { sessionConflictModel } from '@/store/session_conflict.store';
import SessionConflicts from '@/conflicts/session_conflicts.vue';
// import SessionAdminTab from './session_admin_tab';
+import { SESSION_ENVIRONMENT, SESSION_STATUS} from '@/constants/strings';
+import { minorsParticipationMixin } from './minors_participation.mixin';
+import { ageRestrictionMixin } from './age_restriction.mixin';
export default {
name: 'SessionSidebar',
@@ -129,10 +147,14 @@ export default {
personSessionMixin,
areaMixin,
scheduledMixin,
- startTimeMixin
+ startTimeMixin,
+ minorsParticipationMixin,
+ ageRestrictionMixin,
],
data: () => ({
- sessionConflictModel
+ sessionConflictModel,
+ SESSION_ENVIRONMENT,
+ SESSION_STATUS
}),
computed: {
editLink() {
diff --git a/app/javascript/sessions/session_summary.vue b/app/javascript/sessions/session_summary.vue
index 54ae497ac..9ef7508c0 100644
--- a/app/javascript/sessions/session_summary.vue
+++ b/app/javascript/sessions/session_summary.vue
@@ -66,6 +66,14 @@
:checked="scheduled"
>Scheduled
+
+
+ {{SESSION_STATUS.draft}}
+ {{SESSION_STATUS.reviewed}}
+ {{SESSION_STATUS.revised}}
+ {{SESSION_STATUS.dropped}}
+
+
@@ -75,6 +83,7 @@
import { sessionModel } from '@/store/session.store'
import modelUtilsMixin from '@/store/model_utils.mixin';
import { scheduledMixin } from './session_fields.mixin';
+import { SESSION_STATUS, SESSION_MUST_UNSCHEDULE } from '@/constants/strings';
import PlanoEditor from '../components/plano_editor';
@@ -87,6 +96,10 @@ export default {
modelUtilsMixin,
scheduledMixin
],
+ data: () => ({
+ SESSION_STATUS,
+ SESSION_MUST_UNSCHEDULE
+ }),
computed: {
session() {
return this.selected_model(sessionModel);
diff --git a/app/javascript/sessions/session_table.vue b/app/javascript/sessions/session_table.vue
index b7e222afe..b20a92936 100644
--- a/app/javascript/sessions/session_table.vue
+++ b/app/javascript/sessions/session_table.vue
@@ -36,9 +36,6 @@
-
- —
-
—
diff --git a/app/javascript/sessions/view_participants.vue b/app/javascript/sessions/view_participants.vue
index 978bbf251..364247ee7 100644
--- a/app/javascript/sessions/view_participants.vue
+++ b/app/javascript/sessions/view_participants.vue
@@ -1,9 +1,21 @@
-
-
-
-
+
+
+ Moderator
+
+ Participant
+
+ Invisible Participant
+
+ Reserved
+
+
+
+
+
+
+
@@ -26,21 +38,29 @@ export default {
modelMixinNoProp,
],
data: () => ({
- model
+ model,
+ loading: false
}),
+ methods: {
+ load() {
+ this.clear();
+ this.loading = true;
+ this.fetch({session_id: this.session.id}).then(() => {
+ this.loading = false;
+ })
+ }
+ },
watch: {
session(newSession, oldSession) {
if (newSession) {
if ((oldSession && oldSession.id !== newSession.id) || !oldSession) {
- this.clear();
- this.fetch({session_id: this.session.id})
+ this.load();
}
}
}
},
mounted() {
- this.clear();
- this.fetch({session_id: this.session.id})
+ this.load();
}
}
diff --git a/app/javascript/store/model.mixin.js b/app/javascript/store/model.mixin.js
index 971a98618..f48030a85 100644
--- a/app/javascript/store/model.mixin.js
+++ b/app/javascript/store/model.mixin.js
@@ -11,7 +11,7 @@ export const modelMixinNoProp = {
selected() {
return this.$store.getters[SELECTED]({model: this.model})
},
- collection() {
+ collection() {
return Object.values(this.$store.getters['jv/get']({_jv: { type: this.model }}))
}
},
diff --git a/app/javascript/store/session_conflict.mixin.js b/app/javascript/store/session_conflict.mixin.js
index 4fda258eb..7f5db09a1 100644
--- a/app/javascript/store/session_conflict.mixin.js
+++ b/app/javascript/store/session_conflict.mixin.js
@@ -2,21 +2,36 @@ import {mapActions } from 'vuex';
import { sessionConflictModel as model} from '@/store/session_conflict.store';
import {GET_CONFLICTS_FOR_SESSION} from '@/store/session_conflict.store';
import {GET_CONFLICTS_WITH_SESSION} from '@/store/session_conflict.store';
+import {IGNORE_CONFLICT} from '@/store/session_conflict.store';
-import modelMixin from "./model.mixin";
+import { toastMixin, modelMixin } from "@/mixins";
+
+import {
+ ADD_CONFLICT_IGNORE_SUCCESS,
+ ADD_CONFLICT_IGNORE_ERROR
+} from '../constants/strings'
export const sessionConflictMixin = {
- mixins: [modelMixin],
+ mixins: [modelMixin, toastMixin],
methods: {
...mapActions({
get_conflicts_for_session: GET_CONFLICTS_FOR_SESSION,
- get_conflicts_with_session: GET_CONFLICTS_WITH_SESSION
+ get_conflicts_with_session: GET_CONFLICTS_WITH_SESSION,
+ do_ignore_conflict: IGNORE_CONFLICT
}),
get_conflicts({session_id}) {
return this.get_conflicts_for_session({session_id: session_id});
},
get_conflicts_with({session_id}) {
return this.get_conflicts_with_session({session_id: session_id});
+ },
+ ignore_conflict({conflict_id, conflict_type}, success_text = ADD_CONFLICT_IGNORE_SUCCESS, error_text = ADD_CONFLICT_IGNORE_ERROR) {
+ return this.toastPromise(
+ this.do_ignore_conflict({conflict_id: conflict_id, conflict_type: conflict_type}),
+ success_text,
+ error_text
+ );
+
}
}
}
diff --git a/app/javascript/store/session_conflict.store.js b/app/javascript/store/session_conflict.store.js
index 3e3818f71..eaddae892 100644
--- a/app/javascript/store/session_conflict.store.js
+++ b/app/javascript/store/session_conflict.store.js
@@ -1,5 +1,6 @@
export const GET_CONFLICTS_FOR_SESSION = 'GET CONFLICTS FOR SESSION';
export const GET_CONFLICTS_WITH_SESSION = 'GET CONFLICTS WITH SESSION';
+export const IGNORE_CONFLICT = 'IGNORE CONFLICT'
export const sessionConflictModel = 'session_conflict';
export const sessionConflictEndpoints = {
@@ -29,6 +30,9 @@ export const sessionConflictStore = {
res({});
}
})
+ },
+ [IGNORE_CONFLICT] ({commit, dispatch, state}, {conflict_id, conflict_type}) {
+ return dispatch('jv/get',`/session_conflict/ignore/${conflict_type}/${conflict_id}`);
}
},
selected: {
diff --git a/app/lib/migration_helpers/plano_views.rb b/app/lib/migration_helpers/plano_views.rb
index 02a4570ab..4764ebb9d 100644
--- a/app/lib/migration_helpers/plano_views.rb
+++ b/app/lib/migration_helpers/plano_views.rb
@@ -2,9 +2,11 @@ module MigrationHelpers
module PlanoViews
def self.create_views
self.create_person_schedules
+ self.create_person_and_exclusions
self.create_room_allocations
self.create_room_conflicts
self.create_person_schedule_conflicts
+ self.create_person_back_to_back
self.create_person_exclusion_conflicts
self.create_person_back_to_back_to_back
self.create_availability_conflicts
@@ -109,6 +111,7 @@ def self.create_room_conflicts
end
def self.create_person_schedule_conflicts
+ # change for back to backs
query = <<-SQL.squish
CREATE OR REPLACE VIEW person_schedule_conflicts AS
select
@@ -135,15 +138,7 @@ def self.create_person_schedule_conflicts
ps2.session_assignment_role_type_id as conflict_session_assignment_role_type_id,
ps2.session_assignment_role_type as conflict_session_assignment_role_type,
ps2.session_assignment_name as conflict_session_assignment_name,
- ps2.room_id as conflict_room_id,
- case
- when
- ((ps2.start_time >= ps1.end_time) and (ps2.start_time <= (ps1.end_time + (40 || ' minute')::interval)))
- or
- ((ps1.start_time >= ps2.end_time) and (ps1.start_time <= (ps2.end_time + (40 || ' minute')::interval)))
- then true
- else FALSE
- end as back_to_back
+ ps2.room_id as conflict_room_id
from
person_schedules ps1
join
@@ -151,14 +146,78 @@ def self.create_person_schedule_conflicts
and ps2.session_id != ps1.session_id
and ps2.start_time >= ps1.start_time
and (
- ps2.start_time <= ps1.end_time + (40 || ' minute')::interval
+ ps2.start_time < ps1.end_time
or
(
- ps2.end_time >= ps1.start_time - (40 || ' minute')::interval and ps2.end_time <= ps1.end_time
+ ps2.end_time > ps1.start_time and ps2.end_time <= ps1.end_time
)
- )
+ );
+ SQL
+ ActiveRecord::Base.connection.execute(query)
+ end
+
+ def self.create_person_back_to_back
+ query = <<-SQL.squish
+ CREATE OR REPLACE VIEW person_back_to_back AS
+ select
+ CONCAT(ps1.person_id, ':', ps1.session_id, ':', ps2.session_id) as id,
+ ps1.person_id,
+ ps1.name,
+ ps1.published_name,
+ ps1.con_state,
+ ps2.start_time AS conflict_start_time,
+ ps1.session_id,
+ ps1.title,
+ ps1.start_time,
+ ps1.end_time,
+ ps1.duration,
+ ps1.session_assignment_id,
+ ps1.session_assignment_role_type_id,
+ ps1.session_assignment_name as session_assignment_name,
+ ps1.session_assignment_role_type,
+ ps1.room_id,
+ ps2.session_id as conflict_session_id,
+ ps2.title as conflict_session_title,
+ ps2.end_time as conflict_end_time,
+ ps2.duration as conflict_duration,
+ ps2.session_assignment_role_type_id as conflict_session_assignment_role_type_id,
+ ps2.session_assignment_role_type as conflict_session_assignment_role_type,
+ ps2.session_assignment_name as conflict_session_assignment_name,
+ ps2.room_id as conflict_room_id
+ from
+ person_schedules ps1
+ join
+ person_schedules ps2 on ps2.person_id = ps1.person_id
+ and ps2.session_id != ps1.session_id
+ where
+ (ps2.start_time >= ps1.end_time) and (ps2.start_time <= (ps1.end_time + (40 || ' minute')::interval));
+ SQL
+ # or
+ # ((ps1.start_time >= ps2.end_time) and (ps1.start_time <= (ps2.end_time + (40 || ' minute')::interval)))
+
+ ActiveRecord::Base.connection.execute(query)
+ end
+
+ def self.create_person_and_exclusions
+ query = <<-SQL.squish
+ CREATE OR REPLACE VIEW person_and_exclusions AS
+ select
+ pe.exclusion_id,
+ pe.person_id,
+ s.id as session_id,
+ s.start_time,
+ (s.start_time + (s.duration || ' minute')::interval) as end_time,
+ s.title
+ from
+ person_exclusions pe
+ left join exclusions_sessions es on
+ es.exclusion_id = pe.exclusion_id
+ left join sessions s on
+ s.id = es.session_id
+ where
+ session_id is not null
order by
- ps1.person_id
+ pe.person_id, session_id
SQL
ActiveRecord::Base.connection.execute(query)
end
@@ -166,35 +225,53 @@ def self.create_person_schedule_conflicts
def self.create_person_exclusion_conflicts
query = <<-SQL.squish
CREATE OR REPLACE VIEW person_exclusion_conflicts AS
- SELECT
- concat(person_schedules.person_id, ':', es.exclusion_id, ':', person_schedules.session_id) AS id,
- person_schedules.person_id,
- person_schedules.name,
- person_schedules.published_name,
- person_schedules.con_state,
- es.exclusion_id,
- es.session_id AS excluded_session_id,
- s.title as excluded_session_title,
- person_schedules.session_id,
- person_schedules.title,
- person_schedules.start_time,
- person_schedules.end_time,
- person_schedules.duration,
- person_schedules.session_assignment_role_type_id,
- person_schedules.session_assignment_id,
- person_schedules.session_assignment_name,
- person_schedules.session_assignment_role_type
- FROM (((public.person_schedules
- LEFT JOIN public.person_exclusions pe ON ((pe.person_id = person_schedules.person_id)))
- JOIN public.exclusions_sessions es ON ((es.exclusion_id = pe.exclusion_id)))
- LEFT JOIN public.sessions s ON ((s.id = es.session_id)))
- WHERE ((person_schedules.session_id <> s.id) AND (person_schedules.start_time >= s.start_time) AND ((person_schedules.start_time <= (s.start_time + ((s.duration || ' minute'::text))::interval)) OR ((person_schedules.end_time >= s.start_time) AND (person_schedules.end_time <= (s.start_time + ((s.duration || ' minute'::text))::interval)))));
+ select
+ concat(person_schedules.person_id, ':', es.exclusion_id, ':', person_schedules.session_id) as id,
+ person_schedules.person_id,
+ person_schedules.name,
+ person_schedules.published_name,
+ person_schedules.con_state,
+ es.exclusion_id,
+ es.session_id as excluded_session_id,
+ s.title as excluded_session_title,
+ person_schedules.session_id,
+ person_schedules.title,
+ person_schedules.start_time,
+ person_schedules.end_time,
+ person_schedules.duration,
+ person_schedules.session_assignment_role_type_id,
+ person_schedules.session_assignment_id,
+ person_schedules.session_assignment_name,
+ person_schedules.session_assignment_role_type
+ from
+ person_schedules
+ left join person_exclusions pe on
+ pe.person_id = person_schedules.person_id
+ join exclusions_sessions es on
+ es.exclusion_id = pe.exclusion_id
+ left join sessions s on
+ s.id = es.session_id
+ where
+ person_schedules.session_id <> s.id
+ and (
+ (
+ person_schedules.start_time >= s.start_time
+ and
+ person_schedules.start_time < (s.start_time + (s.duration || ' minute'::text)::interval)
+ )
+ or
+ (
+ person_schedules.end_time > s.start_time
+ and
+ person_schedules.end_time <= (s.start_time + (s.duration || ' minute'::text)::interval)
+ )
+ );
SQL
ActiveRecord::Base.connection.execute(query)
end
def self.create_person_back_to_back_to_back
- # check
+ # TODO: change new view
query = <<-SQL.squish
CREATE OR REPLACE VIEW person_back_to_back_to_back AS
select
@@ -233,11 +310,9 @@ def self.create_person_back_to_back_to_back
psc2.conflict_session_assignment_name,
psc2.conflict_room_id
from
- person_schedule_conflicts psc1
- inner join person_schedule_conflicts psc2 on
+ person_back_to_back psc1
+ inner join person_back_to_back psc2 on
psc2.session_id = psc1.conflict_session_id
- and psc2.back_to_back = true
- where psc1.back_to_back = true
SQL
ActiveRecord::Base.connection.execute(query)
end
@@ -382,7 +457,6 @@ def self.create_session_conflicts
id as conflict_id,
'person_schedule_conflict' as conflict_type
from person_schedule_conflicts
- where person_schedule_conflicts.back_to_back = false
UNION
select
session_id,
@@ -401,8 +475,7 @@ def self.create_session_conflicts
conflict_session_assignment_name,
id as conflict_id,
'person_back_to_back' as conflict_type
- from person_schedule_conflicts
- where person_schedule_conflicts.back_to_back = true
+ from person_back_to_back
SQL
ActiveRecord::Base.connection.execute(query)
end
@@ -423,12 +496,18 @@ def self.drop_views
ActiveRecord::Base.connection.execute <<-SQL
DROP VIEW IF EXISTS person_schedule_conflicts;
SQL
+ ActiveRecord::Base.connection.execute <<-SQL
+ DROP VIEW IF EXISTS person_back_to_back;
+ SQL
ActiveRecord::Base.connection.execute <<-SQL
DROP VIEW IF EXISTS room_conflicts;
SQL
ActiveRecord::Base.connection.execute <<-SQL
DROP VIEW IF EXISTS room_allocations;
SQL
+ ActiveRecord::Base.connection.execute <<-SQL
+ DROP VIEW IF EXISTS person_and_exclusions;
+ SQL
ActiveRecord::Base.connection.execute <<-SQL
DROP VIEW IF EXISTS person_schedules;
SQL
diff --git a/app/models/conflicts/person_back_to_back.rb b/app/models/conflicts/person_back_to_back.rb
new file mode 100644
index 000000000..a1d97e5cf
--- /dev/null
+++ b/app/models/conflicts/person_back_to_back.rb
@@ -0,0 +1,19 @@
+class Conflicts::PersonBackToBack < ApplicationRecord
+ self.table_name = :person_back_to_back
+ self.primary_key = :id
+
+ belongs_to :session_assignment
+ belongs_to :person
+ belongs_to :session
+ belongs_to :session_assignment_role_type
+ belongs_to :room
+
+ belongs_to :conflict_session_assignment, class_name: 'SessionAssignment'
+ belongs_to :conflict_session, class_name: 'Session'
+ belongs_to :conflict_session_assignment_role_type, class_name: 'SessionAssignmentRoleType'
+ belongs_to :conflict_room, class_name: 'Room'
+
+ def readonly?
+ true
+ end
+end
diff --git a/app/models/ignored_conflict.rb b/app/models/ignored_conflict.rb
new file mode 100644
index 000000000..6d081a0e1
--- /dev/null
+++ b/app/models/ignored_conflict.rb
@@ -0,0 +1,2 @@
+class IgnoredConflict < ApplicationRecord
+end
diff --git a/app/models/session.rb b/app/models/session.rb
index 48625c530..d02bd50f4 100644
--- a/app/models/session.rb
+++ b/app/models/session.rb
@@ -18,9 +18,22 @@ class Session < ApplicationRecord
before_save :keep_who_did_it, :keep_interest_trail, :schedule_consistency
- has_many :session_conflicts, class_name: 'Conflicts::SessionConflict'
+ has_many :session_conflicts,
+ -> {
+ where("session_conflicts.conflict_id not in (select conflict_id from ignored_conflicts)")
+ .where("session_assignment_name is null or session_assignment_name in (?)", ['Moderator', 'Participant', 'Invisible'])
+ .where("conflict_session_assignment_name is null or conflict_session_assignment_name in (?)", ['Moderator', 'Participant', 'Invisible'])
+ },
+ class_name: 'Conflicts::SessionConflict'
+
# Get where this session is on the other side of the conflict relationship
- has_many :conflict_sessions, foreign_key: :conflict_session_id, class_name: 'Conflicts::SessionConflict'
+ has_many :conflict_sessions,
+ -> {
+ where("session_conflicts.conflict_id not in (select conflict_id from ignored_conflicts)")
+ .where("session_assignment_name is null or session_assignment_name in (?)", ['Moderator', 'Participant', 'Invisible'])
+ .where("conflict_session_assignment_name is null or conflict_session_assignment_name in (?)", ['Moderator', 'Participant', 'Invisible'])
+ },
+ foreign_key: :conflict_session_id, class_name: 'Conflicts::SessionConflict'
has_and_belongs_to_many :room_services
@@ -115,6 +128,7 @@ def self.area_list
def self.conflict_counts
sessions = Session.arel_table
conflicts = Conflicts::SessionConflict.arel_table
+ ignored_conflicts = ::IgnoredConflict.arel_table
sessions.project(
sessions[:id].as('session_id'),
@@ -127,6 +141,10 @@ def self.conflict_counts
.and(
conflicts[:session_assignment_name].eq(nil).or(conflicts[:session_assignment_name].in(['Moderator', 'Participant', 'Invisible'])).and(
conflicts[:conflict_session_assignment_name].eq(nil).or(conflicts[:conflict_session_assignment_name].in(['Moderator', 'Participant', 'Invisible']))
+ ).and(
+ conflicts[:conflict_id].not_in(
+ ignored_conflicts.project(ignored_conflicts[:conflict_id])
+ )
)
)
)
diff --git a/app/policies/conflicts/session_conflict_policy.rb b/app/policies/conflicts/session_conflict_policy.rb
index 743849db6..e097d741c 100644
--- a/app/policies/conflicts/session_conflict_policy.rb
+++ b/app/policies/conflicts/session_conflict_policy.rb
@@ -1,6 +1,6 @@
class Conflicts::SessionConflictPolicy < BasePolicy
- def index?
- allowed?(action: :index)
+ def ignore?
+ allowed?(action: :ignore)
end
def conflicts_with?
diff --git a/app/serializers/conflicts/session_conflict_serializer.rb b/app/serializers/conflicts/session_conflict_serializer.rb
index 20d387d39..2195da9f8 100644
--- a/app/serializers/conflicts/session_conflict_serializer.rb
+++ b/app/serializers/conflicts/session_conflict_serializer.rb
@@ -1,7 +1,7 @@
class Conflicts::SessionConflictSerializer
include JSONAPI::Serializer
- attribute :person_id, :person_name, :person_published_name,
+ attribute :id, :person_id, :person_name, :person_published_name,
:session_assignment_id,
:session_id, :session_title, :session_start_time,
:conflict_session_id, :conflict_session_title,
diff --git a/app/serializers/session_serializer.rb b/app/serializers/session_serializer.rb
index 991226397..7fe0f34d0 100644
--- a/app/serializers/session_serializer.rb
+++ b/app/serializers/session_serializer.rb
@@ -12,8 +12,8 @@ class SessionSerializer
:updated_by, :interest_opened_by, :interest_opened_at,
:room_id, :proofed, :format_id, :room_set_id,
:status, :environment,
- :tech_notes,
- :minors_participation
+ :tech_notes, :room_notes,
+ :minors_participation, :age_restriction_id
# tag_list
attribute :tag_list do |session|
diff --git a/app/services/reports_service.rb b/app/services/reports_service.rb
index 6cef1b244..6c01f905a 100644
--- a/app/services/reports_service.rb
+++ b/app/services/reports_service.rb
@@ -18,16 +18,28 @@ def self.assigned_sessions_not_scheduled
def self.scheduled_session_no_people
active_roles = SessionAssignmentRoleType.where("role_type = 'participant' and (name != 'Invisible' and name != 'Reserve')")
+ # Get all sessions that are scheduled with people in role
+ session_with_people = PersonSchedule.where("session_assignment_role_type_id in (?)", active_roles.collect{|a| a.id})
+ # Then get all scheduled sessions not in the above
Session.select(
::Session.arel_table[Arel.star],
'areas_list.area_list'
)
.joins(self.area_subquery)
- .joins(:session_assignments)
- .eager_load(:areas, :room)
- .where("session_assignments.session_assignment_role_type_id not in (?)", active_roles.collect{|a| a.id})
.where("start_time is not null and room_id is not null")
+ .where("sessions.id not in (?)", session_with_people.collect{|a| a.session_id})
.order(:start_time)
+
+
+ # Session.select(
+ # ::Session.arel_table[Arel.star],
+ # 'areas_list.area_list'
+ # )
+ # .joins(:session_assignments)
+ # .eager_load(:areas, :room)
+ # .where("session_assignments.session_assignment_role_type_id not in (?)", active_roles.collect{|a| a.id})
+ # .where("start_time is not null and room_id is not null")
+ # .order(:start_time)
end
diff --git a/app/views/layouts/application.html.erb b/app/views/layouts/application.html.erb
index 894f9d470..47416aa12 100644
--- a/app/views/layouts/application.html.erb
+++ b/app/views/layouts/application.html.erb
@@ -14,6 +14,7 @@
<%= javascript_pack_tag 'application' %>
<%= stylesheet_pack_tag 'application' %>
+ <%= favicon_link_tag asset_path('p_for_plano.png') %>
Planorama
<%= csp_meta_tag %>
diff --git a/config/routes.rb b/config/routes.rb
index c923c490c..125acfe35 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -85,7 +85,7 @@
get 'agreement/latest', to: 'agreements#latest'
resources :agreements, path: 'agreement'
- get 'session_conflict', to: 'conflicts/session_conflicts#index'
+ get 'session_conflict/ignore/:conflict_type/:conflict_id', to: 'conflicts/session_conflicts#ignore'
get 'session_conflict/conflicts_for/:session_id', to: 'conflicts/session_conflicts#conflicts_for'
get 'session_conflict/conflicts_with/:session_id', to: 'conflicts/session_conflicts#conflicts_with'
diff --git a/db/migrate/20220628121934_create_ignored_conflicts.rb b/db/migrate/20220628121934_create_ignored_conflicts.rb
new file mode 100644
index 000000000..c7ddb112d
--- /dev/null
+++ b/db/migrate/20220628121934_create_ignored_conflicts.rb
@@ -0,0 +1,12 @@
+class CreateIgnoredConflicts < ActiveRecord::Migration[6.1]
+ def change
+ create_table :ignored_conflicts, id: :uuid do |t|
+ t.string :conflict_id, limit: 2048
+ t.string :conflict_type
+
+ t.timestamps
+ end
+
+ add_index :ignored_conflicts, [:conflict_id, :conflict_type], unique: true
+ end
+end
diff --git a/db/migrate/20220630032544_add_room_notes_to_session.rb b/db/migrate/20220630032544_add_room_notes_to_session.rb
new file mode 100644
index 000000000..84357057f
--- /dev/null
+++ b/db/migrate/20220630032544_add_room_notes_to_session.rb
@@ -0,0 +1,5 @@
+class AddRoomNotesToSession < ActiveRecord::Migration[6.1]
+ def change
+ add_column :sessions, :room_notes, :text
+ end
+end
diff --git a/db/structure.sql b/db/structure.sql
index 0380bc9d1..7b5a8cdc1 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -660,7 +660,8 @@ CREATE TABLE public.sessions (
tech_notes text,
age_restriction_id uuid,
minors_participation jsonb,
- room_set_id uuid
+ room_set_id uuid,
+ room_notes text
);
@@ -872,6 +873,19 @@ CREATE TABLE public.formats (
);
+--
+-- Name: ignored_conflicts; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.ignored_conflicts (
+ id uuid DEFAULT public.gen_random_uuid() NOT NULL,
+ conflict_id character varying(2048),
+ conflict_type character varying,
+ created_at timestamp(6) without time zone NOT NULL,
+ updated_at timestamp(6) without time zone NOT NULL
+);
+
+
--
-- Name: label_dimensions; Type: TABLE; Schema: public; Owner: -
--
@@ -1011,6 +1025,38 @@ CREATE TABLE public.person_agreements (
);
+--
+-- Name: person_exclusions; Type: TABLE; Schema: public; Owner: -
+--
+
+CREATE TABLE public.person_exclusions (
+ id uuid DEFAULT public.gen_random_uuid() NOT NULL,
+ person_id uuid,
+ exclusion_id uuid,
+ lock_version integer,
+ created_at timestamp(6) without time zone NOT NULL,
+ updated_at timestamp(6) without time zone NOT NULL
+);
+
+
+--
+-- Name: person_and_exclusions; Type: VIEW; Schema: public; Owner: -
+--
+
+CREATE VIEW public.person_and_exclusions AS
+ SELECT pe.exclusion_id,
+ pe.person_id,
+ s.id AS session_id,
+ s.start_time,
+ (s.start_time + ((s.duration || ' minute'::text))::interval) AS end_time,
+ s.title
+ FROM ((public.person_exclusions pe
+ LEFT JOIN public.exclusions_sessions es ON ((es.exclusion_id = pe.exclusion_id)))
+ LEFT JOIN public.sessions s ON ((s.id = es.session_id)))
+ WHERE (es.session_id IS NOT NULL)
+ ORDER BY pe.person_id, s.id;
+
+
--
-- Name: person_schedules; Type: VIEW; Schema: public; Owner: -
--
@@ -1041,16 +1087,16 @@ CREATE VIEW public.person_schedules AS
--
--- Name: person_schedule_conflicts; Type: VIEW; Schema: public; Owner: -
+-- Name: person_back_to_back; Type: VIEW; Schema: public; Owner: -
--
-CREATE VIEW public.person_schedule_conflicts AS
+CREATE VIEW public.person_back_to_back AS
SELECT concat(ps1.person_id, ':', ps1.session_id, ':', ps2.session_id) AS id,
ps1.person_id,
ps1.name,
ps1.published_name,
ps1.con_state,
- GREATEST(ps1.start_time, ps2.start_time) AS conflict_start_time,
+ ps2.start_time AS conflict_start_time,
ps1.session_id,
ps1.title,
ps1.start_time,
@@ -1068,14 +1114,10 @@ CREATE VIEW public.person_schedule_conflicts AS
ps2.session_assignment_role_type_id AS conflict_session_assignment_role_type_id,
ps2.session_assignment_role_type AS conflict_session_assignment_role_type,
ps2.session_assignment_name AS conflict_session_assignment_name,
- ps2.room_id AS conflict_room_id,
- CASE
- WHEN (((ps2.start_time >= ps1.end_time) AND (ps2.start_time <= (ps1.end_time + ((40 || ' minute'::text))::interval))) OR ((ps1.start_time >= ps2.end_time) AND (ps1.start_time <= (ps2.end_time + ((40 || ' minute'::text))::interval)))) THEN true
- ELSE false
- END AS back_to_back
+ ps2.room_id AS conflict_room_id
FROM (public.person_schedules ps1
- JOIN public.person_schedules ps2 ON (((ps2.person_id = ps1.person_id) AND (ps2.session_id <> ps1.session_id) AND (ps2.start_time >= ps1.start_time) AND ((ps2.start_time <= (ps1.end_time + ((40 || ' minute'::text))::interval)) OR ((ps2.end_time >= (ps1.start_time - ((40 || ' minute'::text))::interval)) AND (ps2.end_time <= ps1.end_time))))))
- ORDER BY ps1.person_id;
+ JOIN public.person_schedules ps2 ON (((ps2.person_id = ps1.person_id) AND (ps2.session_id <> ps1.session_id))))
+ WHERE ((ps2.start_time >= ps1.end_time) AND (ps2.start_time <= (ps1.end_time + ((40 || ' minute'::text))::interval)));
--
@@ -1117,9 +1159,8 @@ CREATE VIEW public.person_back_to_back_to_back AS
psc2.conflict_session_assignment_role_type,
psc2.conflict_session_assignment_name,
psc2.conflict_room_id
- FROM (public.person_schedule_conflicts psc1
- JOIN public.person_schedule_conflicts psc2 ON (((psc2.session_id = psc1.conflict_session_id) AND (psc2.back_to_back = true))))
- WHERE (psc1.back_to_back = true);
+ FROM (public.person_back_to_back psc1
+ JOIN public.person_back_to_back psc2 ON ((psc2.session_id = psc1.conflict_session_id)));
--
@@ -1137,20 +1178,6 @@ CREATE TABLE public.person_constraints (
);
---
--- Name: person_exclusions; Type: TABLE; Schema: public; Owner: -
---
-
-CREATE TABLE public.person_exclusions (
- id uuid DEFAULT public.gen_random_uuid() NOT NULL,
- person_id uuid,
- exclusion_id uuid,
- lock_version integer,
- created_at timestamp(6) without time zone NOT NULL,
- updated_at timestamp(6) without time zone NOT NULL
-);
-
-
--
-- Name: person_exclusion_conflicts; Type: VIEW; Schema: public; Owner: -
--
@@ -1177,7 +1204,7 @@ CREATE VIEW public.person_exclusion_conflicts AS
LEFT JOIN public.person_exclusions pe ON ((pe.person_id = person_schedules.person_id)))
JOIN public.exclusions_sessions es ON ((es.exclusion_id = pe.exclusion_id)))
LEFT JOIN public.sessions s ON ((s.id = es.session_id)))
- WHERE ((person_schedules.session_id <> s.id) AND (person_schedules.start_time >= s.start_time) AND ((person_schedules.start_time <= (s.start_time + ((s.duration || ' minute'::text))::interval)) OR ((person_schedules.end_time >= s.start_time) AND (person_schedules.end_time <= (s.start_time + ((s.duration || ' minute'::text))::interval)))));
+ WHERE ((person_schedules.session_id <> s.id) AND (person_schedules.start_time >= s.start_time) AND ((person_schedules.start_time < (s.start_time + ((s.duration || ' minute'::text))::interval)) OR ((person_schedules.end_time > s.start_time) AND (person_schedules.end_time <= (s.start_time + ((s.duration || ' minute'::text))::interval)))));
--
@@ -1194,6 +1221,39 @@ CREATE TABLE public.person_mailing_assignments (
);
+--
+-- Name: person_schedule_conflicts; Type: VIEW; Schema: public; Owner: -
+--
+
+CREATE VIEW public.person_schedule_conflicts AS
+ SELECT concat(ps1.person_id, ':', ps1.session_id, ':', ps2.session_id) AS id,
+ ps1.person_id,
+ ps1.name,
+ ps1.published_name,
+ ps1.con_state,
+ GREATEST(ps1.start_time, ps2.start_time) AS conflict_start_time,
+ ps1.session_id,
+ ps1.title,
+ ps1.start_time,
+ ps1.end_time,
+ ps1.duration,
+ ps1.session_assignment_id,
+ ps1.session_assignment_role_type_id,
+ ps1.session_assignment_name,
+ ps1.session_assignment_role_type,
+ ps1.room_id,
+ ps2.session_id AS conflict_session_id,
+ ps2.title AS conflict_session_title,
+ ps2.end_time AS conflict_end_time,
+ ps2.duration AS conflict_duration,
+ ps2.session_assignment_role_type_id AS conflict_session_assignment_role_type_id,
+ ps2.session_assignment_role_type AS conflict_session_assignment_role_type,
+ ps2.session_assignment_name AS conflict_session_assignment_name,
+ ps2.room_id AS conflict_room_id
+ FROM (public.person_schedules ps1
+ JOIN public.person_schedules ps2 ON (((ps2.person_id = ps1.person_id) AND (ps2.session_id <> ps1.session_id) AND (ps2.start_time >= ps1.start_time) AND ((ps2.start_time <= ps1.end_time) OR ((ps2.end_time >= ps1.start_time) AND (ps2.end_time <= ps1.end_time))))));
+
+
--
-- Name: publication_dates; Type: TABLE; Schema: public; Owner: -
--
@@ -1468,26 +1528,24 @@ UNION
person_schedule_conflicts.id AS conflict_id,
'person_schedule_conflict'::text AS conflict_type
FROM public.person_schedule_conflicts
- WHERE (person_schedule_conflicts.back_to_back = false)
UNION
- SELECT person_schedule_conflicts.session_id,
- person_schedule_conflicts.title AS session_title,
- person_schedule_conflicts.start_time AS session_start_time,
- person_schedule_conflicts.room_id,
- person_schedule_conflicts.person_id,
- person_schedule_conflicts.name AS person_name,
- person_schedule_conflicts.published_name AS person_published_name,
- person_schedule_conflicts.session_assignment_id,
- person_schedule_conflicts.session_assignment_role_type_id,
- person_schedule_conflicts.session_assignment_name,
- person_schedule_conflicts.conflict_session_id,
- person_schedule_conflicts.conflict_session_title,
- person_schedule_conflicts.conflict_session_assignment_role_type_id,
- person_schedule_conflicts.conflict_session_assignment_name,
- person_schedule_conflicts.id AS conflict_id,
+ SELECT person_back_to_back.session_id,
+ person_back_to_back.title AS session_title,
+ person_back_to_back.start_time AS session_start_time,
+ person_back_to_back.room_id,
+ person_back_to_back.person_id,
+ person_back_to_back.name AS person_name,
+ person_back_to_back.published_name AS person_published_name,
+ person_back_to_back.session_assignment_id,
+ person_back_to_back.session_assignment_role_type_id,
+ person_back_to_back.session_assignment_name,
+ person_back_to_back.conflict_session_id,
+ person_back_to_back.conflict_session_title,
+ person_back_to_back.conflict_session_assignment_role_type_id,
+ person_back_to_back.conflict_session_assignment_name,
+ person_back_to_back.id AS conflict_id,
'person_back_to_back'::text AS conflict_type
- FROM public.person_schedule_conflicts
- WHERE (person_schedule_conflicts.back_to_back = true);
+ FROM public.person_back_to_back;
--
@@ -1989,6 +2047,14 @@ ALTER TABLE ONLY public.formats
ADD CONSTRAINT formats_pkey PRIMARY KEY (id);
+--
+-- Name: ignored_conflicts ignored_conflicts_pkey; Type: CONSTRAINT; Schema: public; Owner: -
+--
+
+ALTER TABLE ONLY public.ignored_conflicts
+ ADD CONSTRAINT ignored_conflicts_pkey PRIMARY KEY (id);
+
+
--
-- Name: label_dimensions label_dimensions_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -2477,6 +2543,13 @@ CREATE UNIQUE INDEX index_exclusions_sessions_on_exclusion_id_and_session_id ON
CREATE INDEX index_exclusions_sessions_on_session_id ON public.exclusions_sessions USING btree (session_id);
+--
+-- Name: index_ignored_conflicts_on_conflict_id_and_conflict_type; Type: INDEX; Schema: public; Owner: -
+--
+
+CREATE UNIQUE INDEX index_ignored_conflicts_on_conflict_id_and_conflict_type ON public.ignored_conflicts USING btree (conflict_id, conflict_type);
+
+
--
-- Name: index_magic_links_on_person_id; Type: INDEX; Schema: public; Owner: -
--
@@ -3069,6 +3142,8 @@ INSERT INTO "schema_migrations" (version) VALUES
('20220623145514'),
('20220623172955'),
('20220624121252'),
-('20220629132145');
+('20220628121934'),
+('20220629132145'),
+('20220630032544');
diff --git a/docs/index.md b/docs/index.md
index 69d87acd8..0be43bbc7 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -7,8 +7,8 @@ This software is open source! If you'd like to contribute, please email planoram
[Planorama Data Privacy & Protection Policy](/planorama/privacy)
-Production version: 1.4.1
+Production version: 1.4.2
-Staging version: 1.4.1
+Staging version: 1.4.2
diff --git a/lib/tasks/rbac.rake b/lib/tasks/rbac.rake
index 2c43479b0..b74c5d162 100644
--- a/lib/tasks/rbac.rake
+++ b/lib/tasks/rbac.rake
@@ -497,7 +497,8 @@ namespace :rbac do
},
"session_conflict": {
"conflicts_with": true,
- "conflicts_for": true
+ "conflicts_for": true,
+ "ignore": true
}
})
end
@@ -752,7 +753,8 @@ namespace :rbac do
},
"session_conflict": {
"conflicts_with": true,
- "conflicts_for": true
+ "conflicts_for": true,
+ "ignore": true
}
})
end
diff --git a/test/factories/ignored_conflicts.rb b/test/factories/ignored_conflicts.rb
new file mode 100644
index 000000000..4f79f435e
--- /dev/null
+++ b/test/factories/ignored_conflicts.rb
@@ -0,0 +1,5 @@
+FactoryBot.define do
+ factory :ignored_conflict do
+
+ end
+end
diff --git a/test/models/ignored_conflict_test.rb b/test/models/ignored_conflict_test.rb
new file mode 100644
index 000000000..0bc33d10c
--- /dev/null
+++ b/test/models/ignored_conflict_test.rb
@@ -0,0 +1,7 @@
+require "test_helper"
+
+class IgnoredConflictTest < ActiveSupport::TestCase
+ # test "the truth" do
+ # assert true
+ # end
+end