diff --git a/src/components/filters/select-filter-criteria/index.module.less b/src/components/filters/select-filter-criteria/index.module.less
deleted file mode 100644
index c9a629fe6..000000000
--- a/src/components/filters/select-filter-criteria/index.module.less
+++ /dev/null
@@ -1,3 +0,0 @@
-.selectFilterWrapper {
- margin-bottom: 20px;
-}
diff --git a/src/i18n/en.json b/src/i18n/en.json
index eda7913d2..1092c1a45 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -1155,19 +1155,18 @@
"add_event": "Add Activity",
"title": "Title",
"type": "Activity Type",
- "event_type_capacity": "Activity Type Capacity",
- "selection_plan": "Selection Plan",
- "location": "Location",
- "level": "Level",
+ "event_type_capacity": "Select..",
+ "selection_plan": "Select Selection Plan",
+ "location": "Select Location",
+ "level": "Select Level",
"tags": "Tags",
"progress_flags": "Progress Flags",
"streaming_url": "Streaming URL",
"meeting_url": "Meeting URL",
"etherpad_link": "Etherpad URL",
"streaming_type": "Streaming Type",
- "status": "Status",
- "selection_status": "Selection Status",
- "submission_status": "Submission Status",
+ "selection_status": "Select Status",
+ "submission_status": "Select Status",
"published": "Published",
"speakers": "Speakers",
"duration": "Duration",
@@ -1176,7 +1175,7 @@
"submitter_company": "Submitter Company",
"sponsor": "Sponsors",
"all_companies": "All Companies",
- "track": "Activity Category",
+ "track": "Select Activity Category",
"start_date": "Start Date",
"end_date": "End Date",
"media_uploads_display": "Display on Site",
@@ -1194,7 +1193,6 @@
"mux_token_secret_info": "MUX Token Secret",
"mux_email_to": "Email to",
"mux_email_to_info": "Recipient to send process excerpt.",
- "export": "Export",
"created_by": "Submitter",
"mux_import_done": "MUX MP4 Import Process Requested Successfuly.",
"allows_attendee_vote_filter": "Allows attendee vote",
@@ -1215,50 +1213,12 @@
"submission_status_accepted": "Accepted",
"submission_status_received": "Received",
"submission_status_not_submitted": "Not Submitted",
- "media_upload_type": "Media Upload Type",
"media_uploads": "Media Uploads",
- "media_upload_with_type": "Media Upload Types",
"edit_selected": "Edit Selected",
- "delete_selected": "Delete Selected",
"placeholders": {
"search_events": "Search by Id, Title, Abstract, Speaker Title",
- "event_type_capacity": "Filter by Activity Type Capacity",
- "selection_plan": "Filter by Selection Plan",
- "location": "Filter by Location",
- "selection_status": "Filter by Selection Status",
- "progress_flag": "Filter by Progress Flag",
- "track": "Filter by Activity Category",
"event_type": "Filter by Activity Type",
- "speaker": "Filter by Speaker",
- "speaker_company": "Filter by Speaker Company",
- "level": "Filter by Level",
- "tags": "Filter by Tags",
- "start_date": "Filter from Date",
- "end_date": "Filter to Date",
- "start_date_from": "Filter Start Date from",
- "start_date_to": "Filter Start Date to",
- "end_date_from": "Filter End Date from",
- "end_date_to": "Filter End Date to",
- "created_from": "Filter Created Date from",
- "created_to": "Filter Created Date to",
- "modified_from": "Filter Modified Date from",
- "modified_to": "Filter Modified Date to",
- "select_fields": "Select data to display",
- "has_rsvp": "Has RSVP?",
- "submitters": "Filter by Submitter",
- "submitter_company": "Filter by Submitter Company",
- "streaming_url": "Filter by Stream URL",
- "meeting_url": "Filter by Meeting URL",
- "etherpad_link": "Filter by Etherpad URL",
- "streaming_type": "Filter by Streaming Type",
- "sponsor": "Filter by Sponsor",
- "all_companies": "Filter by All Companies",
- "submission_status": "Filter by Submission Status",
- "review_status": "Filter by Review Status",
- "media_upload_type": "Filter by Media Upload Type",
- "submission_source": "Filter by Submission Source",
- "media_upload_type_id_to_include": "Select the Media Upload Types to include",
- "media_upload_type_id_to_exclude": "Select the Media Upload Types to exclude"
+ "select_fields": "Select data to display"
}
},
"event_type_list": {
diff --git a/src/pages/events/__tests__/summit-event-list-page.test.js b/src/pages/events/__tests__/summit-event-list-page.test.js
index 00ab2f5c5..e932bbb16 100644
--- a/src/pages/events/__tests__/summit-event-list-page.test.js
+++ b/src/pages/events/__tests__/summit-event-list-page.test.js
@@ -4,19 +4,6 @@ import { renderWithRedux } from "../../../utils/test-utils";
const mockEditableTableSpy = jest.fn(() => null);
-jest.mock("openstack-uicore-foundation/lib/components", () => ({
- CompanyInput: () => null,
- DateTimePicker: () => null,
- Dropdown: () => null,
- FreeTextSearch: () => null,
- Input: () => null,
- MemberInput: () => null,
- OperatorInput: () => null,
- SpeakerInput: () => null,
- TagInput: () => null,
- UploadInput: () => null
-}));
-
jest.mock(
"../../../components/tables/editable-table/EditableTable",
() =>
@@ -51,8 +38,6 @@ jest.mock("react-bootstrap", () => {
};
});
-jest.mock("../../../components/filters/media-type-filter", () => () => null);
-jest.mock("../../../components/filters/or-and-filter", () => () => null);
jest.mock("../../../components/filters/save-filter-criteria", () => () => null);
jest.mock(
"../../../components/filters/select-filter-criteria",
@@ -86,6 +71,9 @@ describe("SummitEventListPage", () => {
presentation_action_types: []
}
},
+ mediaUploadListState: {
+ media_uploads: []
+ },
currentEventListState: {
events: [
{
@@ -104,8 +92,7 @@ describe("SummitEventListPage", () => {
term: "",
filters: {},
extraColumns: ["media_uploads"],
- perPage: 10,
- enabledFilters: []
+ perPage: 10
}
}
});
@@ -134,6 +121,9 @@ describe("SummitEventListPage", () => {
presentation_action_types: []
}
},
+ mediaUploadListState: {
+ media_uploads: []
+ },
currentEventListState: {
events: [
{
@@ -161,8 +151,7 @@ describe("SummitEventListPage", () => {
term: "",
filters: {},
extraColumns: ["media_uploads"],
- perPage: 10,
- enabledFilters: []
+ perPage: 10
}
}
});
@@ -215,6 +204,9 @@ describe("SummitEventListPage", () => {
presentation_action_types: []
}
},
+ mediaUploadListState: {
+ media_uploads: []
+ },
currentEventListState: {
events: [
{
@@ -239,8 +231,7 @@ describe("SummitEventListPage", () => {
term: "",
filters: {},
extraColumns: ["media_uploads"],
- perPage: 10,
- enabledFilters: []
+ perPage: 10
}
}
});
@@ -290,6 +281,9 @@ describe("SummitEventListPage", () => {
presentation_action_types: []
}
},
+ mediaUploadListState: {
+ media_uploads: []
+ },
currentEventListState: {
events: [
{
@@ -315,8 +309,7 @@ describe("SummitEventListPage", () => {
term: "",
filters: {},
extraColumns: ["media_uploads"],
- perPage: 10,
- enabledFilters: []
+ perPage: 10
}
}
});
diff --git a/src/pages/events/summit-event-list-page.js b/src/pages/events/summit-event-list-page.js
deleted file mode 100644
index 058754b88..000000000
--- a/src/pages/events/summit-event-list-page.js
+++ /dev/null
@@ -1,2150 +0,0 @@
-/**
- * Copyright 2026 OpenStack Foundation
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- * http://www.apache.org/licenses/LICENSE-2.0
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- * */
-
-import React from "react";
-import { connect } from "react-redux";
-import T from "i18n-react/dist/i18n-react";
-import Swal from "sweetalert2";
-import { Modal, Pagination } from "react-bootstrap";
-import CompanyInput from "openstack-uicore-foundation/lib/components/inputs/company-input"
-import DateTimePicker from "openstack-uicore-foundation/lib/components/inputs/datetimepicker"
-import Dropdown from "openstack-uicore-foundation/lib/components/inputs/dropdown"
-import FreeTextSearch from "openstack-uicore-foundation/lib/components/free-text-search"
-import Input from "openstack-uicore-foundation/lib/components/inputs/text-input"
-import MemberInput from "openstack-uicore-foundation/lib/components/inputs/member-input"
-import OperatorInput from "openstack-uicore-foundation/lib/components/inputs/operator-input"
-import SpeakerInput from "openstack-uicore-foundation/lib/components/inputs/speaker-input"
-import TagInput from "openstack-uicore-foundation/lib/components/inputs/tag-input"
-import UploadInput from "openstack-uicore-foundation/lib/components/inputs/upload-input";
-import { SegmentedControl } from "segmented-control";
-import { epochToMomentTimeZone } from "openstack-uicore-foundation/lib/utils/methods";
-import {
- bulkUpdateEvents,
- changeEventListSearchTerm,
- deleteEvent,
- exportEvents,
- getEvents,
- importEventsCSV,
- importMP4AssetsFromMUX,
- queryAllCompanies,
- querySpeakerCompany,
- querySubmitterCompany
-} from "../../actions/event-actions";
-import { handleDDLSortByLabel, hasErrors } from "../../utils/methods";
-import "../../styles/summit-event-list-page.less";
-import OrAndFilter from "../../components/filters/or-and-filter";
-import MediaTypeFilter from "../../components/filters/media-type-filter";
-import {
- ALL_FILTER,
- DATE_FILTER_ARRAY_SIZE,
- DEFAULT_CURRENT_PAGE,
- DEFAULT_PER_PAGE,
- DEFAULT_Z_INDEX,
- HIGH_Z_INDEX
-} from "../../utils/constants";
-import {
- defaultColumns,
- editableColumns,
- formatEventData
-} from "../../utils/summitUtils";
-import SaveFilterCriteria from "../../components/filters/save-filter-criteria";
-import SelectFilterCriteria from "../../components/filters/select-filter-criteria";
-import {
- deleteFilterCriteria,
- saveFilterCriteria
-} from "../../actions/filter-criteria-actions";
-import { CONTEXT_ACTIVITIES } from "../../utils/filter-criteria-constants";
-import EditableTable from "../../components/tables/editable-table/EditableTable";
-import { buildNameIdDDL } from "../../utils/events/summit-event-list-page.utils";
-
-const fieldNames = (
- allSelectionPlans,
- allTracks,
- event_types,
- currentSummitId
-) => [
- {
- columnKey: "speakers",
- value: "speakers",
- customStyle: { minWidth: "350px" },
- editableField: (extraProps) => {
- const useSpeakers = extraProps.row.type?.use_speakers;
- return useSpeakers ? (
-
({ ...base, zIndex: 9999 }),
- control: (base, state) => ({
- ...base,
- zIndex: state.menuIsOpen ? HIGH_Z_INDEX : DEFAULT_Z_INDEX
- })
- }}
- getOptionLabel={(speaker) =>
- `${speaker.first_name} ${speaker.last_name} (${speaker.email})`
- }
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...extraProps}
- />
- ) : (
- false
- );
- }
- },
- { columnKey: "created_by_fullname", value: "created_by", sortable: true },
- { columnKey: "published_date", value: "published", sortable: true },
- { columnKey: "duration", value: "duration", sortable: true },
- { columnKey: "speakers_count", value: "speakers_count", sortable: true },
- { columnKey: "speaker_company", value: "speaker_company", sortable: true },
- {
- columnKey: "track",
- value: "track",
- sortable: true,
- editableField: (extraProps) => {
- const track_ddl = buildNameIdDDL(allTracks);
-
- return (
- ({ ...base, zIndex: 9999 }),
- control: (base, state) => ({
- ...base,
- zIndex: state.menuIsOpen ? HIGH_Z_INDEX : DEFAULT_Z_INDEX
- })
- }}
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...extraProps}
- />
- );
- }
- },
- { columnKey: "start_date", value: "start_date", sortable: true },
- { columnKey: "end_date", value: "end_date", sortable: true },
- { columnKey: "submitters", value: "submitters" },
- {
- columnKey: "submitter_company",
- value: "submitter_company",
- sortable: true
- },
- { columnKey: "sponsor", value: "sponsor", sortable: true },
- { columnKey: "event_type_capacity", value: "event_type_capacity" },
- {
- columnKey: "selection_plan",
- value: "selection_plan",
- sortable: true,
- editableField: (extraProps) => {
- if (!extraProps.row?.type?.id) return false;
- const event_type = Array.isArray(event_types)
- ? event_types.find(
- (t) => t?.id !== undefined && t.id === extraProps.row.type?.id
- )
- : null;
- if (!event_type) return false;
-
- const allowSelectionPlanEdit =
- ["PresentationType"].includes(event_type.class_name) ||
- ["PresentationType"].includes(event_type.name);
- if (!allowSelectionPlanEdit) return false;
-
- const trackId = extraProps.row?.track?.id;
- const track =
- trackId !== undefined && trackId !== null
- ? allTracks.find((t) => t?.id !== undefined && t.id === trackId)
- : null;
-
- const selection_plans_per_track = buildNameIdDDL(
- (Array.isArray(allSelectionPlans) ? allSelectionPlans : []).filter(
- (sp) =>
- !track ||
- (Array.isArray(sp.track_groups) &&
- Array.isArray(track.track_groups) &&
- sp.track_groups.some((gr) => track.track_groups.includes(gr)))
- )
- );
-
- return (
- ({ ...base, zIndex: 9999 }),
- control: (base, state) => ({
- ...base,
- width: 220,
- zIndex: state.menuIsOpen ? HIGH_Z_INDEX : DEFAULT_Z_INDEX
- })
- }}
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...extraProps}
- />
- );
- },
- render: (e) => (e?.name ? e.name : "N/A")
- },
- { columnKey: "location", value: "location", sortable: true },
- { columnKey: "level", value: "level", sortable: true },
- { columnKey: "tags", value: "tags", sortable: true },
- {
- columnKey: "streaming_url",
- value: "streaming_url",
- sortable: true,
- title: true,
- editableField: true
- },
- {
- columnKey: "meeting_url",
- value: "meeting_url",
- sortable: true,
- title: true,
- editableField: true
- },
- {
- columnKey: "etherpad_link",
- value: "etherpad_link",
- sortable: true,
- title: true,
- editableField: true
- },
- { columnKey: "streaming_type", value: "streaming_type", sortable: true },
- {
- columnKey: "review_status",
- value: "review_status",
- sortable: true,
- title: true
- },
- {
- columnKey: "status",
- value: "submission_status",
- sortable: true,
- title: true
- },
- {
- columnKey: "progress_flags",
- value: "progress_flags",
- sortable: true,
- title: true
- },
- { columnKey: "created", value: "created", sortable: true },
- { columnKey: "modified", value: "modified", sortable: true },
- {
- columnKey: "submission_source",
- value: "submission_source",
- sortable: true
- },
- {
- columnKey: "media_uploads",
- value: "media_uploads",
- sortable: false,
- render: (e, row) => {
- if (!e?.length) return "N/A";
- return (
- <>
- {e.map((m) => (
-
- {
- ev.preventDefault();
- if (!row?.id || !currentSummitId) return false;
- window.open(
- `/app/summits/${currentSummitId}/events/${row.id}/materials/${m.id}`,
- "_blank"
- );
- return false;
- }}
- >
- {m.media_upload_type.name} - {m.created}
-
-
-
- ))}
- >
- );
- }
- },
- {
- columnKey: "media_uploads_display",
- value: "media_uploads_display",
- sortable: false,
- render: (e, row) => {
- const media_uploads = row?.media_uploads || [];
- if (!media_uploads.length) return "N/A";
- return (
- <>
- {media_uploads.map((m) => (
-
- {`"${m.media_upload_type.name}" : `}
- {`${m.display_on_site ? "Yes" : "No"}`}
-
-
- ))}
- >
- );
- }
- },
- {
- columnKey: "allow_feedback",
- value: "allow_feedback",
- sortable: false,
- render: (field) =>
- field === undefined ? "N/A" : field === true ? "Yes" : "No",
- editableField: (extraProps) => (
- ({ ...base, zIndex: 9999 }),
- control: (base, state) => ({
- ...base,
- zIndex: state.menuIsOpen ? HIGH_Z_INDEX : DEFAULT_Z_INDEX
- })
- }}
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...extraProps}
- />
- )
- },
- {
- columnKey: "to_record",
- value: "to_record",
- sortable: false,
- render: (field) =>
- field === undefined ? "N/A" : field === true ? "Yes" : "No",
- editableField: (extraProps) => (
- ({ ...base, zIndex: 9999 }),
- control: (base, state) => ({
- ...base,
- zIndex: state.menuIsOpen ? HIGH_Z_INDEX : DEFAULT_Z_INDEX
- })
- }}
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...extraProps}
- />
- )
- }
-];
-
-const defaultFilters = {
- event_type_capacity_filter: [],
- selection_plan_id_filter: [],
- location_id_filter: [],
- selection_status_filter: [],
- track_id_filter: [],
- event_type_id_filter: [],
- speaker_id_filter: [],
- speaker_company: [],
- level_filter: [],
- tags_filter: [],
- published_filter: null,
- has_rsvp_filter: null,
- progress_flag: [],
- created_filter: Array(DATE_FILTER_ARRAY_SIZE).fill(null),
- modified_filter: Array(DATE_FILTER_ARRAY_SIZE).fill(null),
- start_date_filter: Array(DATE_FILTER_ARRAY_SIZE).fill(null),
- end_date_filter: Array(DATE_FILTER_ARRAY_SIZE).fill(null),
- duration_filter: "",
- speakers_count_filter: "",
- submitters: [],
- submitter_company: [],
- streaming_url: "",
- meeting_url: "",
- etherpad_link: "",
- streaming_type: "",
- sponsor: [],
- all_companies: [],
- submission_status_filter: [],
- media_upload_with_type: { operator: null, value: [] },
- review_status_filter: [],
- submission_source_filter: ""
-};
-
-class SummitEventListPage extends React.Component {
- constructor(props) {
- super(props);
-
- this.handleEdit = this.handleEdit.bind(this);
- this.handlePageChange = this.handlePageChange.bind(this);
- this.handleSort = this.handleSort.bind(this);
- this.handleSearch = this.handleSearch.bind(this);
- this.handleNewEvent = this.handleNewEvent.bind(this);
- this.handleDeleteEvent = this.handleDeleteEvent.bind(this);
- this.handleExport = this.handleExport.bind(this);
- this.handleChangeSendSpeakerEmail =
- this.handleChangeSendSpeakerEmail.bind(this);
- this.handleImportEvents = this.handleImportEvents.bind(this);
- this.handleMUXImport = this.handleMUXImport.bind(this);
- this.handleChangeMUXModal = this.handleChangeMUXModal.bind(this);
- this.handleImportAssetsFromMUX = this.handleImportAssetsFromMUX.bind(this);
- this.handleExtraFilterChange = this.handleExtraFilterChange.bind(this);
- this.handleTagOrSpeakerFilterChange =
- this.handleTagOrSpeakerFilterChange.bind(this);
- this.handleSetPublishedFilter = this.handleSetPublishedFilter.bind(this);
- this.handleSetRSVPFilter = this.handleSetRSVPFilter.bind(this);
- this.handleChangeDateFilter = this.handleChangeDateFilter.bind(this);
- this.handleApplyEventFilters = this.handleApplyEventFilters.bind(this);
- this.handleFiltersChange = this.handleFiltersChange.bind(this);
- this.handleColumnsChange = this.handleColumnsChange.bind(this);
- this.handleTermChange = this.handleTermChange.bind(this);
- this.handleOrAndFilter = this.handleOrAndFilter.bind(this);
- this.handleFilterCriteriaSave = this.handleFilterCriteriaSave.bind(this);
- this.handleFilterCriteriaChange =
- this.handleFilterCriteriaChange.bind(this);
- this.handleFilterCriteriaDelete =
- this.handleFilterCriteriaDelete.bind(this);
-
- this.state = {
- showImportModal: false,
- send_speaker_email: false,
- showImportFromMUXModal: false,
- importFile: null,
- muxModalState: {
- mux_token_id: "",
- mux_token_secret: "",
- mux_email_to: ""
- },
- enabledFilters: [],
- errors: {},
- eventFilters: {
- ...defaultFilters,
- orAndFilter: ALL_FILTER
- },
- selectedColumns: [],
- selectedFilterCriteria: null
- };
-
- this.extraFilters = {
- allows_attendee_vote_filter: false,
- allows_location_filter: false,
- allows_publishing_dates_filter: false
- };
- }
-
- componentDidMount() {
- const {
- getEvents,
- currentSummit,
- filters,
- extraColumns,
- term,
- currentPage,
- perPage,
- order,
- orderDir
- } = this.props;
- const { eventFilters } = this.state;
- const enabledFilters = Object.keys(filters).filter((e) =>
- Array.isArray(filters[e])
- ? filters[e]?.some((e) => e !== null)
- : filters[e]?.length > 0
- );
-
- this.setState((prevState) => ({
- ...prevState,
- selectedColumns: extraColumns,
- enabledFilters,
- eventFilters: { ...eventFilters, ...filters }
- }));
-
- if (currentSummit) {
- getEvents(
- term,
- currentPage,
- perPage,
- order,
- orderDir,
- filters,
- extraColumns
- );
- }
- }
-
- handleChangeSendSpeakerEmail(ev) {
- this.setState((prevState) => ({
- ...prevState,
- send_speaker_email: ev.target.checked
- }));
- }
-
- handleChangeMUXModal(ev) {
- const { errors, muxModalState } = this.state;
- const newErrors = { ...errors };
- const newMuxModalState = { ...muxModalState };
- const { value, id } = ev.target;
- newErrors[id] = "";
- newMuxModalState[id] = value;
- this.setState((prevState) => ({
- ...prevState,
- muxModalState,
- errors: newErrors
- }));
- }
-
- handleMUXImport(ev) {
- ev.preventDefault();
- this.setState((prevState) => ({
- ...prevState,
- showImportFromMUXModal: true
- }));
- }
-
- handleImportAssetsFromMUX(ev) {
- const { importMP4AssetsFromMUX } = this.props;
- const {
- muxModalState: { mux_token_id, mux_token_secret, mux_email_to }
- } = this.state;
- ev.preventDefault();
- importMP4AssetsFromMUX(mux_token_id, mux_token_secret, mux_email_to).then(
- () =>
- this.setState((prevState) => ({
- ...prevState,
- muxModalState: {
- mux_token_id: "",
- mux_token_secret: "",
- mux_email_to: ""
- }
- }))
- );
- }
-
- handleImportEvents() {
- const { importEventsCSV } = this.props;
- const { importFile, send_speaker_email } = this.state;
- if (importFile) {
- importEventsCSV(importFile, send_speaker_email);
- }
- this.setState((prevState) => ({
- ...prevState,
- showImportModal: false,
- send_speaker_email: false,
- importFile: null
- }));
- }
-
- handleEdit(event_id) {
- const { currentSummit, history } = this.props;
- history.push(`/app/summits/${currentSummit.id}/events/${event_id}`);
- }
-
- handleExport(ev) {
- const { order, orderDir, term, exportEvents } = this.props;
- const { eventFilters, selectedColumns } = this.state;
- ev.preventDefault();
- exportEvents(term, order, orderDir, eventFilters, selectedColumns);
- }
-
- handlePageChange(page) {
- const { order, orderDir, perPage, term, getEvents } = this.props;
- const { eventFilters, selectedColumns } = this.state;
- getEvents(
- term,
- page,
- perPage,
- order,
- orderDir,
- eventFilters,
- selectedColumns
- );
- }
-
- handleSort(index, key, dir) {
- const { term, getEvents } = this.props;
- const { eventFilters, selectedColumns } = this.state;
-
- switch (key) {
- case "name":
- key = "last_name";
- break;
- case "submitter_company":
- key = "created_by_company";
- break;
- case "progress_flags":
- key = "actions";
- break;
- default:
- break;
- }
-
- getEvents(
- term,
- DEFAULT_CURRENT_PAGE,
- DEFAULT_PER_PAGE,
- key,
- dir,
- eventFilters,
- selectedColumns
- );
- }
-
- handleSearch(term) {
- const { order, orderDir, getEvents } = this.props;
- const { eventFilters, selectedColumns } = this.state;
- getEvents(
- term,
- DEFAULT_CURRENT_PAGE,
- DEFAULT_PER_PAGE,
- order,
- orderDir,
- eventFilters,
- selectedColumns
- );
- }
-
- handleNewEvent() {
- const { currentSummit, history } = this.props;
- history.push(`/app/summits/${currentSummit.id}/events/new`);
- }
-
- handleDeleteEvent(eventId) {
- const { deleteEvent, events } = this.props;
- const event = events.find((e) => e.id === eventId);
-
- Swal.fire({
- title: T.translate("general.are_you_sure"),
- text: `${T.translate("event_list.delete_event_warning")} ${event.title}`,
- type: "warning",
- showCancelButton: true,
- confirmButtonColor: "#DD6B55",
- confirmButtonText: T.translate("general.yes_delete")
- }).then((result) => {
- if (result.value) {
- deleteEvent(eventId);
- }
- });
- }
-
- handleTermChange(term) {
- const { changeEventListSearchTerm } = this.props;
- changeEventListSearchTerm(term);
- }
-
- handleApplyEventFilters() {
- const { order, orderDir, term, getEvents } = this.props;
- const { eventFilters, selectedColumns } = this.state;
- getEvents(
- term,
- DEFAULT_CURRENT_PAGE,
- DEFAULT_PER_PAGE,
- order,
- orderDir,
- eventFilters,
- selectedColumns
- );
- this.setState((prevState) => ({
- ...prevState,
- selectedFilterCriteria: null
- }));
- }
-
- handleExtraFilterChange(ev) {
- const { eventFilters } = this.state;
- const { type, id } = ev.target;
- let { value } = ev.target;
- if (type === "operatorinput") {
- value = Array.isArray(value)
- ? value
- : `${ev.target.operator}${ev.target.value}`;
- if (id === "duration_filter") {
- value = Array.isArray(value)
- ? value
- : `${ev.target.operator}${ev.target.value}`;
- }
- }
- if (type === "mediatypeinput") {
- value = {
- operator: ev.target.operator,
- value: ev.target.value
- };
- }
- this.setState((prevState) => ({
- ...prevState,
- eventFilters: { ...eventFilters, [id]: value },
- selectedFilterCriteria: null
- }));
- }
-
- handleOrAndFilter(ev) {
- const { eventFilters } = this.state;
- this.setState((prevState) => ({
- ...prevState,
- eventFilters: { ...eventFilters, orAndFilter: ev }
- }));
- }
-
- handleTagOrSpeakerFilterChange(ev) {
- const { value, id } = ev.target;
- const { eventFilters } = this.state;
- this.setState((prevState) => ({
- ...prevState,
- eventFilters: { ...eventFilters, [id]: value }
- }));
- }
-
- handleSetPublishedFilter(ev) {
- const { eventFilters } = this.state;
- this.extraFilters.published_filter = ev;
- this.setState((prevState) => ({
- ...prevState,
- eventFilters: { ...eventFilters, published_filter: ev }
- }));
- }
-
- handleSetRSVPFilter(ev) {
- const { eventFilters } = this.state;
- this.extraFilters.has_rsvp_filter = ev;
- this.setState((prevState) => ({
- ...prevState,
- eventFilters: { ...eventFilters, has_rsvp_filter: ev }
- }));
- }
-
- handleFiltersChange(ev) {
- const { value } = ev.target;
- const { enabledFilters, eventFilters } = this.state;
- if (value.length < enabledFilters.length) {
- if (value.length === 0) {
- this.setState((prevState) => ({
- ...prevState,
- enabledFilters: value,
- eventFilters: defaultFilters,
- selectedFilterCriteria: null
- }));
- } else {
- const removedFilter = enabledFilters.filter(
- (e) => !value.includes(e)
- )[0];
- let defaultValue;
- if (
- removedFilter === "published_filter" ||
- removedFilter === "has_rsvp_filter"
- ) {
- defaultValue = null;
- } else if (Array.isArray(eventFilters[removedFilter])) {
- defaultValue = [];
- } else {
- defaultValue = "";
- }
- const newEventFilters = {
- ...eventFilters,
- [removedFilter]: defaultValue
- };
- this.setState((prevState) => ({
- ...prevState,
- enabledFilters: value,
- eventFilters: newEventFilters,
- selectedFilterCriteria: null
- }));
- }
- } else {
- this.setState((prevState) => ({
- ...prevState,
- enabledFilters: value,
- selectedFilterCriteria: null
- }));
- }
- }
-
- handleChangeDateFilter(ev, lastDate) {
- const { value, id } = ev.target;
- const { eventFilters } = this.state;
- const newDateFilter = eventFilters[id];
-
- this.setState((prevState) => ({
- ...prevState,
- eventFilters: {
- ...eventFilters,
- [id]: lastDate
- ? [newDateFilter[0], value.unix()]
- : [value.unix(), newDateFilter[1]]
- }
- }));
- }
-
- handleFilterCriteriaSave(filterData) {
- const { enabledFilters, eventFilters } = this.state;
- const { currentSummit, saveFilterCriteria } = this.props;
- const filterToSave = {
- id: filterData.id,
- show_id: currentSummit.id,
- name: filterData.name,
- enabled_filters: enabledFilters,
- // only save criteria for enabled filters
- criteria: Object.fromEntries(
- Object.entries(eventFilters).filter(([key]) =>
- enabledFilters.includes(key)
- )
- ),
- context: CONTEXT_ACTIVITIES,
- visibility: filterData.visibility
- };
- saveFilterCriteria(filterToSave);
- }
-
- handleColumnsChange(ev) {
- const { value } = ev.target;
- const { selectedColumns } = this.state;
- let newColumns = value;
- const all_companies = ["submitter_company", "speaker_company", "sponsor"];
-
- const mediaUploadsSelected = newColumns.includes("media_uploads");
-
- // Ensure 'media_uploads_display' is included if 'media_uploads' is selected
- if (mediaUploadsSelected && !newColumns.includes("media_uploads_display")) {
- newColumns = [...newColumns, "media_uploads_display"];
- }
-
- // Remove 'media_uploads_display' if 'media_uploads' is deselected
- if (!mediaUploadsSelected && newColumns.includes("media_uploads_display")) {
- newColumns = newColumns.filter((col) => col !== "media_uploads_display");
- }
-
- if (
- selectedColumns.includes("all_companies") &&
- !newColumns.includes("all_companies")
- ) {
- newColumns = [...newColumns.filter((e) => !all_companies.includes(e))];
- }
- const selectedCompanies = selectedColumns.filter((c) =>
- all_companies.includes(c)
- ).length;
- const newCompanies = newColumns.filter((c) =>
- all_companies.includes(c)
- ).length;
- if (newColumns.includes("all_companies")) {
- if (newColumns.filter((c) => all_companies.includes(c)).length === 0) {
- newColumns = [...selectedColumns, ...all_companies, "all_companies"];
- } else if (selectedCompanies === newCompanies) {
- newColumns = [
- ...new Set([...newColumns, ...all_companies, "all_companies"])
- ];
- } else if (newCompanies < selectedCompanies) {
- newColumns = [...newColumns.filter((c) => c !== "all_companies")];
- }
- }
- this.setState((prevState) => ({
- ...prevState,
- selectedColumns: newColumns
- }));
- }
-
- handleFilterCriteriaChange(filterCriteria) {
- const { extraColumns, term, order, orderDir, getEvents } = this.props;
- const { eventFilters } = this.state;
- let newEventFilters = {};
- if (filterCriteria) {
- Object.entries(filterCriteria.criteria).forEach(([key, values]) => {
- newEventFilters = { ...newEventFilters, [key]: values };
- });
- }
-
- this.setState(
- (prevState) => ({
- ...prevState,
- eventFilters: { ...defaultFilters, ...newEventFilters },
- enabledFilters: filterCriteria ? filterCriteria.enabled_filters : [],
- selectedFilterCriteria: filterCriteria || null
- }),
- () =>
- getEvents(
- term,
- DEFAULT_CURRENT_PAGE,
- DEFAULT_PER_PAGE,
- order,
- orderDir,
- eventFilters,
- extraColumns
- )
- );
- }
-
- handleFilterCriteriaDelete(filterCriteriaId) {
- const {
- extraColumns,
- term,
- order,
- orderDir,
- getEvents,
- deleteFilterCriteria
- } = this.props;
- const { eventFilters } = this.state;
- deleteFilterCriteria(filterCriteriaId).then(() =>
- this.setState(
- (prevState) => ({
- ...prevState,
- eventFilters: { ...defaultFilters, orAndFilter: ALL_FILTER },
- enabledFilters: [],
- selectedFilterCriteria: null
- }),
- () =>
- getEvents(
- term,
- DEFAULT_CURRENT_PAGE,
- DEFAULT_PER_PAGE,
- order,
- orderDir,
- eventFilters,
- extraColumns
- )
- )
- );
- }
-
- translateSortKey = (key) => {
- switch (key) {
- case "last_name":
- return "name";
- case "created_by_company":
- return "submitter_company";
- case "actions":
- return "progress_flags";
- default:
- break;
- }
-
- return key;
- };
-
- render() {
- const {
- currentSummit,
- events,
- lastPage,
- currentPage,
- order,
- orderDir,
- totalEvents,
- term,
- bulkUpdateEvents
- } = this.props;
- const {
- enabledFilters,
- eventFilters,
- selectedFilterCriteria,
- selectedColumns,
- showImportModal,
- send_speaker_email,
- importFile,
- showImportFromMUXModal,
- errors,
- muxModalState: { mux_token_id, mux_token_secret, mux_email_to }
- } = this.state;
-
- let columns = [
- { columnKey: "id", value: T.translate("general.id"), sortable: true },
- {
- columnKey: "type",
- value: T.translate("event_list.type"),
- sortable: true,
- // eslint-disable-next-line react/no-unstable-nested-components
- editableField: (extraProps) => (
- ({ ...base, zIndex: 9999 }),
- control: (base, state) => ({
- ...base,
- zIndex: state.menuIsOpen ? HIGH_Z_INDEX : DEFAULT_Z_INDEX
- })
- }}
- // eslint-disable-next-line react/jsx-props-no-spreading
- {...extraProps}
- />
- ),
- render: (e) => e.name
- },
- {
- columnKey: "title",
- value: T.translate("event_list.title"),
- sortable: true,
- editableField: true
- },
- {
- columnKey: "selection_status",
- value: T.translate("event_list.selection_status"),
- sortable: true
- }
- ];
-
- const table_options = {
- sortCol: this.translateSortKey(order),
- sortDir: orderDir,
- className: "summit-event-list-table",
- actions: {
- edit: { onClick: this.handleEdit },
- delete: { onClick: this.handleDeleteEvent }
- }
- };
-
- const selection_plans_ddl = buildNameIdDDL(currentSummit.selection_plans);
-
- const location_ddl = buildNameIdDDL(currentSummit.locations);
-
- const selection_status_ddl = [
- { label: "Pending", value: "pending" },
- { label: "Accepted", value: "accepted" },
- { label: "Rejected", value: "rejected" },
- { label: "Alternate", value: "alternate" }
- ];
-
- const track_ddl = buildNameIdDDL(currentSummit.tracks);
-
- const event_type_ddl = buildNameIdDDL(currentSummit.event_types);
-
- const level_ddl = [
- { label: "Beginner", value: "beginner" },
- { label: "Intermediate", value: "intermediate" },
- { label: "Advanced", value: "advanced" },
- { label: "N/A", value: "na" }
- ];
-
- const streaming_type_ddl = [
- { label: "LIVE", value: "LIVE" },
- { label: "VOD", value: "VOD" }
- ];
-
- const submission_source_ddl = [
- { label: "Admin", value: "Admin" },
- { label: "Submission", value: "Submission" }
- ];
-
- const filters_ddl = [
- { label: "Activity Type Capacity", value: "event_type_capacity_filter" },
- { label: "Selection Plan", value: "selection_plan_id_filter" },
- { label: "Activity Type", value: "event_type_id_filter" },
- { label: "Activity Category", value: "track_id_filter" },
- { label: "Level", value: "level_filter" },
- { label: "Etherpad URL", value: "etherpad_link" },
- { label: "Location", value: "location_id_filter" },
- { label: "Meeting URL", value: "meeting_url" },
- { label: "Progress Flag", value: "progress_flag" },
- { label: "Published Status", value: "published_filter" },
- { label: "Speakers", value: "speaker_id_filter" },
- { label: "Speakers Companies", value: "speaker_company" },
- { label: "Tags", value: "tags_filter" },
- { label: "Start Date", value: "start_date_filter" },
- { label: "End Date", value: "end_date_filter" },
- { label: "Duration", value: "duration_filter" },
- { label: "Speakers Count", value: "speakers_count_filter" },
- { label: "Submitter", value: "submitters" },
- { label: "Submitter Company", value: "submitter_company" },
- { label: "Selection Status", value: "selection_status_filter" },
- { label: "Stream URL", value: "streaming_url" },
- { label: "Streaming Type", value: "streaming_type" },
- { label: "Sponsors", value: "sponsor" },
- { label: "All Companies", value: "all_companies" },
- {
- label: T.translate("event_list.submission_status"),
- value: "submission_status_filter"
- },
- {
- label: T.translate("event_list.media_upload_with_type"),
- value: "media_upload_with_type"
- },
- { label: "Review Status", value: "review_status_filter" },
- { label: "Created", value: "created_filter" },
- { label: "Modified", value: "modified_filter" },
- { label: "Submission Source", value: "submission_source_filter" },
- { label: "Has RSVP?", value: "has_rsvp_filter" }
- ];
-
- const ddl_columns = [
- {
- value: "event_type_capacity",
- label: T.translate("event_list.event_type_capacity")
- },
- { value: "speakers", label: T.translate("event_list.speakers") },
- {
- value: "all_companies",
- label: T.translate("event_list.all_companies")
- },
- {
- value: "created_by_fullname",
- label: T.translate("event_list.created_by")
- },
- { value: "duration", label: T.translate("event_list.duration") },
- { value: "end_date", label: T.translate("event_list.end_date") },
- { value: "published_date", label: T.translate("event_list.published") },
- {
- value: "speaker_company",
- label: T.translate("event_list.speaker_company")
- },
- {
- value: "speakers_count",
- label: T.translate("event_list.speakers_count")
- },
- { value: "sponsor", label: T.translate("event_list.sponsor") },
- {
- value: "selection_plan",
- label: T.translate("event_list.selection_plan")
- },
- { value: "location", label: T.translate("event_list.location") },
- { value: "level", label: T.translate("event_list.level") },
- { value: "tags", label: T.translate("event_list.tags") },
- {
- value: "streaming_url",
- label: T.translate("event_list.streaming_url")
- },
- { value: "meeting_url", label: T.translate("event_list.meeting_url") },
- {
- value: "etherpad_link",
- label: T.translate("event_list.etherpad_link")
- },
- {
- value: "streaming_type",
- label: T.translate("event_list.streaming_type")
- },
- { value: "start_date", label: T.translate("event_list.start_date") },
- {
- value: "submitter_company",
- label: T.translate("event_list.submitter_company")
- },
- { value: "track", label: T.translate("event_list.track") },
- { value: "status", label: T.translate("event_list.submission_status") },
- {
- value: "submission_source",
- label: T.translate("event_list.submission_source")
- },
- {
- value: "progress_flags",
- label: T.translate("event_list.progress_flags")
- },
- {
- value: "media_uploads",
- label: T.translate("event_list.media_uploads")
- },
- {
- value: "review_status",
- label: T.translate("event_list.review_status")
- },
- { value: "created", label: T.translate("event_list.created") },
- { value: "modified", label: T.translate("event_list.modified") },
- {
- value: "allow_feedback",
- label: T.translate("event_list.allow_feedback")
- },
- {
- value: "to_record",
- label: T.translate("event_list.to_record")
- }
- ];
-
- const ddl_filterByEventTypeCapacity = [
- {
- value: "allows_attendee_vote_filter",
- label: T.translate("event_list.allows_attendee_vote_filter")
- },
- {
- value: "allows_location_filter",
- label: T.translate("event_list.allows_location_filter")
- },
- {
- value: "allows_publishing_dates_filter",
- label: T.translate("event_list.allows_publishing_dates_filter")
- }
- ];
-
- const submission_status_ddl = [
- {
- label: T.translate("event_list.submission_status_accepted"),
- value: "Accepted"
- },
- {
- label: T.translate("event_list.submission_status_received"),
- value: "Received"
- },
- {
- label: T.translate("event_list.submission_status_not_submitted"),
- value: "NonReceived"
- }
- ];
-
- const review_status_ddl = [
- {
- label: T.translate("event_list.review_status_accepted"),
- value: "Accepted"
- },
- {
- label: T.translate("event_list.review_status_in_review"),
- value: "InReview"
- },
- {
- label: T.translate("event_list.review_status_no_submitted"),
- value: "NotSubmitted"
- },
- {
- label: T.translate("event_list.review_status_published"),
- value: "Published"
- },
- {
- label: T.translate("event_list.review_status_received"),
- value: "Received"
- },
- {
- label: T.translate("event_list.review_status_rejected"),
- value: "Rejected"
- }
- ];
-
- const progress_flag_ddl = currentSummit.presentation_action_types.map(
- (pf) => ({ value: pf.id, label: pf.label })
- );
-
- const showColumns = fieldNames(
- currentSummit.selection_plans,
- currentSummit.tracks,
- currentSummit.event_types,
- currentSummit.id
- )
- .filter(
- (f) =>
- selectedColumns.includes(f.columnKey) &&
- !defaultColumns.includes(f.columnKey)
- )
- .map((f2) => {
- let c = {
- columnKey: f2.columnKey,
- value: T.translate(`event_list.${f2.value}`),
- sortable: f2.sortable,
- editable: !!editableColumns.includes(f2.editable),
- customStyle: f2.customStyle
- };
- // optional fields
- if (f2.hasOwnProperty("title")) c = { ...c, title: f2.title };
-
- if (f2.hasOwnProperty("render")) c = { ...c, render: f2.render };
-
- if (f2.hasOwnProperty("editableField"))
- c = { ...c, editableField: f2.editableField };
-
- return c;
- });
-
- columns = [...columns, ...showColumns];
-
- if (!currentSummit.id) return
;
-
- return (
-
-
- {" "}
- {T.translate("event_list.event_list")} ({totalEvents})
-
-
-
-
-
-
-
- {T.translate("event_list.add_event")}
-
-
- {T.translate("general.export")}
-
-
- {T.translate("event_list.mux_import")}
-
- this.setState({ showImportModal: true })}
- type="button"
- >
- {T.translate("event_list.import")}
-
-
-
-
-
-
- this.handleOrAndFilter(filter)}
- />
-
-
-
-
-
-
-
-
-
-
-
- {T.translate("event_list.apply_filters")}
-
-
-
-
-
- {enabledFilters.includes("event_type_capacity_filter") && (
-
-
-
- )}
- {enabledFilters.includes("selection_plan_id_filter") && (
-
-
-
- )}
- {enabledFilters.includes("location_id_filter") && (
-
-
-
- )}
- {enabledFilters.includes("selection_status_filter") && (
-
-
-
- )}
- {enabledFilters.includes("published_filter") && (
-
- this.handleSetPublishedFilter(newValue)}
- style={{
- width: "100%",
- height: 40,
- color: "#337ab7",
- fontSize: "10px"
- }}
- />
-
- )}
- {enabledFilters.includes("progress_flag") && (
-
-
-
- )}
- {enabledFilters.includes("track_id_filter") && (
-
-
-
- )}
- {enabledFilters.includes("event_type_id_filter") && (
-
-
-
- )}
- {enabledFilters.includes("speaker_id_filter") && (
-
-
-
- )}
- {enabledFilters.includes("speaker_company") && (
-
-
-
- )}
- {enabledFilters.includes("level_filter") && (
-
-
-
- )}
- {enabledFilters.includes("tags_filter") && (
-
-
-
- )}
- {enabledFilters.includes("sponsor") && (
-
-
-
- )}
- {enabledFilters.includes("all_companies") && (
-
- ({ ...base, zIndex: 9999 }),
- control: (base, state) => ({
- ...base,
- zIndex: state.menuIsOpen ? HIGH_Z_INDEX : DEFAULT_Z_INDEX
- })
- }}
- />
-
- )}
- {enabledFilters.includes("start_date_filter") && (
- <>
-
- this.handleChangeDateFilter(ev, false)}
- value={epochToMomentTimeZone(
- eventFilters.start_date_filter[0],
- currentSummit.time_zone_id
- )}
- className="event-list-date-picker"
- />
-
-
- this.handleChangeDateFilter(ev, true)}
- value={epochToMomentTimeZone(
- eventFilters.start_date_filter[1],
- currentSummit.time_zone_id
- )}
- className="event-list-date-picker"
- />
-
- >
- )}
- {enabledFilters.includes("end_date_filter") && (
- <>
-
- this.handleChangeDateFilter(ev, false)}
- value={epochToMomentTimeZone(
- eventFilters.end_date_filter[0],
- currentSummit.time_zone_id
- )}
- className="event-list-date-picker"
- />
-
-
- this.handleChangeDateFilter(ev, true)}
- value={epochToMomentTimeZone(
- eventFilters.end_date_filter[1],
- currentSummit.time_zone_id
- )}
- className="event-list-date-picker"
- />
-
- >
- )}
- {enabledFilters.includes("created_filter") && (
- <>
-
- this.handleChangeDateFilter(ev, false)}
- value={epochToMomentTimeZone(
- eventFilters.created_filter[0],
- currentSummit.time_zone_id
- )}
- className="event-list-date-picker"
- />
-
-
- this.handleChangeDateFilter(ev, true)}
- value={epochToMomentTimeZone(
- eventFilters.created_filter[1],
- currentSummit.time_zone_id
- )}
- className="event-list-date-picker"
- />
-
- >
- )}
- {enabledFilters.includes("modified_filter") && (
- <>
-
- this.handleChangeDateFilter(ev, false)}
- value={epochToMomentTimeZone(
- eventFilters.modified_filter[0],
- currentSummit.time_zone_id
- )}
- className="event-list-date-picker"
- />
-
-
- this.handleChangeDateFilter(ev, true)}
- value={epochToMomentTimeZone(
- eventFilters.modified_filter[1],
- currentSummit.time_zone_id
- )}
- className="event-list-date-picker"
- />
-
- >
- )}
- {enabledFilters.includes("submitters") && (
-
-
- member.hasOwnProperty("email")
- ? `${member.first_name} ${member.last_name} (${member.email})`
- : `${member.first_name} ${member.last_name} (${member.id})`
- }
- />
-
- )}
- {enabledFilters.includes("submitter_company") && (
-
-
-
- )}
- {enabledFilters.includes("streaming_url") && (
-
-
-
- )}
- {enabledFilters.includes("meeting_url") && (
-
-
-
- )}
- {enabledFilters.includes("etherpad_link") && (
-
-
-
- )}
- {enabledFilters.includes("streaming_type") && (
-
-
-
- )}
- {enabledFilters.includes("submission_source_filter") && (
-
-
-
- )}
- {enabledFilters.includes("has_rsvp_filter") && (
-
- this.handleSetRSVPFilter(newValue)}
- style={{
- width: "100%",
- height: 40,
- color: "#337ab7",
- fontSize: "10px"
- }}
- />
-
- )}
- {enabledFilters.includes("duration_filter") && (
-
-
-
- )}
- {enabledFilters.includes("speakers_count_filter") && (
-
-
-
- )}
- {enabledFilters.includes("submission_status_filter") && (
-
-
-
- )}
- {enabledFilters.includes("review_status_filter") && (
-
-
-
- )}
- {enabledFilters.includes("media_upload_with_type") && (
-
-
-
- )}
-
-
-
-
-
-
-
- {T.translate("event_list.select_fields")}
-
-
-
-
-
- {events.length === 0 && (
-
{T.translate("event_list.no_events")}
- )}
-
- {events.length > 0 && (
-
- )}
-
-
this.setState({ showImportModal: false })}
- >
-
- {T.translate("event_list.import_events")}
-
-
-
-
- Format must be the following:
-
- (Minimal data required)
-
- * title ( text )
- * description (text )
- * type_id (int) or type (string type name)
-
- * track_id (int) or track ( string track name)
-
- * speaker_emails ( list of email | delimited) [optional]
-
- * speaker_fullnames ( list of full names | delimited) [optional]
-
- * speaker_companies ( list of companies | delimited) [optional]
-
- * speaker_titles ( list of titles | delimited) [optional]
-
-
-
-
- this.setState({ importFile: file })}
- handleRemove={() => this.setState({ importFile: null })}
- className="dropzone col-md-6"
- multiple={false}
- accept=".csv"
- />
-
-
-
-
-
- {T.translate("event_list.send_speaker_email")}
-
-
-
-
-
-
-
- {T.translate("event_list.ingest")}
-
-
-
-
-
this.setState({ showImportFromMUXModal: false })}
- >
-
- {T.translate("event_list.mux_import")}
-
-
-
-
-
-
- {T.translate("event_list.import")}
-
-
-
-
- );
- }
-}
-
-const mapStateToProps = ({ currentSummitState, currentEventListState }) => ({
- currentSummit: currentSummitState.currentSummit,
- ...currentEventListState
-});
-
-export default connect(mapStateToProps, {
- getEvents,
- deleteEvent,
- exportEvents,
- importEventsCSV,
- importMP4AssetsFromMUX,
- changeEventListSearchTerm,
- saveFilterCriteria,
- deleteFilterCriteria,
- bulkUpdateEvents
-})(SummitEventListPage);
diff --git a/src/pages/events/summit-event-list-page/components/ImportMUXModal/index.jsx b/src/pages/events/summit-event-list-page/components/ImportMUXModal/index.jsx
new file mode 100644
index 000000000..6ab2af527
--- /dev/null
+++ b/src/pages/events/summit-event-list-page/components/ImportMUXModal/index.jsx
@@ -0,0 +1,102 @@
+import React, { useState } from "react";
+import { Modal } from "react-bootstrap";
+import T from "i18n-react";
+import { Input } from "@mui/material";
+
+const ImportMUXModal = ({ show, onClose, onImport }) => {
+ const [tokenId, setTokenId] = useState("");
+ const [tokenSecret, setTokenSecret] = useState("");
+ const [emailTo, setEmailTo] = useState("");
+
+ const handleClose = () => {
+ setTokenId("");
+ setTokenSecret("");
+ setEmailTo("");
+ onClose();
+ };
+
+ const handleImport = (ev) => {
+ ev.preventDefault();
+ onImport(tokenId, tokenSecret, emailTo).then(() => {
+ handleClose();
+ });
+ };
+
+ return (
+
+
+ {T.translate("event_list.mux_import")}
+
+
+
+
+
+
+ {T.translate("event_list.import")}
+
+
+
+ );
+};
+
+export default ImportMUXModal;
diff --git a/src/pages/events/summit-event-list-page/components/ImportModal/index.jsx b/src/pages/events/summit-event-list-page/components/ImportModal/index.jsx
new file mode 100644
index 000000000..1b4a6e962
--- /dev/null
+++ b/src/pages/events/summit-event-list-page/components/ImportModal/index.jsx
@@ -0,0 +1,92 @@
+import React, { useState } from "react";
+import { Modal } from "react-bootstrap";
+import T from "i18n-react";
+import UploadInput from "openstack-uicore-foundation/lib/components/inputs/upload-input";
+
+const ImportModal = ({ show, onClose, onImport }) => {
+ const [importFile, setImportFile] = useState(null);
+ const [sendSpeakerEmail, setSendSpeakerEmail] = useState(false);
+
+ const handleClose = () => {
+ setImportFile(null);
+ setSendSpeakerEmail(false);
+ onClose();
+ };
+
+ const handleImportEvents = () => {
+ if (importFile) {
+ onImport(importFile, sendSpeakerEmail);
+ }
+
+ handleClose();
+ };
+
+ return (
+
+
+ {T.translate("event_list.import_events")}
+
+
+
+
+ Format must be the following:
+
+ (Minimal data required)
+
+ * title ( text )
+ * description (text )
+ * type_id (int) or type (string type name)
+
+ * track_id (int) or track ( string track name)
+
+ * speaker_emails ( list of email | delimited) [optional]
+
+ * speaker_fullnames ( list of full names | delimited) [optional]
+
+ * speaker_companies ( list of companies | delimited) [optional]
+
+ * speaker_titles ( list of titles | delimited) [optional]
+
+
+
+
+ setImportFile(file)}
+ handleRemove={() => setImportFile(null)}
+ className="dropzone col-md-6"
+ multiple={false}
+ accept=".csv"
+ />
+
+
+
+ setSendSpeakerEmail(ev.target.checked)}
+ className="form-check-input"
+ />
+
+ {T.translate("event_list.send_speaker_email")}
+
+
+
+
+
+
+
+ {T.translate("event_list.ingest")}
+
+
+
+ );
+};
+
+export default ImportModal;
diff --git a/src/pages/events/summit-event-list-page/index.js b/src/pages/events/summit-event-list-page/index.js
new file mode 100644
index 000000000..73c9a21ab
--- /dev/null
+++ b/src/pages/events/summit-event-list-page/index.js
@@ -0,0 +1,1472 @@
+/**
+ * Copyright 2026 OpenStack Foundation
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * */
+
+import React, { useEffect, useState } from "react";
+import { connect } from "react-redux";
+import T from "i18n-react/dist/i18n-react";
+import Swal from "sweetalert2";
+import { Pagination } from "react-bootstrap";
+import Dropdown from "openstack-uicore-foundation/lib/components/inputs/dropdown";
+import FreeTextSearch from "openstack-uicore-foundation/lib/components/free-text-search";
+import SpeakerInput from "openstack-uicore-foundation/lib/components/inputs/speaker-input";
+import { escapeFilterValue } from "openstack-uicore-foundation/lib/utils/actions";
+import {
+ GridFilter,
+ OPERATORS,
+ useGridFilter
+} from "openstack-uicore-foundation/lib/components/mui/grid-filter";
+import {
+ queryMembers,
+ queryTags
+} from "openstack-uicore-foundation/lib/utils/query-actions";
+import {
+ bulkUpdateEvents,
+ changeEventListSearchTerm,
+ deleteEvent,
+ exportEvents,
+ getEvents,
+ importEventsCSV,
+ importMP4AssetsFromMUX,
+ queryAllCompanies,
+ querySpeakerCompany,
+ querySubmitterCompany
+} from "../../../actions/event-actions";
+import { getMediaUploads } from "../../../actions/media-upload-actions";
+import { handleDDLSortByLabel } from "../../../utils/methods";
+import {
+ DEFAULT_CURRENT_PAGE,
+ DEFAULT_Z_INDEX,
+ HIGH_Z_INDEX,
+ MAX_PER_PAGE
+} from "../../../utils/constants";
+import {
+ defaultColumns,
+ editableColumns,
+ formatEventData
+} from "../../../utils/summitUtils";
+import SaveFilterCriteria from "../../../components/filters/save-filter-criteria";
+import SelectFilterCriteria from "../../../components/filters/select-filter-criteria";
+import {
+ deleteFilterCriteria,
+ saveFilterCriteria
+} from "../../../actions/filter-criteria-actions";
+import { CONTEXT_ACTIVITIES } from "../../../utils/filter-criteria-constants";
+import EditableTable from "../../../components/tables/editable-table/EditableTable";
+import { buildNameIdDDL } from "../../../utils/events/summit-event-list-page.utils";
+import ImportModal from "./components/ImportModal";
+import ImportMUXModal from "./components/ImportMUXModal";
+
+const FILTER_ID = "summit_activity_list";
+
+const fieldNames = (
+ allSelectionPlans,
+ allTracks,
+ eventTypes,
+ currentSummitId
+) => [
+ {
+ columnKey: "speakers",
+ value: "speakers",
+ customStyle: { minWidth: "350px" },
+ editableField: (extraProps) => {
+ const useSpeakers = extraProps.row.type?.use_speakers;
+ return (
+ useSpeakers && (
+ ({ ...base, zIndex: 9999 }),
+ control: (base, state) => ({
+ ...base,
+ zIndex: state.menuIsOpen ? HIGH_Z_INDEX : DEFAULT_Z_INDEX
+ })
+ }}
+ getOptionLabel={(speaker) =>
+ `${speaker.first_name} ${speaker.last_name} (${speaker.email})`
+ }
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...extraProps}
+ />
+ )
+ );
+ }
+ },
+ { columnKey: "created_by_fullname", value: "created_by", sortable: true },
+ { columnKey: "published_date", value: "published", sortable: true },
+ { columnKey: "duration", value: "duration", sortable: true },
+ { columnKey: "speakers_count", value: "speakers_count", sortable: true },
+ { columnKey: "speaker_company", value: "speaker_company", sortable: true },
+ {
+ columnKey: "track",
+ value: "track",
+ sortable: true,
+ editableField: (extraProps) => {
+ const trackOptions = buildNameIdDDL(allTracks);
+
+ return (
+ ({ ...base, zIndex: 9999 }),
+ control: (base, state) => ({
+ ...base,
+ zIndex: state.menuIsOpen ? HIGH_Z_INDEX : DEFAULT_Z_INDEX
+ })
+ }}
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...extraProps}
+ />
+ );
+ }
+ },
+ { columnKey: "start_date", value: "start_date", sortable: true },
+ { columnKey: "end_date", value: "end_date", sortable: true },
+ { columnKey: "submitters", value: "submitters" },
+ {
+ columnKey: "submitter_company",
+ value: "submitter_company",
+ sortable: true
+ },
+ { columnKey: "sponsor", value: "sponsor", sortable: true },
+ { columnKey: "event_type_capacity", value: "event_type_capacity" },
+ {
+ columnKey: "selection_plan",
+ value: "selection_plan",
+ sortable: true,
+ editableField: (extraProps) => {
+ if (!extraProps.row?.type?.id) return false;
+ const eventType = Array.isArray(eventTypes)
+ ? eventTypes.find(
+ (t) => t?.id !== undefined && t.id === extraProps.row.type?.id
+ )
+ : null;
+ if (!eventType) return false;
+
+ const allowSelectionPlanEdit =
+ ["PresentationType"].includes(eventType.class_name) ||
+ ["PresentationType"].includes(eventType.name);
+ if (!allowSelectionPlanEdit) return false;
+
+ const trackId = extraProps.row?.track?.id;
+ const track =
+ trackId !== undefined && trackId !== null
+ ? allTracks.find((t) => t?.id !== undefined && t.id === trackId)
+ : null;
+
+ const selectionPlansPerTrack = buildNameIdDDL(
+ (Array.isArray(allSelectionPlans) ? allSelectionPlans : []).filter(
+ (sp) =>
+ !track ||
+ (Array.isArray(sp.track_groups) &&
+ Array.isArray(track.track_groups) &&
+ sp.track_groups.some((gr) => track.track_groups.includes(gr)))
+ )
+ );
+
+ return (
+ ({ ...base, zIndex: 9999 }),
+ control: (base, state) => ({
+ ...base,
+ width: 220,
+ zIndex: state.menuIsOpen ? HIGH_Z_INDEX : DEFAULT_Z_INDEX
+ })
+ }}
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...extraProps}
+ />
+ );
+ },
+ render: (e) => (e?.name ? e.name : "N/A")
+ },
+ { columnKey: "location", value: "location", sortable: true },
+ { columnKey: "level", value: "level", sortable: true },
+ { columnKey: "tags", value: "tags", sortable: true },
+ {
+ columnKey: "streaming_url",
+ value: "streaming_url",
+ sortable: true,
+ title: true,
+ editableField: true
+ },
+ {
+ columnKey: "meeting_url",
+ value: "meeting_url",
+ sortable: true,
+ title: true,
+ editableField: true
+ },
+ {
+ columnKey: "etherpad_link",
+ value: "etherpad_link",
+ sortable: true,
+ title: true,
+ editableField: true
+ },
+ { columnKey: "streaming_type", value: "streaming_type", sortable: true },
+ {
+ columnKey: "review_status",
+ value: "review_status",
+ sortable: true,
+ title: true
+ },
+ {
+ columnKey: "status",
+ value: "submission_status",
+ sortable: true,
+ title: true
+ },
+ {
+ columnKey: "progress_flags",
+ value: "progress_flags",
+ sortable: true,
+ title: true
+ },
+ { columnKey: "created", value: "created", sortable: true },
+ { columnKey: "modified", value: "modified", sortable: true },
+ {
+ columnKey: "submission_source",
+ value: "submission_source",
+ sortable: true
+ },
+ {
+ columnKey: "media_uploads",
+ value: "media_uploads",
+ sortable: false,
+ render: (e, row) => {
+ if (!e?.length) return "N/A";
+ return (
+ <>
+ {e.map((m) => (
+
+ {
+ ev.preventDefault();
+ if (!row?.id || !currentSummitId) return false;
+ window.open(
+ `/app/summits/${currentSummitId}/events/${row.id}/materials/${m.id}`,
+ "_blank"
+ );
+ return false;
+ }}
+ >
+ {m.media_upload_type.name} - {m.created}
+
+
+
+ ))}
+ >
+ );
+ }
+ },
+ {
+ columnKey: "media_uploads_display",
+ value: "media_uploads_display",
+ sortable: false,
+ render: (e, row) => {
+ const mediaUploads = row?.media_uploads || [];
+ if (!mediaUploads.length) return "N/A";
+ return (
+ <>
+ {mediaUploads.map((m) => (
+
+ {`"${m.media_upload_type.name}" : `}
+ {`${m.display_on_site ? "Yes" : "No"}`}
+
+
+ ))}
+ >
+ );
+ }
+ },
+ {
+ columnKey: "allow_feedback",
+ value: "allow_feedback",
+ sortable: false,
+ render: (field) =>
+ field === undefined ? "N/A" : field === true ? "Yes" : "No",
+ editableField: (extraProps) => (
+ ({ ...base, zIndex: 9999 }),
+ control: (base, state) => ({
+ ...base,
+ zIndex: state.menuIsOpen ? HIGH_Z_INDEX : DEFAULT_Z_INDEX
+ })
+ }}
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...extraProps}
+ />
+ )
+ },
+ {
+ columnKey: "to_record",
+ value: "to_record",
+ sortable: false,
+ render: (field) =>
+ field === undefined ? "N/A" : field === true ? "Yes" : "No",
+ editableField: (extraProps) => (
+ ({ ...base, zIndex: 9999 }),
+ control: (base, state) => ({
+ ...base,
+ zIndex: state.menuIsOpen ? HIGH_Z_INDEX : DEFAULT_Z_INDEX
+ })
+ }}
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...extraProps}
+ />
+ )
+ }
+];
+
+const eventTypeCapacityOptions = [
+ {
+ value: "allows_attendee_vote_filter",
+ label: T.translate("event_list.allows_attendee_vote_filter")
+ },
+ {
+ value: "allows_location_filter",
+ label: T.translate("event_list.allows_location_filter")
+ },
+ {
+ value: "allows_publishing_dates_filter",
+ label: T.translate("event_list.allows_publishing_dates_filter")
+ }
+];
+
+const levelOptions = [
+ { label: "Beginner", value: "beginner" },
+ { label: "Intermediate", value: "intermediate" },
+ { label: "Advanced", value: "advanced" },
+ { label: "N/A", value: "na" }
+];
+
+const selectionStatusOptions = [
+ { label: "Pending", value: "pending" },
+ { label: "Accepted", value: "accepted" },
+ { label: "Rejected", value: "rejected" },
+ { label: "Alternate", value: "alternate" }
+];
+
+const publishedStatusOptions = [
+ {
+ label: "Published",
+ value: "1"
+ },
+ {
+ label: "Non Published",
+ value: "0"
+ }
+];
+
+const rsvpOptions = [
+ {
+ label: "Has RSVP",
+ value: true
+ },
+ {
+ label: "No RSVP",
+ value: false
+ }
+];
+
+const streamingTypeOptions = [
+ { label: "LIVE", value: "LIVE" },
+ { label: "VOD", value: "VOD" }
+];
+
+const submissionStatusOptions = [
+ {
+ label: T.translate("event_list.submission_status_accepted"),
+ value: "Accepted"
+ },
+ {
+ label: T.translate("event_list.submission_status_received"),
+ value: "Received"
+ },
+ {
+ label: T.translate("event_list.submission_status_not_submitted"),
+ value: "NonReceived"
+ }
+];
+
+const reviewStatusOptions = [
+ {
+ label: T.translate("event_list.review_status_accepted"),
+ value: "Accepted"
+ },
+ {
+ label: T.translate("event_list.review_status_in_review"),
+ value: "InReview"
+ },
+ {
+ label: T.translate("event_list.review_status_no_submitted"),
+ value: "NotSubmitted"
+ },
+ {
+ label: T.translate("event_list.review_status_published"),
+ value: "Published"
+ },
+ {
+ label: T.translate("event_list.review_status_received"),
+ value: "Received"
+ },
+ {
+ label: T.translate("event_list.review_status_rejected"),
+ value: "Rejected"
+ }
+];
+
+const submissionSourceOptions = [
+ { label: "Admin", value: "Admin" },
+ { label: "Submission", value: "Submission" }
+];
+
+// queryTags' response shape differs depending on whether it's summit-scoped
+// (nested `tag.tag`) or global (flat `tag`); handle both defensively.
+const tagFormatOption = (item) => ({
+ value: item.id,
+ label:
+ typeof item.tag === "string" ? item.tag : item.tag?.tag || String(item.id)
+});
+
+const getCriterias = (summit, mediaUploadTypes) => [
+ {
+ key: "event_type_capacity",
+ label: "Activity Type Capacity",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: eventTypeCapacityOptions,
+ multiple: true
+ }
+ },
+ customParser: (f) => {
+ const filter = [];
+
+ if (f.value.includes("allows_attendee_vote_filter")) {
+ filter.push("type_allows_attendee_vote==1");
+ }
+ if (f.value.includes("allows_location_filter")) {
+ filter.push("type_allows_location==1");
+ }
+ if (f.value.includes("allows_publishing_dates_filter")) {
+ filter.push("type_allows_publishing_dates==1");
+ }
+
+ return filter;
+ }
+ },
+ {
+ key: "selection_plan_id",
+ label: "Selection Plan",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: summit.selection_plans.map((sp) => ({
+ label: sp.name,
+ value: sp.id
+ })),
+ multiple: true
+ }
+ }
+ },
+ {
+ key: "location_id",
+ label: "Location",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: summit.locations.map((sp) => ({
+ label: sp.name,
+ value: sp.id
+ })),
+ multiple: true
+ }
+ }
+ },
+ {
+ key: "selection_status",
+ label: "Selection Status",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: selectionStatusOptions,
+ multiple: true
+ }
+ }
+ },
+ {
+ key: "track_id",
+ label: "Activity Category",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: summit.tracks.map((t) => ({ label: t.name, value: t.id })),
+ multiple: true
+ }
+ }
+ },
+ {
+ key: "event_type_id",
+ label: "Activity Type",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: summit.event_types.map((type) => ({
+ label: type.name,
+ value: type.id
+ })),
+ multiple: true
+ }
+ }
+ },
+ {
+ key: "speaker_id",
+ label: "Speakers",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "speaker",
+ props: {
+ summitId: summit.id,
+ multiple: true
+ }
+ },
+ customParser: (f) => [
+ `speaker_id==${f.value.map((s) => s.value).join("||")}`
+ ]
+ },
+ {
+ key: "speaker_company",
+ label: "Speaker Company",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "company",
+ props: {
+ queryFunction: querySpeakerCompany,
+ multiple: true
+ }
+ },
+ customParser: (f) => [
+ `speaker_company==${f.value
+ .map((c) => escapeFilterValue(c.raw.name))
+ .join("||")}`
+ ]
+ },
+ {
+ key: "level",
+ label: "Activity Level",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: levelOptions,
+ multiple: true
+ }
+ }
+ },
+ {
+ key: "tags",
+ label: "Tags",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "asyncSelect",
+ props: {
+ queryFunction: (input, callback) =>
+ queryTags(summit.id, input, callback),
+ formatOption: tagFormatOption,
+ multiple: true
+ }
+ },
+ customParser: (f) => [
+ `tags==${f.value.map((t) => escapeFilterValue(t.label)).join("||")}`
+ ]
+ },
+ {
+ key: "published",
+ label: "Published",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: publishedStatusOptions
+ }
+ }
+ },
+ {
+ key: "rsvp_type",
+ label: "Has RSVP?",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: rsvpOptions
+ }
+ },
+ customParser: (f) => [`rsvp_type${f.value ? "<>" : "=="}None`]
+ },
+ {
+ key: "progress_flag",
+ label: "Progress Flag",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: summit.presentation_action_types.map((pf) => ({
+ value: pf.id,
+ label: pf.label
+ })),
+ multiple: true
+ }
+ },
+ customParser: (f) => [
+ f.value.map((pf) => `actions==type_id==${pf}&&is_completed==1`).join(",")
+ ]
+ },
+ {
+ key: "created",
+ label: "Created",
+ operators: [OPERATORS.BEFORE, OPERATORS.AFTER],
+ values: {
+ type: "datetime",
+ props: {
+ mode: "datetime"
+ }
+ }
+ },
+ {
+ key: "last_edited",
+ label: "Modified",
+ operators: [OPERATORS.BEFORE, OPERATORS.AFTER],
+ values: {
+ type: "datetime",
+ props: {
+ mode: "datetime"
+ }
+ }
+ },
+ {
+ key: "start_date",
+ label: "Start Date",
+ operators: [OPERATORS.BEFORE, OPERATORS.AFTER],
+ values: {
+ type: "datetime",
+ props: {
+ mode: "datetime"
+ }
+ }
+ },
+ {
+ key: "end_date",
+ label: "End Date",
+ operators: [OPERATORS.BEFORE, OPERATORS.AFTER],
+ values: {
+ type: "datetime",
+ props: {
+ mode: "datetime"
+ }
+ }
+ },
+ {
+ key: "duration",
+ label: "Duration",
+ operators: [OPERATORS.IS, OPERATORS.LESS, OPERATORS.GREATER],
+ values: {
+ type: "number",
+ props: {
+ min: 0,
+ integer: true
+ }
+ }
+ },
+ {
+ key: "speakers_count",
+ label: "Speaker Count",
+ operators: [OPERATORS.IS, OPERATORS.LESS, OPERATORS.GREATER],
+ values: {
+ type: "number",
+ props: {
+ min: 0,
+ integer: true
+ }
+ }
+ },
+ {
+ key: "submitters",
+ label: "Submitters",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "asyncSelect",
+ props: {
+ queryFunction: queryMembers,
+ formatOption: (m) => ({
+ value: m.id,
+ label: `${m.first_name} ${m.last_name} (${m.email})`
+ }),
+ multiple: true
+ }
+ },
+ customParser: (f) => [
+ f.value
+ .flatMap((s) => {
+ const escapedFullName = escapeFilterValue(
+ `${s.raw.first_name} ${s.raw.last_name}`
+ );
+ const escapedEmail = escapeFilterValue(s.raw.email);
+ const fullNameFilter = `created_by_fullname==${escapedFullName}`;
+ const emailFilter = `created_by_email==${escapedEmail}`;
+ return [fullNameFilter, emailFilter];
+ })
+ .join(",")
+ ]
+ },
+ {
+ key: "created_by_company",
+ label: "Submitter Company",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "company",
+ props: {
+ queryFunction: querySubmitterCompany,
+ multiple: true
+ }
+ },
+ customParser: (f) => [
+ `created_by_company==${f.value
+ .map((c) => escapeFilterValue(c.raw.name))
+ .join("||")}`
+ ]
+ },
+ {
+ key: "streaming_url",
+ label: "Streaming URL",
+ operators: [OPERATORS.IS, OPERATORS.LIKE_START, OPERATORS.LIKE],
+ values: {
+ type: "text",
+ props: {}
+ }
+ },
+ {
+ key: "meeting_url",
+ label: "Meeting URL",
+ operators: [OPERATORS.IS, OPERATORS.LIKE_START, OPERATORS.LIKE],
+ values: {
+ type: "text",
+ props: {}
+ }
+ },
+ {
+ key: "etherpad_link",
+ label: "Etherpad Link",
+ operators: [OPERATORS.IS, OPERATORS.LIKE_START, OPERATORS.LIKE],
+ values: {
+ type: "text",
+ props: {}
+ }
+ },
+ {
+ key: "streaming_type",
+ label: "Streaming Type",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: streamingTypeOptions
+ }
+ }
+ },
+ {
+ key: "sponsor",
+ label: "Sponsor",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "company",
+ props: {
+ multiple: true
+ }
+ },
+ customParser: (f) => [
+ `sponsor==${f.value.map((s) => escapeFilterValue(s.raw.name)).join("||")}`
+ ]
+ },
+ {
+ key: "all_companies",
+ label: "All Companies",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "company",
+ props: {
+ queryFunction: queryAllCompanies,
+ multiple: true
+ }
+ },
+ customParser: (f) => {
+ const companies = f.value
+ .map((c) => escapeFilterValue(c.raw.name))
+ .join("||");
+ return [
+ `speaker_company==${companies},created_by_company==${companies},sponsor==${companies}`
+ ];
+ }
+ },
+ {
+ key: "submission_status",
+ label: "Submitter Company",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: submissionStatusOptions
+ }
+ }
+ },
+ {
+ key: "media_upload_with_type",
+ label: "Media Upload Type",
+ operators: [OPERATORS.HAS, OPERATORS.HAS_NOT],
+ values: {
+ type: "select",
+ props: {
+ options: mediaUploadTypes.map((type) => ({
+ value: type.id,
+ label: type.name
+ })),
+ multiple: true
+ }
+ },
+ customParser: (f) => {
+ const filter = [];
+
+ if (f.operator === OPERATORS.HAS.value) {
+ const value = Array.isArray(f.value) ? f.value.join("||") : f.value;
+ filter.push(`has_media_upload_with_type==${value}`);
+ } else {
+ const value = Array.isArray(f.value) ? f.value.join("&&") : f.value;
+ filter.push(`has_not_media_upload_with_type==${value}`);
+ }
+
+ return filter;
+ }
+ },
+ {
+ key: "review_status",
+ label: "Review Status",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: reviewStatusOptions,
+ multiple: true
+ }
+ }
+ },
+ {
+ key: "submission_source",
+ label: "Submitter Status",
+ operators: [OPERATORS.IS],
+ values: {
+ type: "select",
+ props: {
+ options: submissionSourceOptions
+ }
+ }
+ }
+];
+
+const SummitEventListPage = ({
+ events,
+ currentSummit,
+ extraColumns,
+ term,
+ currentPage,
+ perPage,
+ lastPage,
+ order,
+ orderDir,
+ totalEvents,
+ history,
+ mediaUploadTypes,
+ getEvents,
+ deleteEvent,
+ getMediaUploads,
+ exportEvents,
+ importEventsCSV,
+ importMP4AssetsFromMUX,
+ changeEventListSearchTerm,
+ saveFilterCriteria,
+ deleteFilterCriteria,
+ bulkUpdateEvents
+}) => {
+ const [showImportModal, setShowImportModal] = useState(false);
+ const [showImportFromMUXModal, setShowImportFromMUXModal] = useState(false);
+ const [selectedColumns, setSelectedColumns] = useState([]);
+ const [selectedFilterCriteria, setSelectedFilterCriteria] = useState(null);
+ const { parsedFilter, resetFilters, filterValues, setFilters } =
+ useGridFilter(FILTER_ID);
+
+ // eslint-disable-next-line no-underscore-dangle
+ const _getEvents = (params = {}) => {
+ const mergedParams = {
+ term,
+ page: currentPage,
+ perPage,
+ order,
+ orderDir,
+ ...params
+ };
+
+ const {
+ term: t,
+ page: p,
+ perPage: pp,
+ order: o,
+ orderDir: od
+ } = mergedParams;
+
+ getEvents(t, p, pp, o, od, parsedFilter, extraColumns);
+ };
+
+ useEffect(() => {
+ if (currentSummit) {
+ getMediaUploads("", 1, MAX_PER_PAGE, "name", 1);
+ getEvents();
+ // GridFilter persists criteria to localStorage under a summit-agnostic
+ // FILTER_ID, so it survives a summit switch unless cleared explicitly here.
+ setSelectedFilterCriteria(null);
+ resetFilters();
+ }
+ }, [currentSummit?.id]);
+
+ useEffect(() => {
+ _getEvents();
+ }, [parsedFilter.join(",")]);
+
+ useEffect(() => {
+ if (selectedFilterCriteria) {
+ setFilters(selectedFilterCriteria.criteria);
+ } else {
+ resetFilters();
+ }
+ }, [selectedFilterCriteria]);
+
+ useEffect(() => {
+ setSelectedColumns(extraColumns);
+ }, [extraColumns]);
+
+ const handleMUXImport = (ev) => {
+ ev.preventDefault();
+ setShowImportFromMUXModal(true);
+ };
+
+ const handleEdit = (eventId) => {
+ history.push(`/app/summits/${currentSummit.id}/events/${eventId}`);
+ };
+
+ const handleExport = (ev) => {
+ ev.preventDefault();
+ exportEvents(term, order, orderDir, parsedFilter, selectedColumns);
+ };
+
+ const handlePageChange = (page) => {
+ _getEvents({ page });
+ };
+
+ const handleSort = (index, key, dir) => {
+ let translatedKey = key;
+ switch (key) {
+ case "name":
+ translatedKey = "last_name";
+ break;
+ case "submitter_company":
+ translatedKey = "created_by_company";
+ break;
+ case "progress_flags":
+ translatedKey = "actions";
+ break;
+ default:
+ break;
+ }
+
+ _getEvents({ order: translatedKey, orderDir: dir });
+ };
+
+ const handleSearch = (newTerm) => {
+ _getEvents({ term: newTerm, page: DEFAULT_CURRENT_PAGE });
+ };
+
+ const handleNewEvent = () => {
+ history.push(`/app/summits/${currentSummit.id}/events/new`);
+ };
+
+ const handleDeleteEvent = (eventId) => {
+ const event = events.find((e) => e.id === eventId);
+
+ Swal.fire({
+ title: T.translate("general.are_you_sure"),
+ text: `${T.translate("event_list.delete_event_warning")} ${event.title}`,
+ type: "warning",
+ showCancelButton: true,
+ confirmButtonColor: "#DD6B55",
+ confirmButtonText: T.translate("general.yes_delete")
+ }).then((result) => {
+ if (result.value) {
+ deleteEvent(eventId);
+ }
+ });
+ };
+
+ const handleTermChange = (newTerm) => {
+ changeEventListSearchTerm(newTerm);
+ };
+
+ const handleFilterCriteriaSave = ({ name, id, visibility }) => {
+ const filterToSave = {
+ id,
+ show_id: currentSummit.id,
+ name,
+ enabled_filters: filterValues.map((f) => f.criteria),
+ // only save criteria for enabled filters
+ criteria: filterValues,
+ context: CONTEXT_ACTIVITIES,
+ visibility
+ };
+
+ saveFilterCriteria(filterToSave);
+ };
+
+ const handleColumnsChange = (ev) => {
+ const { value } = ev.target;
+ let newColumns = value;
+ const allCompanies = ["submitter_company", "speaker_company", "sponsor"];
+ const mediaUploadsSelected = newColumns.includes("media_uploads");
+
+ newColumns = newColumns.filter((col) => col !== "media_uploads_display");
+ if (mediaUploadsSelected) newColumns.push("media_uploads_display");
+
+ const hasAllCompanies = newColumns.includes("all_companies");
+ const selectedCompanies = selectedColumns.filter((c) =>
+ allCompanies.includes(c)
+ ).length;
+ const newCompanies = newColumns.filter((c) =>
+ allCompanies.includes(c)
+ ).length;
+
+ if (selectedColumns.includes("all_companies") && !hasAllCompanies) {
+ newColumns = newColumns.filter((e) => !allCompanies.includes(e));
+ } else if (hasAllCompanies) {
+ if (newCompanies === 0) {
+ newColumns = [...selectedColumns, ...allCompanies, "all_companies"];
+ } else if (newCompanies === selectedCompanies) {
+ newColumns = [
+ ...new Set([...newColumns, ...allCompanies, "all_companies"])
+ ];
+ } else if (newCompanies < selectedCompanies) {
+ newColumns = newColumns.filter((c) => c !== "all_companies");
+ }
+ }
+
+ setSelectedColumns(newColumns);
+ };
+
+ const handleFilterCriteriaChange = (filterCriteria) => {
+ setSelectedFilterCriteria(filterCriteria);
+ };
+
+ const handleFilterCriteriaDelete = (filterCriteriaId) => {
+ deleteFilterCriteria(filterCriteriaId).then(() => {
+ setSelectedFilterCriteria(null);
+ });
+ };
+
+ const translateSortKey = (key) => {
+ switch (key) {
+ case "last_name":
+ return "name";
+ case "created_by_company":
+ return "submitter_company";
+ case "actions":
+ return "progress_flags";
+ default:
+ break;
+ }
+
+ return key;
+ };
+
+ const eventTypeOptions = buildNameIdDDL(currentSummit.event_types);
+
+ let columns = [
+ { columnKey: "id", value: T.translate("general.id"), sortable: true },
+ {
+ columnKey: "type",
+ value: T.translate("event_list.type"),
+ sortable: true,
+ // eslint-disable-next-line react/no-unstable-nested-components
+ editableField: (extraProps) => (
+ ({ ...base, zIndex: 9999 }),
+ control: (base, state) => ({
+ ...base,
+ zIndex: state.menuIsOpen ? HIGH_Z_INDEX : DEFAULT_Z_INDEX
+ })
+ }}
+ // eslint-disable-next-line react/jsx-props-no-spreading
+ {...extraProps}
+ />
+ ),
+ render: (e) => e.name
+ },
+ {
+ columnKey: "title",
+ value: T.translate("event_list.title"),
+ sortable: true,
+ editableField: true
+ },
+ {
+ columnKey: "selection_status",
+ value: T.translate("event_list.selection_status"),
+ sortable: true
+ }
+ ];
+
+ const tableOptions = {
+ sortCol: translateSortKey(order),
+ sortDir: orderDir,
+ className: "summit-event-list-table",
+ actions: {
+ edit: { onClick: handleEdit },
+ delete: { onClick: handleDeleteEvent }
+ }
+ };
+
+ const columnOptions = [
+ {
+ value: "event_type_capacity",
+ label: T.translate("event_list.event_type_capacity")
+ },
+ { value: "speakers", label: T.translate("event_list.speakers") },
+ {
+ value: "all_companies",
+ label: T.translate("event_list.all_companies")
+ },
+ {
+ value: "created_by_fullname",
+ label: T.translate("event_list.created_by")
+ },
+ { value: "duration", label: T.translate("event_list.duration") },
+ { value: "end_date", label: T.translate("event_list.end_date") },
+ { value: "published_date", label: T.translate("event_list.published") },
+ {
+ value: "speaker_company",
+ label: T.translate("event_list.speaker_company")
+ },
+ {
+ value: "speakers_count",
+ label: T.translate("event_list.speakers_count")
+ },
+ { value: "sponsor", label: T.translate("event_list.sponsor") },
+ {
+ value: "selection_plan",
+ label: T.translate("event_list.selection_plan")
+ },
+ { value: "location", label: T.translate("event_list.location") },
+ { value: "level", label: T.translate("event_list.level") },
+ { value: "tags", label: T.translate("event_list.tags") },
+ {
+ value: "streaming_url",
+ label: T.translate("event_list.streaming_url")
+ },
+ { value: "meeting_url", label: T.translate("event_list.meeting_url") },
+ {
+ value: "etherpad_link",
+ label: T.translate("event_list.etherpad_link")
+ },
+ {
+ value: "streaming_type",
+ label: T.translate("event_list.streaming_type")
+ },
+ { value: "start_date", label: T.translate("event_list.start_date") },
+ {
+ value: "submitter_company",
+ label: T.translate("event_list.submitter_company")
+ },
+ { value: "track", label: T.translate("event_list.track") },
+ { value: "status", label: T.translate("event_list.submission_status") },
+ {
+ value: "submission_source",
+ label: T.translate("event_list.submission_source")
+ },
+ {
+ value: "progress_flags",
+ label: T.translate("event_list.progress_flags")
+ },
+ {
+ value: "media_uploads",
+ label: T.translate("event_list.media_uploads")
+ },
+ {
+ value: "review_status",
+ label: T.translate("event_list.review_status")
+ },
+ { value: "created", label: T.translate("event_list.created") },
+ { value: "modified", label: T.translate("event_list.modified") },
+ {
+ value: "allow_feedback",
+ label: T.translate("event_list.allow_feedback")
+ },
+ {
+ value: "to_record",
+ label: T.translate("event_list.to_record")
+ }
+ ];
+
+ const showColumns = fieldNames(
+ currentSummit.selection_plans,
+ currentSummit.tracks,
+ currentSummit.event_types,
+ currentSummit.id
+ )
+ .filter(
+ (f) =>
+ selectedColumns.includes(f.columnKey) &&
+ !defaultColumns.includes(f.columnKey)
+ )
+ .map((f2) => {
+ let c = {
+ columnKey: f2.columnKey,
+ value: T.translate(`event_list.${f2.value}`),
+ sortable: f2.sortable,
+ editable: !!editableColumns.includes(f2.editable),
+ customStyle: f2.customStyle
+ };
+ // optional fields
+ if (f2?.title) c = { ...c, title: f2.title };
+
+ if (f2?.render) c = { ...c, render: f2.render };
+
+ if (f2?.editableField) c = { ...c, editableField: f2.editableField };
+
+ return c;
+ });
+
+ columns = [...columns, ...showColumns];
+
+ if (!currentSummit.id) return
;
+
+ return (
+
+
+ {T.translate("event_list.event_list")} ({totalEvents})
+
+
+
+
+
+
+ {T.translate("event_list.add_event")}
+
+
+ {T.translate("general.export")}
+
+
+ {T.translate("event_list.mux_import")}
+
+
setShowImportModal(true)}
+ type="button"
+ >
+ {T.translate("event_list.import")}
+
+
+
+
+
+
+
+
+
+ {T.translate("event_list.select_fields")}
+
+
+
+
+
+ {events.length === 0 &&
{T.translate("event_list.no_events")}
}
+
+ {events.length > 0 && (
+
+ )}
+
+
setShowImportModal(false)}
+ onImport={importEventsCSV}
+ />
+
+ setShowImportFromMUXModal(false)}
+ onImport={importMP4AssetsFromMUX}
+ />
+
+ );
+};
+
+const mapStateToProps = ({
+ currentSummitState,
+ currentEventListState,
+ mediaUploadListState
+}) => ({
+ currentSummit: currentSummitState.currentSummit,
+ mediaUploadTypes: mediaUploadListState.media_uploads,
+ ...currentEventListState
+});
+
+export default connect(mapStateToProps, {
+ getEvents,
+ deleteEvent,
+ exportEvents,
+ importEventsCSV,
+ importMP4AssetsFromMUX,
+ changeEventListSearchTerm,
+ saveFilterCriteria,
+ deleteFilterCriteria,
+ bulkUpdateEvents,
+ getMediaUploads
+})(SummitEventListPage);
diff --git a/src/store.js b/src/store.js
index 326f84399..9d9d6e57c 100644
--- a/src/store.js
+++ b/src/store.js
@@ -16,6 +16,7 @@ import { loggedUserReducer } from "openstack-uicore-foundation/lib/security/redu
import thunk from "redux-thunk";
import { persistStore, persistCombineReducers } from "redux-persist";
import storage from "redux-persist/es/storage";
+import { allFiltersReducer } from "openstack-uicore-foundation/lib/components/mui/grid-filter";
import baseReducer from "./reducers/base-reducer";
import currentSummitReducer from "./reducers/summits/current-summit-reducer";
import directoryReducer from "./reducers/summits/directory-reducer";
@@ -185,6 +186,7 @@ const config = {
const reducers = persistCombineReducers(config, {
loggedUserState: loggedUserReducer,
+ allGridFiltersState: allFiltersReducer,
baseState: baseReducer,
directoryState: directoryReducer,
currentSummitState: currentSummitReducer,
diff --git a/src/styles/summit-event-list-page.less b/src/styles/summit-event-list-page.less
deleted file mode 100644
index fd043173d..000000000
--- a/src/styles/summit-event-list-page.less
+++ /dev/null
@@ -1,23 +0,0 @@
-.filters-row {
- margin: 25px -15px 0px;
- display: flex;
- flex-wrap: wrap;
- align-items: start;
-
- .col-md-6,
- .col-md-3 {
- margin-bottom: 10px;
- }
-}
-
-.event-list-date-picker {
- > div:first-of-type {
- width: 100%;
- }
-}
-
-@media (max-width: 991px) {
- .filters-row {
- display: block;
- }
-}
diff --git a/yarn.lock b/yarn.lock
index b60b5f3ea..43300d058 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -9056,10 +9056,10 @@ open@^10.0.3:
is-inside-container "^1.0.0"
wsl-utils "^0.1.0"
-openstack-uicore-foundation@5.0.34:
- version "5.0.34"
- resolved "https://registry.npmjs.org/openstack-uicore-foundation/-/openstack-uicore-foundation-5.0.34.tgz#28345b0c4338f6a24237862864236d989129c85b"
- integrity sha512-gVvfJn7DtKC4s/2HRCOnCqiLFZqWL+P3+Wh0jnNQpGurUrk6UrC2lTkYZ6Vw2W/qqJeJwWjus7rG17+Ff32LaA==
+openstack-uicore-foundation@5.0.36-beta.1:
+ version "5.0.36-beta.1"
+ resolved "https://registry.yarnpkg.com/openstack-uicore-foundation/-/openstack-uicore-foundation-5.0.36-beta.1.tgz#2982cb73482ce662b0cd32c01eb4d4f88bbbf447"
+ integrity sha512-g0bXh7z/vlWOlB/vSWN4R3SoLUAJgyU01WCf6+wbBAITkI9pJ/7tWStzAf6iZPyfu5r4q23ySyl6m7Z9Wy5PTQ==
dependencies:
use-sync-external-store "^1.6.0"
@@ -10015,7 +10015,7 @@ react-input-autosize@^2.2.1:
dependencies:
prop-types "^15.5.8"
-react-is@^16.13.1, react-is@^16.3.2, react-is@^16.6.0, react-is@^16.7.0:
+react-is@^16.13.1, react-is@^16.3.2, react-is@^16.7.0:
version "16.13.1"
resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4"
integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==
@@ -10035,7 +10035,7 @@ react-is@^19.0.0, react-is@^19.2.3:
resolved "https://registry.yarnpkg.com/react-is/-/react-is-19.2.5.tgz#7e7b54143e9313fed787b23fd4295d5a23872ad9"
integrity sha512-Dn0t8IQhCmeIT3wu+Apm1/YVsJXsGWi6k4sPdnBIdqMVtHtv0IGi6dcpNpNkNac0zB2uUAqNX3MHzN8c+z2rwQ==
-react-lifecycles-compat@^3.0.0, react-lifecycles-compat@^3.0.4:
+react-lifecycles-compat@^3.0.4:
version "3.0.4"
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
@@ -10056,20 +10056,7 @@ react-overlays@^0.7.4:
prop-types-extra "^1.0.1"
warning "^3.0.0"
-react-redux@^5.0.7:
- version "5.1.2"
- resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-5.1.2.tgz#b19cf9e21d694422727bf798e934a916c4080f57"
- integrity sha512-Ns1G0XXc8hDyH/OcBHOxNgQx9ayH3SPxBnFCOidGKSle8pKihysQw2rG/PmciUQRoclhVBO8HMhiRmGXnDja9Q==
- dependencies:
- "@babel/runtime" "^7.1.2"
- hoist-non-react-statics "^3.3.0"
- invariant "^2.2.4"
- loose-envify "^1.1.0"
- prop-types "^15.6.1"
- react-is "^16.6.0"
- react-lifecycles-compat "^3.0.0"
-
-react-redux@^7.2.0:
+react-redux@^7.1.0, react-redux@^7.2.0:
version "7.2.9"
resolved "https://registry.yarnpkg.com/react-redux/-/react-redux-7.2.9.tgz#09488fbb9416a4efe3735b7235055442b042481d"
integrity sha512-Gx4L3uM182jEEayZfRbI/G11ZpYdNAnBs70lFVMNdHJI76XYtR+7m0MN+eAs7UHBPhWXcnFPaS+9owSCJQHNpQ==
@@ -10275,7 +10262,7 @@ redux-thunk@^2.3.0:
resolved "https://registry.yarnpkg.com/redux-thunk/-/redux-thunk-2.4.2.tgz#b9d05d11994b99f7a91ea223e8b04cf0afa5ef3b"
integrity sha512-+P3TjtnP0k/FEjcBL5FZpoovtvrTNT/UXd4/sluaSyrURlSlhLSzEdfsTBW7WsKB6yPvgd7q/iZPICFjW4o57Q==
-redux@^3.6.0, redux@^3.7.2:
+redux@^3.6.0:
version "3.7.2"
resolved "https://registry.yarnpkg.com/redux/-/redux-3.7.2.tgz#06b73123215901d25d065be342eb026bc1c8537b"
integrity sha512-pNqnf9q1hI5HHZRBkj3bAngGZW/JMCmexDlOxw4XagXY2o1327nHH54LoTjiPJ0gizoqPDRqWyX/00g0hD6w+A==
@@ -10285,7 +10272,7 @@ redux@^3.6.0, redux@^3.7.2:
loose-envify "^1.1.0"
symbol-observable "^1.0.3"
-redux@^4.0.0, redux@^4.0.4, redux@^4.2.0:
+redux@^4.0.0, redux@^4.0.4, redux@^4.2.0, redux@^4.2.1:
version "4.2.1"
resolved "https://registry.yarnpkg.com/redux/-/redux-4.2.1.tgz#c08f4306826c49b5e9dc901dee0452ea8fce6197"
integrity sha512-LAUYz4lc+Do8/g7aeRa8JkyDErK6ekstQaqWQrNRW//MY1TvCEpMtpTWvlQ+FPbWCx+Xixu/6SHt5N0HR+SB4w==