diff --git a/src/actions/event-type-actions.js b/src/actions/event-type-actions.js index 9c4cb7005..502194260 100644 --- a/src/actions/event-type-actions.js +++ b/src/actions/event-type-actions.js @@ -21,10 +21,12 @@ import { startLoading, showMessage, showSuccessMessage, - authErrorHandler + authErrorHandler, + escapeFilterValue } from "openstack-uicore-foundation/lib/utils/actions"; import history from "../history"; import { getAccessTokenSafely } from "../utils/methods"; +import { DEFAULT_PER_PAGE, DEFAULT_CURRENT_PAGE } from "../utils/constants"; export const REQUEST_EVENT_TYPES = "REQUEST_EVENT_TYPES"; export const RECEIVE_EVENT_TYPES = "RECEIVE_EVENT_TYPES"; @@ -36,28 +38,52 @@ export const EVENT_TYPE_ADDED = "EVENT_TYPE_ADDED"; export const EVENT_TYPE_DELETED = "EVENT_TYPE_DELETED"; export const EVENT_TYPES_SEEDED = "EVENT_TYPES_SEEDED"; -export const getEventTypes = () => async (dispatch, getState) => { - const { currentSummitState } = getState(); - const accessToken = await getAccessTokenSafely(); - const { currentSummit } = currentSummitState; +export const getEventTypes = + ( + term = null, + page = DEFAULT_CURRENT_PAGE, + perPage = DEFAULT_PER_PAGE, + order = "id", + orderDir = 1 + ) => + async (dispatch, getState) => { + const { currentSummitState } = getState(); + const accessToken = await getAccessTokenSafely(); + const { currentSummit } = currentSummitState; + const filter = []; + + dispatch(startLoading()); + + const params = { + access_token: accessToken, + page, + per_page: perPage + }; - dispatch(startLoading()); + if (term) { + const escapedTerm = escapeFilterValue(term); + filter.push(`name=@${escapedTerm}`); + } - const params = { - access_token: accessToken, - per_page: 100, - page: 1 - }; + if (filter.length > 0) { + params["filter[]"] = filter; + } - return getRequest( - createAction(REQUEST_EVENT_TYPES), - createAction(RECEIVE_EVENT_TYPES), - `${window.API_BASE_URL}/api/v1/summits/${currentSummit.id}/event-types`, - authErrorHandler - )(params)(dispatch).then(() => { - dispatch(stopLoading()); - }); -}; + if (order != null && orderDir != null) { + const orderDirSign = orderDir === 1 ? "" : "-"; + params.order = `${orderDirSign}${order}`; + } + + return getRequest( + createAction(REQUEST_EVENT_TYPES), + createAction(RECEIVE_EVENT_TYPES), + `${window.API_BASE_URL}/api/v1/summits/${currentSummit.id}/event-types`, + authErrorHandler, + { order, orderDir, term, perPage } + )(params)(dispatch).then(() => { + dispatch(stopLoading()); + }); + }; export const getEventType = (eventTypeId) => async (dispatch, getState) => { const { currentSummitState } = getState(); diff --git a/src/i18n/en.json b/src/i18n/en.json index 0bb5e83e8..13f236f34 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -1255,7 +1255,7 @@ "name": "Name", "class": "Class", "seed_event_types": "Seed Types", - "remove_warning": "Are you sure you want to delete activity type " + "remove_warning": "Please verify you want to delete activity type " }, "edit_event_type": { "event_type": "Activity Type", diff --git a/src/pages/events/event-type-list-page.js b/src/pages/events/event-type-list-page.js index 91f803ea4..72d2e2259 100644 --- a/src/pages/events/event-type-list-page.js +++ b/src/pages/events/event-type-list-page.js @@ -1,5 +1,5 @@ /** - * Copyright 2017 OpenStack Foundation + * 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 @@ -9,127 +9,206 @@ * 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 React, { useEffect } from "react"; import { connect } from "react-redux"; +import PropTypes from "prop-types"; import T from "i18n-react/dist/i18n-react"; -import Swal from "sweetalert2"; -import Table from "openstack-uicore-foundation/lib/components/table"; +import Box from "@mui/material/Box"; +import Button from "@mui/material/Button"; +import Grid2 from "@mui/material/Grid2"; +import AddIcon from "@mui/icons-material/Add"; +import MuiTable from "openstack-uicore-foundation/lib/components/mui/table"; +import SearchInput from "openstack-uicore-foundation/lib/components/mui/search-input"; import { + getEventTypes as getEventTypesAction, + deleteEventType as deleteEventTypeAction, + seedEventTypes as seedEventTypesAction +} from "../../actions/event-type-actions"; +import { DEFAULT_CURRENT_PAGE } from "../../utils/constants"; + +const EventTypeListPage = ({ + currentSummit, + eventTypes, + term, + currentPage, + perPage, + order, + orderDir, + totalEventTypes, getEventTypes, deleteEventType, - seedEventTypes -} from "../../actions/event-type-actions"; - -class EventTypeListPage extends React.Component { - constructor(props) { - super(props); - this.state = {}; - props.getEventTypes(); - - this.handleEdit = this.handleEdit.bind(this); - this.handleNew = this.handleNew.bind(this); - this.handleDelete = this.handleDelete.bind(this); - this.isNotDefault = this.isNotDefault.bind(this); - } - - componentDidMount() { - const { currentSummit } = this.props; - if (currentSummit) { - this.props.getEventTypes(); - } - } - - handleEdit(eventTypeId) { - const { currentSummit, history } = this.props; - history.push(`/app/summits/${currentSummit.id}/event-types/${eventTypeId}`); - } - - handleNew(ev) { - const { currentSummit, history } = this.props; + seedEventTypes, + history +}) => { + useEffect(() => { + getEventTypes(); + }, []); + + const handleEdit = (row) => { + history.push(`/app/summits/${currentSummit.id}/event-types/${row.id}`); + }; + + const handleNew = () => { history.push(`/app/summits/${currentSummit.id}/event-types/new`); - } - - handleDelete(eventTypeId) { - const { deleteEventType, eventTypes } = this.props; - let eventType = eventTypes.find((e) => e.id === eventTypeId); - - Swal.fire({ - title: T.translate("general.are_you_sure"), - text: - T.translate("event_type_list.remove_warning") + " " + eventType.name, - type: "warning", - showCancelButton: true, - confirmButtonColor: "#DD6B55", - confirmButtonText: T.translate("general.yes_delete") - }).then(function (result) { - if (result.value) { - deleteEventType(eventTypeId); - } - }); - } - - isNotDefault(eventTypeId) { - const { eventTypes } = this.props; - let eventType = eventTypes.find((e) => e.id === eventTypeId); - - return !eventType.is_default; - } - - render() { - const { currentSummit, eventTypes } = this.props; - - const columns = [ - { columnKey: "name", value: T.translate("event_type_list.name") }, - { columnKey: "class_name", value: T.translate("event_type_list.class") } - ]; - - const table_options = { - actions: { - edit: { onClick: this.handleEdit }, - delete: { onClick: this.handleDelete, display: this.isNotDefault } - } - }; - - if (!currentSummit.id) return
; - - return ( -
-

{T.translate("event_type_list.event_type_list")}

-
-
- - -
-
- - {eventTypes.length === 0 && ( -
- {T.translate("event_type_list.no_items")} -
- )} - - {eventTypes.length > 0 && ( -
- - - )} - + }; + + const handleDelete = (eventTypeId) => { + deleteEventType(eventTypeId).then(() => + getEventTypes(term, DEFAULT_CURRENT_PAGE, perPage, order, orderDir) ); - } -} + }; + + const handleSearch = (searchTerm) => { + getEventTypes(searchTerm, DEFAULT_CURRENT_PAGE, perPage, order, orderDir); + }; + + const handlePageChange = (page) => { + getEventTypes(term, page, perPage, order, orderDir); + }; + + const handlePerPageChange = (newPerPage) => { + getEventTypes(term, DEFAULT_CURRENT_PAGE, newPerPage, order, orderDir); + }; + + const handleSort = (key, dir) => { + getEventTypes(term, currentPage, perPage, key, dir); + }; + + const columns = [ + { + columnKey: "name", + header: T.translate("event_type_list.name"), + sortable: true + }, + { + columnKey: "class_name", + header: T.translate("event_type_list.class") + } + ]; + + const tableOptions = { sortCol: order, sortDir: orderDir }; + + if (!currentSummit.id) return
; + + return ( +
+

{T.translate("event_type_list.event_type_list")}

+ + + + {totalEventTypes} {T.translate("event_type_list.event_types")} + + + + + + + + + + + + {eventTypes.length > 0 && ( + !row.is_default} + deleteDialogBody={(name) => + `${T.translate("event_type_list.remove_warning")} ${name}` + } + confirmButtonColor="error" + /> + )} + + {eventTypes.length === 0 && ( +
{T.translate("event_type_list.no_items")}
+ )} +
+ ); +}; + +EventTypeListPage.propTypes = { + currentSummit: PropTypes.shape({ id: PropTypes.number }).isRequired, + eventTypes: PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.number, + name: PropTypes.string, + class_name: PropTypes.string, + is_default: PropTypes.bool + }) + ).isRequired, + term: PropTypes.string, + currentPage: PropTypes.number, + perPage: PropTypes.number, + order: PropTypes.string, + orderDir: PropTypes.number, + totalEventTypes: PropTypes.number, + getEventTypes: PropTypes.func.isRequired, + deleteEventType: PropTypes.func.isRequired, + seedEventTypes: PropTypes.func.isRequired, + history: PropTypes.shape({ push: PropTypes.func }).isRequired +}; + +EventTypeListPage.defaultProps = { + term: "", + currentPage: 1, + perPage: 10, + order: "id", + orderDir: 1, + totalEventTypes: 0 +}; const mapStateToProps = ({ currentSummitState, @@ -140,7 +219,7 @@ const mapStateToProps = ({ }); export default connect(mapStateToProps, { - getEventTypes, - deleteEventType, - seedEventTypes + getEventTypes: getEventTypesAction, + deleteEventType: deleteEventTypeAction, + seedEventTypes: seedEventTypesAction })(EventTypeListPage); diff --git a/src/reducers/events/event-type-list-reducer.js b/src/reducers/events/event-type-list-reducer.js index 1f9244980..527fd155d 100644 --- a/src/reducers/events/event-type-list-reducer.js +++ b/src/reducers/events/event-type-list-reducer.js @@ -9,8 +9,9 @@ * 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 { LOGOUT_USER } from "openstack-uicore-foundation/lib/security/actions"; import { RECEIVE_EVENT_TYPES, REQUEST_EVENT_TYPES, @@ -19,10 +20,16 @@ import { } from "../../actions/event-type-actions"; import { SET_CURRENT_SUMMIT } from "../../actions/summit-actions"; -import { LOGOUT_USER } from "openstack-uicore-foundation/lib/security/actions"; const DEFAULT_STATE = { - eventTypes: [] + eventTypes: [], + term: "", + order: "id", + orderDir: 1, + currentPage: 1, + lastPage: 1, + perPage: 10, + totalEventTypes: 0 }; const eventTypeListReducer = (state = DEFAULT_STATE, action) => { @@ -33,30 +40,37 @@ const eventTypeListReducer = (state = DEFAULT_STATE, action) => { return DEFAULT_STATE; } case REQUEST_EVENT_TYPES: { - return { ...state }; + const { order, orderDir, term, perPage } = payload; + return { ...state, order, orderDir, term, perPage }; } case RECEIVE_EVENT_TYPES: { - let eventTypes = [...payload.response.data]; + const { total, last_page, current_page } = payload.response; + const eventTypes = [...payload.response.data]; - return { ...state, eventTypes }; + return { + ...state, + eventTypes, + currentPage: current_page, + lastPage: last_page, + totalEventTypes: total + }; } case EVENT_TYPE_DELETED: { - let { eventTypeId } = payload; + const { eventTypeId } = payload; return { ...state, eventTypes: state.eventTypes.filter((e) => e.id !== eventTypeId) }; } case EVENT_TYPES_SEEDED: { - let eventTypesAdded = payload.response.data; + const eventTypesAdded = payload.response.data; if (eventTypesAdded.length > 0) { return { ...state, eventTypes: [...state.eventTypes, ...eventTypesAdded] }; - } else { - return state; } + return state; } default: return state;