From d4621d42a3c2b0a3ce0f8065ea7b4990b47e4cc2 Mon Sep 17 00:00:00 2001 From: Pablo Hoch Date: Tue, 1 Mar 2022 15:28:08 +0100 Subject: [PATCH] RSL 2021 AP4 (#202) --- .clang-tidy.in | 3 +- .github/workflows/unix.yml | 18 +- .github/workflows/windows.yml | 21 +- .pkg | 2 +- base/core/include/motis/core/common/logging.h | 2 + base/core/include/motis/core/debug/trip.h | 129 ++ base/core/src/logging.cc | 10 +- base/module/src/dispatcher.cc | 1 + .../measures/trip_recommendation.h | 1 - modules/paxforecast/src/messages.cc | 3 +- modules/paxforecast/src/paxforecast.cc | 71 +- .../include/motis/paxmon/graph_access.h | 2 + .../paxmon/include/motis/paxmon/multiverse.h | 3 +- .../paxmon/include/motis/paxmon/statistics.h | 1 + .../paxmon/include/motis/paxmon/universe.h | 17 +- .../include/motis/paxmon/update_tracker.h | 44 + modules/paxmon/src/api/add_groups.cc | 3 + modules/paxmon/src/api/filter_trips.cc | 165 ++- modules/paxmon/src/api/get_groups_in_trip.cc | 91 +- modules/paxmon/src/api/get_interchanges.cc | 3 +- modules/paxmon/src/api/remove_groups.cc | 1 + modules/paxmon/src/checks.cc | 76 ++ modules/paxmon/src/get_load.cc | 4 +- modules/paxmon/src/graph_access.cc | 7 +- modules/paxmon/src/messages.cc | 13 +- modules/paxmon/src/paxmon.cc | 3 +- modules/paxmon/src/print_stats.cc | 4 +- modules/paxmon/src/reroute.cc | 47 +- modules/paxmon/src/statistics.cc | 1 + modules/paxmon/src/update_tracker.cc | 366 ++++++ modules/paxmon/test/get_load_test.cc | 2 +- protocol/Message.fbs | 4 +- protocol/paxforecast/Measures.fbs | 1 - .../PaxForecastApplyMeasuresRequest.fbs | 3 + .../PaxForecastApplyMeasuresResponse.fbs | 25 + protocol/paxmon/PaxMonFilterTripsRequest.fbs | 20 +- protocol/paxmon/PaxMonFilterTripsResponse.fbs | 25 +- .../paxmon/PaxMonGetGroupsInTripRequest.fbs | 3 +- .../paxmon/PaxMonGetGroupsInTripResponse.fbs | 2 + .../paxmon/PaxMonGetInterchangesResponse.fbs | 1 + protocol/paxmon/PaxMonTrackedUpdates.fbs | 56 + ui/rsl/.prettierrc.js | 18 + ui/rsl/.prettierrc.json | 1 - ui/rsl/package.json | 38 +- ui/rsl/pnpm-lock.yaml | 1145 +++++++++++------ ui/rsl/src/api/endpoint.ts | 2 +- ui/rsl/src/api/guesser.ts | 10 +- ui/rsl/src/api/lookup.ts | 10 +- ui/rsl/src/api/paxforecast.ts | 17 +- ui/rsl/src/api/paxmon.ts | 36 +- ui/rsl/src/api/protocol/checks.ts | 2 +- ui/rsl/src/api/protocol/motis.ts | 71 +- ui/rsl/src/api/protocol/motis/guesser.ts | 3 +- ui/rsl/src/api/protocol/motis/lookup.ts | 11 +- ui/rsl/src/api/protocol/motis/paxforecast.ts | 33 +- ui/rsl/src/api/protocol/motis/paxmon.ts | 81 +- ui/rsl/src/api/protocol/motis/routing.ts | 9 +- ui/rsl/src/api/request.ts | 5 +- ui/rsl/src/api/ris.ts | 7 +- ui/rsl/src/api/routing.ts | 7 +- ui/rsl/src/components/App.tsx | 63 +- ui/rsl/src/components/CombinedGroup.tsx | 72 +- ui/rsl/src/components/CriticialTripList.tsx | 70 + ui/rsl/src/components/JourneyTripNameView.tsx | 2 +- ui/rsl/src/components/MiniTripLoadGraph.tsx | 151 +++ ui/rsl/src/components/SimPanel.tsx | 92 ++ ui/rsl/src/components/SimResultsPanel.tsx | 237 ++++ ui/rsl/src/components/StationPicker.tsx | 14 +- ui/rsl/src/components/TimeControl.tsx | 12 +- ui/rsl/src/components/TripDetails.tsx | 9 +- .../src/components/TripLoadForecastChart.tsx | 43 +- ui/rsl/src/components/TripPicker.tsx | 40 +- ui/rsl/src/components/TripSectionDetails.tsx | 27 +- ui/rsl/src/components/TripSelection.tsx | 52 + ui/rsl/src/components/TripServiceInfoView.tsx | 28 +- ui/rsl/src/components/UniverseControl.tsx | 20 +- .../src/components/measures/MeasureEditor.tsx | 202 +++ .../src/components/measures/MeasureInput.tsx | 394 ------ .../src/components/measures/MeasureList.tsx | 343 +++++ .../src/components/measures/MeasurePanel.tsx | 54 + .../measures/RtUpdateMeasureEditor.tsx | 478 +++++++ .../components/measures/SharedDataEditor.tsx | 139 ++ ui/rsl/src/components/measures/TimeInput.tsx | 57 +- .../measures/TripLoadInfoMeasureEditor.tsx | 99 ++ .../TripRecommendationMeasureEditor.tsx | 75 ++ ui/rsl/src/components/util/ModalDialog.tsx | 92 ++ ui/rsl/src/data/journey.ts | 4 +- ui/rsl/src/data/loadInfo.ts | 4 +- ui/rsl/src/data/measures.ts | 157 +++ ui/rsl/src/data/numberFormat.ts | 16 + ui/rsl/src/data/rtMeasureFormData.ts | 305 +++++ ui/rsl/src/data/simulation.ts | 24 +- ui/rsl/src/index.tsx | 6 +- ui/rsl/src/util/classNames.ts | 5 + ui/rsl/src/util/dateFormat.ts | 36 +- ui/rsl/src/util/ribasis.ts | 105 ++ ui/rsl/src/util/statistics.ts | 5 +- ui/rsl/src/util/typeGuards.ts | 11 + ui/rsl/src/util/useRenderCount.ts | 6 + ui/rsl/tsconfig.json | 8 +- ui/rsl/vite.config.js | 7 +- 101 files changed, 5129 insertions(+), 1195 deletions(-) create mode 100644 base/core/include/motis/core/debug/trip.h create mode 100644 modules/paxmon/include/motis/paxmon/update_tracker.h create mode 100644 modules/paxmon/src/update_tracker.cc create mode 100644 protocol/paxforecast/PaxForecastApplyMeasuresResponse.fbs create mode 100644 protocol/paxmon/PaxMonTrackedUpdates.fbs create mode 100644 ui/rsl/.prettierrc.js delete mode 100644 ui/rsl/.prettierrc.json create mode 100644 ui/rsl/src/components/CriticialTripList.tsx create mode 100644 ui/rsl/src/components/MiniTripLoadGraph.tsx create mode 100644 ui/rsl/src/components/SimPanel.tsx create mode 100644 ui/rsl/src/components/SimResultsPanel.tsx create mode 100644 ui/rsl/src/components/TripSelection.tsx create mode 100644 ui/rsl/src/components/measures/MeasureEditor.tsx delete mode 100644 ui/rsl/src/components/measures/MeasureInput.tsx create mode 100644 ui/rsl/src/components/measures/MeasureList.tsx create mode 100644 ui/rsl/src/components/measures/MeasurePanel.tsx create mode 100644 ui/rsl/src/components/measures/RtUpdateMeasureEditor.tsx create mode 100644 ui/rsl/src/components/measures/SharedDataEditor.tsx create mode 100644 ui/rsl/src/components/measures/TripLoadInfoMeasureEditor.tsx create mode 100644 ui/rsl/src/components/measures/TripRecommendationMeasureEditor.tsx create mode 100644 ui/rsl/src/components/util/ModalDialog.tsx create mode 100644 ui/rsl/src/data/measures.ts create mode 100644 ui/rsl/src/data/numberFormat.ts create mode 100644 ui/rsl/src/data/rtMeasureFormData.ts create mode 100644 ui/rsl/src/util/classNames.ts create mode 100644 ui/rsl/src/util/ribasis.ts create mode 100644 ui/rsl/src/util/typeGuards.ts create mode 100644 ui/rsl/src/util/useRenderCount.ts diff --git a/.clang-tidy.in b/.clang-tidy.in index 9c8366c1b..3508bed0b 100644 --- a/.clang-tidy.in +++ b/.clang-tidy.in @@ -48,7 +48,7 @@ Checks: "*,\ -cppcoreguidelines-pro-bounds-constant-array-index,\ -*-avoid-c-arrays,\ -*-narrowing-conversions,\ --*-avoid-goto, +-*-avoid-goto,\ -hicpp-multiway-paths-covered,\ -clang-analyzer-cplusplus.NewDeleteLeaks,\ -clang-analyzer-cplusplus.NewDelete,\ @@ -73,6 +73,7 @@ Checks: "*,\ WarningsAsErrors: '*' HeaderFilterRegex: '^${RELATIVE_SOURCE_DIR}(base|modules|test)/' AnalyzeTemporaryDtors: false +UseColor: true User: root CheckOptions: - key: cert-err61-cpp.CheckThrowTemporaries diff --git a/.github/workflows/unix.yml b/.github/workflows/unix.yml index f7e3772ad..6a4e2e187 100644 --- a/.github/workflows/unix.yml +++ b/.github/workflows/unix.yml @@ -55,9 +55,9 @@ jobs: pnpm-${{ runner.os }}- - name: Install RSL Web Interface Dependencies - uses: pnpm/action-setup@v2.0.1 + uses: pnpm/action-setup@v2.2.0 with: - version: 6.25.1 + version: ^6.32.2 run_install: | - cwd: ui/rsl @@ -348,7 +348,7 @@ jobs: - name: Compile Web Interface if: matrix.config.webui == 'On' run: | - cmake --build build --target motis-web-ui + cmake --build build --target motis-web-ui || (sleep 10 && cmake --build build --target motis-web-ui) rm -r ui/web/elm-stuff rm -r ui/web/src @@ -362,10 +362,10 @@ jobs: pnpm-${{ runner.os }}- - name: Install RSL Web Interface Dependencies - uses: pnpm/action-setup@v2.0.1 + uses: pnpm/action-setup@v2.2.0 if: matrix.config.webui == 'On' with: - version: 6.20.1 + version: ^6.32.2 run_install: | - cwd: ./ui/rsl @@ -379,9 +379,11 @@ jobs: if: matrix.config.artifact run: | mkdir motis - mv ui/web motis - mv ui/rsl/dist motis/rsl - mv build/motis motis + mkdir motis/web + mv ui/web/{external_lib,img,js,style} motis/web/ + mv ui/web/{*.html,*.js,*.ico} motis/web/ + mv ui/rsl/dist motis/web/rsl + mv build/motis motis/ cp -r deps/osrm-backend/profiles motis/osrm-profiles cp -r deps/ppr/profiles motis/ppr-profiles cp -r deps/tiles/profile motis/tiles-profiles diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index 44b495e35..51d81a2c2 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -106,10 +106,10 @@ jobs: pnpm-${{ runner.os }}- - name: Install RSL Web Interface Dependencies - uses: pnpm/action-setup@v2.0.1 + uses: pnpm/action-setup@v2.2.0 if: matrix.config.webui == 'On' with: - version: 6.25.1 + version: ^6.32.2 run_install: | - cwd: ./ui/rsl @@ -122,13 +122,17 @@ jobs: - name: Move Profiles if: matrix.config.mode == 'Release' run: | - echo d | xcopy /s .\deps\osrm-backend\profiles .\osrm-profiles - echo d | xcopy /s .\deps\ppr\profiles .\ppr-profiles - echo d | xcopy /s .\deps\tiles\profile .\tiles-profiles + Copy-Item .\deps\osrm-backend\profiles .\osrm-profiles -Recurse + Copy-Item .\deps\ppr\profiles .\ppr-profiles -Recurse + Copy-Item .\deps\tiles\profile .\tiles-profiles -Recurse - - name: Move RSL UI + - name: Move Web UI if: matrix.config.mode == 'Release' - run: echo d | xcopy /s .\ui\rsl\dist .\rsl + run: | + mkdir web + Copy-Item .\ui\web\external_lib,.\ui\web\img,.\ui\web\js,.\ui\web\style .\web\ -Recurse + Copy-Item .\ui\web\*.html,.\ui\web\*.js,.\ui\web\*.ico .\web\ + Copy-Item .\ui\rsl\dist .\web\rsl -Recurse - name: Create Distribution if: matrix.config.mode == 'Release' @@ -138,8 +142,7 @@ jobs: .\osrm-profiles .\ppr-profiles .\tiles-profiles - .\ui\web - .\rsl + .\web - name: Upload Distribution if: matrix.config.mode == 'Release' diff --git a/.pkg b/.pkg index 9b8c95bf1..a4be24ed5 100644 --- a/.pkg +++ b/.pkg @@ -45,7 +45,7 @@ [net] url=git@github.com:motis-project/net.git branch=master - commit=9ea612ff034accbd01825959496ee03a3fece1ef + commit=126869fa3a2ea5c3024c44c180daf4031f802853 [osrm-backend] url=git@github.com:motis-project/osrm-backend.git branch=motis diff --git a/base/core/include/motis/core/common/logging.h b/base/core/include/motis/core/common/logging.h index 47396ec15..fd05515d2 100644 --- a/base/core/include/motis/core/common/logging.h +++ b/base/core/include/motis/core/common/logging.h @@ -85,9 +85,11 @@ struct scoped_timer final { struct manual_timer final { explicit manual_timer(std::string name); void stop_and_print(); + double duration_ms() const; std::string name_; std::chrono::time_point start_; + std::chrono::time_point stop_; }; } // namespace motis::logging diff --git a/base/core/include/motis/core/debug/trip.h b/base/core/include/motis/core/debug/trip.h new file mode 100644 index 000000000..e8087dfa7 --- /dev/null +++ b/base/core/include/motis/core/debug/trip.h @@ -0,0 +1,129 @@ +#pragma once + +#include +#include + +#include "motis/core/schedule/schedule.h" + +#include "motis/core/access/realtime_access.h" +#include "motis/core/access/trip_iterator.h" + +namespace motis::debug { + +struct station { + friend std::ostream& operator<<(std::ostream& out, station const& s) { + auto const& sched = s.sched_; + auto const idx = s.idx_; + auto const& st = sched.stations_[idx]; + out << "{idx=" << idx << ", eva=" << st->eva_nr_ << ", name=" << st->name_ + << "}"; + return out; + } + + schedule const& sched_; + uint32_t idx_; +}; + +struct trip_id { + friend std::ostream& operator<<(std::ostream& out, trip_id const& t) { + auto const& sched = t.sched_; + auto const& id = t.id_; + if (id == full_trip_id{}) { + return out << "{expanded rule service trip}"; + } + out << "{primary={station=" + << station{sched, static_cast(id.primary_.station_id_)} + << ", time=" << format_time(id.primary_.get_time()) + << ", train_nr=" << id.primary_.get_train_nr() + << "}, secondary={station=" + << station{sched, + static_cast(id.secondary_.target_station_id_)} + << ", time=" << format_time(id.secondary_.target_time_) << ", line " + << id.secondary_.line_id_ << "}}"; + return out; + } + + schedule const& sched_; + full_trip_id id_; +}; + +struct trip { + friend std::ostream& operator<<(std::ostream& out, trip const& t) { + auto const& sched = t.sched_; + auto const* trp = t.trp_; + out << "{" + << "ptr=" << trp << ", id=" << trip_id{sched, trp->id_} + << ", edges=" << trp->edges_->size() << ", lcon_idx=" << trp->lcon_idx_ + << ", dbg=" << trp->dbg_.str() << "}"; + return out; + } + + schedule const& sched_; + motis::trip const* trp_; +}; + +struct trip_with_sections { + friend std::ostream& operator<<(std::ostream& out, + trip_with_sections const& t) { + auto const& sched = t.sched_; + auto const* trp = t.trp_; + + auto const print_event = [&](ev_key const& ek) { + auto const di = get_delay_info(sched, ek); + out << " " << (ek.is_departure() ? "dep" : "arr"); + out << "={time=" << format_time(ek.get_time()) + << ", current=" << format_time(di.get_current_time()) + << ", schedule=" << format_time(di.get_schedule_time()) + << ", reason=" << di.get_reason() << ", canceled=" << ek.is_canceled() + << ", station=" << station{sched, ek.get_station_idx()} << "}"; + }; + + out << "trip " << trip{sched, trp} << ":\n"; + auto sec_idx = 0U; + auto last_time = time{0}; + auto last_merged_trips = 0U; + for (auto const& sec : access::sections{trp}) { + auto const kd = sec.ev_key_from(); + auto const ka = sec.ev_key_to(); + + out << " section " << std::setw(2) << sec_idx + << ": route_edge={ptr=" << sec.get_route_edge() + << ", node=" << kd.route_edge_.route_node_ + << ", edge_idx=" << kd.route_edge_.outgoing_edge_idx_ + << "}, lcons=" << sec.get_route_edge()->m_.route_edge_.conns_.size() + << ", route=" << kd.get_node()->route_ + << ", merged_trips=" << sec.lcon().trips_ << " [ "; + for (auto const& mt : *sched.merged_trips_[sec.lcon().trips_]) { + out << cista::ptr_cast(mt) << " "; + } + out << "]"; + if (sec_idx != 0U && last_merged_trips != sec.lcon().trips_) { + out << " (merged trips change)"; + } + out << "\n"; + + print_event(kd); + if (kd.get_time() < last_time) { + out << " !!! time < previous arrival time !!!"; + } + out << "\n"; + + print_event(ka); + if (ka.get_time() < kd.get_time()) { + out << " !!! time < previous departure time !!!"; + } + out << "\n\n"; + + ++sec_idx; + last_time = ka.get_time(); + last_merged_trips = sec.lcon().trips_; + } + out << "\n"; + return out; + } + + schedule const& sched_; + motis::trip const* trp_; +}; + +} // namespace motis::debug diff --git a/base/core/src/logging.cc b/base/core/src/logging.cc index 1f3765080..615b04ee6 100644 --- a/base/core/src/logging.cc +++ b/base/core/src/logging.cc @@ -36,10 +36,14 @@ manual_timer::manual_timer(std::string name) void manual_timer::stop_and_print() { using namespace std::chrono; - auto stop = steady_clock::now(); - double t = duration_cast(stop - start_).count() / 1000.0; + stop_ = steady_clock::now(); LOG(info) << "[" << name_ << "] finished" - << " (" << t << "ms)"; + << " (" << duration_ms() << "ms)"; +} + +double manual_timer::duration_ms() const { + using namespace std::chrono; + return duration_cast(stop_ - start_).count() / 1000.0; } // NOLINTNEXTLINE(cppcoreguidelines-avoid-non-const-global-variables) diff --git a/base/module/src/dispatcher.cc b/base/module/src/dispatcher.cc index 05dc1b37e..9f8aacadc 100644 --- a/base/module/src/dispatcher.cc +++ b/base/module/src/dispatcher.cc @@ -118,6 +118,7 @@ void dispatcher::dispatch(msg_ptr const& msg, callback const& cb, ctx::op_id id, [op = remote_op.value(), msg, cb]() { op(msg, cb); }); return; } else { + LOG(logging::warn) << "target not found: " << id.name; return handle_no_target(msg, cb); } } catch (std::system_error const& e) { diff --git a/modules/paxforecast/include/motis/paxforecast/measures/trip_recommendation.h b/modules/paxforecast/include/motis/paxforecast/measures/trip_recommendation.h index 1f6936fb7..68c5ca319 100644 --- a/modules/paxforecast/include/motis/paxforecast/measures/trip_recommendation.h +++ b/modules/paxforecast/include/motis/paxforecast/measures/trip_recommendation.h @@ -16,7 +16,6 @@ struct trip_recommendation { std::vector planned_trips_; std::vector planned_destinations_; extern_trip recommended_trip_{}; - std::uint32_t interchange_station_{}; }; } // namespace motis::paxforecast::measures diff --git a/modules/paxforecast/src/messages.cc b/modules/paxforecast/src/messages.cc index fe44642cb..f27edd81f 100644 --- a/modules/paxforecast/src/messages.cc +++ b/modules/paxforecast/src/messages.cc @@ -81,8 +81,7 @@ measures::trip_recommendation from_fbs(schedule const& sched, utl::to_vec( *m->planned_destinations(), [&](String const* eva) { return get_station_index(sched, eva); }), - to_extern_trip(m->recommended_trip()), - get_station_index(sched, m->interchange_station())}; + to_extern_trip(m->recommended_trip())}; } measures::trip_load_information from_fbs(schedule const& sched, diff --git a/modules/paxforecast/src/paxforecast.cc b/modules/paxforecast/src/paxforecast.cc index 4accf80fe..851ef6e24 100644 --- a/modules/paxforecast/src/paxforecast.cc +++ b/modules/paxforecast/src/paxforecast.cc @@ -19,6 +19,7 @@ #include "motis/core/common/date_time_util.h" #include "motis/core/common/logging.h" +#include "motis/core/common/raii.h" #include "motis/core/common/timing.h" #include "motis/core/access/service_access.h" #include "motis/core/access/station_access.h" @@ -293,7 +294,10 @@ void paxforecast::on_monitoring_event(msg_ptr const& msg) { auto const current_time = unix_to_motistime(sched.schedule_begin_, sched.system_time_); - utl::verify(current_time != INVALID_TIME, "invalid current system time"); + utl::verify(current_time != INVALID_TIME, + "paxforecast::on_monitoring_event: invalid current system time: " + "system_time={}, schedule_begin={}", + sched.system_time_, sched.schedule_begin_); std::map> combined_groups; std::map pg_event_types; @@ -366,7 +370,7 @@ void paxforecast::on_monitoring_event(msg_ptr const& msg) { { MOTIS_START_TIMING(find_alternatives); - scoped_timer alt_timer{"find alternatives"}; + scoped_timer alt_timer{"on_monitoring_event: find alternatives"}; std::vector> futures; for (auto& cgs : combined_groups) { auto const destination_station_id = cgs.first; @@ -591,19 +595,43 @@ msg_ptr paxforecast::apply_measures(msg_ptr const& msg) { LOG(info) << "apply_measures: measures for " << measures.size() << " time points"; + uv.update_tracker_.start_tracking(uv, sched, + req->include_before_trip_load_info(), + req->include_after_trip_load_info()); + MOTIS_FINALLY([&]() { uv.update_tracker_.stop_tracking(); }); + + // stats + auto measure_time_points = 0ULL; + auto total_measures_applied = 0ULL; + auto total_affected_groups = 0ULL; + auto total_alternative_routings = 0ULL; + auto total_alternatives_found = 0ULL; + // timings (ms) + auto t_rt_updates = 0.; + auto t_get_affected_groups = 0.; + auto t_find_alternatives = 0.; + auto t_add_alternatives_to_graph = 0.; + auto t_behavior_simulation = 0.; + auto t_update_groups = 0.; + auto t_update_tracker = 0.; + // simulate passenger behavior with measures for (auto const& [t, ms] : measures) { scoped_timer measure_timer{"measure"}; + ++measure_time_points; + total_measures_applied += ms.size(); auto const contains_rt_updates = std::any_of(begin(ms), end(ms), [](auto const& m) { return std::holds_alternative(m); }); LOG(info) << "apply_measures @" << format_time(t) - << " [contains_rt_updates=" << contains_rt_updates << "]"; + << " [contains_rt_updates=" << contains_rt_updates + << "], system_time=" << sched.system_time_ + << ", schedule_begin=" << sched.schedule_begin_; if (contains_rt_updates) { - scoped_timer rt_timer{"applying rt updates"}; + manual_timer rt_timer{"applying rt updates"}; auto rt_lock = lock_resources({{uv.schedule_res_id_, ctx::access_t::WRITE}}); message_creator mc; @@ -615,12 +643,15 @@ msg_ptr paxforecast::apply_measures(msg_ptr const& msg) { mc, rtum.type_, mc.CreateString(rtum.content_))); } } + // TODO(pablo): check for errors? -> ri basis parser should throw errors mc.create_and_finish( MsgContent_RISApplyRequest, CreateRISApplyRequest(mc, uv.schedule_res_id_, mc.CreateVector(rims)) .Union(), "/ris/apply"); motis_call(make_msg(mc))->val(); + rt_timer.stop_and_print(); + t_rt_updates += rt_timer.duration_ms(); } auto const loc_time = t + req->preparation_time(); @@ -628,7 +659,9 @@ msg_ptr paxforecast::apply_measures(msg_ptr const& msg) { auto const affected_groups = measures::get_affected_groups(sched, uv, loc_time, ms); get_affected_groups_timer.stop_and_print(); + t_get_affected_groups += get_affected_groups_timer.duration_ms(); + total_affected_groups += affected_groups.measures_.size(); LOG(info) << "affected groups: " << affected_groups.measures_.size(); // combine groups by (localization, remaining planned journey) @@ -649,7 +682,7 @@ msg_ptr paxforecast::apply_measures(msg_ptr const& msg) { LOG(info) << "combined: " << combined.size(); - manual_timer alternatives_timer{"find alternatives"}; + manual_timer alternatives_timer{"apply_measures: find alternatives"}; std::vector> futures; for (auto& ce : combined) { auto const& loc = ce.first.first; @@ -673,16 +706,21 @@ msg_ptr paxforecast::apply_measures(msg_ptr const& msg) { ctx::await_all(futures); routing_cache_.sync(); alternatives_timer.stop_and_print(); + t_find_alternatives += alternatives_timer.duration_ms(); + total_alternative_routings += combined.size(); { - scoped_timer alt_trips_timer{"add alternatives to graph"}; + manual_timer alt_trips_timer{"add alternatives to graph"}; for (auto& [grp_key, cpg] : combined) { + total_alternatives_found += cpg.alternatives_.size(); for (auto const& alt : cpg.alternatives_) { for (auto const& leg : alt.compact_journey_.legs_) { get_or_add_trip(sched, caps, uv, leg.trip_idx_); } } } + alt_trips_timer.stop_and_print(); + t_add_alternatives_to_graph += alt_trips_timer.duration_ms(); } manual_timer sim_timer{"passenger behavior simulation"}; @@ -690,14 +728,33 @@ msg_ptr paxforecast::apply_measures(msg_ptr const& msg) { auto const sim_result = simulate_behavior(sched, caps, uv, combined, pb.pb_); sim_timer.stop_and_print(); + t_behavior_simulation += sim_timer.duration_ms(); manual_timer update_groups_timer{"update groups"}; tick_statistics tick_stats; update_tracked_groups(sched, uv, sim_result, {}, tick_stats); update_groups_timer.stop_and_print(); + t_update_groups += update_groups_timer.duration_ms(); } - return make_success_msg(); + manual_timer update_tracker_timer{"update tracker"}; + auto [mc, fb_updates] = uv.update_tracker_.finish_updates(); + update_tracker_timer.stop_and_print(); + t_update_tracker = update_tracker_timer.duration_ms(); + + mc.create_and_finish( + MsgContent_PaxForecastApplyMeasuresResponse, + CreatePaxForecastApplyMeasuresResponse( + mc, + CreatePaxForecastApplyMeasuresStatistics( + mc, measure_time_points, total_measures_applied, + total_affected_groups, total_alternative_routings, + total_alternatives_found, t_rt_updates, t_get_affected_groups, + t_find_alternatives, t_add_alternatives_to_graph, + t_behavior_simulation, t_update_groups, t_update_tracker), + fb_updates) + .Union()); + return make_msg(mc); } } // namespace motis::paxforecast diff --git a/modules/paxmon/include/motis/paxmon/graph_access.h b/modules/paxmon/include/motis/paxmon/graph_access.h index 0c88f3c28..f04433e7a 100644 --- a/modules/paxmon/include/motis/paxmon/graph_access.h +++ b/modules/paxmon/include/motis/paxmon/graph_access.h @@ -27,6 +27,8 @@ trip_data_index get_or_add_trip(schedule const& sched, capacity_maps const& caps, universe& uv, extern_trip const& et); +trip_data_index get_trip(universe const& uv, trip_idx_t trip_idx); + void update_event_times(schedule const& sched, universe& uv, motis::rt::RtDelayUpdate const* du, std::vector& updated_interchange_edges); diff --git a/modules/paxmon/include/motis/paxmon/multiverse.h b/modules/paxmon/include/motis/paxmon/multiverse.h index f0b8f982b..708a16099 100644 --- a/modules/paxmon/include/motis/paxmon/multiverse.h +++ b/modules/paxmon/include/motis/paxmon/multiverse.h @@ -44,11 +44,12 @@ struct multiverse { universe_id const id, ctx::access_t const universe_access = ctx::access_t::READ, ctx::access_t const schedule_access = ctx::access_t::READ) { - std::lock_guard lock{mutex_}; + std::unique_lock lock{mutex_}; if (auto const it = universe_res_map_.find(id); it != end(universe_res_map_)) { auto const uv_res_id = it->second; auto const schedule_res_id = schedule_res_map_.at(id); + lock.unlock(); auto res_lock = mod_.lock_resources( {{uv_res_id, universe_access}, {schedule_res_id, schedule_access}}); auto const& sched = diff --git a/modules/paxmon/include/motis/paxmon/statistics.h b/modules/paxmon/include/motis/paxmon/statistics.h index 314cc8558..b6fc1f948 100644 --- a/modules/paxmon/include/motis/paxmon/statistics.h +++ b/modules/paxmon/include/motis/paxmon/statistics.h @@ -85,6 +85,7 @@ struct graph_statistics { std::uint64_t interchange_edges_{}; std::uint64_t wait_edges_{}; std::uint64_t through_edges_{}; + std::uint64_t disabled_edges_{}; std::uint64_t canceled_edges_{}; std::uint64_t broken_edges_{}; std::uint64_t trips_{}; diff --git a/modules/paxmon/include/motis/paxmon/universe.h b/modules/paxmon/include/motis/paxmon/universe.h index f5974d86a..1d3c70771 100644 --- a/modules/paxmon/include/motis/paxmon/universe.h +++ b/modules/paxmon/include/motis/paxmon/universe.h @@ -30,6 +30,7 @@ #include "motis/paxmon/rt_update_context.h" #include "motis/paxmon/statistics.h" #include "motis/paxmon/trip_data_container.h" +#include "motis/paxmon/update_tracker.h" namespace motis::paxmon { @@ -74,7 +75,13 @@ struct event_node { std::uint32_t station_{0}; }; -enum class edge_type : std::uint8_t { TRIP, INTERCHANGE, WAIT, THROUGH }; +enum class edge_type : std::uint8_t { + TRIP, + INTERCHANGE, + WAIT, + THROUGH, + DISABLED +}; inline std::ostream& operator<<(std::ostream& out, edge_type const et) { switch (et) { @@ -82,17 +89,18 @@ inline std::ostream& operator<<(std::ostream& out, edge_type const et) { case edge_type::INTERCHANGE: return out << "INTERCHANGE"; case edge_type::WAIT: return out << "WAIT"; case edge_type::THROUGH: return out << "THROUGH"; + case edge_type::DISABLED: return out << "DISABLED"; } return out; } struct edge { inline bool is_valid(universe const& u) const { - return from(u)->is_valid() && to(u)->is_valid(); + return !is_disabled() && from(u)->is_valid() && to(u)->is_valid(); } inline bool is_canceled(universe const& u) const { - return from(u)->is_canceled() || to(u)->is_canceled(); + return is_disabled() || from(u)->is_canceled() || to(u)->is_canceled(); } inline bool is_trip() const { return type() == edge_type::TRIP; } @@ -103,6 +111,8 @@ struct edge { inline bool is_wait() const { return type() == edge_type::WAIT; } + inline bool is_disabled() const { return type() == edge_type::DISABLED; } + event_node const* from(universe const&) const; event_node* from(universe&) const; @@ -175,6 +185,7 @@ struct universe { system_statistics system_stats_; tick_statistics tick_stats_; tick_statistics last_tick_stats_; + update_tracker update_tracker_; }; } // namespace motis::paxmon diff --git a/modules/paxmon/include/motis/paxmon/update_tracker.h b/modules/paxmon/include/motis/paxmon/update_tracker.h new file mode 100644 index 000000000..208050b13 --- /dev/null +++ b/modules/paxmon/include/motis/paxmon/update_tracker.h @@ -0,0 +1,44 @@ +#pragma once + +#include +#include + +#include "motis/core/schedule/schedule.h" +#include "motis/module/message.h" + +#include "motis/paxmon/passenger_group.h" + +namespace motis::paxmon { + +struct universe; + +struct update_tracker { + update_tracker(); + update_tracker(update_tracker const&); + update_tracker(update_tracker&&) noexcept; + ~update_tracker(); + + update_tracker& operator=(update_tracker const&); + update_tracker& operator=(update_tracker&&) noexcept; + + void start_tracking(universe const&, schedule const&, + bool include_before_trip_load_info, + bool include_after_trip_load_info); + std::pair> + finish_updates(); + void stop_tracking(); + bool is_tracking() const; + + void before_group_added(passenger_group const*); + void before_group_reused(passenger_group const*); + void after_group_reused(passenger_group const*); + void before_group_removed(passenger_group const*); + void before_trip_rerouted(trip const*); + +private: + struct impl; + std::unique_ptr impl_; +}; + +} // namespace motis::paxmon diff --git a/modules/paxmon/src/api/add_groups.cc b/modules/paxmon/src/api/add_groups.cc index 09a34d830..f08474d1e 100644 --- a/modules/paxmon/src/api/add_groups.cc +++ b/modules/paxmon/src/api/add_groups.cc @@ -46,15 +46,18 @@ msg_ptr add_groups(paxmon_data& data, bool const allow_reuse, if (existing_pg != nullptr && existing_pg->valid() && existing_pg->compact_planned_journey_ == input_pg.compact_planned_journey_) { + uv.update_tracker_.before_group_reused(existing_pg); existing_pg->probability_ = std::min( 1.F, existing_pg->probability_ + input_pg.probability_); ++reused_groups; + uv.update_tracker_.after_group_reused(existing_pg); return existing_pg; } } } } auto pg = uv.passenger_groups_.add(std::move(input_pg)); + uv.update_tracker_.before_group_added(pg); add_passenger_group_to_graph(sched, data.capacity_maps_, uv, *pg); return pg; }); diff --git a/modules/paxmon/src/api/filter_trips.cc b/modules/paxmon/src/api/filter_trips.cc index 82edcb153..a4ef699ad 100644 --- a/modules/paxmon/src/api/filter_trips.cc +++ b/modules/paxmon/src/api/filter_trips.cc @@ -1,10 +1,13 @@ #include "motis/paxmon/api/filter_trips.h" +#include +#include +#include + #include "utl/to_vec.h" #include "utl/verify.h" #include "motis/core/access/trip_access.h" -#include "motis/hash_set.h" #include "motis/paxmon/get_load.h" #include "motis/paxmon/get_universe.h" @@ -15,6 +18,26 @@ using namespace motis::paxmon; namespace motis::paxmon::api { +namespace { + +struct trip_info { + trip_idx_t trip_idx_{}; + time first_departure_{}; + + unsigned section_count_{}; + unsigned critical_sections_{}; + unsigned crowded_sections_{}; + + unsigned max_excess_pax_{}; + unsigned cumulative_excess_pax_{}; + + std::uint16_t max_expected_pax_{}; + + std::vector edge_load_infos_{}; +}; + +} // namespace + msg_ptr filter_trips(paxmon_data& data, msg_ptr const& msg) { auto const req = motis_content(PaxMonFilterTripsRequest, msg); auto const uv_access = get_universe_and_schedule(data, req->universe()); @@ -22,43 +45,141 @@ msg_ptr filter_trips(paxmon_data& data, msg_ptr const& msg) { auto& uv = uv_access.uv_; auto const current_time = unix_to_motistime(sched.schedule_begin_, sched.system_time_); - utl::verify(current_time != INVALID_TIME, "invalid current system time"); - auto const load_factor_threshold = req->load_factor_possibly_ge(); - auto const ignore_past_sections = req->ignore_past_sections(); + auto const ignore_past_sections = + req->ignore_past_sections() && current_time != INVALID_TIME; + auto const include_load_threshold = req->include_load_threshold(); + auto const max_results = req->max_results(); + auto const skip_first = req->skip_first(); + auto const critical_load_threshold = req->critical_load_threshold(); + auto const crowded_load_threshold = req->crowded_load_threshold(); + auto const include_edges = req->include_edges(); - auto critical_sections = 0ULL; - mcd::hash_set selected_trips; + auto total_critical_sections = 0ULL; + std::vector selected_trips; for (auto const& [trp_idx, tdi] : uv.trip_data_.mapping_) { + auto ti = trip_info{trp_idx}; + auto include = false; + for (auto const& ei : uv.trip_data_.edges(tdi)) { auto const* e = ei.get(uv); - if (!e->is_trip() || !e->has_capacity()) { + if (!e->is_trip()) { continue; } - if (ignore_past_sections && e->to(uv)->current_time() < current_time) { + if (ti.first_departure_ == 0) { + ti.first_departure_ = e->from(uv)->schedule_time(); + } + auto const ignore_section = + ignore_past_sections && e->to(uv)->current_time() < current_time; + if (!include_edges && ignore_section) { continue; } - auto const pdf = get_load_pdf(uv.passenger_groups_, - uv.pax_connection_info_.groups_[e->pci_]); + auto const groups = uv.pax_connection_info_.groups_[e->pci_]; + auto const pdf = get_load_pdf(uv.passenger_groups_, groups); auto const cdf = get_cdf(pdf); - if (load_factor_possibly_ge(cdf, e->capacity(), load_factor_threshold)) { - selected_trips.insert(get_trip(sched, trp_idx)); - ++critical_sections; + auto const capacity = e->capacity(); + auto const pax_limits = get_pax_limits(uv.passenger_groups_, groups); + auto const expected_pax = get_expected_load(uv, e->pci_); + if (include_edges) { + ti.edge_load_infos_.emplace_back(edge_load_info{ + e, cdf, false, load_factor_possibly_ge(cdf, capacity, 1.0F), + expected_pax}); + if (ignore_section) { + continue; + } + } + ++ti.section_count_; + ti.max_expected_pax_ = std::max(ti.max_expected_pax_, expected_pax); + if (!e->has_capacity()) { + continue; + } + if (!include && + load_factor_possibly_ge(cdf, capacity, include_load_threshold)) { + include = true; + } + if (load_factor_possibly_ge(cdf, capacity, critical_load_threshold)) { + ++ti.critical_sections_; + ++total_critical_sections; + } else if (load_factor_possibly_ge(cdf, capacity, + crowded_load_threshold)) { + ++ti.crowded_sections_; } + if (pax_limits.max_ > capacity) { + auto const excess_pax = + static_cast(pax_limits.max_ - capacity); + ti.max_excess_pax_ = std::max(ti.max_excess_pax_, excess_pax); + ti.cumulative_excess_pax_ += excess_pax; + } + } + if (include) { + selected_trips.emplace_back(ti); } } + switch (req->sort_by()) { + case PaxMonFilterTripsSortOrder_MostCritical: + std::stable_sort( + begin(selected_trips), end(selected_trips), + [](trip_info const& lhs, trip_info const& rhs) { + return std::tie(lhs.max_excess_pax_, lhs.cumulative_excess_pax_, + lhs.critical_sections_, lhs.crowded_sections_) > + std::tie(rhs.max_excess_pax_, rhs.cumulative_excess_pax_, + rhs.critical_sections_, rhs.crowded_sections_); + }); + break; + case PaxMonFilterTripsSortOrder_FirstDeparture: + std::stable_sort(begin(selected_trips), end(selected_trips), + [](trip_info const& lhs, trip_info const& rhs) { + return lhs.first_departure_ < rhs.first_departure_; + }); + break; + case PaxMonFilterTripsSortOrder_ExpectedPax: + std::stable_sort(begin(selected_trips), end(selected_trips), + [](trip_info const& lhs, trip_info const& rhs) { + return lhs.max_expected_pax_ > rhs.max_expected_pax_; + }); + break; + default: break; + } + + auto const total_matching_trips = selected_trips.size(); + if (skip_first > 0) { + selected_trips.erase( + begin(selected_trips), + std::next(begin(selected_trips), + std::min(static_cast(skip_first), + selected_trips.size()))); + } + + auto remaining_trips = 0ULL; + if (max_results != 0 && selected_trips.size() > max_results) { + remaining_trips = selected_trips.size() - max_results; + selected_trips.resize(max_results); + } + message_creator mc; - auto const selected_tsis = utl::to_vec(selected_trips, [&](trip const* trp) { - return to_fbs_trip_service_info(mc, sched, trp); - }); - - mc.create_and_finish(MsgContent_PaxMonFilterTripsResponse, - CreatePaxMonFilterTripsResponse( - mc, selected_trips.size(), critical_sections, - mc.CreateVector(selected_tsis)) - .Union()); + mc.create_and_finish( + MsgContent_PaxMonFilterTripsResponse, + CreatePaxMonFilterTripsResponse( + mc, total_matching_trips, selected_trips.size(), remaining_trips, + total_critical_sections, + mc.CreateVector(utl::to_vec( + selected_trips, + [&](trip_info const& ti) { + return CreatePaxMonFilteredTripInfo( + mc, + to_fbs_trip_service_info(mc, sched, + get_trip(sched, ti.trip_idx_)), + ti.section_count_, ti.critical_sections_, + ti.crowded_sections_, ti.max_excess_pax_, + ti.cumulative_excess_pax_, ti.max_expected_pax_, + mc.CreateVector(utl::to_vec( + ti.edge_load_infos_, [&](edge_load_info const& eli) { + return to_fbs(mc, sched, uv, eli); + }))); + }))) + .Union()); return make_msg(mc); } diff --git a/modules/paxmon/src/api/get_groups_in_trip.cc b/modules/paxmon/src/api/get_groups_in_trip.cc index cdeaa4fa8..b8264f31d 100644 --- a/modules/paxmon/src/api/get_groups_in_trip.cc +++ b/modules/paxmon/src/api/get_groups_in_trip.cc @@ -20,6 +20,40 @@ using namespace motis::paxmon; namespace motis::paxmon::api { +struct grouped_key { + std::uint32_t group_station_{}; + std::uint32_t entry_station_{}; + time entry_time_{}; + trip const* other_trp_{}; +}; + +std::pair get_group_entry( + passenger_group const* pg, trip_idx_t const ti) { + for (auto const& leg : pg->compact_planned_journey_.legs_) { + if (leg.trip_idx_ == ti) { + return {leg.enter_station_id_, leg.enter_time_}; + } + } + return {0, 0}; +} + +trip const* get_trip_before_entry(schedule const& sched, + passenger_group const* pg, + trip_idx_t const ti) { + for (auto const& [leg_idx, leg] : + utl::enumerate(pg->compact_planned_journey_.legs_)) { + if (leg.trip_idx_ == ti) { + if (leg_idx > 0) { + return get_trip( + sched, pg->compact_planned_journey_.legs_[leg_idx - 1].trip_idx_); + } else { + break; + } + } + } + return nullptr; +} + motis::module::msg_ptr get_groups_in_trip(paxmon_data& data, motis::module::msg_ptr const& msg) { auto const req = motis_content(PaxMonGetGroupsInTripRequest, msg); @@ -33,25 +67,38 @@ motis::module::msg_ptr get_groups_in_trip(paxmon_data& data, auto const include_group_infos = req->include_group_infos(); auto const get_key = [&](passenger_group const* pg, trip const* other_trip) { - std::uint32_t station = 0U; - trip const* trp = grp_by_other_trip ? other_trip : nullptr; + auto key = grouped_key{}; + if (grp_by_other_trip) { + key.other_trp_ = other_trip; + } auto const& cj = pg->compact_planned_journey_; switch (grp_by_station) { - case PaxMonGroupByStation_First: station = cj.start_station_id(); break; + case PaxMonGroupByStation_First: + key.group_station_ = cj.start_station_id(); + break; case PaxMonGroupByStation_Last: - station = cj.destination_station_id(); + key.group_station_ = cj.destination_station_id(); break; case PaxMonGroupByStation_FirstLongDistance: - station = get_first_long_distance_station_id(uv, cj).value_or( - cj.start_station_id()); + key.group_station_ = + get_first_long_distance_station_id(uv, cj).value_or( + cj.start_station_id()); break; case PaxMonGroupByStation_LastLongDistance: - station = get_last_long_distance_station_id(uv, cj).value_or( + key.group_station_ = get_last_long_distance_station_id(uv, cj).value_or( cj.destination_station_id()); break; + case PaxMonGroupByStation_EntryAndLast: { + key.group_station_ = cj.destination_station_id(); + auto const [entry_station, entry_time] = + get_group_entry(pg, trp->trip_idx_); + key.entry_station_ = entry_station; + key.entry_time_ = entry_time; + break; + } default: break; } - return mcd::pair{station, trp}; + return key; }; auto const group_enters_here = @@ -105,7 +152,7 @@ motis::module::msg_ptr get_groups_in_trip(paxmon_data& data, float avg_pax_{}; }; - mcd::hash_map, grouped_pgs_t> grouped; + mcd::hash_map grouped; std::vector> grouped_pgs_vec; for (auto const pgi : uv.pax_connection_info_.groups_[e->pci_]) { @@ -131,6 +178,11 @@ motis::module::msg_ptr get_groups_in_trip(paxmon_data& data, } } + if (grp_by_other_trip && + grp_by_station == PaxMonGroupByStation_EntryAndLast) { + other_trp = get_trip_before_entry(sched, pg, trp->trip_idx_); + } + auto const key = get_key(pg, other_trp); auto& gg = grouped[key]; gg.groups_.emplace_back(pg); @@ -147,26 +199,33 @@ motis::module::msg_ptr get_groups_in_trip(paxmon_data& data, [&](auto const& a, auto const& b) { return grouped[a].max_pax_ > grouped[b].max_pax_; }); - for (auto const key : sorted_keys) { - auto const& [station_id, other_trp] = key; + for (auto const& key : sorted_keys) { auto const& gbd = grouped[key]; auto const grouped_by_station = - station_id != 0 + key.group_station_ != 0 ? mc.CreateVector(std::vector>{ - to_fbs(mc, *sched.stations_[station_id])}) + to_fbs(mc, *sched.stations_[key.group_station_])}) : mc.CreateVector( static_cast*>(nullptr), 0); auto const grouped_by_trip = - other_trp != nullptr + key.other_trp_ != nullptr ? mc.CreateVector( std::vector>{ - to_fbs_trip_service_info(mc, sched, other_trp)}) + to_fbs_trip_service_info(mc, sched, key.other_trp_)}) : mc.CreateVector( static_cast*>(nullptr), 0); + auto const entry_station = + key.entry_station_ != 0 + ? mc.CreateVector(std::vector>{ + to_fbs(mc, *sched.stations_[key.entry_station_])}) + : mc.CreateVector( + static_cast*>(nullptr), 0); + auto const entry_time = + key.entry_time_ != 0 ? motis_to_unixtime(sched, key.entry_time_) : 0; grouped_pgs_vec.emplace_back(CreateGroupedPassengerGroups( - mc, grouped_by_station, grouped_by_trip, + mc, grouped_by_station, grouped_by_trip, entry_station, entry_time, CreatePaxMonCombinedGroups( mc, mc.CreateVectorOfStructs( diff --git a/modules/paxmon/src/api/get_interchanges.cc b/modules/paxmon/src/api/get_interchanges.cc index 41e616649..94ad5afec 100644 --- a/modules/paxmon/src/api/get_interchanges.cc +++ b/modules/paxmon/src/api/get_interchanges.cc @@ -70,7 +70,8 @@ msg_ptr get_interchanges(paxmon_data& data, msg_ptr const& msg) { res.emplace_back(CreatePaxMonTripStopInfo( mc, motis_to_unixtime(sched, ev->schedule_time()), motis_to_unixtime(sched, ev->current_time()), - mc.CreateVector(fbs_trips))); + mc.CreateVector(fbs_trips), + to_fbs(mc, *sched.stations_.at(ev->station_idx())))); } return mc.CreateVector(res); }; diff --git a/modules/paxmon/src/api/remove_groups.cc b/modules/paxmon/src/api/remove_groups.cc index 6f4f688d6..6b3af9459 100644 --- a/modules/paxmon/src/api/remove_groups.cc +++ b/modules/paxmon/src/api/remove_groups.cc @@ -33,6 +33,7 @@ msg_ptr remove_groups(paxmon_data& data, bool const keep_group_history, continue; } ++removed_groups; + uv.update_tracker_.before_group_removed(pg); remove_passenger_group_from_graph(uv, pg); if (!keep_group_history) { uv.passenger_groups_.release(pg->id_); diff --git a/modules/paxmon/src/checks.cc b/modules/paxmon/src/checks.cc index 19c3987cb..312fb11df 100644 --- a/modules/paxmon/src/checks.cc +++ b/modules/paxmon/src/checks.cc @@ -10,8 +10,10 @@ #include "motis/core/access/realtime_access.h" #include "motis/core/access/trip_access.h" +#include "motis/core/debug/trip.h" #include "motis/paxmon/debug.h" +#include "motis/paxmon/service_info.h" namespace motis::paxmon { @@ -49,6 +51,77 @@ bool check_graph_integrity(universe const& uv, schedule const& sched) { } } } + + if (!n.is_enter_exit_node() && n.is_valid()) { + auto const in_trip_edges = + std::count_if(begin(n.incoming_edges(uv)), end(n.incoming_edges(uv)), + [&](edge const& e) { + return e.is_trip() && e.is_valid(uv) && + !e.from(uv)->is_enter_exit_node(); + }); + auto const out_trip_edges = + std::count_if(begin(n.outgoing_edges(uv)), end(n.outgoing_edges(uv)), + [&](edge const& e) { + return e.is_trip() && e.is_valid(uv) && + !e.to(uv)->is_enter_exit_node(); + }); + if (in_trip_edges > 1 || out_trip_edges > 1) { + auto const& st = sched.stations_.at(n.station_idx()); + std::cout << "!! " << in_trip_edges << " incoming + " << out_trip_edges + << " outgoing trip edges at station " << st->eva_nr_ << " (" + << st->name_ << ")\n"; + ok = false; + + std::cout << " incoming edges:\n"; + for (auto const& in_edge : n.incoming_edges(uv)) { + auto const& from_station = + sched.stations_.at(in_edge.from(uv)->station_idx()); + std::cout << " " << in_edge.type() + << " (valid=" << in_edge.is_valid(uv) + << ", canceled=" << in_edge.is_canceled(uv) + << "), merged_trips_idx=" << in_edge.get_merged_trips_idx() + << " => " << in_edge.get_trips(sched).size() + << " trips, from=" << from_station->eva_nr_ << " " + << from_station->name_ + << ", capacity=" << in_edge.capacity() << "\n"; + for (auto const& trp : in_edge.get_trips(sched)) { + auto const service_infos = get_service_infos(sched, trp); + std::cout << " " << debug::trip{sched, trp} + << "\n services:"; + for (auto const& [si, count] : service_infos) { + std::cout << " " << count << "x " << si.category_ << " " + << si.train_nr_ << ", line=" << si.line_ + << ", name=" << si.name_; + } + std::cout << "\n"; + } + } + std::cout << " outgoing edges:\n"; + for (auto const& out_edge : n.outgoing_edges(uv)) { + auto const& to_station = + sched.stations_.at(out_edge.to(uv)->station_idx()); + std::cout << " " << out_edge.type() + << " (valid=" << out_edge.is_valid(uv) + << ", canceled=" << out_edge.is_canceled(uv) + << "), merged_trips_idx=" << out_edge.get_merged_trips_idx() + << " => " << out_edge.get_trips(sched).size() + << " trips, to=" << to_station->eva_nr_ << " " + << to_station->name_ << ", capacity=" << out_edge.capacity() + << "\n"; + for (auto const& trp : out_edge.get_trips(sched)) { + auto const service_infos = get_service_infos(sched, trp); + std::cout << " " << debug::trip{sched, trp} + << "\n services:"; + for (auto const& [si, count] : service_infos) { + std::cout << " " << count << "x " << si.category_ << " " + << si.train_nr_ << ", line=" << si.line_ + << ", name=" << si.name_; + } + std::cout << "\n"; + } + } + } + } } for (auto const& [trp_idx, tdi] : uv.trip_data_.mapping_) { @@ -78,6 +151,9 @@ bool check_graph_integrity(universe const& uv, schedule const& sched) { } } + if (!ok) { + std::cout << "check_graph_integrity failed" << std::endl; + } return ok; } diff --git a/modules/paxmon/src/get_load.cc b/modules/paxmon/src/get_load.cc index b63b68a27..844a38892 100644 --- a/modules/paxmon/src/get_load.cc +++ b/modules/paxmon/src/get_load.cc @@ -102,7 +102,7 @@ pax_pdf get_load_pdf_base(passenger_group_container const& pgc, pdf.data_[limits.min_] = 1.0F; for (auto const grp_id : groups) { auto const* grp = pgc[grp_id]; - if (grp->probability_ != 1.0F) { + if (grp->probability_ != 1.0F && grp->probability_ != 0.0F) { convolve_base(pdf, grp->passengers_, grp->probability_); } } @@ -164,7 +164,7 @@ pax_pdf get_load_pdf_avx(passenger_group_container const& pgc, for (auto const grp_id : groups) { auto const* grp = pgc[grp_id]; - if (grp->probability_ != 1.0F) { + if (grp->probability_ != 1.0F && grp->probability_ != 0.0F) { convolve_avx(pdf, grp->passengers_, grp->probability_, limits, buf); } } diff --git a/modules/paxmon/src/graph_access.cc b/modules/paxmon/src/graph_access.cc index bcdbd7010..c4745f4d1 100644 --- a/modules/paxmon/src/graph_access.cc +++ b/modules/paxmon/src/graph_access.cc @@ -182,7 +182,7 @@ trip_data_index add_trip(schedule const& sched, capacity_maps const& caps, trip_data_index get_or_add_trip(schedule const& sched, capacity_maps const& caps, universe& uv, - trip_idx_t trip_idx) { + trip_idx_t const trip_idx) { if (auto const idx = uv.trip_data_.find_index(trip_idx); idx != INVALID_TRIP_DATA_INDEX) { return idx; @@ -208,6 +208,10 @@ trip_data_index get_or_add_trip(schedule const& sched, return get_or_add_trip(sched, caps, uv, get_trip(sched, et)); } +trip_data_index get_trip(universe const& uv, trip_idx_t const trip_idx) { + return uv.trip_data_.find_index(trip_idx); +} + void add_interchange_edges(event_node* evn, std::vector& updated_interchange_edges, universe& uv) { @@ -280,6 +284,7 @@ void update_trip_route(schedule const& sched, capacity_maps const& caps, return; } ++uv.system_stats_.update_trip_route_trip_edges_found_; + uv.update_tracker_.before_trip_rerouted(trp); auto const current_teks = to_trip_ev_keys(tdi, uv); auto const new_teks = to_trip_ev_keys(sched, *ru->new_route()); diff --git a/modules/paxmon/src/messages.cc b/modules/paxmon/src/messages.cc index 17e453983..d951bb1e4 100644 --- a/modules/paxmon/src/messages.cc +++ b/modules/paxmon/src/messages.cc @@ -202,11 +202,14 @@ Offset> cdf_to_fbs(FlatBufferBuilder& fbb, pax_cdf const& cdf) { auto entries = std::vector{}; entries.reserve(cdf.data_.size()); - auto last_prob = 0.0F; - for (auto const& [pax, prob] : utl::enumerate(cdf.data_)) { - if (prob != last_prob) { - entries.emplace_back(static_cast(pax), prob); - last_prob = prob; + if (!cdf.data_.empty()) { + auto last_prob = 0.0F; + auto const last_index = cdf.data_.size() - 1; + for (auto const& [pax, prob] : utl::enumerate(cdf.data_)) { + if (prob != last_prob || pax == last_index) { + entries.emplace_back(static_cast(pax), prob); + last_prob = prob; + } } } return fbb.CreateVectorOfStructs(entries); diff --git a/modules/paxmon/src/paxmon.cc b/modules/paxmon/src/paxmon.cc index 5322315c6..a776699dc 100644 --- a/modules/paxmon/src/paxmon.cc +++ b/modules/paxmon/src/paxmon.cc @@ -600,8 +600,7 @@ void paxmon::rt_updates_applied(universe& uv, schedule const& sched) { LOG(info) << "affected by last rt update: " << uv.rt_update_ctx_.groups_affected_by_last_update_.size() - << " passenger groups, " - << " passengers"; + << " passenger groups"; uv.rt_update_ctx_.groups_affected_by_last_update_.clear(); LOG(info) << "passenger groups: " << uv.tick_stats_.ok_groups_ << " ok, " diff --git a/modules/paxmon/src/print_stats.cc b/modules/paxmon/src/print_stats.cc index c9e70befb..6391edc72 100644 --- a/modules/paxmon/src/print_stats.cc +++ b/modules/paxmon/src/print_stats.cc @@ -16,10 +16,10 @@ void print_graph_stats(graph_statistics const& graph_stats) { graph_stats.nodes_, graph_stats.canceled_nodes_); LOG(info) << fmt::format( "{:L} graph edges ({:L} canceled): {:L} trip + {:L} interchange + {:L} " - "wait + {:L} through", + "wait + {:L} through + {:L} disabled", graph_stats.edges_, graph_stats.canceled_edges_, graph_stats.trip_edges_, graph_stats.interchange_edges_, graph_stats.wait_edges_, - graph_stats.through_edges_); + graph_stats.through_edges_, graph_stats.disabled_edges_); LOG(info) << fmt::format("{:L} stations", graph_stats.stations_); LOG(info) << fmt::format("{:L} trips", graph_stats.trips_); LOG(info) << fmt::format("over capacity: {:L} trips, {:L} edges", diff --git a/modules/paxmon/src/reroute.cc b/modules/paxmon/src/reroute.cc index a348309e5..060d3afa5 100644 --- a/modules/paxmon/src/reroute.cc +++ b/modules/paxmon/src/reroute.cc @@ -97,6 +97,42 @@ edge* get_connecting_edge(event_node const* from, event_node const* to, return nullptr; } +// the following functions are split because otherwise clang-tidy complains +// that begin(from->outgoing_edges(uv)) allegedly returns nullptr + +void disable_outgoing_edges(universe& uv, event_node* from, + edge const* except) { + for (auto& e : from->outgoing_edges(uv)) { + if (&e != except && (e.is_trip() || e.is_wait())) { + e.type_ = edge_type::DISABLED; + } + } +} + +void disable_outgoing_edges(universe& uv, event_node* from) { + for (auto& e : from->outgoing_edges(uv)) { + if (e.is_trip() || e.is_wait()) { + e.type_ = edge_type::DISABLED; + } + } +} + +void disable_incoming_edges(universe& uv, event_node* to, edge const* except) { + for (auto& e : to->incoming_edges(uv)) { + if (&e != except && (e.is_trip() || e.is_wait())) { + e.type_ = edge_type::DISABLED; + } + } +} + +void disable_incoming_edges(universe& uv, event_node* to) { + for (auto& e : to->incoming_edges(uv)) { + if (e.is_trip() || e.is_wait()) { + e.type_ = edge_type::DISABLED; + } + } +} + edge* connect_nodes(event_node* from, event_node* to, merged_trips_idx merged_trips, std::uint16_t encoded_capacity, universe& uv) { @@ -107,11 +143,18 @@ edge* connect_nodes(event_node* from, event_node* to, (from->type_ == event_type::DEP && to->type_ == event_type::ARR) || (from->type_ == event_type::ARR && to->type_ == event_type::DEP), "invalid event sequence"); + auto const type = + from->type_ == event_type::DEP ? edge_type::TRIP : edge_type::WAIT; if (auto e = get_connecting_edge(from, to, uv); e != nullptr) { + if (e->is_disabled()) { + e->type_ = type; + } + disable_outgoing_edges(uv, from, e); + disable_incoming_edges(uv, to, e); return e; } - auto const type = - from->type_ == event_type::DEP ? edge_type::TRIP : edge_type::WAIT; + disable_outgoing_edges(uv, from); + disable_incoming_edges(uv, to); auto const cap = from->type_ == event_type::DEP ? encoded_capacity : UNLIMITED_ENCODED_CAPACITY; return add_edge( diff --git a/modules/paxmon/src/statistics.cc b/modules/paxmon/src/statistics.cc index e5e8d66a3..19777e5d5 100644 --- a/modules/paxmon/src/statistics.cc +++ b/modules/paxmon/src/statistics.cc @@ -32,6 +32,7 @@ graph_statistics calc_graph_statistics(schedule const& sched, case edge_type::INTERCHANGE: ++stats.interchange_edges_; break; case edge_type::WAIT: ++stats.wait_edges_; break; case edge_type::THROUGH: ++stats.through_edges_; break; + case edge_type::DISABLED: ++stats.disabled_edges_; break; } if (e.is_canceled(uv)) { ++stats.canceled_edges_; diff --git a/modules/paxmon/src/update_tracker.cc b/modules/paxmon/src/update_tracker.cc new file mode 100644 index 000000000..b2c78644e --- /dev/null +++ b/modules/paxmon/src/update_tracker.cc @@ -0,0 +1,366 @@ +#include "motis/paxmon/update_tracker.h" + +#include +#include +#include +#include +#include + +#include "utl/get_or_create.h" +#include "utl/to_vec.h" +#include "utl/verify.h" + +#include "motis/hash_map.h" +#include "motis/hash_set.h" + +#include "motis/core/access/trip_access.h" + +#include "motis/paxmon/load_info.h" +#include "motis/paxmon/messages.h" +#include "motis/paxmon/universe.h" + +using namespace flatbuffers; + +namespace motis::paxmon { + +struct update_tracker::impl { + struct pg_base_info { + data_source source_{}; + std::uint16_t pax_{}; + float probability_{}; + float previous_probability_{}; + }; + + struct critical_trip_info { + int critical_sections_{}; + int max_excess_pax_{}; + int cumulative_excess_pax_{}; + }; + + struct updated_trip_info { + Offset>> before_edges_{}; + mcd::hash_set added_groups_; + mcd::hash_set removed_groups_; + mcd::hash_set reused_groups_; + critical_trip_info before_cti_; + critical_trip_info after_cti_; + int critical_sections_diff_{}; + int max_excess_pax_diff_{}; + int cumulative_excess_pax_diff_{}; + }; + + impl(universe const& uv, schedule const& sched, + bool const include_before_trip_load_info, + bool const include_after_trip_load_info) + : uv_{uv}, + sched_{sched}, + include_before_trip_load_info_{include_before_trip_load_info}, + include_after_trip_load_info_{include_after_trip_load_info} {} + + void before_group_added(passenger_group const* pg) { + store_group_info(pg); + added_groups_.emplace_back(pg->id_); + for (auto& leg : pg->compact_planned_journey_.legs_) { + auto& uti = get_or_create_updated_trip_info(leg.trip_idx_); + uti.added_groups_.insert(pg->id_); + } + } + + void before_group_reused(passenger_group const* pg) { + store_group_info(pg); + reused_groups_.insert(pg->id_); + // TODO(pablo): maybe use pg->edges_ instead + for (auto& leg : pg->compact_planned_journey_.legs_) { + auto& uti = get_or_create_updated_trip_info(leg.trip_idx_); + uti.reused_groups_.insert(pg->id_); + } + } + + void after_group_reused(passenger_group const* pg) { store_group_info(pg); } + + void before_group_removed(passenger_group const* pg) { + store_group_info(pg); + removed_groups_.emplace_back(pg->id_); + // TODO(pablo): maybe use pg->edges_ instead + for (auto& leg : pg->compact_planned_journey_.legs_) { + auto& uti = get_or_create_updated_trip_info(leg.trip_idx_); + uti.removed_groups_.insert(pg->id_); + } + } + + void before_trip_rerouted(trip const* trp) { + get_or_create_updated_trip_info(trp->trip_idx_); + } + + std::pair> + finish_updates() { + finish_trips(); + + auto sorted_trips = utl::to_vec(updated_trip_infos_, [](auto const& entry) { + return std::pair{entry.first, &entry.second}; + }); + + std::sort(begin(sorted_trips), end(sorted_trips), + [](auto const& lhs, auto const& rhs) { + updated_trip_info const* l = lhs.second; + updated_trip_info const* r = rhs.second; + return std::tie(l->max_excess_pax_diff_, + l->cumulative_excess_pax_diff_, + l->critical_sections_diff_, + l->after_cti_.max_excess_pax_, + l->after_cti_.cumulative_excess_pax_, + l->after_cti_.critical_sections_) > + std::tie(r->max_excess_pax_diff_, + r->cumulative_excess_pax_diff_, + r->critical_sections_diff_, + r->after_cti_.max_excess_pax_, + r->after_cti_.cumulative_excess_pax_, + r->after_cti_.critical_sections_); + }); + + auto const fb_updates = CreatePaxMonTrackedUpdates( + mc_, added_groups_.size(), reused_groups_.size(), + removed_groups_.size(), updated_trip_infos_.size(), + mc_.CreateVector(utl::to_vec(sorted_trips, [&](auto& entry) { + return get_fbs_updated_trip(entry.first, *entry.second); + }))); + return {mc_, fb_updates}; + } + +private: + updated_trip_info& get_or_create_updated_trip_info(trip_idx_t const ti) { + return utl::get_or_create(updated_trip_infos_, ti, [&]() { + auto uti = updated_trip_info{}; + auto const tli = calc_trip_load_info(uv_, get_trip(sched_, ti)); + uti.before_edges_ = include_before_trip_load_info_ + ? get_fbs_trip_load_info(tli) + : get_empty_fbs_trip_load_info(); + uti.before_cti_ = get_critical_trip_info(tli); + return uti; + }); + } + + void store_group_info(passenger_group const* pg) { + if (auto it = group_infos_.find(pg->id_); it != end(group_infos_)) { + auto& pgbi = it->second; + pgbi.probability_ = pg->probability_; + } else { + group_infos_[pg->id_] = pg_base_info{pg->source_, pg->passengers_, + pg->probability_, pg->probability_}; + } + } + + void finish_trips() { + for (auto& [ti, uti] : updated_trip_infos_) { + uti.after_cti_ = get_critical_trip_info( + calc_trip_load_info(uv_, get_trip(sched_, ti))); + uti.critical_sections_diff_ = + std::abs(uti.before_cti_.critical_sections_ - + uti.after_cti_.critical_sections_); + uti.max_excess_pax_diff_ = std::abs(uti.before_cti_.max_excess_pax_ - + uti.after_cti_.max_excess_pax_); + uti.cumulative_excess_pax_diff_ = + std::abs(uti.before_cti_.cumulative_excess_pax_ - + uti.after_cti_.cumulative_excess_pax_); + } + } + + static critical_trip_info get_critical_trip_info(trip_load_info const& tli) { + critical_trip_info cti; + cti.critical_sections_ = 0; + cti.cumulative_excess_pax_ = 0; + cti.max_excess_pax_ = 0; + for (auto const& eli : tli.edges_) { + if (!eli.edge_->has_capacity()) { + continue; + } + if (eli.possibly_over_capacity_) { + ++cti.critical_sections_; + } + auto const capacity = eli.edge_->capacity(); + auto const max_pax = eli.forecast_cdf_.data_.size(); + if (max_pax > capacity) { + auto const excess_pax = static_cast(max_pax - capacity); + cti.cumulative_excess_pax_ += excess_pax; + cti.max_excess_pax_ = std::max(cti.max_excess_pax_, excess_pax); + } + } + return cti; + } + + Offset>> get_fbs_trip_load_info( + trip_idx_t const ti) { + return get_fbs_trip_load_info( + calc_trip_load_info(uv_, get_trip(sched_, ti))); + } + + Offset>> get_fbs_trip_load_info( + trip_load_info const& tli) { + return mc_.CreateVector(utl::to_vec(tli.edges_, [&](auto const& eli) { + return to_fbs(mc_, sched_, uv_, eli); + })); + } + + Offset>> get_empty_fbs_trip_load_info() { + return mc_.CreateVector(std::vector>{}); + } + + Offset get_fbs_updated_trip(trip_idx_t const ti, + updated_trip_info const& uti) { + auto const* trp = get_trip(sched_, ti); + auto removed_max_pax = 0U; + auto removed_mean_pax = 0.F; + auto added_max_pax = 0U; + auto added_mean_pax = 0.F; + + mcd::hash_set added_groups; + for (auto const& pgi : uti.added_groups_) { + auto const& pgbi = group_infos_.at(pgi); + added_max_pax += pgbi.pax_; + added_mean_pax += pgbi.probability_ * pgbi.pax_; + added_groups.insert(pgi); + } + for (auto const& pgi : uti.reused_groups_) { + // groups may be added first, then reused later, in that case all + // pax have already been added above + if (added_groups.find(pgi) != end(added_groups)) { + continue; + } + auto const& pgbi = group_infos_.at(pgi); + added_max_pax += pgbi.pax_; + added_mean_pax += + (pgbi.probability_ - pgbi.previous_probability_) * pgbi.pax_; + added_groups.insert(pgi); + } + for (auto const& pgi : uti.removed_groups_) { + auto const& pgbi = group_infos_.at(pgi); + removed_max_pax += pgbi.pax_; + removed_mean_pax += pgbi.probability_ * pgbi.pax_; + } + + return CreatePaxMonUpdatedTrip( + mc_, to_fbs_trip_service_info(mc_, sched_, trp), removed_max_pax, + removed_mean_pax, added_max_pax, added_mean_pax, + get_fbs_critical_trip_info(uti.before_cti_), + get_fbs_critical_trip_info(uti.after_cti_), + mc_.CreateVectorOfStructs( + utl::to_vec(uti.removed_groups_, + [&](passenger_group_index const pgi) { + return get_fbs_group_base_info(pgi); + })), + mc_.CreateVectorOfStructs( + utl::to_vec(uti.added_groups_, + [&](passenger_group_index const pgi) { + return get_fbs_group_base_info(pgi); + })), + mc_.CreateVectorOfStructs( + utl::to_vec(uti.reused_groups_, + [&](passenger_group_index const pgi) { + return get_fbs_reused_group_base_info(pgi); + })), + uti.before_edges_, + include_after_trip_load_info_ ? get_fbs_trip_load_info(ti) + : get_empty_fbs_trip_load_info()); + } + + PaxMonGroupBaseInfo get_fbs_group_base_info(passenger_group_index const pgi) { + auto const& pgbi = group_infos_.at(pgi); + return PaxMonGroupBaseInfo{pgi, pgbi.pax_, pgbi.probability_}; + } + + PaxMonReusedGroupBaseInfo get_fbs_reused_group_base_info( + passenger_group_index const pgi) { + auto const& pgbi = group_infos_.at(pgi); + return PaxMonReusedGroupBaseInfo{pgi, pgbi.pax_, pgbi.probability_, + pgbi.previous_probability_}; + } + + Offset get_fbs_critical_trip_info( + critical_trip_info const& cti) { + return CreatePaxMonCriticalTripInfo(mc_, cti.critical_sections_, + cti.max_excess_pax_, + cti.cumulative_excess_pax_); + } + + universe const& uv_; + schedule const& sched_; + motis::module::message_creator mc_; + bool include_before_trip_load_info_{}; + bool include_after_trip_load_info_{}; + + mcd::hash_map group_infos_; + std::vector added_groups_; + mcd::hash_set reused_groups_; + std::vector removed_groups_; + + mcd::hash_map updated_trip_infos_; +}; + +update_tracker::update_tracker() = default; + +update_tracker::update_tracker(update_tracker const&) {} + +update_tracker::update_tracker(update_tracker&& o) noexcept + : impl_{std::exchange(o.impl_, nullptr)} {} + +update_tracker::~update_tracker() = default; + +// NOLINTNEXTLINE(bugprone-unhandled-self-assignment, cert-oop54-cpp) +update_tracker& update_tracker::operator=(update_tracker const&) { + return *this; +} + +update_tracker& update_tracker::operator=(update_tracker&& o) noexcept { + std::swap(impl_, o.impl_); + return *this; +} + +void update_tracker::start_tracking(universe const& uv, schedule const& sched, + bool const include_before_trip_load_info, + bool const include_after_trip_load_info) { + utl::verify(!is_tracking(), "paxmon::update_tracker: already tracking"); + impl_ = std::make_unique(uv, sched, include_before_trip_load_info, + include_after_trip_load_info); +} + +std::pair> +update_tracker::finish_updates() { + utl::verify(is_tracking(), "paxmon::update_tracker: not tracking"); + return impl_->finish_updates(); +} + +void update_tracker::stop_tracking() { impl_.reset(); } + +bool update_tracker::is_tracking() const { return impl_ != nullptr; } + +void update_tracker::before_group_added(passenger_group const* pg) { + if (impl_) { + impl_->before_group_added(pg); + } +} + +void update_tracker::before_group_reused(passenger_group const* pg) { + if (impl_) { + impl_->before_group_reused(pg); + } +} + +void update_tracker::after_group_reused(passenger_group const* pg) { + if (impl_) { + impl_->after_group_reused(pg); + } +} + +void update_tracker::before_group_removed(passenger_group const* pg) { + if (impl_) { + impl_->before_group_removed(pg); + } +} + +void update_tracker::before_trip_rerouted(trip const* trp) { + if (impl_) { + impl_->before_trip_rerouted(trp); + } +} + +} // namespace motis::paxmon diff --git a/modules/paxmon/test/get_load_test.cc b/modules/paxmon/test/get_load_test.cc index 7795bbb8c..7944055e1 100644 --- a/modules/paxmon/test/get_load_test.cc +++ b/modules/paxmon/test/get_load_test.cc @@ -183,7 +183,7 @@ TEST(paxmon_get_load, two_groups) { EXPECT_FALSE(load_factor_possibly_ge(lf_pdf, 2.0F)); for (auto const& cdf : {get_cdf(pdf), get_load_cdf(pgc, pcig)}) { - EXPECT_EQ(cdf, (make_cdf({{10, 0.6F}, {30, 1.0F}}))); + EXPECT_EQ(cdf.data_, (make_cdf({{10, 0.6F}, {30, 1.0F}}).data_)); EXPECT_TRUE(load_factor_possibly_ge(cdf, capacity, 0.2F)); EXPECT_TRUE(load_factor_possibly_ge(cdf, capacity, 0.5F)); EXPECT_TRUE(load_factor_possibly_ge(cdf, capacity, 1.0F)); diff --git a/protocol/Message.fbs b/protocol/Message.fbs index c983a3be6..869180f3e 100644 --- a/protocol/Message.fbs +++ b/protocol/Message.fbs @@ -104,6 +104,7 @@ include "paxmon/PaxMonGetInterchangesRequest.fbs"; include "paxmon/PaxMonGetInterchangesResponse.fbs"; include "paxforecast/PaxForecastUpdate.fbs"; include "paxforecast/PaxForecastApplyMeasuresRequest.fbs"; +include "paxforecast/PaxForecastApplyMeasuresResponse.fbs"; include "HTTPMessage.fbs"; @@ -276,7 +277,8 @@ union MsgContent { motis.ris.RISSystemTimeChanged = 125, motis.rt.RtGraphUpdated = 126, motis.lookup.LookupRiBasisRequest = 127, - motis.lookup.LookupRiBasisResponse = 128 + motis.lookup.LookupRiBasisResponse = 128, + motis.paxforecast.PaxForecastApplyMeasuresResponse = 129 } // Destination Examples: diff --git a/protocol/paxforecast/Measures.fbs b/protocol/paxforecast/Measures.fbs index 1f89bc572..303a64057 100644 --- a/protocol/paxforecast/Measures.fbs +++ b/protocol/paxforecast/Measures.fbs @@ -24,7 +24,6 @@ table TripRecommendationMeasure { planned_destinations: [string]; // station ids planned_long_distance_destinations: [string]; // station ids recommended_trip: TripId; - interchange_station: string; // station id } table RtUpdateMeasure { diff --git a/protocol/paxforecast/PaxForecastApplyMeasuresRequest.fbs b/protocol/paxforecast/PaxForecastApplyMeasuresRequest.fbs index 6ae3de116..aa5cdf1a8 100644 --- a/protocol/paxforecast/PaxForecastApplyMeasuresRequest.fbs +++ b/protocol/paxforecast/PaxForecastApplyMeasuresRequest.fbs @@ -8,4 +8,7 @@ table PaxForecastApplyMeasuresRequest { measures: [MeasureWrapper]; replace_existing: bool; preparation_time: short; // min + + include_before_trip_load_info: bool; + include_after_trip_load_info: bool; } diff --git a/protocol/paxforecast/PaxForecastApplyMeasuresResponse.fbs b/protocol/paxforecast/PaxForecastApplyMeasuresResponse.fbs new file mode 100644 index 000000000..3fdcd8a25 --- /dev/null +++ b/protocol/paxforecast/PaxForecastApplyMeasuresResponse.fbs @@ -0,0 +1,25 @@ +include "paxmon/PaxMonTrackedUpdates.fbs"; + +namespace motis.paxforecast; + +table PaxForecastApplyMeasuresStatistics { + measure_time_points: ulong; + total_measures_applied: ulong; + total_affected_groups: ulong; + total_alternative_routings: ulong; + total_alternatives_found: ulong; + + // timings (ms) + t_rt_updates: double; + t_get_affected_groups: double; + t_find_alternatives: double; + t_add_alternatives_to_graph: double; + t_behavior_simulation: double; + t_update_groups: double; + t_update_tracker: double; +} + +table PaxForecastApplyMeasuresResponse { + stats: PaxForecastApplyMeasuresStatistics; + updates: motis.paxmon.PaxMonTrackedUpdates; +} diff --git a/protocol/paxmon/PaxMonFilterTripsRequest.fbs b/protocol/paxmon/PaxMonFilterTripsRequest.fbs index 7240ba635..eb97cb99c 100644 --- a/protocol/paxmon/PaxMonFilterTripsRequest.fbs +++ b/protocol/paxmon/PaxMonFilterTripsRequest.fbs @@ -1,8 +1,24 @@ namespace motis.paxmon; +enum PaxMonFilterTripsSortOrder : byte { + MostCritical, // most critical trip first + FirstDeparture, // earliest trip first + ExpectedPax // trip with most expected passengers first +} + table PaxMonFilterTripsRequest { universe: uint; - load_factor_possibly_ge: float; - ignore_past_sections: bool; + ignore_past_sections: bool; // sections in the past don't count + include_load_threshold: float; // only include trips with load >= this + + // used for critical/crowded section counts: + critical_load_threshold: float = 1.0; + crowded_load_threshold: float = 0.8; // must be <= critical_load_threshold + + include_edges: bool; + + sort_by: PaxMonFilterTripsSortOrder; + max_results: uint; // 0 = unlimited + skip_first: uint; } diff --git a/protocol/paxmon/PaxMonFilterTripsResponse.fbs b/protocol/paxmon/PaxMonFilterTripsResponse.fbs index 9994261ef..a66d21bfc 100644 --- a/protocol/paxmon/PaxMonFilterTripsResponse.fbs +++ b/protocol/paxmon/PaxMonFilterTripsResponse.fbs @@ -1,10 +1,29 @@ include "base/TripServiceInfo.fbs"; +include "paxmon/PaxMonTripLoadInfo.fbs"; namespace motis.paxmon; +table PaxMonFilteredTripInfo { + tsi: motis.TripServiceInfo; + + section_count: uint; + critical_sections: uint; + crowded_sections: uint; + + max_excess_pax: uint; + cumulative_excess_pax: uint; + + max_expected_pax: uint; + + edges: [PaxMonEdgeLoadInfo]; // only if include_edges +} + table PaxMonFilterTripsResponse { - filtered_trips: ulong; - critical_sections: ulong; + total_matching_trips: ulong; // total number of matching trips + filtered_trips: ulong; // number of trips included in response + remaining_trips: ulong; // number of remaining matching trips + + total_critical_sections: ulong; - trips: [motis.TripServiceInfo]; + trips: [PaxMonFilteredTripInfo]; } diff --git a/protocol/paxmon/PaxMonGetGroupsInTripRequest.fbs b/protocol/paxmon/PaxMonGetGroupsInTripRequest.fbs index 839fcbdcb..af8dd04b6 100644 --- a/protocol/paxmon/PaxMonGetGroupsInTripRequest.fbs +++ b/protocol/paxmon/PaxMonGetGroupsInTripRequest.fbs @@ -8,7 +8,8 @@ enum PaxMonGroupByStation : byte { First, Last, FirstLongDistance, - LastLongDistance + LastLongDistance, + EntryAndLast } table PaxMonGetGroupsInTripRequest { diff --git a/protocol/paxmon/PaxMonGetGroupsInTripResponse.fbs b/protocol/paxmon/PaxMonGetGroupsInTripResponse.fbs index 4deb34d69..6f33f7c30 100644 --- a/protocol/paxmon/PaxMonGetGroupsInTripResponse.fbs +++ b/protocol/paxmon/PaxMonGetGroupsInTripResponse.fbs @@ -7,6 +7,8 @@ namespace motis.paxmon; table GroupedPassengerGroups { grouped_by_station: [motis.Station]; grouped_by_trip: [motis.TripServiceInfo]; + entry_station: [motis.Station]; + entry_time: long; info: PaxMonCombinedGroups; } diff --git a/protocol/paxmon/PaxMonGetInterchangesResponse.fbs b/protocol/paxmon/PaxMonGetInterchangesResponse.fbs index dcc29902d..b005b177c 100644 --- a/protocol/paxmon/PaxMonGetInterchangesResponse.fbs +++ b/protocol/paxmon/PaxMonGetInterchangesResponse.fbs @@ -8,6 +8,7 @@ table PaxMonTripStopInfo { schedule_time: ulong; current_time: ulong; trips: [TripServiceInfo]; + station: Station; } table PaxMonInterchangeInfo { diff --git a/protocol/paxmon/PaxMonTrackedUpdates.fbs b/protocol/paxmon/PaxMonTrackedUpdates.fbs new file mode 100644 index 000000000..296314b6f --- /dev/null +++ b/protocol/paxmon/PaxMonTrackedUpdates.fbs @@ -0,0 +1,56 @@ +include "base/TripServiceInfo.fbs"; +include "paxmon/PaxMonGroup.fbs"; +include "paxmon/PaxMonTripLoadInfo.fbs"; + +namespace motis.paxmon; + +struct PaxMonReusedGroupBaseInfo { + id: ulong; + passenger_count: uint; + probability: float; + previous_probability: float; +} + +/* +// for later use +table PaxMonUpdatedGroup { + source: PaxMonDataSource; + removed_groups: [PaxMonGroupBaseInfo]; + added_groups: [PaxMonGroupBaseInfo]; + reused_groups: [PaxMonReusedGroupBaseInfo]; +} +*/ + +table PaxMonCriticalTripInfo { + critical_sections: uint; + max_excess_pax: uint; + cumulative_excess_pax: uint; +} + +table PaxMonUpdatedTrip { + tsi: motis.TripServiceInfo; + + removed_max_pax: uint; + removed_mean_pax: float; + added_max_pax: uint; + added_mean_pax: float; + + critical_info_before: PaxMonCriticalTripInfo; + critical_info_after: PaxMonCriticalTripInfo; + + removed_groups: [PaxMonGroupBaseInfo]; + added_groups: [PaxMonGroupBaseInfo]; + reused_groups: [PaxMonReusedGroupBaseInfo]; + + before_edges: [PaxMonEdgeLoadInfo]; // only if include_before_trip_load_info + after_edges: [PaxMonEdgeLoadInfo]; // only if include_after_trip_load_info +} + +table PaxMonTrackedUpdates { + added_group_count: ulong; + reused_group_count: ulong; + removed_group_count: ulong; + updated_trip_count: ulong; + updated_trips: [PaxMonUpdatedTrip]; + // updated_groups: [PaxMonUpdatedGroup]; // for later use +} diff --git a/ui/rsl/.prettierrc.js b/ui/rsl/.prettierrc.js new file mode 100644 index 000000000..3f77616b1 --- /dev/null +++ b/ui/rsl/.prettierrc.js @@ -0,0 +1,18 @@ +module.exports = { + plugins: [ + require.resolve("@trivago/prettier-plugin-sort-imports"), + require.resolve("prettier-plugin-alias-imports"), + ], + // https://github.com/trivago/prettier-plugin-sort-imports + importOrder: [ + "^@/api/protocol/(.*)$", + "^@/api/(.*)$", + "^@/data/(.*)$", + "^@/util/(.*)$", + "^@/components/(.*)$", + "^@/(.*)$", + "^[./]", + ], + importOrderSeparation: true, + importOrderSortSpecifiers: true, +}; diff --git a/ui/rsl/.prettierrc.json b/ui/rsl/.prettierrc.json deleted file mode 100644 index 0967ef424..000000000 --- a/ui/rsl/.prettierrc.json +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/ui/rsl/package.json b/ui/rsl/package.json index b47e5e2b8..a04cb887a 100644 --- a/ui/rsl/package.json +++ b/ui/rsl/package.json @@ -17,31 +17,41 @@ "update-protocol": "node --trace-uncaught tools/protocol.js && prettier --write src/api/protocol" }, "dependencies": { + "@headlessui/react": "^1.5.0", "@heroicons/react": "^1.0.5", - "@radix-ui/react-tooltip": "^0.1.6", + "@radix-ui/react-tooltip": "^0.1.7", "date-fns": "^2.28.0", "downshift": "^6.1.7", - "jotai": "^1.5.2", + "jotai": "^1.6.0", + "lodash-es": "^4.17.21", + "optics-ts": "^2.3.0", "react": "^17.0.2", "react-dom": "^17.0.2", - "react-query": "^3.34.8" + "react-hook-form": "^7.27.1", + "react-query": "^3.34.16", + "react-virtuoso": "^2.7.2", + "uuid": "^8.3.2" }, "devDependencies": { "@tailwindcss/forms": "^0.4.0", - "@types/react": "^17.0.38", + "@trivago/prettier-plugin-sort-imports": "^3.2.0", + "@types/lodash-es": "^4.17.6", + "@types/react": "^17.0.39", "@types/react-dom": "^17.0.11", - "@typescript-eslint/eslint-plugin": "^5.9.1", - "@typescript-eslint/parser": "^5.9.1", - "@vitejs/plugin-react": "^1.1.4", + "@types/uuid": "^8.3.4", + "@typescript-eslint/eslint-plugin": "^5.12.1", + "@typescript-eslint/parser": "^5.12.1", + "@vitejs/plugin-react": "^1.2.0", "autoprefixer": "^10.4.2", - "eslint": "^8.6.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-react": "^7.28.0", + "eslint": "^8.10.0", + "eslint-config-prettier": "^8.4.0", + "eslint-plugin-react": "^7.29.2", "eslint-plugin-react-hooks": "^4.3.0", - "postcss": "^8.4.5", + "postcss": "^8.4.7", "prettier": "^2.5.1", - "tailwindcss": "^3.0.13", - "typescript": "^4.5.4", - "vite": "^2.7.10" + "prettier-plugin-alias-imports": "^0.1.6", + "tailwindcss": "^3.0.23", + "typescript": "^4.5.5", + "vite": "^2.8.4" } } diff --git a/ui/rsl/pnpm-lock.yaml b/ui/rsl/pnpm-lock.yaml index 5b17ce2e4..5b268593a 100644 --- a/ui/rsl/pnpm-lock.yaml +++ b/ui/rsl/pnpm-lock.yaml @@ -1,101 +1,160 @@ lockfileVersion: 5.3 specifiers: + '@headlessui/react': ^1.5.0 '@heroicons/react': ^1.0.5 - '@radix-ui/react-tooltip': ^0.1.6 + '@radix-ui/react-tooltip': ^0.1.7 '@tailwindcss/forms': ^0.4.0 - '@types/react': ^17.0.38 + '@trivago/prettier-plugin-sort-imports': ^3.2.0 + '@types/lodash-es': ^4.17.6 + '@types/react': ^17.0.39 '@types/react-dom': ^17.0.11 - '@typescript-eslint/eslint-plugin': ^5.9.1 - '@typescript-eslint/parser': ^5.9.1 - '@vitejs/plugin-react': ^1.1.4 + '@types/uuid': ^8.3.4 + '@typescript-eslint/eslint-plugin': ^5.12.1 + '@typescript-eslint/parser': ^5.12.1 + '@vitejs/plugin-react': ^1.2.0 autoprefixer: ^10.4.2 date-fns: ^2.28.0 downshift: ^6.1.7 - eslint: ^8.6.0 - eslint-config-prettier: ^8.3.0 - eslint-plugin-react: ^7.28.0 + eslint: ^8.10.0 + eslint-config-prettier: ^8.4.0 + eslint-plugin-react: ^7.29.2 eslint-plugin-react-hooks: ^4.3.0 - jotai: ^1.5.2 - postcss: ^8.4.5 + jotai: ^1.6.0 + lodash-es: ^4.17.21 + optics-ts: ^2.3.0 + postcss: ^8.4.7 prettier: ^2.5.1 + prettier-plugin-alias-imports: ^0.1.6 react: ^17.0.2 react-dom: ^17.0.2 - react-query: ^3.34.8 - tailwindcss: ^3.0.13 - typescript: ^4.5.4 - vite: ^2.7.10 + react-hook-form: ^7.27.1 + react-query: ^3.34.16 + react-virtuoso: ^2.7.2 + tailwindcss: ^3.0.23 + typescript: ^4.5.5 + uuid: ^8.3.2 + vite: ^2.8.4 dependencies: + '@headlessui/react': 1.5.0_react-dom@17.0.2+react@17.0.2 '@heroicons/react': 1.0.5_react@17.0.2 - '@radix-ui/react-tooltip': 0.1.6_react-dom@17.0.2+react@17.0.2 + '@radix-ui/react-tooltip': 0.1.7_react-dom@17.0.2+react@17.0.2 date-fns: 2.28.0 downshift: 6.1.7_react@17.0.2 - jotai: 1.5.2_react-query@3.34.8+react@17.0.2 + jotai: 1.6.0_132ee0e5b630db37c4346783b3583448 + lodash-es: 4.17.21 + optics-ts: 2.3.0 react: 17.0.2 react-dom: 17.0.2_react@17.0.2 - react-query: 3.34.8_react-dom@17.0.2+react@17.0.2 + react-hook-form: 7.27.1_react@17.0.2 + react-query: 3.34.16_react-dom@17.0.2+react@17.0.2 + react-virtuoso: 2.7.2_react@17.0.2 + uuid: 8.3.2 devDependencies: - '@tailwindcss/forms': 0.4.0_tailwindcss@3.0.13 - '@types/react': 17.0.38 + '@tailwindcss/forms': 0.4.0_tailwindcss@3.0.23 + '@trivago/prettier-plugin-sort-imports': 3.2.0_prettier@2.5.1 + '@types/lodash-es': 4.17.6 + '@types/react': 17.0.39 '@types/react-dom': 17.0.11 - '@typescript-eslint/eslint-plugin': 5.9.1_b7b2e42b32ee097737cd3e626b10847b - '@typescript-eslint/parser': 5.9.1_eslint@8.6.0+typescript@4.5.4 - '@vitejs/plugin-react': 1.1.4 - autoprefixer: 10.4.2_postcss@8.4.5 - eslint: 8.6.0 - eslint-config-prettier: 8.3.0_eslint@8.6.0 - eslint-plugin-react: 7.28.0_eslint@8.6.0 - eslint-plugin-react-hooks: 4.3.0_eslint@8.6.0 - postcss: 8.4.5 + '@types/uuid': 8.3.4 + '@typescript-eslint/eslint-plugin': 5.12.1_27a0c788acac7d65514027b167e3b3f6 + '@typescript-eslint/parser': 5.12.1_eslint@8.10.0+typescript@4.5.5 + '@vitejs/plugin-react': 1.2.0 + autoprefixer: 10.4.2_postcss@8.4.7 + eslint: 8.10.0 + eslint-config-prettier: 8.4.0_eslint@8.10.0 + eslint-plugin-react: 7.29.2_eslint@8.10.0 + eslint-plugin-react-hooks: 4.3.0_eslint@8.10.0 + postcss: 8.4.7 prettier: 2.5.1 - tailwindcss: 3.0.13_ef48b3b8837f8a23677bffe8f9cd866d - typescript: 4.5.4 - vite: 2.7.10 + prettier-plugin-alias-imports: 0.1.6_prettier@2.5.1 + tailwindcss: 3.0.23_autoprefixer@10.4.2 + typescript: 4.5.5 + vite: 2.8.4 packages: + /@ampproject/remapping/2.1.2: + resolution: {integrity: sha512-hoyByceqwKirw7w3Z7gnIIZC3Wx3J484Y3L/cMpXFbr7d9ZQj2mODrirNzcJa+SM3UlpWXYvKV4RlRpFXlWgXg==} + engines: {node: '>=6.0.0'} + dependencies: + '@jridgewell/trace-mapping': 0.3.4 + dev: true + /@babel/code-frame/7.16.7: resolution: {integrity: sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/highlight': 7.16.7 + '@babel/highlight': 7.16.10 dev: true - /@babel/compat-data/7.16.8: - resolution: {integrity: sha512-m7OkX0IdKLKPpBlJtF561YJal5y/jyI5fNfWbPxh2D/nbzzGI4qRyrD8xO2jB24u7l+5I2a43scCG2IrfjC50Q==} + /@babel/compat-data/7.17.0: + resolution: {integrity: sha512-392byTlpGWXMv4FbyWw3sAZ/FrW/DrwqLGXpy0mbyNe9Taqv1mg9yON5/o0cnr8XYCkFTZbC1eV+c+LAROgrng==} engines: {node: '>=6.9.0'} dev: true - /@babel/core/7.16.7: - resolution: {integrity: sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==} + /@babel/core/7.13.10: + resolution: {integrity: sha512-bfIYcT0BdKeAZrovpMqX2Mx5NrgAckGbwT982AkdS5GNfn3KMGiprlBAtmBcFZRUmpaufS6WZFP8trvx8ptFDw==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.16.7 - '@babel/generator': 7.16.8 - '@babel/helper-compilation-targets': 7.16.7_@babel+core@7.16.7 - '@babel/helper-module-transforms': 7.16.7 - '@babel/helpers': 7.16.7 - '@babel/parser': 7.16.8 + '@babel/generator': 7.13.9 + '@babel/helper-compilation-targets': 7.16.7_@babel+core@7.13.10 + '@babel/helper-module-transforms': 7.17.6 + '@babel/helpers': 7.17.2 + '@babel/parser': 7.14.6 '@babel/template': 7.16.7 - '@babel/traverse': 7.16.8 - '@babel/types': 7.16.8 + '@babel/traverse': 7.13.0 + '@babel/types': 7.13.0 convert-source-map: 1.8.0 debug: 4.3.3 gensync: 1.0.0-beta.2 json5: 2.2.0 + lodash: 4.17.21 semver: 6.3.0 source-map: 0.5.7 transitivePeerDependencies: - supports-color dev: true - /@babel/generator/7.16.8: - resolution: {integrity: sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==} + /@babel/core/7.17.5: + resolution: {integrity: sha512-/BBMw4EvjmyquN5O+t5eh0+YqB3XXJkYD2cjKpYtWOfFy4lQ4UozNSmxAcWT8r2XtZs0ewG+zrfsqeR15i1ajA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.16.8 + '@ampproject/remapping': 2.1.2 + '@babel/code-frame': 7.16.7 + '@babel/generator': 7.17.3 + '@babel/helper-compilation-targets': 7.16.7_@babel+core@7.17.5 + '@babel/helper-module-transforms': 7.17.6 + '@babel/helpers': 7.17.2 + '@babel/parser': 7.17.3 + '@babel/template': 7.16.7 + '@babel/traverse': 7.17.3 + '@babel/types': 7.17.0 + convert-source-map: 1.8.0 + debug: 4.3.3 + gensync: 1.0.0-beta.2 + json5: 2.2.0 + semver: 6.3.0 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/generator/7.13.9: + resolution: {integrity: sha512-mHOOmY0Axl/JCTkxTU6Lf5sWOg/v8nUa+Xkt4zMTftX0wqmb6Sh7J8gvcehBw7q0AhrhAR+FDacKjCZ2X8K+Sw==} + dependencies: + '@babel/types': 7.13.0 + jsesc: 2.5.2 + source-map: 0.5.7 + dev: true + + /@babel/generator/7.17.3: + resolution: {integrity: sha512-+R6Dctil/MgUsZsZAkYgK+ADNSZzJRRy0TvY65T71z/CR854xHQ1EweBYXdfT+HNeN7w0cSJJEzgxZMv40pxsg==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.17.0 jsesc: 2.5.2 source-map: 0.5.7 dev: true @@ -104,19 +163,32 @@ packages: resolution: {integrity: sha512-s6t2w/IPQVTAET1HitoowRGXooX8mCgtuP5195wD/QJPV6wYjpujCGF7JuMODVX2ZAJOf1GT6DT9MHEZvLOFSw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.16.8 + '@babel/types': 7.17.0 + dev: true + + /@babel/helper-compilation-targets/7.16.7_@babel+core@7.13.10: + resolution: {integrity: sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/compat-data': 7.17.0 + '@babel/core': 7.13.10 + '@babel/helper-validator-option': 7.16.7 + browserslist: 4.19.3 + semver: 6.3.0 dev: true - /@babel/helper-compilation-targets/7.16.7_@babel+core@7.16.7: + /@babel/helper-compilation-targets/7.16.7_@babel+core@7.17.5: resolution: {integrity: sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/compat-data': 7.16.8 - '@babel/core': 7.16.7 + '@babel/compat-data': 7.17.0 + '@babel/core': 7.17.5 '@babel/helper-validator-option': 7.16.7 - browserslist: 4.19.1 + browserslist: 4.19.3 semver: 6.3.0 dev: true @@ -124,7 +196,7 @@ packages: resolution: {integrity: sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.16.8 + '@babel/types': 7.17.0 dev: true /@babel/helper-function-name/7.16.7: @@ -133,32 +205,32 @@ packages: dependencies: '@babel/helper-get-function-arity': 7.16.7 '@babel/template': 7.16.7 - '@babel/types': 7.16.8 + '@babel/types': 7.17.0 dev: true /@babel/helper-get-function-arity/7.16.7: resolution: {integrity: sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.16.8 + '@babel/types': 7.17.0 dev: true /@babel/helper-hoist-variables/7.16.7: resolution: {integrity: sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.16.8 + '@babel/types': 7.17.0 dev: true /@babel/helper-module-imports/7.16.7: resolution: {integrity: sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.16.8 + '@babel/types': 7.17.0 dev: true - /@babel/helper-module-transforms/7.16.7: - resolution: {integrity: sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==} + /@babel/helper-module-transforms/7.17.6: + resolution: {integrity: sha512-2ULmRdqoOMpdvkbT8jONrZML/XALfzxlb052bldftkicAUy8AxSCkD5trDPQcwHNmolcl7wP6ehNqMlyUw6AaA==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-environment-visitor': 7.16.7 @@ -167,8 +239,8 @@ packages: '@babel/helper-split-export-declaration': 7.16.7 '@babel/helper-validator-identifier': 7.16.7 '@babel/template': 7.16.7 - '@babel/traverse': 7.16.8 - '@babel/types': 7.16.8 + '@babel/traverse': 7.17.3 + '@babel/types': 7.17.0 transitivePeerDependencies: - supports-color dev: true @@ -182,14 +254,14 @@ packages: resolution: {integrity: sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.16.8 + '@babel/types': 7.17.0 dev: true /@babel/helper-split-export-declaration/7.16.7: resolution: {integrity: sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.16.8 + '@babel/types': 7.17.0 dev: true /@babel/helper-validator-identifier/7.16.7: @@ -202,19 +274,19 @@ packages: engines: {node: '>=6.9.0'} dev: true - /@babel/helpers/7.16.7: - resolution: {integrity: sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==} + /@babel/helpers/7.17.2: + resolution: {integrity: sha512-0Qu7RLR1dILozr/6M0xgj+DFPmi6Bnulgm9M8BVa9ZCWxDqlSnqt3cf8IDPB5m45sVXUZ0kuQAgUrdSFFH79fQ==} engines: {node: '>=6.9.0'} dependencies: '@babel/template': 7.16.7 - '@babel/traverse': 7.16.8 - '@babel/types': 7.16.8 + '@babel/traverse': 7.17.3 + '@babel/types': 7.17.0 transitivePeerDependencies: - supports-color dev: true - /@babel/highlight/7.16.7: - resolution: {integrity: sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==} + /@babel/highlight/7.16.10: + resolution: {integrity: sha512-5FnTQLSLswEj6IkgVw5KusNUUFY9ZGqe/TRFnP/BKYHYgfh7tc+C7mwiy95/yNP7Dh9x580Vv8r7u7ZfTBFxdw==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-validator-identifier': 7.16.7 @@ -222,68 +294,74 @@ packages: js-tokens: 4.0.0 dev: true - /@babel/parser/7.16.8: - resolution: {integrity: sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==} + /@babel/parser/7.14.6: + resolution: {integrity: sha512-oG0ej7efjEXxb4UgE+klVx+3j4MVo+A2vCzm7OUN4CLo6WhQ+vSOD2yJ8m7B+DghObxtLxt3EfgMWpq+AsWehQ==} engines: {node: '>=6.0.0'} hasBin: true dev: true - /@babel/plugin-syntax-jsx/7.16.7_@babel+core@7.16.7: + /@babel/parser/7.17.3: + resolution: {integrity: sha512-7yJPvPV+ESz2IUTPbOL+YkIGyCqOyNIzdguKQuJGnH7bg1WTIifuM21YqokFt/THWh1AkCRn9IgoykTRCBVpzA==} + engines: {node: '>=6.0.0'} + hasBin: true + dev: true + + /@babel/plugin-syntax-jsx/7.16.7_@babel+core@7.17.5: resolution: {integrity: sha512-Esxmk7YjA8QysKeT3VhTXvF6y77f/a91SIs4pWb4H2eWGQkCKFgQaG6hdoEVZtGsrAcb2K5BW66XsOErD4WU3Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.16.7 + '@babel/core': 7.17.5 '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-transform-react-jsx-development/7.16.7_@babel+core@7.16.7: + /@babel/plugin-transform-react-jsx-development/7.16.7_@babel+core@7.17.5: resolution: {integrity: sha512-RMvQWvpla+xy6MlBpPlrKZCMRs2AGiHOGHY3xRwl0pEeim348dDyxeH4xBsMPbIMhujeq7ihE702eM2Ew0Wo+A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.16.7 - '@babel/plugin-transform-react-jsx': 7.16.7_@babel+core@7.16.7 + '@babel/core': 7.17.5 + '@babel/plugin-transform-react-jsx': 7.17.3_@babel+core@7.17.5 dev: true - /@babel/plugin-transform-react-jsx-self/7.16.7_@babel+core@7.16.7: + /@babel/plugin-transform-react-jsx-self/7.16.7_@babel+core@7.17.5: resolution: {integrity: sha512-oe5VuWs7J9ilH3BCCApGoYjHoSO48vkjX2CbA5bFVhIuO2HKxA3vyF7rleA4o6/4rTDbk6r8hBW7Ul8E+UZrpA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.16.7 + '@babel/core': 7.17.5 '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-transform-react-jsx-source/7.16.7_@babel+core@7.16.7: + /@babel/plugin-transform-react-jsx-source/7.16.7_@babel+core@7.17.5: resolution: {integrity: sha512-rONFiQz9vgbsnaMtQlZCjIRwhJvlrPET8TabIUK2hzlXw9B9s2Ieaxte1SCOOXMbWRHodbKixNf3BLcWVOQ8Bw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.16.7 + '@babel/core': 7.17.5 '@babel/helper-plugin-utils': 7.16.7 dev: true - /@babel/plugin-transform-react-jsx/7.16.7_@babel+core@7.16.7: - resolution: {integrity: sha512-8D16ye66fxiE8m890w0BpPpngG9o9OVBBy0gH2E+2AR7qMR2ZpTYJEqLxAsoroenMId0p/wMW+Blc0meDgu0Ag==} + /@babel/plugin-transform-react-jsx/7.17.3_@babel+core@7.17.5: + resolution: {integrity: sha512-9tjBm4O07f7mzKSIlEmPdiE6ub7kfIe6Cd+w+oQebpATfTQMAgW+YOuWxogbKVTulA+MEO7byMeIUtQ1z+z+ZQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.16.7 + '@babel/core': 7.17.5 '@babel/helper-annotate-as-pure': 7.16.7 '@babel/helper-module-imports': 7.16.7 '@babel/helper-plugin-utils': 7.16.7 - '@babel/plugin-syntax-jsx': 7.16.7_@babel+core@7.16.7 - '@babel/types': 7.16.8 + '@babel/plugin-syntax-jsx': 7.16.7_@babel+core@7.17.5 + '@babel/types': 7.17.0 dev: true - /@babel/runtime/7.16.7: - resolution: {integrity: sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ==} + /@babel/runtime/7.17.2: + resolution: {integrity: sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==} engines: {node: '>=6.9.0'} dependencies: regenerator-runtime: 0.13.9 @@ -294,53 +372,88 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.16.7 - '@babel/parser': 7.16.8 - '@babel/types': 7.16.8 + '@babel/parser': 7.17.3 + '@babel/types': 7.17.0 dev: true - /@babel/traverse/7.16.8: - resolution: {integrity: sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==} + /@babel/traverse/7.13.0: + resolution: {integrity: sha512-xys5xi5JEhzC3RzEmSGrs/b3pJW/o87SypZ+G/PhaE7uqVQNv/jlmVIBXuoh5atqQ434LfXV+sf23Oxj0bchJQ==} + dependencies: + '@babel/code-frame': 7.16.7 + '@babel/generator': 7.13.9 + '@babel/helper-function-name': 7.16.7 + '@babel/helper-split-export-declaration': 7.16.7 + '@babel/parser': 7.14.6 + '@babel/types': 7.13.0 + debug: 4.3.3 + globals: 11.12.0 + lodash: 4.17.21 + transitivePeerDependencies: + - supports-color + dev: true + + /@babel/traverse/7.17.3: + resolution: {integrity: sha512-5irClVky7TxRWIRtxlh2WPUUOLhcPN06AGgaQSB8AEwuyEBgJVuJ5imdHm5zxk8w0QS5T+tDfnDxAlhWjpb7cw==} engines: {node: '>=6.9.0'} dependencies: '@babel/code-frame': 7.16.7 - '@babel/generator': 7.16.8 + '@babel/generator': 7.17.3 '@babel/helper-environment-visitor': 7.16.7 '@babel/helper-function-name': 7.16.7 '@babel/helper-hoist-variables': 7.16.7 '@babel/helper-split-export-declaration': 7.16.7 - '@babel/parser': 7.16.8 - '@babel/types': 7.16.8 + '@babel/parser': 7.17.3 + '@babel/types': 7.17.0 debug: 4.3.3 globals: 11.12.0 transitivePeerDependencies: - supports-color dev: true - /@babel/types/7.16.8: - resolution: {integrity: sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==} + /@babel/types/7.13.0: + resolution: {integrity: sha512-hE+HE8rnG1Z6Wzo+MhaKE5lM5eMx71T4EHJgku2E3xIfaULhDcxiiRxUYgwX8qwP1BBSlag+TdGOt6JAidIZTA==} + dependencies: + '@babel/helper-validator-identifier': 7.16.7 + lodash: 4.17.21 + to-fast-properties: 2.0.0 + dev: true + + /@babel/types/7.17.0: + resolution: {integrity: sha512-TmKSNO4D5rzhL5bjWFcVHHLETzfQ/AmbKpKPOSjlP0WoHZ6L911fgoOKY4Alp/emzG4cHJdyN49zpgkbXFEHHw==} engines: {node: '>=6.9.0'} dependencies: '@babel/helper-validator-identifier': 7.16.7 to-fast-properties: 2.0.0 dev: true - /@eslint/eslintrc/1.0.5: - resolution: {integrity: sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==} + /@eslint/eslintrc/1.2.0: + resolution: {integrity: sha512-igm9SjJHNEJRiUnecP/1R5T3wKLEJ7pL6e2P+GUSfCd0dGjPYYZve08uzw8L2J8foVHFz+NGu12JxRcU2gGo6w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 debug: 4.3.3 - espree: 9.3.0 - globals: 13.12.0 + espree: 9.3.1 + globals: 13.12.1 ignore: 4.0.6 import-fresh: 3.3.0 js-yaml: 4.1.0 - minimatch: 3.0.4 + minimatch: 3.1.2 strip-json-comments: 3.1.1 transitivePeerDependencies: - supports-color dev: true + /@headlessui/react/1.5.0_react-dom@17.0.2+react@17.0.2: + resolution: {integrity: sha512-aaRnYxBb3MU2FNJf3Ut9RMTUqqU3as0aI1lQhgo2n9Fa67wRu14iOGqx93xB+uMNVfNwZ5B3y/Ndm7qZGuFeMQ==} + engines: {node: '>=10'} + peerDependencies: + react: ^16 || ^17 || ^18 + react-dom: ^16 || ^17 || ^18 + dependencies: + react: 17.0.2 + react-dom: 17.0.2_react@17.0.2 + dev: false + /@heroicons/react/1.0.5_react@17.0.2: resolution: {integrity: sha512-UDMyLM2KavIu2vlWfMspapw9yii7aoLwzI2Hudx4fyoPwfKfxU8r3cL8dEBXOjcLG0/oOONZzbT14M1HoNtEcg==} peerDependencies: @@ -349,13 +462,13 @@ packages: react: 17.0.2 dev: false - /@humanwhocodes/config-array/0.9.2: - resolution: {integrity: sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==} + /@humanwhocodes/config-array/0.9.5: + resolution: {integrity: sha512-ObyMyWxZiCu/yTisA7uzx81s40xR2fD5Cg/2Kq7G02ajkNubJf6BopgDTmDyc3U7sXpNKM8cYOw7s7Tyr+DnCw==} engines: {node: '>=10.10.0'} dependencies: '@humanwhocodes/object-schema': 1.2.1 debug: 4.3.3 - minimatch: 3.0.4 + minimatch: 3.1.2 transitivePeerDependencies: - supports-color dev: true @@ -364,6 +477,22 @@ packages: resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} dev: true + /@jridgewell/resolve-uri/3.0.5: + resolution: {integrity: sha512-VPeQ7+wH0itvQxnG+lIzWgkysKIr3L9sslimFW55rHMdGu/qCQ5z5h9zq4gI8uBtqkpHhsF4Z/OwExufUCThew==} + engines: {node: '>=6.0.0'} + dev: true + + /@jridgewell/sourcemap-codec/1.4.11: + resolution: {integrity: sha512-Fg32GrJo61m+VqYSdRSjRXMjQ06j8YIYfcTqndLYVAaHmroZHLJZCydsWBOTDqXS2v+mjxohBWEMfg97GXmYQg==} + dev: true + + /@jridgewell/trace-mapping/0.3.4: + resolution: {integrity: sha512-vFv9ttIedivx0ux3QSjhgtCVjPZd5l46ZOMDSCwnH1yUO2e964gO8LZGyv2QkqcgR6TnBU1v+1IFqmeoG+0UJQ==} + dependencies: + '@jridgewell/resolve-uri': 3.0.5 + '@jridgewell/sourcemap-codec': 1.4.11 + dev: true + /@nodelib/fs.scandir/2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -388,23 +517,23 @@ packages: /@radix-ui/popper/0.1.0: resolution: {integrity: sha512-uzYeElL3w7SeNMuQpXiFlBhTT+JyaNMCwDfjKkrzugEcYrf5n52PHqncNdQPUtR42hJh8V9FsqyEDbDxkeNjJQ==} dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 csstype: 3.0.10 dev: false /@radix-ui/primitive/0.1.0: resolution: {integrity: sha512-tqxZKybwN5Fa3VzZry4G6mXAAb9aAqKmPtnVbZpL0vsBwvOHTBwsjHVPXylocYLwEtBY9SCe665bYnNB515uoA==} dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 dev: false - /@radix-ui/react-arrow/0.1.3_react@17.0.2: - resolution: {integrity: sha512-9x1gRYdlUD5OUwY7L+M+4FY/YltDSsrNSj8QXGPbxZxL5ghWXB/4lhyIGccCwk/e8ggfmQYv9SRNmn3LavPo3A==} + /@radix-ui/react-arrow/0.1.4_react@17.0.2: + resolution: {integrity: sha512-BB6XzAb7Ml7+wwpFdYVtZpK1BlMgqyafSQNGzhIpSZ4uXvXOHPlR5GP8M449JkeQzgQjv9Mp1AsJxFC0KuOtuA==} peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 - '@radix-ui/react-primitive': 0.1.3_react@17.0.2 + '@babel/runtime': 7.17.2 + '@radix-ui/react-primitive': 0.1.4_react@17.0.2 react: 17.0.2 dev: false @@ -413,7 +542,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 react: 17.0.2 dev: false @@ -422,67 +551,67 @@ packages: peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 react: 17.0.2 dev: false - /@radix-ui/react-id/0.1.4_react@17.0.2: - resolution: {integrity: sha512-/hq5m/D0ZfJWOS7TLF+G0l08KDRs87LBE46JkAvgKkg1fW4jkucx9At9D9vauIPSbdNmww5kXEp566hMlA8eXA==} + /@radix-ui/react-id/0.1.5_react@17.0.2: + resolution: {integrity: sha512-IPc4H/63bes0IZ1GJJozSEkSWcDyhNGtKFWUpJ+XtaLyQ1X3x7Mf6fWwWhDcpqlYEP+5WtAvfqcyEsyjP+ZhBQ==} peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 '@radix-ui/react-use-layout-effect': 0.1.0_react@17.0.2 react: 17.0.2 dev: false - /@radix-ui/react-popper/0.1.3_react@17.0.2: - resolution: {integrity: sha512-2OV2YaJv7iTZexJY3HJ7B6Fs1A/3JXd3fRGU4JY0guACfGMD1C/jSgds505MKQOTiHE/quI6j3/q8yfzFjJR9g==} + /@radix-ui/react-popper/0.1.4_react@17.0.2: + resolution: {integrity: sha512-18gDYof97t8UQa7zwklG1Dr8jIdj3u+rVOQLzPi9f5i1YQak/pVGkaqw8aY+iDUknKKuZniTk/7jbAJUYlKyOw==} peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 '@radix-ui/popper': 0.1.0 - '@radix-ui/react-arrow': 0.1.3_react@17.0.2 + '@radix-ui/react-arrow': 0.1.4_react@17.0.2 '@radix-ui/react-compose-refs': 0.1.0_react@17.0.2 '@radix-ui/react-context': 0.1.1_react@17.0.2 - '@radix-ui/react-primitive': 0.1.3_react@17.0.2 + '@radix-ui/react-primitive': 0.1.4_react@17.0.2 '@radix-ui/react-use-rect': 0.1.1_react@17.0.2 - '@radix-ui/react-use-size': 0.1.0_react@17.0.2 + '@radix-ui/react-use-size': 0.1.1_react@17.0.2 '@radix-ui/rect': 0.1.1 react: 17.0.2 dev: false - /@radix-ui/react-portal/0.1.3_react-dom@17.0.2+react@17.0.2: - resolution: {integrity: sha512-DrV+sPYLs0HhmX5/b7yRT6nLM9Nl6FtQe2KUG+46kiCOKQ+0XzNMO5hmeQtyq0mRf/qlC02rFu6OMsWpIqVsJg==} + /@radix-ui/react-portal/0.1.4_react-dom@17.0.2+react@17.0.2: + resolution: {integrity: sha512-MO0wRy2eYRTZ/CyOri9NANCAtAtq89DEtg90gicaTlkCfdqCLEBsLb+/q66BZQTr3xX/Vq01nnVfc/TkCqoqvw==} peerDependencies: react: ^16.8 || ^17.0 react-dom: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 - '@radix-ui/react-primitive': 0.1.3_react@17.0.2 + '@babel/runtime': 7.17.2 + '@radix-ui/react-primitive': 0.1.4_react@17.0.2 '@radix-ui/react-use-layout-effect': 0.1.0_react@17.0.2 react: 17.0.2 react-dom: 17.0.2_react@17.0.2 dev: false - /@radix-ui/react-presence/0.1.1_react@17.0.2: - resolution: {integrity: sha512-LsL+NcWDpFUAYCmXeH02o4pgqcSLpwxP84UIjCtpIKrsPe2vLuhcp79KC/jZJeXz+of2lUpMAxpM+eCpxFZtlg==} + /@radix-ui/react-presence/0.1.2_react@17.0.2: + resolution: {integrity: sha512-3BRlFZraooIUfRlyN+b/Xs5hq1lanOOo/+3h6Pwu2GMFjkGKKa4Rd51fcqGqnVlbr3jYg+WLuGyAV4KlgqwrQw==} peerDependencies: react: '>=16.8' dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 '@radix-ui/react-compose-refs': 0.1.0_react@17.0.2 '@radix-ui/react-use-layout-effect': 0.1.0_react@17.0.2 react: 17.0.2 dev: false - /@radix-ui/react-primitive/0.1.3_react@17.0.2: - resolution: {integrity: sha512-fcyADaaAx2jdqEDLsTs6aX50S3L1c9K9CC6XMpJpuXFJCU4n9PGTFDZRtY2gAoXXoRCPIBsklCopSmGb6SsDjQ==} + /@radix-ui/react-primitive/0.1.4_react@17.0.2: + resolution: {integrity: sha512-6gSl2IidySupIMJFjYnDIkIWRyQdbu/AHK7rbICPani+LW4b0XdxBXc46og/iZvuwW8pjCS8I2SadIerv84xYA==} peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 '@radix-ui/react-slot': 0.1.2_react@17.0.2 react: 17.0.2 dev: false @@ -492,32 +621,32 @@ packages: peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 '@radix-ui/react-compose-refs': 0.1.0_react@17.0.2 react: 17.0.2 dev: false - /@radix-ui/react-tooltip/0.1.6_react-dom@17.0.2+react@17.0.2: - resolution: {integrity: sha512-0uaRpRmTCQo5yMUkDpv4LEDnaQDoeLXcNNhZonCZdbZBQ7ntvjURIWIigq1/pXZp0UX7oPpFzsXD9jUp8JT0WA==} + /@radix-ui/react-tooltip/0.1.7_react-dom@17.0.2+react@17.0.2: + resolution: {integrity: sha512-eiBUsVOHenZ0JR16tl970bB0DafJBz6mFgSGfIGIVpflFj0LIsIDiLMsYyvYdx1KwwsIUDTEZtxcPm/sWjPzqA==} peerDependencies: react: ^16.8 || ^17.0 react-dom: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 '@radix-ui/primitive': 0.1.0 '@radix-ui/react-compose-refs': 0.1.0_react@17.0.2 '@radix-ui/react-context': 0.1.1_react@17.0.2 - '@radix-ui/react-id': 0.1.4_react@17.0.2 - '@radix-ui/react-popper': 0.1.3_react@17.0.2 - '@radix-ui/react-portal': 0.1.3_react-dom@17.0.2+react@17.0.2 - '@radix-ui/react-presence': 0.1.1_react@17.0.2 - '@radix-ui/react-primitive': 0.1.3_react@17.0.2 + '@radix-ui/react-id': 0.1.5_react@17.0.2 + '@radix-ui/react-popper': 0.1.4_react@17.0.2 + '@radix-ui/react-portal': 0.1.4_react-dom@17.0.2+react@17.0.2 + '@radix-ui/react-presence': 0.1.2_react@17.0.2 + '@radix-ui/react-primitive': 0.1.4_react@17.0.2 '@radix-ui/react-slot': 0.1.2_react@17.0.2 '@radix-ui/react-use-controllable-state': 0.1.0_react@17.0.2 '@radix-ui/react-use-escape-keydown': 0.1.0_react@17.0.2 - '@radix-ui/react-use-previous': 0.1.0_react@17.0.2 + '@radix-ui/react-use-previous': 0.1.1_react@17.0.2 '@radix-ui/react-use-rect': 0.1.1_react@17.0.2 - '@radix-ui/react-visually-hidden': 0.1.3_react@17.0.2 + '@radix-ui/react-visually-hidden': 0.1.4_react@17.0.2 react: 17.0.2 react-dom: 17.0.2_react@17.0.2 dev: false @@ -527,7 +656,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 react: 17.0.2 dev: false @@ -536,7 +665,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 '@radix-ui/react-use-callback-ref': 0.1.0_react@17.0.2 react: 17.0.2 dev: false @@ -546,7 +675,7 @@ packages: peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 '@radix-ui/react-use-callback-ref': 0.1.0_react@17.0.2 react: 17.0.2 dev: false @@ -556,16 +685,16 @@ packages: peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 react: 17.0.2 dev: false - /@radix-ui/react-use-previous/0.1.0_react@17.0.2: - resolution: {integrity: sha512-0fxNc33rYnCzDMPSiSnfS8YklnxQo8WqbAQXPAgIaaA1jRu2qFB916PL4qCIW+avcAAqFD38vWhqDqcVmBharA==} + /@radix-ui/react-use-previous/0.1.1_react@17.0.2: + resolution: {integrity: sha512-O/ZgrDBr11dR8rhO59ED8s5zIXBRFi8MiS+CmFGfi7MJYdLbfqVOmQU90Ghf87aifEgWe6380LA69KBneaShAg==} peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 react: 17.0.2 dev: false @@ -574,34 +703,34 @@ packages: peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 '@radix-ui/rect': 0.1.1 react: 17.0.2 dev: false - /@radix-ui/react-use-size/0.1.0_react@17.0.2: - resolution: {integrity: sha512-TcZAsR+BYI46w/RbaSFCRACl+Jh6mDqhu6GS2r0iuJpIVrj8atff7qtTjmMmfGtEDNEjhl7DxN3pr1nTS/oruQ==} + /@radix-ui/react-use-size/0.1.1_react@17.0.2: + resolution: {integrity: sha512-pTgWM5qKBu6C7kfKxrKPoBI2zZYZmp2cSXzpUiGM3qEBQlMLtYhaY2JXdXUCxz+XmD1YEjc8oRwvyfsD4AG4WA==} peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 react: 17.0.2 dev: false - /@radix-ui/react-visually-hidden/0.1.3_react@17.0.2: - resolution: {integrity: sha512-dPU6ZR2WQ/W9qv7E1Y8/I8ymqG+8sViU6dQQ6sfr2/8yGr0I4mmI7ywTnqXaE+YS9gHLEZHdQcEqTNESg6YfdQ==} + /@radix-ui/react-visually-hidden/0.1.4_react@17.0.2: + resolution: {integrity: sha512-K/q6AEEzqeeEq/T0NPChvBqnwlp8Tl4NnQdrI/y8IOY7BRR+Ug0PEsVk6g48HJ7cA1//COugdxXXVVK/m0X1mA==} peerDependencies: react: ^16.8 || ^17.0 dependencies: - '@babel/runtime': 7.16.7 - '@radix-ui/react-primitive': 0.1.3_react@17.0.2 + '@babel/runtime': 7.17.2 + '@radix-ui/react-primitive': 0.1.4_react@17.0.2 react: 17.0.2 dev: false /@radix-ui/rect/0.1.1: resolution: {integrity: sha512-g3hnE/UcOg7REdewduRPAK88EPuLZtaq7sA9ouu8S+YEtnyFRI16jgv6GZYe3VMoQLL1T171ebmEPtDjyxWLzw==} dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 dev: false /@rollup/pluginutils/4.1.2: @@ -612,19 +741,50 @@ packages: picomatch: 2.3.1 dev: true - /@tailwindcss/forms/0.4.0_tailwindcss@3.0.13: + /@tailwindcss/forms/0.4.0_tailwindcss@3.0.23: resolution: {integrity: sha512-DeaQBx6EgEeuZPQACvC+mKneJsD8am1uiJugjgQK1+/Vt+Ai0GpFBC2T2fqnUad71WgOxyrZPE6BG1VaI6YqfQ==} peerDependencies: tailwindcss: '>=3.0.0 || >= 3.0.0-alpha.1' dependencies: mini-svg-data-uri: 1.4.3 - tailwindcss: 3.0.13_ef48b3b8837f8a23677bffe8f9cd866d + tailwindcss: 3.0.23_autoprefixer@10.4.2 + dev: true + + /@trivago/prettier-plugin-sort-imports/3.2.0_prettier@2.5.1: + resolution: {integrity: sha512-DnwLe+z8t/dZX5xBbYZV1+C5STkyK/P6SSq3Nk6NXlJZsgvDZX2eN4ND7bMFgGV/NL/YChWzcNf6ziGba1ktQQ==} + peerDependencies: + prettier: 2.x + dependencies: + '@babel/core': 7.13.10 + '@babel/generator': 7.13.9 + '@babel/parser': 7.14.6 + '@babel/traverse': 7.13.0 + '@babel/types': 7.13.0 + javascript-natural-sort: 0.7.1 + lodash: 4.17.21 + prettier: 2.5.1 + transitivePeerDependencies: + - supports-color dev: true /@types/json-schema/7.0.9: resolution: {integrity: sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==} dev: true + /@types/json5/0.0.29: + resolution: {integrity: sha1-7ihweulOEdK4J7y+UnC86n8+ce4=} + dev: true + + /@types/lodash-es/4.17.6: + resolution: {integrity: sha512-R+zTeVUKDdfoRxpAryaQNRKk3105Rrgx2CFRClIgRGaqDTdjsm8h6IYA8ir584W3ePzkZfst5xIgDwYrlh9HLg==} + dependencies: + '@types/lodash': 4.14.179 + dev: true + + /@types/lodash/4.14.179: + resolution: {integrity: sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w==} + dev: true + /@types/parse-json/4.0.0: resolution: {integrity: sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==} dev: true @@ -636,11 +796,11 @@ packages: /@types/react-dom/17.0.11: resolution: {integrity: sha512-f96K3k+24RaLGVu/Y2Ng3e1EbZ8/cVJvypZWd7cy0ofCBaf2lcM46xNhycMZ2xGwbBjRql7hOlZ+e2WlJ5MH3Q==} dependencies: - '@types/react': 17.0.38 + '@types/react': 17.0.39 dev: true - /@types/react/17.0.38: - resolution: {integrity: sha512-SI92X1IA+FMnP3qM5m4QReluXzhcmovhZnLNm3pyeQlooi02qI7sLiepEYqT678uNiyc25XfCqxREFpy3W7YhQ==} + /@types/react/17.0.39: + resolution: {integrity: sha512-UVavlfAxDd/AgAacMa60Azl7ygyQNRwC/DsHZmKgNvPmRR5p70AJ5Q9EAmL2NWOJmeV+vVUI4IAP7GZrN8h8Ug==} dependencies: '@types/prop-types': 15.7.4 '@types/scheduler': 0.16.2 @@ -651,8 +811,12 @@ packages: resolution: {integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==} dev: true - /@typescript-eslint/eslint-plugin/5.9.1_b7b2e42b32ee097737cd3e626b10847b: - resolution: {integrity: sha512-Xv9tkFlyD4MQGpJgTo6wqDqGvHIRmRgah/2Sjz1PUnJTawjHWIwBivUE9x0QtU2WVii9baYgavo/bHjrZJkqTw==} + /@types/uuid/8.3.4: + resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} + dev: true + + /@typescript-eslint/eslint-plugin/5.12.1_27a0c788acac7d65514027b167e3b3f6: + resolution: {integrity: sha512-M499lqa8rnNK7mUv74lSFFttuUsubIRdAbHcVaP93oFcKkEmHmLqy2n7jM9C8DVmFMYK61ExrZU6dLYhQZmUpw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -662,42 +826,24 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/experimental-utils': 5.9.1_eslint@8.6.0+typescript@4.5.4 - '@typescript-eslint/parser': 5.9.1_eslint@8.6.0+typescript@4.5.4 - '@typescript-eslint/scope-manager': 5.9.1 - '@typescript-eslint/type-utils': 5.9.1_eslint@8.6.0+typescript@4.5.4 + '@typescript-eslint/parser': 5.12.1_eslint@8.10.0+typescript@4.5.5 + '@typescript-eslint/scope-manager': 5.12.1 + '@typescript-eslint/type-utils': 5.12.1_eslint@8.10.0+typescript@4.5.5 + '@typescript-eslint/utils': 5.12.1_eslint@8.10.0+typescript@4.5.5 debug: 4.3.3 - eslint: 8.6.0 + eslint: 8.10.0 functional-red-black-tree: 1.0.1 ignore: 5.2.0 regexpp: 3.2.0 semver: 7.3.5 - tsutils: 3.21.0_typescript@4.5.4 - typescript: 4.5.4 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/experimental-utils/5.9.1_eslint@8.6.0+typescript@4.5.4: - resolution: {integrity: sha512-cb1Njyss0mLL9kLXgS/eEY53SZQ9sT519wpX3i+U457l2UXRDuo87hgKfgRazmu9/tQb0x2sr3Y0yrU+Zz0y+w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - '@types/json-schema': 7.0.9 - '@typescript-eslint/scope-manager': 5.9.1 - '@typescript-eslint/types': 5.9.1 - '@typescript-eslint/typescript-estree': 5.9.1_typescript@4.5.4 - eslint: 8.6.0 - eslint-scope: 5.1.1 - eslint-utils: 3.0.0_eslint@8.6.0 + tsutils: 3.21.0_typescript@4.5.5 + typescript: 4.5.5 transitivePeerDependencies: - supports-color - - typescript dev: true - /@typescript-eslint/parser/5.9.1_eslint@8.6.0+typescript@4.5.4: - resolution: {integrity: sha512-PLYO0AmwD6s6n0ZQB5kqPgfvh73p0+VqopQQLuNfi7Lm0EpfKyDalchpVwkE+81k5HeiRrTV/9w1aNHzjD7C4g==} + /@typescript-eslint/parser/5.12.1_eslint@8.10.0+typescript@4.5.5: + resolution: {integrity: sha512-6LuVUbe7oSdHxUWoX/m40Ni8gsZMKCi31rlawBHt7VtW15iHzjbpj2WLiToG2758KjtCCiLRKZqfrOdl3cNKuw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -706,26 +852,26 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.9.1 - '@typescript-eslint/types': 5.9.1 - '@typescript-eslint/typescript-estree': 5.9.1_typescript@4.5.4 + '@typescript-eslint/scope-manager': 5.12.1 + '@typescript-eslint/types': 5.12.1 + '@typescript-eslint/typescript-estree': 5.12.1_typescript@4.5.5 debug: 4.3.3 - eslint: 8.6.0 - typescript: 4.5.4 + eslint: 8.10.0 + typescript: 4.5.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager/5.9.1: - resolution: {integrity: sha512-8BwvWkho3B/UOtzRyW07ffJXPaLSUKFBjpq8aqsRvu6HdEuzCY57+ffT7QoV4QXJXWSU1+7g3wE4AlgImmQ9pQ==} + /@typescript-eslint/scope-manager/5.12.1: + resolution: {integrity: sha512-J0Wrh5xS6XNkd4TkOosxdpObzlYfXjAFIm9QxYLCPOcHVv1FyyFCPom66uIh8uBr0sZCrtS+n19tzufhwab8ZQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.9.1 - '@typescript-eslint/visitor-keys': 5.9.1 + '@typescript-eslint/types': 5.12.1 + '@typescript-eslint/visitor-keys': 5.12.1 dev: true - /@typescript-eslint/type-utils/5.9.1_eslint@8.6.0+typescript@4.5.4: - resolution: {integrity: sha512-tRSpdBnPRssjlUh35rE9ug5HrUvaB9ntREy7gPXXKwmIx61TNN7+l5YKgi1hMKxo5NvqZCfYhA5FvyuJG6X6vg==} + /@typescript-eslint/type-utils/5.12.1_eslint@8.10.0+typescript@4.5.5: + resolution: {integrity: sha512-Gh8feEhsNLeCz6aYqynh61Vsdy+tiNNkQtc+bN3IvQvRqHkXGUhYkUi+ePKzP0Mb42se7FDb+y2SypTbpbR/Sg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: '*' @@ -734,22 +880,22 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/experimental-utils': 5.9.1_eslint@8.6.0+typescript@4.5.4 + '@typescript-eslint/utils': 5.12.1_eslint@8.10.0+typescript@4.5.5 debug: 4.3.3 - eslint: 8.6.0 - tsutils: 3.21.0_typescript@4.5.4 - typescript: 4.5.4 + eslint: 8.10.0 + tsutils: 3.21.0_typescript@4.5.5 + typescript: 4.5.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/types/5.9.1: - resolution: {integrity: sha512-SsWegWudWpkZCwwYcKoDwuAjoZXnM1y2EbEerTHho19Hmm+bQ56QG4L4jrtCu0bI5STaRTvRTZmjprWlTw/5NQ==} + /@typescript-eslint/types/5.12.1: + resolution: {integrity: sha512-hfcbq4qVOHV1YRdhkDldhV9NpmmAu2vp6wuFODL71Y0Ixak+FLeEU4rnPxgmZMnGreGEghlEucs9UZn5KOfHJA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree/5.9.1_typescript@4.5.4: - resolution: {integrity: sha512-gL1sP6A/KG0HwrahVXI9fZyeVTxEYV//6PmcOn1tD0rw8VhUWYeZeuWHwwhnewnvEMcHjhnJLOBhA9rK4vmb8A==} + /@typescript-eslint/typescript-estree/5.12.1_typescript@4.5.5: + resolution: {integrity: sha512-ahOdkIY9Mgbza7L9sIi205Pe1inCkZWAHE1TV1bpxlU4RZNPtXaDZfiiFWcL9jdxvW1hDYZJXrFm+vlMkXRbBw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -757,38 +903,70 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.9.1 - '@typescript-eslint/visitor-keys': 5.9.1 + '@typescript-eslint/types': 5.12.1 + '@typescript-eslint/visitor-keys': 5.12.1 debug: 4.3.3 globby: 11.1.0 is-glob: 4.0.3 semver: 7.3.5 - tsutils: 3.21.0_typescript@4.5.4 - typescript: 4.5.4 + tsutils: 3.21.0_typescript@4.5.5 + typescript: 4.5.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/visitor-keys/5.9.1: - resolution: {integrity: sha512-Xh37pNz9e9ryW4TVdwiFzmr4hloty8cFj8GTWMXh3Z8swGwyQWeCcNgF0hm6t09iZd6eiZmIf4zHedQVP6TVtg==} + /@typescript-eslint/utils/5.12.1_eslint@8.10.0+typescript@4.5.5: + resolution: {integrity: sha512-Qq9FIuU0EVEsi8fS6pG+uurbhNTtoYr4fq8tKjBupsK5Bgbk2I32UGm0Sh+WOyjOPgo/5URbxxSNV6HYsxV4MQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/types': 5.9.1 - eslint-visitor-keys: 3.1.0 + '@types/json-schema': 7.0.9 + '@typescript-eslint/scope-manager': 5.12.1 + '@typescript-eslint/types': 5.12.1 + '@typescript-eslint/typescript-estree': 5.12.1_typescript@4.5.5 + eslint: 8.10.0 + eslint-scope: 5.1.1 + eslint-utils: 3.0.0_eslint@8.10.0 + transitivePeerDependencies: + - supports-color + - typescript dev: true - /@vitejs/plugin-react/1.1.4: - resolution: {integrity: sha512-cMUBDonNY8PPeHWjIrYKbRn6bLSunh/Ixo2XLLBd3DM0uYBZft+c+04zkGhhN1lAwvoRKJ2FdtvhGhPgViHc6w==} + /@typescript-eslint/visitor-keys/5.12.1: + resolution: {integrity: sha512-l1KSLfupuwrXx6wc0AuOmC7Ko5g14ZOQ86wJJqRbdLbXLK02pK/DPiDDqCc7BqqiiA04/eAA6ayL0bgOrAkH7A==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dependencies: + '@typescript-eslint/types': 5.12.1 + eslint-visitor-keys: 3.3.0 + dev: true + + /@virtuoso.dev/react-urx/0.2.12_react@17.0.2: + resolution: {integrity: sha512-Lcrrmq/UztM+rgepAdThdIk8dL3LEi9o2NTkL6ZLKPrTGjr5tSmsauD30/O8yu7Q0ncDnptmMR3OObdvMGuEKQ==} + engines: {node: '>=10'} + peerDependencies: + react: '>=16' + dependencies: + '@virtuoso.dev/urx': 0.2.12 + react: 17.0.2 + dev: false + + /@virtuoso.dev/urx/0.2.12: + resolution: {integrity: sha512-Q9nlRqYb5Uq4Ynu8cWPSJ7LxpuZsI+MZ09IJlDAAgwuNgfWRArpVRP0VN0coYgUo2fKMjhmV69MTqaUbIBhu/g==} + dev: false + + /@vitejs/plugin-react/1.2.0: + resolution: {integrity: sha512-Rywwt0IXXg6yQ0hv3cMT3mtdDcGIw31mGaa+MMMAT651LhoXLF2yFy4LrakiTs7UKs7RPBo9eNgaS8pgl2A6Qw==} engines: {node: '>=12.0.0'} dependencies: - '@babel/core': 7.16.7 - '@babel/plugin-transform-react-jsx': 7.16.7_@babel+core@7.16.7 - '@babel/plugin-transform-react-jsx-development': 7.16.7_@babel+core@7.16.7 - '@babel/plugin-transform-react-jsx-self': 7.16.7_@babel+core@7.16.7 - '@babel/plugin-transform-react-jsx-source': 7.16.7_@babel+core@7.16.7 + '@babel/core': 7.17.5 + '@babel/plugin-transform-react-jsx': 7.17.3_@babel+core@7.17.5 + '@babel/plugin-transform-react-jsx-development': 7.16.7_@babel+core@7.17.5 + '@babel/plugin-transform-react-jsx-self': 7.16.7_@babel+core@7.17.5 + '@babel/plugin-transform-react-jsx-source': 7.16.7_@babel+core@7.17.5 '@rollup/pluginutils': 4.1.2 react-refresh: 0.11.0 - resolve: 1.21.0 + resolve: 1.22.0 transitivePeerDependencies: - supports-color dev: true @@ -835,11 +1013,6 @@ packages: uri-js: 4.4.1 dev: true - /ansi-colors/4.1.1: - resolution: {integrity: sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==} - engines: {node: '>=6'} - dev: true - /ansi-regex/5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} @@ -900,19 +1073,19 @@ packages: es-abstract: 1.19.1 dev: true - /autoprefixer/10.4.2_postcss@8.4.5: + /autoprefixer/10.4.2_postcss@8.4.7: resolution: {integrity: sha512-9fOPpHKuDW1w/0EKfRmVnxTDt8166MAnLI3mgZ1JCnhNtYWxcJ6Ud5CO/AVOZi/AvFa8DY9RTy3h3+tFBlrrdQ==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: postcss: ^8.1.0 dependencies: - browserslist: 4.19.1 - caniuse-lite: 1.0.30001299 - fraction.js: 4.1.2 + browserslist: 4.19.3 + caniuse-lite: 1.0.30001312 + fraction.js: 4.1.3 normalize-range: 0.1.2 picocolors: 1.0.0 - postcss: 8.4.5 + postcss: 8.4.7 postcss-value-parser: 4.2.0 dev: true @@ -945,7 +1118,7 @@ packages: /broadcast-channel/3.7.0: resolution: {integrity: sha512-cIAKJXAxGJceNZGTZSBzMxzyOn72cVgPnKx4dc6LRjQgbaJUQqhy5rzL3zbMxkMWsGKkv2hSFkPRMEXfoMZ2Mg==} dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 detect-node: 2.1.0 js-sha3: 0.8.0 microseconds: 0.2.0 @@ -955,15 +1128,15 @@ packages: unload: 2.2.0 dev: false - /browserslist/4.19.1: - resolution: {integrity: sha512-u2tbbG5PdKRTUoctO3NBD8FQ5HdPh1ZXPHzp1rwaa5jTc+RV9/+RlWiAIKmjRPQF+xbGM9Kklj5bZQFa2s/38A==} + /browserslist/4.19.3: + resolution: {integrity: sha512-XK3X4xtKJ+Txj8G5c30B4gsm71s69lqXlkYui4s6EkKxuv49qjYlY6oVd+IFJ73d4YymtM3+djvvt/R/iJwwDg==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001299 - electron-to-chromium: 1.4.44 + caniuse-lite: 1.0.30001312 + electron-to-chromium: 1.4.73 escalade: 3.1.1 - node-releases: 2.0.1 + node-releases: 2.0.2 picocolors: 1.0.0 dev: true @@ -984,8 +1157,8 @@ packages: engines: {node: '>= 6'} dev: true - /caniuse-lite/1.0.30001299: - resolution: {integrity: sha512-iujN4+x7QzqA2NCSrS5VUy+4gLmRd4xv6vbBBsmfVqTx8bLAD8097euLqQgKxSVLvxjSDcvF1T/i9ocgnUFexw==} + /caniuse-lite/1.0.30001312: + resolution: {integrity: sha512-Wiz1Psk2MEK0pX3rUzWaunLTZzqS2JYZFzNKqAiJGiuxIjRPLgV6+VDPOg6lQOUxmDwhTlh198JsTTi8Hzw6aQ==} dev: true /chalk/2.4.2: @@ -1005,8 +1178,8 @@ packages: supports-color: 7.2.0 dev: true - /chokidar/3.5.2: - resolution: {integrity: sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==} + /chokidar/3.5.3: + resolution: {integrity: sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==} engines: {node: '>= 8.10.0'} dependencies: anymatch: 3.1.2 @@ -1163,7 +1336,7 @@ packages: peerDependencies: react: '>=16.12.0' dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 compute-scroll-into-view: 1.0.17 prop-types: 15.8.1 react: 17.0.2 @@ -1171,15 +1344,8 @@ packages: tslib: 2.3.1 dev: false - /electron-to-chromium/1.4.44: - resolution: {integrity: sha512-tHGWiUUmY7GABK8+DNcr474cnZDTzD8x1736SlDosVH8+/vRJeqfaIBAEHFtMjddz/0T4rKKYsxEc8BwQRdBpw==} - dev: true - - /enquirer/2.3.6: - resolution: {integrity: sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==} - engines: {node: '>=8.6'} - dependencies: - ansi-colors: 4.1.1 + /electron-to-chromium/1.4.73: + resolution: {integrity: sha512-RlCffXkE/LliqfA5m29+dVDPB2r72y2D2egMMfIy3Le8ODrxjuZNVo4NIC2yPL01N4xb4nZQLwzi6Z5tGIGLnA==} dev: true /error-ex/1.3.2: @@ -1223,164 +1389,202 @@ packages: is-symbol: 1.0.4 dev: true - /esbuild-android-arm64/0.13.15: - resolution: {integrity: sha512-m602nft/XXeO8YQPUDVoHfjyRVPdPgjyyXOxZ44MK/agewFFkPa8tUo6lAzSWh5Ui5PB4KR9UIFTSBKh/RrCmg==} + /esbuild-android-arm64/0.14.23: + resolution: {integrity: sha512-k9sXem++mINrZty1v4FVt6nC5BQCFG4K2geCIUUqHNlTdFnuvcqsY7prcKZLFhqVC1rbcJAr9VSUGFL/vD4vsw==} + engines: {node: '>=12'} cpu: [arm64] os: [android] requiresBuild: true dev: true optional: true - /esbuild-darwin-64/0.13.15: - resolution: {integrity: sha512-ihOQRGs2yyp7t5bArCwnvn2Atr6X4axqPpEdCFPVp7iUj4cVSdisgvEKdNR7yH3JDjW6aQDw40iQFoTqejqxvQ==} + /esbuild-darwin-64/0.14.23: + resolution: {integrity: sha512-lB0XRbtOYYL1tLcYw8BoBaYsFYiR48RPrA0KfA/7RFTr4MV7Bwy/J4+7nLsVnv9FGuQummM3uJ93J3ptaTqFug==} + engines: {node: '>=12'} cpu: [x64] os: [darwin] requiresBuild: true dev: true optional: true - /esbuild-darwin-arm64/0.13.15: - resolution: {integrity: sha512-i1FZssTVxUqNlJ6cBTj5YQj4imWy3m49RZRnHhLpefFIh0To05ow9DTrXROTE1urGTQCloFUXTX8QfGJy1P8dQ==} + /esbuild-darwin-arm64/0.14.23: + resolution: {integrity: sha512-yat73Z/uJ5tRcfRiI4CCTv0FSnwErm3BJQeZAh+1tIP0TUNh6o+mXg338Zl5EKChD+YGp6PN+Dbhs7qa34RxSw==} + engines: {node: '>=12'} cpu: [arm64] os: [darwin] requiresBuild: true dev: true optional: true - /esbuild-freebsd-64/0.13.15: - resolution: {integrity: sha512-G3dLBXUI6lC6Z09/x+WtXBXbOYQZ0E8TDBqvn7aMaOCzryJs8LyVXKY4CPnHFXZAbSwkCbqiPuSQ1+HhrNk7EA==} + /esbuild-freebsd-64/0.14.23: + resolution: {integrity: sha512-/1xiTjoLuQ+LlbfjJdKkX45qK/M7ARrbLmyf7x3JhyQGMjcxRYVR6Dw81uH3qlMHwT4cfLW4aEVBhP1aNV7VsA==} + engines: {node: '>=12'} cpu: [x64] os: [freebsd] requiresBuild: true dev: true optional: true - /esbuild-freebsd-arm64/0.13.15: - resolution: {integrity: sha512-KJx0fzEDf1uhNOZQStV4ujg30WlnwqUASaGSFPhznLM/bbheu9HhqZ6mJJZM32lkyfGJikw0jg7v3S0oAvtvQQ==} + /esbuild-freebsd-arm64/0.14.23: + resolution: {integrity: sha512-uyPqBU/Zcp6yEAZS4LKj5jEE0q2s4HmlMBIPzbW6cTunZ8cyvjG6YWpIZXb1KK3KTJDe62ltCrk3VzmWHp+iLg==} + engines: {node: '>=12'} cpu: [arm64] os: [freebsd] requiresBuild: true dev: true optional: true - /esbuild-linux-32/0.13.15: - resolution: {integrity: sha512-ZvTBPk0YWCLMCXiFmD5EUtB30zIPvC5Itxz0mdTu/xZBbbHJftQgLWY49wEPSn2T/TxahYCRDWun5smRa0Tu+g==} + /esbuild-linux-32/0.14.23: + resolution: {integrity: sha512-37R/WMkQyUfNhbH7aJrr1uCjDVdnPeTHGeDhZPUNhfoHV0lQuZNCKuNnDvlH/u/nwIYZNdVvz1Igv5rY/zfrzQ==} + engines: {node: '>=12'} cpu: [ia32] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-64/0.13.15: - resolution: {integrity: sha512-eCKzkNSLywNeQTRBxJRQ0jxRCl2YWdMB3+PkWFo2BBQYC5mISLIVIjThNtn6HUNqua1pnvgP5xX0nHbZbPj5oA==} + /esbuild-linux-64/0.14.23: + resolution: {integrity: sha512-H0gztDP60qqr8zoFhAO64waoN5yBXkmYCElFklpd6LPoobtNGNnDe99xOQm28+fuD75YJ7GKHzp/MLCLhw2+vQ==} + engines: {node: '>=12'} cpu: [x64] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-arm/0.13.15: - resolution: {integrity: sha512-wUHttDi/ol0tD8ZgUMDH8Ef7IbDX+/UsWJOXaAyTdkT7Yy9ZBqPg8bgB/Dn3CZ9SBpNieozrPRHm0BGww7W/jA==} + /esbuild-linux-arm/0.14.23: + resolution: {integrity: sha512-x64CEUxi8+EzOAIpCUeuni0bZfzPw/65r8tC5cy5zOq9dY7ysOi5EVQHnzaxS+1NmV+/RVRpmrzGw1QgY2Xpmw==} + engines: {node: '>=12'} cpu: [arm] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-arm64/0.13.15: - resolution: {integrity: sha512-bYpuUlN6qYU9slzr/ltyLTR9YTBS7qUDymO8SV7kjeNext61OdmqFAzuVZom+OLW1HPHseBfJ/JfdSlx8oTUoA==} + /esbuild-linux-arm64/0.14.23: + resolution: {integrity: sha512-c4MLOIByNHR55n3KoYf9hYDfBRghMjOiHLaoYLhkQkIabb452RWi+HsNgB41sUpSlOAqfpqKPFNg7VrxL3UX9g==} + engines: {node: '>=12'} cpu: [arm64] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-mips64le/0.13.15: - resolution: {integrity: sha512-KlVjIG828uFPyJkO/8gKwy9RbXhCEUeFsCGOJBepUlpa7G8/SeZgncUEz/tOOUJTcWMTmFMtdd3GElGyAtbSWg==} + /esbuild-linux-mips64le/0.14.23: + resolution: {integrity: sha512-kHKyKRIAedYhKug2EJpyJxOUj3VYuamOVA1pY7EimoFPzaF3NeY7e4cFBAISC/Av0/tiV0xlFCt9q0HJ68IBIw==} + engines: {node: '>=12'} cpu: [mips64el] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-linux-ppc64le/0.13.15: - resolution: {integrity: sha512-h6gYF+OsaqEuBjeesTBtUPw0bmiDu7eAeuc2OEH9S6mV9/jPhPdhOWzdeshb0BskRZxPhxPOjqZ+/OqLcxQwEQ==} + /esbuild-linux-ppc64le/0.14.23: + resolution: {integrity: sha512-7ilAiJEPuJJnJp/LiDO0oJm5ygbBPzhchJJh9HsHZzeqO+3PUzItXi+8PuicY08r0AaaOe25LA7sGJ0MzbfBag==} + engines: {node: '>=12'} cpu: [ppc64] os: [linux] requiresBuild: true dev: true optional: true - /esbuild-netbsd-64/0.13.15: - resolution: {integrity: sha512-3+yE9emwoevLMyvu+iR3rsa+Xwhie7ZEHMGDQ6dkqP/ndFzRHkobHUKTe+NCApSqG5ce2z4rFu+NX/UHnxlh3w==} + /esbuild-linux-riscv64/0.14.23: + resolution: {integrity: sha512-fbL3ggK2wY0D8I5raPIMPhpCvODFE+Bhb5QGtNP3r5aUsRR6TQV+ZBXIaw84iyvKC8vlXiA4fWLGhghAd/h/Zg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-linux-s390x/0.14.23: + resolution: {integrity: sha512-GHMDCyfy7+FaNSO8RJ8KCFsnax8fLUsOrj9q5Gi2JmZMY0Zhp75keb5abTFCq2/Oy6KVcT0Dcbyo/bFb4rIFJA==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: true + optional: true + + /esbuild-netbsd-64/0.14.23: + resolution: {integrity: sha512-ovk2EX+3rrO1M2lowJfgMb/JPN1VwVYrx0QPUyudxkxLYrWeBxDKQvc6ffO+kB4QlDyTfdtAURrVzu3JeNdA2g==} + engines: {node: '>=12'} cpu: [x64] os: [netbsd] requiresBuild: true dev: true optional: true - /esbuild-openbsd-64/0.13.15: - resolution: {integrity: sha512-wTfvtwYJYAFL1fSs8yHIdf5GEE4NkbtbXtjLWjM3Cw8mmQKqsg8kTiqJ9NJQe5NX/5Qlo7Xd9r1yKMMkHllp5g==} + /esbuild-openbsd-64/0.14.23: + resolution: {integrity: sha512-uYYNqbVR+i7k8ojP/oIROAHO9lATLN7H2QeXKt2H310Fc8FJj4y3Wce6hx0VgnJ4k1JDrgbbiXM8rbEgQyg8KA==} + engines: {node: '>=12'} cpu: [x64] os: [openbsd] requiresBuild: true dev: true optional: true - /esbuild-sunos-64/0.13.15: - resolution: {integrity: sha512-lbivT9Bx3t1iWWrSnGyBP9ODriEvWDRiweAs69vI+miJoeKwHWOComSRukttbuzjZ8r1q0mQJ8Z7yUsDJ3hKdw==} + /esbuild-sunos-64/0.14.23: + resolution: {integrity: sha512-hAzeBeET0+SbScknPzS2LBY6FVDpgE+CsHSpe6CEoR51PApdn2IB0SyJX7vGelXzlyrnorM4CAsRyb9Qev4h9g==} + engines: {node: '>=12'} cpu: [x64] os: [sunos] requiresBuild: true dev: true optional: true - /esbuild-windows-32/0.13.15: - resolution: {integrity: sha512-fDMEf2g3SsJ599MBr50cY5ve5lP1wyVwTe6aLJsM01KtxyKkB4UT+fc5MXQFn3RLrAIAZOG+tHC+yXObpSn7Nw==} + /esbuild-windows-32/0.14.23: + resolution: {integrity: sha512-Kttmi3JnohdaREbk6o9e25kieJR379TsEWF0l39PQVHXq3FR6sFKtVPgY8wk055o6IB+rllrzLnbqOw/UV60EA==} + engines: {node: '>=12'} cpu: [ia32] os: [win32] requiresBuild: true dev: true optional: true - /esbuild-windows-64/0.13.15: - resolution: {integrity: sha512-9aMsPRGDWCd3bGjUIKG/ZOJPKsiztlxl/Q3C1XDswO6eNX/Jtwu4M+jb6YDH9hRSUflQWX0XKAfWzgy5Wk54JQ==} + /esbuild-windows-64/0.14.23: + resolution: {integrity: sha512-JtIT0t8ymkpl6YlmOl6zoSWL5cnCgyLaBdf/SiU/Eg3C13r0NbHZWNT/RDEMKK91Y6t79kTs3vyRcNZbfu5a8g==} + engines: {node: '>=12'} cpu: [x64] os: [win32] requiresBuild: true dev: true optional: true - /esbuild-windows-arm64/0.13.15: - resolution: {integrity: sha512-zzvyCVVpbwQQATaf3IG8mu1IwGEiDxKkYUdA4FpoCHi1KtPa13jeScYDjlW0Qh+ebWzpKfR2ZwvqAQkSWNcKjA==} + /esbuild-windows-arm64/0.14.23: + resolution: {integrity: sha512-cTFaQqT2+ik9e4hePvYtRZQ3pqOvKDVNarzql0VFIzhc0tru/ZgdLoXd6epLiKT+SzoSce6V9YJ+nn6RCn6SHw==} + engines: {node: '>=12'} cpu: [arm64] os: [win32] requiresBuild: true dev: true optional: true - /esbuild/0.13.15: - resolution: {integrity: sha512-raCxt02HBKv8RJxE8vkTSCXGIyKHdEdGfUmiYb8wnabnaEmHzyW7DCHb5tEN0xU8ryqg5xw54mcwnYkC4x3AIw==} + /esbuild/0.14.23: + resolution: {integrity: sha512-XjnIcZ9KB6lfonCa+jRguXyRYcldmkyZ99ieDksqW/C8bnyEX299yA4QH2XcgijCgaddEZePPTgvx/2imsq7Ig==} + engines: {node: '>=12'} hasBin: true requiresBuild: true optionalDependencies: - esbuild-android-arm64: 0.13.15 - esbuild-darwin-64: 0.13.15 - esbuild-darwin-arm64: 0.13.15 - esbuild-freebsd-64: 0.13.15 - esbuild-freebsd-arm64: 0.13.15 - esbuild-linux-32: 0.13.15 - esbuild-linux-64: 0.13.15 - esbuild-linux-arm: 0.13.15 - esbuild-linux-arm64: 0.13.15 - esbuild-linux-mips64le: 0.13.15 - esbuild-linux-ppc64le: 0.13.15 - esbuild-netbsd-64: 0.13.15 - esbuild-openbsd-64: 0.13.15 - esbuild-sunos-64: 0.13.15 - esbuild-windows-32: 0.13.15 - esbuild-windows-64: 0.13.15 - esbuild-windows-arm64: 0.13.15 + esbuild-android-arm64: 0.14.23 + esbuild-darwin-64: 0.14.23 + esbuild-darwin-arm64: 0.14.23 + esbuild-freebsd-64: 0.14.23 + esbuild-freebsd-arm64: 0.14.23 + esbuild-linux-32: 0.14.23 + esbuild-linux-64: 0.14.23 + esbuild-linux-arm: 0.14.23 + esbuild-linux-arm64: 0.14.23 + esbuild-linux-mips64le: 0.14.23 + esbuild-linux-ppc64le: 0.14.23 + esbuild-linux-riscv64: 0.14.23 + esbuild-linux-s390x: 0.14.23 + esbuild-netbsd-64: 0.14.23 + esbuild-openbsd-64: 0.14.23 + esbuild-sunos-64: 0.14.23 + esbuild-windows-32: 0.14.23 + esbuild-windows-64: 0.14.23 + esbuild-windows-arm64: 0.14.23 dev: true /escalade/3.1.1: @@ -1398,26 +1602,26 @@ packages: engines: {node: '>=10'} dev: true - /eslint-config-prettier/8.3.0_eslint@8.6.0: - resolution: {integrity: sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==} + /eslint-config-prettier/8.4.0_eslint@8.10.0: + resolution: {integrity: sha512-CFotdUcMY18nGRo5KGsnNxpznzhkopOcOo0InID+sgQssPrzjvsyKZPvOgymTFeHrFuC3Tzdf2YndhXtULK9Iw==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.6.0 + eslint: 8.10.0 dev: true - /eslint-plugin-react-hooks/4.3.0_eslint@8.6.0: + /eslint-plugin-react-hooks/4.3.0_eslint@8.10.0: resolution: {integrity: sha512-XslZy0LnMn+84NEG9jSGR6eGqaZB3133L8xewQo3fQagbQuGt7a63gf+P1NGKZavEYEC3UXaWEAA/AqDkuN6xA==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 dependencies: - eslint: 8.6.0 + eslint: 8.10.0 dev: true - /eslint-plugin-react/7.28.0_eslint@8.6.0: - resolution: {integrity: sha512-IOlFIRHzWfEQQKcAD4iyYDndHwTQiCMcJVJjxempf203jnNLUnW34AXLrV33+nEXoifJE2ZEGmcjKPL8957eSw==} + /eslint-plugin-react/7.29.2_eslint@8.10.0: + resolution: {integrity: sha512-ypEBTKOy5liFQXZWMchJ3LN0JX1uPI6n7MN7OPHKacqXAxq5gYC30TdO7wqGYQyxD1OrzpobdHC3hDmlRWDg9w==} engines: {node: '>=4'} peerDependencies: eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 @@ -1425,10 +1629,10 @@ packages: array-includes: 3.1.4 array.prototype.flatmap: 1.2.5 doctrine: 2.1.0 - eslint: 8.6.0 + eslint: 8.10.0 estraverse: 5.3.0 jsx-ast-utils: 3.2.1 - minimatch: 3.0.4 + minimatch: 3.1.2 object.entries: 1.1.5 object.fromentries: 2.0.5 object.hasown: 1.1.0 @@ -1447,21 +1651,21 @@ packages: estraverse: 4.3.0 dev: true - /eslint-scope/7.1.0: - resolution: {integrity: sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==} + /eslint-scope/7.1.1: + resolution: {integrity: sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 dev: true - /eslint-utils/3.0.0_eslint@8.6.0: + /eslint-utils/3.0.0_eslint@8.10.0: resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} peerDependencies: eslint: '>=5' dependencies: - eslint: 8.6.0 + eslint: 8.10.0 eslint-visitor-keys: 2.1.0 dev: true @@ -1470,37 +1674,36 @@ packages: engines: {node: '>=10'} dev: true - /eslint-visitor-keys/3.1.0: - resolution: {integrity: sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==} + /eslint-visitor-keys/3.3.0: + resolution: {integrity: sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint/8.6.0: - resolution: {integrity: sha512-UvxdOJ7mXFlw7iuHZA4jmzPaUqIw54mZrv+XPYKNbKdLR0et4rf60lIZUU9kiNtnzzMzGWxMV+tQ7uG7JG8DPw==} + /eslint/8.10.0: + resolution: {integrity: sha512-tcI1D9lfVec+R4LE1mNDnzoJ/f71Kl/9Cv4nG47jOueCMBrCCKYXr4AUVS7go6mWYGFD4+EoN6+eXSrEbRzXVw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} hasBin: true dependencies: - '@eslint/eslintrc': 1.0.5 - '@humanwhocodes/config-array': 0.9.2 + '@eslint/eslintrc': 1.2.0 + '@humanwhocodes/config-array': 0.9.5 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.3 debug: 4.3.3 doctrine: 3.0.0 - enquirer: 2.3.6 escape-string-regexp: 4.0.0 - eslint-scope: 7.1.0 - eslint-utils: 3.0.0_eslint@8.6.0 - eslint-visitor-keys: 3.1.0 - espree: 9.3.0 + eslint-scope: 7.1.1 + eslint-utils: 3.0.0_eslint@8.10.0 + eslint-visitor-keys: 3.3.0 + espree: 9.3.1 esquery: 1.4.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 functional-red-black-tree: 1.0.1 glob-parent: 6.0.2 - globals: 13.12.0 - ignore: 4.0.6 + globals: 13.12.1 + ignore: 5.2.0 import-fresh: 3.3.0 imurmurhash: 0.1.4 is-glob: 4.0.3 @@ -1508,12 +1711,10 @@ packages: json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 lodash.merge: 4.6.2 - minimatch: 3.0.4 + minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.1 - progress: 2.0.3 regexpp: 3.2.0 - semver: 7.3.5 strip-ansi: 6.0.1 strip-json-comments: 3.1.1 text-table: 0.2.0 @@ -1522,13 +1723,13 @@ packages: - supports-color dev: true - /espree/9.3.0: - resolution: {integrity: sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ==} + /espree/9.3.1: + resolution: {integrity: sha512-bvdyLmJMfwkV3NCRl5ZhJf22zBFo1y8bYh3VYb+bfzqNB4Je68P2sSuXyuFquzWLebHpNd2/d5uv7yoP9ISnGQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: acorn: 8.7.0 acorn-jsx: 5.3.2_acorn@8.7.0 - eslint-visitor-keys: 3.1.0 + eslint-visitor-keys: 3.3.0 dev: true /esquery/1.4.0: @@ -1568,8 +1769,8 @@ packages: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} dev: true - /fast-glob/3.2.10: - resolution: {integrity: sha512-s9nFhFnvR63wls6/kM88kQqDhMu0AfdjqouE2l5GVQPbqLgyFjjU5ry/r2yKsJxpb9Py1EYNqieFrmMaX4v++A==} + /fast-glob/3.2.11: + resolution: {integrity: sha512-xrO3+1bxSo3ZVHAnqzyuewYT6aMFHRAd4Kcs92MAonjwQZLsK9d0SF1IyQ3k5PoirxTW0Oe/RqFgMQ6TcNE5Ew==} engines: {node: '>=8.6.0'} dependencies: '@nodelib/fs.stat': 2.0.5 @@ -1607,20 +1808,28 @@ packages: to-regex-range: 5.0.1 dev: true + /find-up/5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + dev: true + /flat-cache/3.0.4: resolution: {integrity: sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==} engines: {node: ^10.12.0 || >=12.0.0} dependencies: - flatted: 3.2.4 + flatted: 3.2.5 rimraf: 3.0.2 dev: true - /flatted/3.2.4: - resolution: {integrity: sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==} + /flatted/3.2.5: + resolution: {integrity: sha512-WIWGi2L3DyTUvUrwRKgGi9TwxQMUEqPOPQBVi71R96jZXJdFskXEmf54BoZaS1kknGODoIGASGEzBUYdyMCBJg==} dev: true - /fraction.js/4.1.2: - resolution: {integrity: sha512-o2RiJQ6DZaR/5+Si0qJUIy637QMRudSi9kU/FFzx9EZazrIdnBgpU+3sEWCxAVhH2RtxW2Oz+T4p2o8uOPVcgA==} + /fraction.js/4.1.3: + resolution: {integrity: sha512-pUHWWt6vHzZZiQJcM6S/0PXfS+g6FM4BF5rj9wZyreivhQPdsh5PpE25VtSNxq80wHS5RfY51Ii+8Z0Zl/pmzg==} dev: true /fs.realpath/1.0.0: @@ -1683,7 +1892,7 @@ packages: fs.realpath: 1.0.0 inflight: 1.0.6 inherits: 2.0.4 - minimatch: 3.0.4 + minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 @@ -1692,8 +1901,8 @@ packages: engines: {node: '>=4'} dev: true - /globals/13.12.0: - resolution: {integrity: sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==} + /globals/13.12.1: + resolution: {integrity: sha512-317dFlgY2pdJZ9rspXDks7073GpDmXdfbM3vYYp0HAMKGDh1FfWPleI2ljVNLQX5M5lXcAslTcPTrOrMEFOjyw==} engines: {node: '>=8'} dependencies: type-fest: 0.20.2 @@ -1705,7 +1914,7 @@ packages: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.2.10 + fast-glob: 3.2.11 ignore: 5.2.0 merge2: 1.4.1 slash: 3.0.0 @@ -1893,8 +2102,12 @@ packages: resolution: {integrity: sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=} dev: true - /jotai/1.5.2_react-query@3.34.8+react@17.0.2: - resolution: {integrity: sha512-h9rlP7Mxov8BglO6Xh9jttZlxEuPt3r8wJNU3zSNKvVFXmb1fw4808JkyUodVvZTBDZHrukz9Z6aigOh+nxK/A==} + /javascript-natural-sort/0.7.1: + resolution: {integrity: sha1-+eIwPUUH9tdDVac2ZNFED7Wg71k=} + dev: true + + /jotai/1.6.0_132ee0e5b630db37c4346783b3583448: + resolution: {integrity: sha512-J/+aD9R1XDcNeY8drg/y/I47eUivQ13HGmLmA33w95SvJJLBStSF5WxYrmLgbuWcDC6MpRecF3g/GBchPJNcZg==} engines: {node: '>=12.7.0'} peerDependencies: '@babel/core': '*' @@ -1927,8 +2140,9 @@ packages: xstate: optional: true dependencies: + optics-ts: 2.3.0 react: 17.0.2 - react-query: 3.34.8_react-dom@17.0.2+react@17.0.2 + react-query: 3.34.16_react-dom@17.0.2+react@17.0.2 dev: false /js-sha3/0.8.0: @@ -1963,6 +2177,13 @@ packages: resolution: {integrity: sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=} dev: true + /json5/1.0.1: + resolution: {integrity: sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==} + hasBin: true + dependencies: + minimist: 1.2.5 + dev: true + /json5/2.2.0: resolution: {integrity: sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==} engines: {node: '>=6'} @@ -1996,10 +2217,25 @@ packages: resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} dev: true + /locate-path/6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + dependencies: + p-locate: 5.0.0 + dev: true + + /lodash-es/4.17.21: + resolution: {integrity: sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw==} + dev: false + /lodash.merge/4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} dev: true + /lodash/4.17.21: + resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} + dev: true + /loose-envify/1.4.0: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true @@ -2016,7 +2252,7 @@ packages: /match-sorter/6.3.1: resolution: {integrity: sha512-mxybbo3pPNuA+ZuCUhm5bwNkXrJTbsk5VWbR5wiwz/GC6LIiegBGn2w3O08UG/jdbYLinw51fSQ5xNU1U3MgBw==} dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 remove-accents: 0.4.2 dev: false @@ -2042,8 +2278,8 @@ packages: hasBin: true dev: true - /minimatch/3.0.4: - resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} + /minimatch/3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: brace-expansion: 1.1.11 @@ -2061,8 +2297,8 @@ packages: big-integer: 1.6.51 dev: false - /nanoid/3.1.32: - resolution: {integrity: sha512-F8mf7R3iT9bvThBoW4tGXhXFHCctyCiUUPrWF8WaTqa3h96d9QybkSeba43XVOOE3oiLfkVDe4bT8MeGmkrTxw==} + /nanoid/3.3.1: + resolution: {integrity: sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true dev: true @@ -2071,8 +2307,8 @@ packages: resolution: {integrity: sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=} dev: true - /node-releases/2.0.1: - resolution: {integrity: sha512-CqyzN6z7Q6aMeF/ktcMVTzhAHCEpf8SOarwpzpf8pNBY2k5/oM34UHldUwp8VKI7uxct2HxSRdJjBaZeESzcxA==} + /node-releases/2.0.2: + resolution: {integrity: sha512-XxYDdcQ6eKqp/YjI+tb2C5WM2LgjnZrfYg4vgQt49EK268b6gYCHsBLrK2qvJo4FmCtqmKezb0WZFK4fkrZNsg==} dev: true /normalize-path/3.0.0: @@ -2156,6 +2392,10 @@ packages: dependencies: wrappy: 1.0.2 + /optics-ts/2.3.0: + resolution: {integrity: sha512-iu6//uEMAKsowlq7hd8pNTc43KOjxMPW60BBA8DIt0q311iiOaWPilMHGOyCDvQ7llRutwlCkGX6e4HnUD0ARg==} + dev: false + /optionator/0.9.1: resolution: {integrity: sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==} engines: {node: '>= 0.8.0'} @@ -2168,6 +2408,20 @@ packages: word-wrap: 1.2.3 dev: true + /p-limit/3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + dependencies: + yocto-queue: 0.1.0 + dev: true + + /p-locate/5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + dependencies: + p-limit: 3.1.0 + dev: true + /parent-module/1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} engines: {node: '>=6'} @@ -2185,6 +2439,11 @@ packages: lines-and-columns: 1.2.4 dev: true + /path-exists/4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + dev: true + /path-is-absolute/1.0.1: resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=} engines: {node: '>=0.10.0'} @@ -2212,18 +2471,18 @@ packages: engines: {node: '>=8.6'} dev: true - /postcss-js/4.0.0_postcss@8.4.5: + /postcss-js/4.0.0_postcss@8.4.7: resolution: {integrity: sha512-77QESFBwgX4irogGVPgQ5s07vLvFqWr228qZY+w6lW599cRlK/HmnlivnnVUxkjHnCu4J16PDMHcH+e+2HbvTQ==} engines: {node: ^12 || ^14 || >= 16} peerDependencies: postcss: ^8.3.3 dependencies: camelcase-css: 2.0.1 - postcss: 8.4.5 + postcss: 8.4.7 dev: true - /postcss-load-config/3.1.1: - resolution: {integrity: sha512-c/9XYboIbSEUZpiD1UQD0IKiUe8n9WHYV7YFe7X7J+ZwCsEKkUJSFWjS9hBU1RR9THR7jMXst8sxiqP0jjo2mg==} + /postcss-load-config/3.1.3: + resolution: {integrity: sha512-5EYgaM9auHGtO//ljHH+v/aC/TQ5LHXtL7bQajNAUBKUVKiYE8rYpFms7+V26D9FncaGe2zwCoPQsFKb5zF/Hw==} engines: {node: '>= 10'} peerDependencies: ts-node: '>=9.0.0' @@ -2235,18 +2494,18 @@ packages: yaml: 1.10.2 dev: true - /postcss-nested/5.0.6_postcss@8.4.5: + /postcss-nested/5.0.6_postcss@8.4.7: resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} engines: {node: '>=12.0'} peerDependencies: postcss: ^8.2.14 dependencies: - postcss: 8.4.5 - postcss-selector-parser: 6.0.8 + postcss: 8.4.7 + postcss-selector-parser: 6.0.9 dev: true - /postcss-selector-parser/6.0.8: - resolution: {integrity: sha512-D5PG53d209Z1Uhcc0qAZ5U3t5HagH3cxu+WLZ22jt3gLUpXM4eXXfiO14jiDWST3NNooX/E8wISfOhZ9eIjGTQ==} + /postcss-selector-parser/6.0.9: + resolution: {integrity: sha512-UO3SgnZOVTwu4kyLR22UQ1xZh086RyNZppb7lLAKBFK8a32ttG5i87Y/P3+2bRSjZNyJ1B7hfFNo273tKe9YxQ==} engines: {node: '>=4'} dependencies: cssesc: 3.0.0 @@ -2257,13 +2516,13 @@ packages: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} dev: true - /postcss/8.4.5: - resolution: {integrity: sha512-jBDboWM8qpaqwkMwItqTQTiFikhs/67OYVvblFFTM7MrZjt6yMKd6r2kgXizEbTTljacm4NldIlZnhbjr84QYg==} + /postcss/8.4.7: + resolution: {integrity: sha512-L9Ye3r6hkkCeOETQX6iOaWZgjp3LL6Lpqm6EtgbKrgqGGteRMNb9vzBfRL96YOSu8o7x3MfIH9Mo5cPJFGrW6A==} engines: {node: ^10 || ^12 || >=14} dependencies: - nanoid: 3.1.32 + nanoid: 3.3.1 picocolors: 1.0.0 - source-map-js: 1.0.1 + source-map-js: 1.0.2 dev: true /prelude-ls/1.2.1: @@ -2271,17 +2530,30 @@ packages: engines: {node: '>= 0.8.0'} dev: true + /prettier-plugin-alias-imports/0.1.6_prettier@2.5.1: + resolution: {integrity: sha512-Q2hoVsdwg6ornZ02nNLO5ewggpO0Kz/WVyZuK9oMf+Ljtm7hQ47fdA2XoATky5TITRyuiBpsPn3kRr4Ppt4S/g==} + peerDependencies: + prettier: ^2.0.0 + dependencies: + '@babel/generator': 7.17.3 + '@babel/parser': 7.17.3 + '@babel/traverse': 7.17.3 + debug: 4.3.3 + find-up: 5.0.0 + micromatch: 4.0.4 + prettier: 2.5.1 + slash: 3.0.0 + tsconfig-paths: 3.12.0 + transitivePeerDependencies: + - supports-color + dev: true + /prettier/2.5.1: resolution: {integrity: sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==} engines: {node: '>=10.13.0'} hasBin: true dev: true - /progress/2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - dev: true - /prop-types/15.8.1: resolution: {integrity: sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==} dependencies: @@ -2314,6 +2586,15 @@ packages: scheduler: 0.20.2 dev: false + /react-hook-form/7.27.1_react@17.0.2: + resolution: {integrity: sha512-N3a7A6zIQ8DJeThisVZGtOUabTbJw+7DHJidmB9w8m3chckv2ZWKb5MHps9d2pPJqmCDoWe53Bos56bYmJms5w==} + engines: {node: '>=12.22.0'} + peerDependencies: + react: ^16.8.0 || ^17 + dependencies: + react: 17.0.2 + dev: false + /react-is/16.13.1: resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} @@ -2321,8 +2602,8 @@ packages: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} dev: false - /react-query/3.34.8_react-dom@17.0.2+react@17.0.2: - resolution: {integrity: sha512-pl9e2VmVbgKf29Qn/WpmFVtB2g17JPqLLyOQg3GfSs/S2WABvip5xlT464vfXtilLPcJVg9bEHHlqmC38/nvDw==} + /react-query/3.34.16_react-dom@17.0.2+react@17.0.2: + resolution: {integrity: sha512-7FvBvjgEM4YQ8nPfmAr+lJfbW95uyW/TVjFoi2GwCkF33/S8ajx45tuPHPFGWs4qYwPy1mzwxD4IQfpUDrefNQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 react-dom: '*' @@ -2333,7 +2614,7 @@ packages: react-native: optional: true dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 broadcast-channel: 3.7.0 match-sorter: 6.3.1 react: 17.0.2 @@ -2345,6 +2626,17 @@ packages: engines: {node: '>=0.10.0'} dev: true + /react-virtuoso/2.7.2_react@17.0.2: + resolution: {integrity: sha512-EJm0e1hTpMK8xXzgtfbvr2dr2l2gek8p8dCJleJ6EJoQjr9sf+XCYkODThN1vTxhksvAT8uQxmxR5ASPDoS/uA==} + engines: {node: '>=10'} + peerDependencies: + react: '>=16' + dependencies: + '@virtuoso.dev/react-urx': 0.2.12_react@17.0.2 + '@virtuoso.dev/urx': 0.2.12 + react: 17.0.2 + dev: false + /react/17.0.2: resolution: {integrity: sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA==} engines: {node: '>=0.10.0'} @@ -2364,8 +2656,8 @@ packages: resolution: {integrity: sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==} dev: false - /regexp.prototype.flags/1.3.1: - resolution: {integrity: sha512-JiBdRBq91WlY7uRJ0ds7R+dU02i6LKi8r3BuQhNXn+kmeLN+EfHhfjqMRis1zJxnlu88hq/4dx0P2OP3APRTOA==} + /regexp.prototype.flags/1.4.1: + resolution: {integrity: sha512-pMR7hBVUUGI7PMA37m2ofIdQCsomVnas+Jn5UPGAHQ+/LlwKm/aTLJHdasmHRzlfeZwHiAOaRSo2rbBDm3nNUQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.2 @@ -2386,8 +2678,8 @@ packages: engines: {node: '>=4'} dev: true - /resolve/1.21.0: - resolution: {integrity: sha512-3wCbTpk5WJlyE4mSOtDLhqQmGFi0/TD9VPwmiolnk8U0wRgMEktqCXd3vy5buTO3tljvalNvKrjHEfrd2WpEKA==} + /resolve/1.22.0: + resolution: {integrity: sha512-Hhtrw0nLeSrFQ7phPp4OOcVjLPIeMnRlr5mcnVuMe7M/7eBn98A3hmFRLoFo3DLZkivSYwhRUJTyPyWAk56WLw==} hasBin: true dependencies: is-core-module: 2.8.1 @@ -2413,8 +2705,8 @@ packages: dependencies: glob: 7.2.0 - /rollup/2.63.0: - resolution: {integrity: sha512-nps0idjmD+NXl6OREfyYXMn/dar3WGcyKn+KBzPdaLecub3x/LrId0wUcthcr8oZUAcZAR8NKcfGGFlNgGL1kQ==} + /rollup/2.68.0: + resolution: {integrity: sha512-XrMKOYK7oQcTio4wyTz466mucnd8LzkiZLozZ4Rz0zQD+HeX4nUK4B8GrTX/2EvN2/vBF/i2WnaXboPxo0JylA==} engines: {node: '>=10.0.0'} hasBin: true optionalDependencies: @@ -2476,8 +2768,8 @@ packages: engines: {node: '>=8'} dev: true - /source-map-js/1.0.1: - resolution: {integrity: sha512-4+TN2b3tqOCd/kaGRJ/sTYA0tR0mdXx26ipdolxcwtJVqEnqNYvlCAt1q3ypy4QMlYus+Zh34RNtYLoq2oQ4IA==} + /source-map-js/1.0.2: + resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} dev: true @@ -2495,7 +2787,7 @@ packages: get-intrinsic: 1.1.1 has-symbols: 1.0.2 internal-slot: 1.0.3 - regexp.prototype.flags: 1.3.1 + regexp.prototype.flags: 1.4.1 side-channel: 1.0.4 dev: true @@ -2520,6 +2812,11 @@ packages: ansi-regex: 5.0.1 dev: true + /strip-bom/3.0.0: + resolution: {integrity: sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=} + engines: {node: '>=4'} + dev: true + /strip-json-comments/3.1.1: resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} engines: {node: '>=8'} @@ -2544,36 +2841,35 @@ packages: engines: {node: '>= 0.4'} dev: true - /tailwindcss/3.0.13_ef48b3b8837f8a23677bffe8f9cd866d: - resolution: {integrity: sha512-raRPGFwQSGXn/3h0ttHND9jyPYfqk/ur2NXtlQuK25+ZnrCjlH1s1j4/oPswHGMoZzGNykUVycZ/LcROanUE0A==} + /tailwindcss/3.0.23_autoprefixer@10.4.2: + resolution: {integrity: sha512-+OZOV9ubyQ6oI2BXEhzw4HrqvgcARY38xv3zKcjnWtMIZstEsXdI9xftd1iB7+RbOnj2HOEzkA0OyB5BaSxPQA==} engines: {node: '>=12.13.0'} hasBin: true peerDependencies: autoprefixer: ^10.0.2 - postcss: ^8.0.9 dependencies: arg: 5.0.1 - autoprefixer: 10.4.2_postcss@8.4.5 + autoprefixer: 10.4.2_postcss@8.4.7 chalk: 4.1.2 - chokidar: 3.5.2 + chokidar: 3.5.3 color-name: 1.1.4 cosmiconfig: 7.0.1 detective: 5.2.0 didyoumean: 1.2.2 dlv: 1.1.3 - fast-glob: 3.2.10 + fast-glob: 3.2.11 glob-parent: 6.0.2 is-glob: 4.0.3 normalize-path: 3.0.0 object-hash: 2.2.0 - postcss: 8.4.5 - postcss-js: 4.0.0_postcss@8.4.5 - postcss-load-config: 3.1.1 - postcss-nested: 5.0.6_postcss@8.4.5 - postcss-selector-parser: 6.0.8 + postcss: 8.4.7 + postcss-js: 4.0.0_postcss@8.4.7 + postcss-load-config: 3.1.3 + postcss-nested: 5.0.6_postcss@8.4.7 + postcss-selector-parser: 6.0.9 postcss-value-parser: 4.2.0 quick-lru: 5.1.1 - resolve: 1.21.0 + resolve: 1.22.0 transitivePeerDependencies: - ts-node dev: true @@ -2594,6 +2890,15 @@ packages: is-number: 7.0.0 dev: true + /tsconfig-paths/3.12.0: + resolution: {integrity: sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==} + dependencies: + '@types/json5': 0.0.29 + json5: 1.0.1 + minimist: 1.2.5 + strip-bom: 3.0.0 + dev: true + /tslib/1.14.1: resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} dev: true @@ -2602,14 +2907,14 @@ packages: resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==} dev: false - /tsutils/3.21.0_typescript@4.5.4: + /tsutils/3.21.0_typescript@4.5.5: resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.5.4 + typescript: 4.5.5 dev: true /type-check/0.4.0: @@ -2624,8 +2929,8 @@ packages: engines: {node: '>=10'} dev: true - /typescript/4.5.4: - resolution: {integrity: sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==} + /typescript/4.5.5: + resolution: {integrity: sha512-TCTIul70LyWe6IJWT8QSYeA54WQe8EjQFU4wY52Fasj5UKx88LNYKCgBEHcOMOrFF1rKGbD8v/xcNWVUq9SymA==} engines: {node: '>=4.2.0'} hasBin: true dev: true @@ -2642,7 +2947,7 @@ packages: /unload/2.2.0: resolution: {integrity: sha512-B60uB5TNBLtN6/LsgAf3udH9saB5p7gqJwcFfbOEZ8BcBHnGwCf6G/TGiEqkRAxX7zAFIUtzdrXQSdL3Q/wqNA==} dependencies: - '@babel/runtime': 7.16.7 + '@babel/runtime': 7.17.2 detect-node: 2.1.0 dev: false @@ -2656,12 +2961,17 @@ packages: resolution: {integrity: sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=} dev: true + /uuid/8.3.2: + resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} + hasBin: true + dev: false + /v8-compile-cache/2.3.0: resolution: {integrity: sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==} dev: true - /vite/2.7.10: - resolution: {integrity: sha512-KEY96ntXUid1/xJihJbgmLZx7QSC2D4Tui0FdS0Old5OokYzFclcofhtxtjDdGOk/fFpPbHv9yw88+rB93Tb8w==} + /vite/2.8.4: + resolution: {integrity: sha512-GwtOkkaT2LDI82uWZKcrpRQxP5tymLnC7hVHHqNkhFNknYr0hJUlDLfhVRgngJvAy3RwypkDCWtTKn1BjO96Dw==} engines: {node: '>=12.2.0'} hasBin: true peerDependencies: @@ -2676,10 +2986,10 @@ packages: stylus: optional: true dependencies: - esbuild: 0.13.15 - postcss: 8.4.5 - resolve: 1.21.0 - rollup: 2.63.0 + esbuild: 0.14.23 + postcss: 8.4.7 + resolve: 1.22.0 + rollup: 2.68.0 optionalDependencies: fsevents: 2.3.2 dev: true @@ -2723,3 +3033,8 @@ packages: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} engines: {node: '>= 6'} dev: true + + /yocto-queue/0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + dev: true diff --git a/ui/rsl/src/api/endpoint.ts b/ui/rsl/src/api/endpoint.ts index ab91ea5f3..e21be1615 100644 --- a/ui/rsl/src/api/endpoint.ts +++ b/ui/rsl/src/api/endpoint.ts @@ -1,4 +1,4 @@ -import getQueryParameters from "../util/queryParameters"; +import getQueryParameters from "@/util/queryParameters"; function getApiEndpoint(params: Record) { const defaultProtocol = window.location.protocol; diff --git a/ui/rsl/src/api/guesser.ts b/ui/rsl/src/api/guesser.ts index 51effc1bf..49cd3b909 100644 --- a/ui/rsl/src/api/guesser.ts +++ b/ui/rsl/src/api/guesser.ts @@ -1,10 +1,12 @@ -import { sendRequest } from "./request"; -import { verifyContentType } from "./protocol/checks"; +import { UseQueryResult, useQuery } from "react-query"; + +import { verifyContentType } from "@/api/protocol/checks"; import { StationGuesserRequest, StationGuesserResponse, -} from "./protocol/motis/guesser"; -import { useQuery, UseQueryResult } from "react-query"; +} from "@/api/protocol/motis/guesser"; + +import { sendRequest } from "@/api/request"; export async function sendStationGuesserRequest( content: StationGuesserRequest diff --git a/ui/rsl/src/api/lookup.ts b/ui/rsl/src/api/lookup.ts index 1bed7ee84..e3fce07fa 100644 --- a/ui/rsl/src/api/lookup.ts +++ b/ui/rsl/src/api/lookup.ts @@ -1,11 +1,13 @@ +import { UseQueryResult, useQuery } from "react-query"; + +import { verifyContentType } from "@/api/protocol/checks"; import { LookupRiBasisRequest, LookupRiBasisResponse, LookupScheduleInfoResponse, -} from "./protocol/motis/lookup"; -import { sendRequest } from "./request"; -import { verifyContentType } from "./protocol/checks"; -import { useQuery, UseQueryResult } from "react-query"; +} from "@/api/protocol/motis/lookup"; + +import { sendRequest } from "@/api/request"; export async function sendLookupScheduleInfoRequest(): Promise { const msg = await sendRequest("/lookup/schedule_info"); diff --git a/ui/rsl/src/api/paxforecast.ts b/ui/rsl/src/api/paxforecast.ts index 23aa1f8f5..7d4ddf006 100644 --- a/ui/rsl/src/api/paxforecast.ts +++ b/ui/rsl/src/api/paxforecast.ts @@ -1,16 +1,19 @@ -import { sendRequest } from "./request"; -import { verifyContentType } from "./protocol/checks"; -import { PaxForecastApplyMeasuresRequest } from "./protocol/motis/paxforecast"; -import { MotisSuccess } from "./protocol/motis"; +import { verifyContentType } from "@/api/protocol/checks"; +import { + PaxForecastApplyMeasuresRequest, + PaxForecastApplyMeasuresResponse, +} from "@/api/protocol/motis/paxforecast"; + +import { sendRequest } from "@/api/request"; export async function sendPaxForecastApplyMeasuresRequest( content: PaxForecastApplyMeasuresRequest -): Promise { +): Promise { const msg = await sendRequest( "/paxforecast/apply_measures", "PaxForecastApplyMeasuresRequest", content ); - verifyContentType(msg, "MotisSuccess"); - return msg.content as MotisSuccess; + verifyContentType(msg, "PaxForecastApplyMeasuresResponse"); + return msg.content as PaxForecastApplyMeasuresResponse; } diff --git a/ui/rsl/src/api/paxmon.ts b/ui/rsl/src/api/paxmon.ts index 3e4d3c742..aaeb1de1d 100644 --- a/ui/rsl/src/api/paxmon.ts +++ b/ui/rsl/src/api/paxmon.ts @@ -1,8 +1,11 @@ -import { sendRequest } from "./request"; -import { verifyContentType } from "./protocol/checks"; -import { MotisSuccess, TripId } from "./protocol/motis"; +import { UseQueryResult, useQuery } from "react-query"; + +import { verifyContentType } from "@/api/protocol/checks"; +import { MotisSuccess, TripId } from "@/api/protocol/motis"; import { PaxMonDestroyUniverseRequest, + PaxMonFilterTripsRequest, + PaxMonFilterTripsResponse, PaxMonFindTripsRequest, PaxMonFindTripsResponse, PaxMonForkUniverseRequest, @@ -15,8 +18,9 @@ import { PaxMonGetTripLoadInfosResponse, PaxMonStatusRequest, PaxMonStatusResponse, -} from "./protocol/motis/paxmon"; -import { useQuery, UseQueryResult } from "react-query"; +} from "@/api/protocol/motis/paxmon"; + +import { sendRequest } from "@/api/request"; export async function sendPaxMonStatusRequest( content: PaxMonStatusRequest @@ -151,6 +155,26 @@ export function usePaxMonGetInterchangesQuery( ); } +export async function sendPaxMonFilterTripsRequest( + content: PaxMonFilterTripsRequest +): Promise { + const msg = await sendRequest( + "/paxmon/filter_trips", + "PaxMonFilterTripsRequest", + content + ); + verifyContentType(msg, "PaxMonFilterTripsResponse"); + return msg.content as PaxMonFilterTripsResponse; +} + +export function usePaxMonFilterTripsRequest( + content: PaxMonFilterTripsRequest +): UseQueryResult { + return useQuery(queryKeys.filterTrips(content), () => + sendPaxMonFilterTripsRequest(content) + ); +} + export const queryKeys = { all: ["paxmon"] as const, status: (universe: number) => [...queryKeys.all, "status", universe] as const, @@ -163,4 +187,6 @@ export const queryKeys = { [...queryKeys.trip(), "groups", req] as const, interchanges: (req: PaxMonGetInterchangesRequest) => [...queryKeys.all, "interchanges", req] as const, + filterTrips: (req: PaxMonFilterTripsRequest) => + [...queryKeys.all, "filter_trips", req] as const, }; diff --git a/ui/rsl/src/api/protocol/checks.ts b/ui/rsl/src/api/protocol/checks.ts index cc2c0c8b1..668462f4d 100644 --- a/ui/rsl/src/api/protocol/checks.ts +++ b/ui/rsl/src/api/protocol/checks.ts @@ -1,4 +1,4 @@ -import { Message, MsgContentType } from "./motis"; +import { Message, MsgContentType } from "@/api/protocol/motis"; export function verifyContentType( msg: Message, diff --git a/ui/rsl/src/api/protocol/motis.ts b/ui/rsl/src/api/protocol/motis.ts index 6bc6560fd..bf9190407 100644 --- a/ui/rsl/src/api/protocol/motis.ts +++ b/ui/rsl/src/api/protocol/motis.ts @@ -1,58 +1,61 @@ // generated file - do not modify - run update-protocol to update - -import { StationGuesserRequest, StationGuesserResponse } from "./motis/guesser"; import { - LookupGeoStationIdRequest, - LookupGeoStationRequest, - LookupGeoStationResponse, + StationGuesserRequest, + StationGuesserResponse, +} from "@/api/protocol/motis/guesser"; +import { LookupBatchGeoStationRequest, LookupBatchGeoStationResponse, - LookupStationEventsRequest, - LookupStationEventsResponse, - LookupScheduleInfoResponse, - LookupMetaStationRequest, - LookupMetaStationResponse, LookupBatchMetaStationRequest, LookupBatchMetaStationResponse, + LookupGeoStationIdRequest, + LookupGeoStationRequest, + LookupGeoStationResponse, LookupIdTrainRequest, LookupIdTrainResponse, + LookupMetaStationRequest, + LookupMetaStationResponse, LookupRiBasisRequest, LookupRiBasisResponse, -} from "./motis/lookup"; -import { RISForwardTimeRequest } from "./motis/ris"; -import { RoutingRequest, RoutingResponse } from "./motis/routing"; + LookupScheduleInfoResponse, + LookupStationEventsRequest, + LookupStationEventsResponse, +} from "@/api/protocol/motis/lookup"; +import { + PaxForecastApplyMeasuresRequest, + PaxForecastApplyMeasuresResponse, + PaxForecastUpdate, +} from "@/api/protocol/motis/paxforecast"; import { - PaxMonUpdate, PaxMonAddGroupsRequest, PaxMonAddGroupsResponse, - PaxMonRemoveGroupsRequest, - PaxMonTripLoadInfo, - PaxMonFindTripsRequest, - PaxMonFindTripsResponse, - PaxMonStatusResponse, - PaxMonGetGroupsRequest, - PaxMonGetGroupsResponse, + PaxMonDestroyUniverseRequest, PaxMonFilterGroupsRequest, PaxMonFilterGroupsResponse, PaxMonFilterTripsRequest, PaxMonFilterTripsResponse, - PaxMonGetTripLoadInfosRequest, - PaxMonGetTripLoadInfosResponse, + PaxMonFindTripsRequest, + PaxMonFindTripsResponse, PaxMonForkUniverseRequest, PaxMonForkUniverseResponse, - PaxMonDestroyUniverseRequest, PaxMonGetGroupsInTripRequest, PaxMonGetGroupsInTripResponse, - PaxMonUniverseForked, - PaxMonUniverseDestroyed, + PaxMonGetGroupsRequest, + PaxMonGetGroupsResponse, PaxMonGetInterchangesRequest, PaxMonGetInterchangesResponse, + PaxMonGetTripLoadInfosRequest, + PaxMonGetTripLoadInfosResponse, + PaxMonRemoveGroupsRequest, PaxMonStatusRequest, -} from "./motis/paxmon"; -import { - PaxForecastUpdate, - PaxForecastApplyMeasuresRequest, -} from "./motis/paxforecast"; + PaxMonStatusResponse, + PaxMonTripLoadInfo, + PaxMonUniverseDestroyed, + PaxMonUniverseForked, + PaxMonUpdate, +} from "@/api/protocol/motis/paxmon"; +import { RISForwardTimeRequest } from "@/api/protocol/motis/ris"; +import { RoutingRequest, RoutingResponse } from "@/api/protocol/motis/routing"; // base/Connection.fbs export interface EventInfo { @@ -359,7 +362,8 @@ export type MsgContent = | PaxMonGetInterchangesResponse | PaxMonStatusRequest | LookupRiBasisRequest - | LookupRiBasisResponse; + | LookupRiBasisResponse + | PaxForecastApplyMeasuresResponse; export type MsgContentType = | "MotisNoMessage" @@ -418,7 +422,8 @@ export type MsgContentType = | "PaxMonGetInterchangesResponse" | "PaxMonStatusRequest" | "LookupRiBasisRequest" - | "LookupRiBasisResponse"; + | "LookupRiBasisResponse" + | "PaxForecastApplyMeasuresResponse"; // Message.fbs export type DestinationType = "Module" | "Topic"; diff --git a/ui/rsl/src/api/protocol/motis/guesser.ts b/ui/rsl/src/api/protocol/motis/guesser.ts index c8ba13085..5e60d075f 100644 --- a/ui/rsl/src/api/protocol/motis/guesser.ts +++ b/ui/rsl/src/api/protocol/motis/guesser.ts @@ -1,6 +1,5 @@ // generated file - do not modify - run update-protocol to update - -import { Station } from "../motis"; +import { Station } from "@/api/protocol/motis"; // guesser/StationGuesserRequest.fbs export interface StationGuesserRequest { diff --git a/ui/rsl/src/api/protocol/motis/lookup.ts b/ui/rsl/src/api/protocol/motis/lookup.ts index 5a92a52de..c2ef660a7 100644 --- a/ui/rsl/src/api/protocol/motis/lookup.ts +++ b/ui/rsl/src/api/protocol/motis/lookup.ts @@ -1,14 +1,13 @@ // generated file - do not modify - run update-protocol to update - import { + Connection, + EventType, + Interval, Position, Station, TripId, - Connection, - Interval, - EventType, -} from "../motis"; -import { RiBasisFahrt } from "./ribasis"; +} from "@/api/protocol/motis"; +import { RiBasisFahrt } from "@/api/protocol/motis/ribasis"; // lookup/LookupGeoStationIdRequest.fbs export interface LookupGeoStationIdRequest { diff --git a/ui/rsl/src/api/protocol/motis/paxforecast.ts b/ui/rsl/src/api/protocol/motis/paxforecast.ts index 559be7829..57d099100 100644 --- a/ui/rsl/src/api/protocol/motis/paxforecast.ts +++ b/ui/rsl/src/api/protocol/motis/paxforecast.ts @@ -1,14 +1,14 @@ // generated file - do not modify - run update-protocol to update - -import { TripId } from "../motis"; -import { RISContentType } from "./ris"; +import { TripId } from "@/api/protocol/motis"; import { PaxMonCompactJourney, PaxMonGroup, PaxMonLocalization, PaxMonLocalizationType, + PaxMonTrackedUpdates, PaxMonTripLoadInfo, -} from "./paxmon"; +} from "@/api/protocol/motis/paxmon"; +import { RISContentType } from "@/api/protocol/motis/ris"; // paxforecast/Measures.fbs export interface MeasureRecipients { @@ -35,7 +35,6 @@ export interface TripRecommendationMeasure { planned_destinations: string[]; planned_long_distance_destinations: string[]; recommended_trip: TripId; - interchange_station: string; } // paxforecast/Measures.fbs @@ -69,6 +68,30 @@ export interface PaxForecastApplyMeasuresRequest { measures: MeasureWrapper[]; replace_existing: boolean; preparation_time: number; + include_before_trip_load_info: boolean; + include_after_trip_load_info: boolean; +} + +// paxforecast/PaxForecastApplyMeasuresResponse.fbs +export interface PaxForecastApplyMeasuresStatistics { + measure_time_points: number; + total_measures_applied: number; + total_affected_groups: number; + total_alternative_routings: number; + total_alternatives_found: number; + t_rt_updates: number; + t_get_affected_groups: number; + t_find_alternatives: number; + t_add_alternatives_to_graph: number; + t_behavior_simulation: number; + t_update_groups: number; + t_update_tracker: number; +} + +// paxforecast/PaxForecastApplyMeasuresResponse.fbs +export interface PaxForecastApplyMeasuresResponse { + stats: PaxForecastApplyMeasuresStatistics; + updates: PaxMonTrackedUpdates; } // paxforecast/PaxForecastUpdate.fbs diff --git a/ui/rsl/src/api/protocol/motis/paxmon.ts b/ui/rsl/src/api/protocol/motis/paxmon.ts index d715b7799..c6dde8797 100644 --- a/ui/rsl/src/api/protocol/motis/paxmon.ts +++ b/ui/rsl/src/api/protocol/motis/paxmon.ts @@ -1,6 +1,5 @@ // generated file - do not modify - run update-protocol to update - -import { TripServiceInfo, Station, TripId } from "../motis"; +import { Station, TripId, TripServiceInfo } from "@/api/protocol/motis"; // paxmon/PaxMonAddGroupsRequest.fbs export interface PaxMonAddGroupsRequest { @@ -74,18 +73,44 @@ export interface PaxMonFilterGroupsResponse { localizations: PaxMonLocalizationWrapper[]; } +// paxmon/PaxMonFilterTripsRequest.fbs +export type PaxMonFilterTripsSortOrder = + | "MostCritical" + | "FirstDeparture" + | "ExpectedPax"; + // paxmon/PaxMonFilterTripsRequest.fbs export interface PaxMonFilterTripsRequest { universe: number; - load_factor_possibly_ge: number; ignore_past_sections: boolean; + include_load_threshold: number; + critical_load_threshold: number; // default: 1 + crowded_load_threshold: number; // default: 0.8 + include_edges: boolean; + sort_by: PaxMonFilterTripsSortOrder; + max_results: number; + skip_first: number; +} + +// paxmon/PaxMonFilterTripsResponse.fbs +export interface PaxMonFilteredTripInfo { + tsi: TripServiceInfo; + section_count: number; + critical_sections: number; + crowded_sections: number; + max_excess_pax: number; + cumulative_excess_pax: number; + max_expected_pax: number; + edges: PaxMonEdgeLoadInfo[]; } // paxmon/PaxMonFilterTripsResponse.fbs export interface PaxMonFilterTripsResponse { + total_matching_trips: number; filtered_trips: number; - critical_sections: number; - trips: TripServiceInfo[]; + remaining_trips: number; + total_critical_sections: number; + trips: PaxMonFilteredTripInfo[]; } // paxmon/PaxMonFindTripsRequest.fbs @@ -131,7 +156,8 @@ export type PaxMonGroupByStation = | "First" | "Last" | "FirstLongDistance" - | "LastLongDistance"; + | "LastLongDistance" + | "EntryAndLast"; // paxmon/PaxMonGetGroupsInTripRequest.fbs export interface PaxMonGetGroupsInTripRequest { @@ -147,6 +173,8 @@ export interface PaxMonGetGroupsInTripRequest { export interface GroupedPassengerGroups { grouped_by_station: Station[]; grouped_by_trip: TripServiceInfo[]; + entry_station: Station[]; + entry_time: number; info: PaxMonCombinedGroups; } @@ -198,6 +226,7 @@ export interface PaxMonTripStopInfo { schedule_time: number; current_time: number; trips: TripServiceInfo[]; + station: Station; } // paxmon/PaxMonGetInterchangesResponse.fbs @@ -299,6 +328,46 @@ export interface PaxMonStatusResponse { trip_count: number; } +// paxmon/PaxMonTrackedUpdates.fbs +export interface PaxMonReusedGroupBaseInfo { + id: number; + passenger_count: number; + probability: number; + previous_probability: number; +} + +// paxmon/PaxMonTrackedUpdates.fbs +export interface PaxMonCriticalTripInfo { + critical_sections: number; + max_excess_pax: number; + cumulative_excess_pax: number; +} + +// paxmon/PaxMonTrackedUpdates.fbs +export interface PaxMonUpdatedTrip { + tsi: TripServiceInfo; + removed_max_pax: number; + removed_mean_pax: number; + added_max_pax: number; + added_mean_pax: number; + critical_info_before: PaxMonCriticalTripInfo; + critical_info_after: PaxMonCriticalTripInfo; + removed_groups: PaxMonGroupBaseInfo[]; + added_groups: PaxMonGroupBaseInfo[]; + reused_groups: PaxMonReusedGroupBaseInfo[]; + before_edges: PaxMonEdgeLoadInfo[]; + after_edges: PaxMonEdgeLoadInfo[]; +} + +// paxmon/PaxMonTrackedUpdates.fbs +export interface PaxMonTrackedUpdates { + added_group_count: number; + reused_group_count: number; + removed_group_count: number; + updated_trip_count: number; + updated_trips: PaxMonUpdatedTrip[]; +} + // paxmon/PaxMonTripLoadInfo.fbs export interface PaxMonCdfEntry { passengers: number; diff --git a/ui/rsl/src/api/protocol/motis/routing.ts b/ui/rsl/src/api/protocol/motis/routing.ts index 942eec2d0..fc9704cfc 100644 --- a/ui/rsl/src/api/protocol/motis/routing.ts +++ b/ui/rsl/src/api/protocol/motis/routing.ts @@ -1,12 +1,11 @@ // generated file - do not modify - run update-protocol to update - import { - Interval, - TripId, - Statistics, Connection, DirectConnection, -} from "../motis"; + Interval, + Statistics, + TripId, +} from "@/api/protocol/motis"; // routing/RoutingRequest.fbs export interface InputStation { diff --git a/ui/rsl/src/api/request.ts b/ui/rsl/src/api/request.ts index 839af4366..fe4ffe880 100644 --- a/ui/rsl/src/api/request.ts +++ b/ui/rsl/src/api/request.ts @@ -1,5 +1,6 @@ -import { Message, MsgContent, MsgContentType } from "./protocol/motis"; -import apiEndpoint from "./endpoint"; +import { Message, MsgContent, MsgContentType } from "@/api/protocol/motis"; + +import apiEndpoint from "@/api/endpoint"; export function makeMessage( target: string, diff --git a/ui/rsl/src/api/ris.ts b/ui/rsl/src/api/ris.ts index f75420fea..b56e0163d 100644 --- a/ui/rsl/src/api/ris.ts +++ b/ui/rsl/src/api/ris.ts @@ -1,6 +1,7 @@ -import { sendRequest } from "./request"; -import { verifyContentType } from "./protocol/checks"; -import { Message } from "./protocol/motis"; +import { verifyContentType } from "@/api/protocol/checks"; +import { Message } from "@/api/protocol/motis"; + +import { sendRequest } from "@/api/request"; export function sendRISForwardTimeRequest( newTime: number | Date, diff --git a/ui/rsl/src/api/routing.ts b/ui/rsl/src/api/routing.ts index 0aa576201..1edc3afe0 100644 --- a/ui/rsl/src/api/routing.ts +++ b/ui/rsl/src/api/routing.ts @@ -1,6 +1,7 @@ -import { sendRequest } from "./request"; -import { verifyContentType } from "./protocol/checks"; -import { RoutingRequest, RoutingResponse } from "./protocol/motis/routing"; +import { verifyContentType } from "@/api/protocol/checks"; +import { RoutingRequest, RoutingResponse } from "@/api/protocol/motis/routing"; + +import { sendRequest } from "@/api/request"; export async function sendRoutingRequest( content: RoutingRequest diff --git a/ui/rsl/src/components/App.tsx b/ui/rsl/src/components/App.tsx index 9a6cce02a..d15f4dc9c 100644 --- a/ui/rsl/src/components/App.tsx +++ b/ui/rsl/src/components/App.tsx @@ -2,14 +2,15 @@ import { useState } from "react"; import { QueryClient, QueryClientProvider } from "react-query"; import { ReactQueryDevtools } from "react-query/devtools"; -import { TripId } from "../api/protocol/motis"; -import getQueryParameters from "../util/queryParameters"; +import { TripId } from "@/api/protocol/motis"; -import TimeControl from "./TimeControl"; -import TripPicker from "./TripPicker"; -import TripDetails from "./TripDetails"; -import MeasureInput from "./measures/MeasureInput"; -import UniverseControl from "./UniverseControl"; +import getQueryParameters from "@/util/queryParameters"; + +import SimPanel from "@/components/SimPanel"; +import TimeControl from "@/components/TimeControl"; +import TripDetails from "@/components/TripDetails"; +import TripSelection from "@/components/TripSelection"; +import UniverseControl from "@/components/UniverseControl"; const queryClient = new QueryClient({ defaultOptions: { @@ -21,51 +22,29 @@ const allowForwarding = getQueryParameters()["allowForwarding"] === "yes"; function App(): JSX.Element { const [selectedTrip, setSelectedTrip] = useState(); - const [simActive, setSimActive] = useState(false); - - const tripDisplay = - selectedTrip !== undefined ? : null; return ( -
+
-
- -
-
- {simActive && ( -
- -
- )} -
-
- Trip: - setSelectedTrip(tsi?.trip)} - clearOnPick={false} - longDistanceOnly={true} - className="w-96" - /> -
- {tripDisplay} +
+
+ +
+
+ {selectedTrip !== undefined ? ( + + ) : null} +
+
+
diff --git a/ui/rsl/src/components/CombinedGroup.tsx b/ui/rsl/src/components/CombinedGroup.tsx index 39b3dff8a..4cf82b810 100644 --- a/ui/rsl/src/components/CombinedGroup.tsx +++ b/ui/rsl/src/components/CombinedGroup.tsx @@ -1,17 +1,20 @@ -import { useQuery } from "react-query"; -import { useAtom } from "jotai"; import * as Tooltip from "@radix-ui/react-tooltip"; +import { useAtom } from "jotai"; +import { useQuery } from "react-query"; + +import { Station, TripId } from "@/api/protocol/motis"; +import { GroupedPassengerGroups } from "@/api/protocol/motis/paxmon"; + +import { sendRoutingRequest } from "@/api/routing"; + +import { Journey, connectionToJourney } from "@/data/journey"; +import { scheduleAtom } from "@/data/simulation"; -import { Station, TripId } from "../api/protocol/motis"; -import { GroupedPassengerGroups } from "../api/protocol/motis/paxmon"; -import { sendRoutingRequest } from "../api/routing"; -import { connectionToJourney, Journey } from "../data/journey"; -import { formatTime } from "../util/dateFormat"; -import { scheduleAtom } from "../data/simulation"; +import { formatTime } from "@/util/dateFormat"; -import TripLoadForecastChart from "./TripLoadForecastChart"; -import JourneyTripNameView from "./JourneyTripNameView"; -import TripServiceInfoView from "./TripServiceInfoView"; +import JourneyTripNameView from "@/components/JourneyTripNameView"; +import TripLoadForecastChart from "@/components/TripLoadForecastChart"; +import TripServiceInfoView from "@/components/TripServiceInfoView"; export type GroupByDirection = "Origin" | "Destination"; @@ -45,10 +48,26 @@ function getDepartureTime(j: Journey): number { } } -function CombinedGroup(props: CombinedGroupProps): JSX.Element { - const destinationStation = props.combinedGroup.grouped_by_station[0]; - const previousTrip = props.combinedGroup.grouped_by_trip[0]; - const findAlternatives = props.groupByDirection === "Destination"; +/* +export type CombinedGroupProps = { + plannedTrip: TripId; + combinedGroup: GroupedPassengerGroups; + startStation: Station; + earliestDeparture: number; + groupByDirection: GroupByDirection; +}; + */ + +function CombinedGroup({ + plannedTrip, + combinedGroup, + startStation, + earliestDeparture, + groupByDirection, +}: CombinedGroupProps): JSX.Element { + const destinationStation = combinedGroup.grouped_by_station[0]; + const previousTrip = combinedGroup.grouped_by_trip[0]; + const findAlternatives = groupByDirection === "Destination"; const [schedule] = useAtom(scheduleAtom); @@ -56,9 +75,9 @@ function CombinedGroup(props: CombinedGroupProps): JSX.Element { [ "alternatives", { - from: props.startStation.id, + from: startStation.id, to: destinationStation.id, - earliestDeparture: props.earliestDeparture, + earliestDeparture: earliestDeparture, intervalDuration: SEARCH_INTERVAL, }, ], @@ -66,10 +85,10 @@ function CombinedGroup(props: CombinedGroupProps): JSX.Element { sendRoutingRequest({ start_type: "PretripStart", start: { - station: { id: props.startStation.id, name: "" }, + station: { id: startStation.id, name: "" }, interval: { - begin: props.earliestDeparture, - end: props.earliestDeparture + SEARCH_INTERVAL * 60, + begin: earliestDeparture, + end: earliestDeparture + SEARCH_INTERVAL * 60, }, min_connection_count: 0, extend_interval_earlier: false, @@ -88,7 +107,7 @@ function CombinedGroup(props: CombinedGroupProps): JSX.Element { { enabled: findAlternatives } ); - const plannedTripId = JSON.stringify(props.plannedTrip); + const plannedTripId = JSON.stringify(plannedTrip); const containsCurrentTrip = (j: Journey) => j.tripLegs.find((leg) => leg.trips.find((t) => JSON.stringify(t.trip.id) === plannedTripId) @@ -99,10 +118,13 @@ function CombinedGroup(props: CombinedGroupProps): JSX.Element { const groupInfo = (
- {props.combinedGroup.info.min_passenger_count}- - {props.combinedGroup.info.max_passenger_count} Reisende - {props.groupByDirection === "Origin" ? " aus " : " in "}Richtung{" "} + {combinedGroup.info.min_passenger_count}- + {combinedGroup.info.max_passenger_count} Reisende + {groupByDirection === "Origin" ? " aus " : " in "}Richtung{" "} {destinationStation.name} + {combinedGroup.entry_station.length === 1 + ? `, Einstieg in ${combinedGroup.entry_station[0].name}` + : null} {previousTrip && (
@@ -117,7 +139,7 @@ function CombinedGroup(props: CombinedGroupProps): JSX.Element { const alternativesInfo = journeys ? (
{journeys.length} Mögliche Verbindungen (ab{" "} - {formatTime(props.earliestDeparture)}): + {formatTime(earliestDeparture)}):
    {journeys.map((j, idx) => (
  • void; +}; + +function CriticalTripList({ + onTripSelected, +}: CriticalTripListProps): JSX.Element { + const [universe] = useAtom(universeAtom); + + const { data /*, isLoading, error */ } = usePaxMonFilterTripsRequest({ + universe, + ignore_past_sections: true, + include_load_threshold: 1.0, + critical_load_threshold: 1.0, + crowded_load_threshold: 0.8, + include_edges: false, + sort_by: "MostCritical", + max_results: 100, + skip_first: 0, + }); + + if (!data) { + return
    Kritische Züge werden geladen...
    ; + } + + return ( +
    +
    Kritische Züge:
    +
    + {data.trips.map((ti) => ( +
    onTripSelected(ti.tsi.trip)} + > + +
    +
    + Kritische Abschnitte: {ti.critical_sections}/{ti.section_count}{" "} +
    +
    + Reisende über Kapazität: {formatNumber(ti.max_excess_pax)} max.,{" "} + {formatNumber(ti.cumulative_excess_pax)} gesamt +
    +
    +
    + ))} +
    + {data.remaining_trips > 0 ? ( +
    + ...und {formatNumber(data.remaining_trips)} weitere kritische Züge ( + {formatNumber(data.total_matching_trips)} insgesamt) +
    + ) : null} +
    + ); +} + +export default CriticalTripList; diff --git a/ui/rsl/src/components/JourneyTripNameView.tsx b/ui/rsl/src/components/JourneyTripNameView.tsx index e9f6b3234..97373064c 100644 --- a/ui/rsl/src/components/JourneyTripNameView.tsx +++ b/ui/rsl/src/components/JourneyTripNameView.tsx @@ -1,4 +1,4 @@ -import { JourneyTrip } from "../data/journey"; +import { JourneyTrip } from "@/data/journey"; type JourneyTripNameViewProps = { jt: JourneyTrip; diff --git a/ui/rsl/src/components/MiniTripLoadGraph.tsx b/ui/rsl/src/components/MiniTripLoadGraph.tsx new file mode 100644 index 000000000..c4b3abd07 --- /dev/null +++ b/ui/rsl/src/components/MiniTripLoadGraph.tsx @@ -0,0 +1,151 @@ +import { PaxMonEdgeLoadInfo } from "@/api/protocol/motis/paxmon"; + +import { paxQuantile } from "@/util/statistics"; + +export type MiniTripLoadGraphProps = { + edges: PaxMonEdgeLoadInfo[]; +}; + +function MiniTripLoadGraph({ edges }: MiniTripLoadGraphProps): JSX.Element { + const graphWidth = 1000; + const graphHeight = 100; + + const minEdgeLoad = (eli: PaxMonEdgeLoadInfo) => + eli.passenger_cdf.length > 0 ? eli.passenger_cdf[0].passengers : 0; + const maxEdgeLoad = (eli: PaxMonEdgeLoadInfo) => + eli.passenger_cdf.length > 0 + ? eli.passenger_cdf[eli.passenger_cdf.length - 1].passengers + : 0; + const avgEdgeLoad = (eli: PaxMonEdgeLoadInfo) => + eli.passenger_cdf.length > 0 ? paxQuantile(eli.passenger_cdf, 0.5) : 0; + + const maxCapacity = edges.reduce( + (max, eli) => (eli.capacity ? Math.max(max, eli.capacity) : max), + 0 + ); + const maxPax = edges.reduce((max, eli) => Math.max(max, maxEdgeLoad(eli)), 0); + const maxLoad = Math.max(maxCapacity, maxPax, 1); + + const sectionWidth = graphWidth / edges.length; + + const sectionXStart = (idx: number) => idx * sectionWidth; + const loadY = (load: number) => (1 - load / maxLoad) * graphHeight; + + // TODO: + // - diff graph - 2 edge sets + // - if trip route was changed, show new route and only matching edges + // - show +/- pax per section (min/max/avg?) + // - section infos (station names) @hover? + + return ( + + + {edges.map((eli, idx) => { + const capacity = eli.capacity; + const left = sectionXStart(idx); + const bgs = []; + if (capacity) { + const yRed = 0; + const yYellow = loadY(capacity); + const yGreen = loadY(capacity * 0.8); + const hRed = yYellow - yRed; + const hYellow = yGreen - yYellow; + const hGreen = graphHeight - yGreen; + + if (hRed > 0) { + bgs.push( + + ); + } + if (hYellow > 0) { + bgs.push( + + ); + } + if (hGreen > 0) { + bgs.push( + + ); + } + } else { + bgs.push( + + ); + } + return {bgs}; + })} + + + {edges.map((eli, idx) => ( + + ))} + + + {edges.map((eli, idx) => ( + + ))} + + + {edges.map((_, idx) => ( + + ))} + + + + ); +} + +export default MiniTripLoadGraph; diff --git a/ui/rsl/src/components/SimPanel.tsx b/ui/rsl/src/components/SimPanel.tsx new file mode 100644 index 000000000..536a91ae2 --- /dev/null +++ b/ui/rsl/src/components/SimPanel.tsx @@ -0,0 +1,92 @@ +import { useAtom } from "jotai"; +import { useCallback, useState } from "react"; + +import { hasSimResultsAtom } from "@/data/simulation"; + +import classNames from "@/util/classNames"; + +import SimResultsPanel from "@/components/SimResultsPanel"; +import MeasurePanel from "@/components/measures/MeasurePanel"; + +type TabId = "measures" | "results"; + +type TabProps = { + id: TabId; + label: string; + selectedTab: TabId; + setSelectedTab: (id: TabId) => void; + disabled?: boolean; +}; + +function Tab({ + id, + label, + selectedTab, + setSelectedTab, + disabled, +}: TabProps): JSX.Element { + return ( + + ); +} + +function SimPanel(): JSX.Element { + const [selectedTab, setSelectedTab] = useState("measures"); + const [hasSimResults] = useAtom(hasSimResultsAtom); + + const onSimulationFinished = useCallback(() => { + setSelectedTab("results"); + }, [setSelectedTab]); + + return ( +
    +
    + + +
    +
    + +
    +
    + +
    +
    + ); +} + +export default SimPanel; diff --git a/ui/rsl/src/components/SimResultsPanel.tsx b/ui/rsl/src/components/SimResultsPanel.tsx new file mode 100644 index 000000000..9d3e53177 --- /dev/null +++ b/ui/rsl/src/components/SimResultsPanel.tsx @@ -0,0 +1,237 @@ +import { Listbox, Transition } from "@headlessui/react"; +import { CheckIcon, SelectorIcon } from "@heroicons/react/solid"; +import { differenceInMilliseconds } from "date-fns"; +import { PrimitiveAtom, useAtom } from "jotai"; +import { Fragment, memo } from "react"; +import { Virtuoso } from "react-virtuoso"; + +import { PaxMonUpdatedTrip } from "@/api/protocol/motis/paxmon"; + +import { formatMiliseconds, formatNumber } from "@/data/numberFormat"; +import { + SimulationResult, + selectedSimResultAtom, + simResultsAtom, +} from "@/data/simulation"; + +import classNames from "@/util/classNames"; +import { formatDateTime } from "@/util/dateFormat"; + +import MiniTripLoadGraph from "@/components/MiniTripLoadGraph"; +import TripServiceInfoView from "@/components/TripServiceInfoView"; + +type SimResultsListEntryProps = { + simResultAtom: PrimitiveAtom; +}; + +function SimResultsListEntry({ + simResultAtom, +}: SimResultsListEntryProps): JSX.Element { + const [simResult] = useAtom(simResultAtom); + + return ( + + {formatDateTime(simResult.startedAt)} – Universum # + {simResult.universe} + + ); +} + +function SimResultsList(): JSX.Element { + const [simResultsList] = useAtom(simResultsAtom); + const [selectedSimResult, setSelectedSimResult] = useAtom( + selectedSimResultAtom + ); + + return ( +
    + +
    + + + {selectedSimResult ? ( + + ) : ( + + Simulation auswählen... + + )} + + + + + + + {simResultsList.map((resultAtom, resultIdx) => ( + + classNames( + "cursor-default select-none relative py-2 pl-10 pr-4", + active ? "text-amber-900 bg-amber-100" : "text-gray-900" + ) + } + value={resultAtom} + > + {({ selected, active }) => ( + <> + + + + {selected ? ( + + + ) : null} + + )} + + ))} + + +
    +
    +
    + ); +} + +type SimResultDetailsProps = { + simResultAtom: PrimitiveAtom; +}; + +function SimResultDetails({ + simResultAtom, +}: SimResultDetailsProps): JSX.Element { + const [simResult] = useAtom(simResultAtom); + + const r = simResult.response; + const duration = differenceInMilliseconds( + simResult.finishedAt, + simResult.startedAt + ); + + const MemoizedUpdatedTrip = memo(function MemoizedUpdatedTripWrapper({ + index, + }: { + index: number; + }) { + return ; + }); + + const runtimeStats = [ + { duration: r.stats.t_rt_updates, label: "Einspielen der Echtzeitupdates" }, + { + duration: r.stats.t_get_affected_groups, + label: "Bestimmung betroffener Gruppen", + }, + { duration: r.stats.t_find_alternatives, label: "Alternativensuche" }, + { duration: r.stats.t_behavior_simulation, label: "Verhaltenssimulation" }, + { + duration: r.stats.t_update_groups, + label: "Aktualisierung der Reisendengruppen", + }, + { duration: r.stats.t_update_tracker, label: "Statistiken zu Änderungen" }, + ] + .map(({ duration, label }) => `${formatMiliseconds(duration)} ${label}`) + .join("\n"); + + return ( + <> +
    +
    Statistiken:
    +
      +
    • + Betroffene Reisendengruppen:{" "} + {formatNumber(r.stats.total_affected_groups)} +
    • +
    • + Alternativensuchen:{" "} + {formatNumber(r.stats.total_alternative_routings)} ( + {formatNumber(r.stats.total_alternatives_found)} Ergebnisse,{" "} + {formatMiliseconds(r.stats.t_find_alternatives)}) +
    • +
    • + Simulationsdauer insgesamt: {formatMiliseconds(duration)} +
    • +
    +
    + {formatNumber(r.updates.updated_trip_count)} betroffene Züge: +
    +
    +
    + } + /> +
    + + ); +} + +type UpdatedTripProps = { + ut: PaxMonUpdatedTrip; +}; + +function UpdatedTrip({ ut }: UpdatedTripProps) { + return ( +
    + +
      +
    • + Reisende über Kapazität: {ut.critical_info_before.max_excess_pax} + {" → "} + {ut.critical_info_after.max_excess_pax} max. /{" "} + {ut.critical_info_before.cumulative_excess_pax} {" → "} + {ut.critical_info_after.cumulative_excess_pax} gesamt +
    • +
    • + Kritische Abschnitte: {ut.critical_info_before.critical_sections} + {" → "} + {ut.critical_info_after.critical_sections} +
    • +
    • + Reisende: Avg: -{Math.round(ut.removed_mean_pax)} + + {Math.round(ut.added_mean_pax)} / Max: -{ut.removed_max_pax} + + {ut.added_max_pax} +
    • +
    + + +
    + ); +} + +function SimResultsPanel(): JSX.Element { + const [selectedSimResult] = useAtom(selectedSimResultAtom); + + return ( +
    + + {selectedSimResult ? ( + + ) : null} +
    + ); +} + +export default SimResultsPanel; diff --git a/ui/rsl/src/components/StationPicker.tsx b/ui/rsl/src/components/StationPicker.tsx index 2e82704f0..538761df5 100644 --- a/ui/rsl/src/components/StationPicker.tsx +++ b/ui/rsl/src/components/StationPicker.tsx @@ -1,17 +1,21 @@ -import { useState } from "react"; -import { useCombobox } from "downshift"; import { ChevronDownIcon } from "@heroicons/react/solid"; -import { Station } from "../api/protocol/motis"; -import { useStationGuesserQuery } from "../api/guesser"; +import { useCombobox } from "downshift"; +import { useState } from "react"; + +import { Station } from "@/api/protocol/motis"; + +import { useStationGuesserQuery } from "@/api/guesser"; type StationPickerProps = { onStationPicked: (station: Station | undefined) => void; clearOnPick: boolean; + initialStation?: Station | undefined; }; function StationPicker({ onStationPicked, clearOnPick, + initialStation, }: StationPickerProps): JSX.Element { const [input, setInput] = useState(""); const { data } = useStationGuesserQuery({ input, guess_count: 10 }); @@ -29,6 +33,7 @@ function StationPicker({ } = useCombobox({ items: stationList, itemToString: (item: Station | null) => (item !== null ? item.name : ""), + initialSelectedItem: initialStation ?? null, onInputValueChange: ({ inputValue }) => { if (inputValue != undefined) { setInput(inputValue); @@ -46,7 +51,6 @@ function StationPicker({ return (
    - {/* */}
    - si.line ? `${si.train_nr} [${si.name}]` : si.name + data.tsi.service_infos.map( + (si) => + `${si.category} ${si.train_nr}` + + (si.line ? ` [Linie ${si.line}]` : "") ) ), ]; - const title = `${names.join(", ")} (${data.tsi.primary_station.name} - ${ - data.tsi.secondary_station.name - }), Vorhersage vom ${formatLongDateTime(systemTime)}`; + const title = `${names.join(", ")}, Vorhersage vom ${formatLongDateTime( + systemTime + )}`; const baseFileName = getBaseFileName(data, systemTime); diff --git a/ui/rsl/src/components/TripPicker.tsx b/ui/rsl/src/components/TripPicker.tsx index 604678b42..eea69e6f4 100644 --- a/ui/rsl/src/components/TripPicker.tsx +++ b/ui/rsl/src/components/TripPicker.tsx @@ -1,15 +1,17 @@ -import { useState } from "react"; -import { useCombobox } from "downshift"; import { ChevronDownIcon, XIcon } from "@heroicons/react/solid"; +import { useCombobox } from "downshift"; +import { useAtom } from "jotai"; +import { useState } from "react"; -import { PaxMonTripInfo } from "../api/protocol/motis/paxmon"; -import { TripServiceInfo } from "../api/protocol/motis"; -import { ServiceClass } from "../api/constants"; -import { usePaxMonFindTripsQuery } from "../api/paxmon"; +import { TripServiceInfo } from "@/api/protocol/motis"; +import { PaxMonTripInfo } from "@/api/protocol/motis/paxmon"; -import TripServiceInfoView from "./TripServiceInfoView"; -import { useAtom } from "jotai"; -import { universeAtom } from "../data/simulation"; +import { ServiceClass } from "@/api/constants"; +import { usePaxMonFindTripsQuery } from "@/api/paxmon"; + +import { universeAtom } from "@/data/simulation"; + +import TripServiceInfoView from "@/components/TripServiceInfoView"; function filterTrips(trips: PaxMonTripInfo[]) { return trips.filter((trip) => @@ -25,8 +27,10 @@ function filterTrips(trips: PaxMonTripInfo[]) { function shortTripName(tsi: TripServiceInfo) { const names = [ ...new Set( - tsi.service_infos.map((si) => - si.line ? `${si.train_nr} [${si.name}]` : si.name + tsi.service_infos.map( + (si) => + `${si.category} ${si.train_nr}` + + (si.line ? ` [Linie ${si.line}]` : "") ) ), ]; @@ -38,6 +42,7 @@ type TripPickerProps = { clearOnPick: boolean; longDistanceOnly: boolean; className?: string; + initialTrip?: TripServiceInfo | undefined; }; function TripPicker({ @@ -45,6 +50,7 @@ function TripPicker({ clearOnPick, longDistanceOnly, className, + initialTrip, }: TripPickerProps): JSX.Element { const [universe] = useAtom(universeAtom); const [trainNr, setTrainNr] = useState(); @@ -53,6 +59,15 @@ function TripPicker({ ? filterTrips(data?.trips || []) : data?.trips || []; + const initialSelectedItem = initialTrip + ? { + tsi: initialTrip, + has_paxmon_data: true, + all_edges_have_capacity_info: true, + has_passengers: true, + } + : null; + const { isOpen, getToggleButtonProps, @@ -67,6 +82,7 @@ function TripPicker({ items: tripList, itemToString: (item: PaxMonTripInfo | null) => item !== null ? shortTripName(item.tsi) : "", + initialSelectedItem, onInputValueChange: ({ inputValue }) => { if (inputValue != undefined) { const parsed = parseInt(inputValue); @@ -118,7 +134,7 @@ function TripPicker({ {...getMenuProps()} className={`${ isOpen && tripList.length > 0 ? "" : "hidden" - } absolute w-96 z-50 top-12 bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none p-2`} + } absolute w-64 z-50 top-12 bg-white rounded-md shadow-lg ring-1 ring-black ring-opacity-5 focus:outline-none p-2`} > {isOpen && tripList.map((item, index) => ( diff --git a/ui/rsl/src/components/TripSectionDetails.tsx b/ui/rsl/src/components/TripSectionDetails.tsx index 080bfc533..53333a2e1 100644 --- a/ui/rsl/src/components/TripSectionDetails.tsx +++ b/ui/rsl/src/components/TripSectionDetails.tsx @@ -1,17 +1,19 @@ +import { useAtom } from "jotai"; import { useState } from "react"; -import { TripId } from "../api/protocol/motis"; -import { usePaxMonGroupsInTripQuery } from "../api/paxmon"; -import { PaxMonEdgeLoadInfoWithStats } from "../data/loadInfo"; +import { TripId } from "@/api/protocol/motis"; import { GroupsInTripSection, PaxMonGroupByStation, PaxMonGroupFilter, -} from "../api/protocol/motis/paxmon"; +} from "@/api/protocol/motis/paxmon"; -import CombinedGroup from "./CombinedGroup"; -import { useAtom } from "jotai"; -import { universeAtom } from "../data/simulation"; +import { usePaxMonGroupsInTripQuery } from "@/api/paxmon"; + +import { PaxMonEdgeLoadInfoWithStats } from "@/data/loadInfo"; +import { universeAtom } from "@/data/simulation"; + +import CombinedGroup from "@/components/CombinedGroup"; function isSameSection( sec: GroupsInTripSection, @@ -37,9 +39,10 @@ const groupByStationOptions: Array<{ label: string; }> = [ { groupBy: "Last", label: "Letzter Halt" }, - { groupBy: "LastLongDistance", label: "Letzter Fernverkehrshalt" }, + { groupBy: "LastLongDistance", label: "Letzter FV-Halt" }, { groupBy: "First", label: "Erster Halt" }, - { groupBy: "FirstLongDistance", label: "Erster Fernverkehrshalt" }, + { groupBy: "FirstLongDistance", label: "Erster FV-Halt" }, + { groupBy: "EntryAndLast", label: "Einstiegshalt und Ziel" }, ]; type TripSectionDetailsProps = { @@ -157,7 +160,7 @@ function TripSectionDetails({ {label} ))} - {groupFilter !== "All" ? ( + {groupFilter !== "All" || groupByStation === "EntryAndLast" ? ( ) : null}
    diff --git a/ui/rsl/src/components/TripSelection.tsx b/ui/rsl/src/components/TripSelection.tsx new file mode 100644 index 000000000..7bc3637d3 --- /dev/null +++ b/ui/rsl/src/components/TripSelection.tsx @@ -0,0 +1,52 @@ +import { useState } from "react"; + +import { TripId, TripServiceInfo } from "@/api/protocol/motis"; + +import CriticalTripList from "@/components/CriticialTripList"; +import TripPicker from "@/components/TripPicker"; +import TripServiceInfoView from "@/components/TripServiceInfoView"; + +export type TripSelectionProps = { + onTripSelected: (trip: TripId | undefined) => void; +}; + +function TripSelection({ onTripSelected }: TripSelectionProps): JSX.Element { + const [trips, setTrips] = useState([]); + + function addTrip(tsi: TripServiceInfo | undefined) { + if (tsi) { + setTrips((ts) => [tsi, ...ts]); + } + onTripSelected(tsi?.trip); + } + + return ( +
    +
    + Zugnummer: + +
    +
    + {trips.map((trip) => ( +
    onTripSelected(trip.trip)} + > + +
    + ))} +
    +
    + +
    +
    + ); +} + +export default TripSelection; diff --git a/ui/rsl/src/components/TripServiceInfoView.tsx b/ui/rsl/src/components/TripServiceInfoView.tsx index f5457eef8..ecfa7b089 100644 --- a/ui/rsl/src/components/TripServiceInfoView.tsx +++ b/ui/rsl/src/components/TripServiceInfoView.tsx @@ -1,5 +1,6 @@ -import { formatDateTime } from "../util/dateFormat"; -import { TripServiceInfo } from "../api/protocol/motis"; +import { TripServiceInfo } from "@/api/protocol/motis"; + +import { formatDateTime } from "@/util/dateFormat"; type TripServiceInfoViewProps = { tsi: TripServiceInfo; @@ -12,8 +13,9 @@ function TripServiceInfoView({ }: TripServiceInfoViewProps): JSX.Element { const names = [ ...new Set( - tsi.service_infos.map((si) => - si.line ? `${si.train_nr} [${si.name}]` : si.name + tsi.service_infos.map( + (si) => `${si.category} ${si.train_nr}` + //+ (si.line ? ` [Linie ${si.line}]` : "") ) ), ]; @@ -21,11 +23,19 @@ function TripServiceInfoView({ return {names.join(", ")}; } else { return ( - - {names.join(", ")} ({tsi.primary_station.name} ( - {formatDateTime(tsi.trip.time)}) – {tsi.secondary_station.name} ( - {formatDateTime(tsi.trip.target_time)})) - +
    +
    {names.join(", ")}
    +
    +
    +
    {tsi.primary_station.name}
    +
    {formatDateTime(tsi.trip.time)}
    +
    +
    +
    {tsi.secondary_station.name}
    +
    {formatDateTime(tsi.trip.target_time)}
    +
    +
    +
    ); } } diff --git a/ui/rsl/src/components/UniverseControl.tsx b/ui/rsl/src/components/UniverseControl.tsx index 3ca7e71e0..47a4d6fc6 100644 --- a/ui/rsl/src/components/UniverseControl.tsx +++ b/ui/rsl/src/components/UniverseControl.tsx @@ -1,12 +1,13 @@ +import { useAtom } from "jotai"; import { useState } from "react"; import { useIsMutating, useMutation } from "react-query"; -import { useAtom } from "jotai"; -import { scheduleAtom, universeAtom } from "../data/simulation"; import { sendPaxMonDestroyUniverseRequest, sendPaxMonForkUniverseRequest, -} from "../api/paxmon"; +} from "@/api/paxmon"; + +import { scheduleAtom, universeAtom } from "@/data/simulation"; type Universe = { universe: number; @@ -35,7 +36,10 @@ function UniverseControl(): JSX.Element { { onSuccess: (data) => { const newUv = { universe: data.universe, schedule: data.schedule }; - setUniverses([...new Set([...universes, newUv])]); + setUniverses([ + ...universes.filter((uv) => uv.universe !== data.universe), + newUv, + ]); switchTo(newUv); }, } @@ -43,7 +47,13 @@ function UniverseControl(): JSX.Element { const destroyMutation = useMutation( (uv: number) => sendPaxMonDestroyUniverseRequest({ universe: uv }), { - onSuccess: (data, variables) => { + onSettled: (data, error, variables) => { + if (error) { + console.log( + `error while trying to destroy universe ${variables}:`, + error + ); + } setUniverses(universes.filter((u) => u.universe != variables)); switchTo(universes[0]); }, diff --git a/ui/rsl/src/components/measures/MeasureEditor.tsx b/ui/rsl/src/components/measures/MeasureEditor.tsx new file mode 100644 index 000000000..90ed89428 --- /dev/null +++ b/ui/rsl/src/components/measures/MeasureEditor.tsx @@ -0,0 +1,202 @@ +import { PrimitiveAtom, useAtom } from "jotai"; +import { focusAtom } from "jotai/optics"; +import { useUpdateAtom } from "jotai/utils"; +import { useMemo, useState } from "react"; + +import { MeasureUnion } from "@/data/measures"; + +import RtUpdateMeasureEditor from "@/components/measures/RtUpdateMeasureEditor"; +import SharedDataEditor from "@/components/measures/SharedDataEditor"; +import TripLoadInfoMeasureEditor from "@/components/measures/TripLoadInfoMeasureEditor"; +import TripRecommendationMeasureEditor from "@/components/measures/TripRecommendationMeasureEditor"; +import ModalDialog from "@/components/util/ModalDialog"; + +export type MeasureEditorProps = { + measureAtom: PrimitiveAtom; + deleteMeasure: (measureAtom: PrimitiveAtom) => void; + closeEditor: () => void; +}; + +function MeasureEditor({ + measureAtom, + deleteMeasure, + closeEditor, +}: MeasureEditorProps): JSX.Element { + const typeAtom = useMemo( + () => focusAtom(measureAtom, (optic) => optic.prop("type")), + [measureAtom] + ); + const [measureType] = useAtom(typeAtom); + const setMeasure = useUpdateAtom(measureAtom); + const [changeTypeDialogOpen, setChangeTypeDialogOpen] = useState(false); + + const onChangeTypeDialogClose = (cancel: boolean) => { + if (!cancel) { + setMeasure((m) => { + return { type: "Empty", shared: m.shared }; + }); + } + setChangeTypeDialogOpen(false); + }; + + const measureEditor = (e: JSX.Element) => ( +
    +
    + Maßnahme bearbeiten + +
    + + {e} + + Wirklich den Maßnahmentyp ändern? Dabei gehen alle bisherigen + Einstellungen der Maßnahme verloren. + +
    + ); + + switch (measureType) { + case "Empty": + return ( + + ); + case "TripLoadInfoMeasure": + return measureEditor( + + ); + case "TripRecommendationMeasure": + return measureEditor( + + ); + case "RtUpdateMeasure": + return measureEditor( + + ); + } +} + +interface MeasureTypeOptionProps { + title: string; + children: React.ReactNode; + onClick: () => void; +} + +function MeasureTypeOption({ + title, + children, + onClick, +}: MeasureTypeOptionProps) { + return ( +
    +
    + {title} +
    +
    + {children} +
    +
    + ); +} + +function EmptyMeasureEditor({ + measureAtom, + deleteMeasure, +}: MeasureEditorProps) { + const setMeasure = useUpdateAtom(measureAtom); + + const setTripLoadInfo = () => { + setMeasure((m) => { + return { + type: "TripLoadInfoMeasure", + shared: m.shared, + data: { trip: undefined, level: "Unknown" }, + }; + }); + }; + + const setTripRecommendation = () => { + setMeasure((m) => { + return { + type: "TripRecommendationMeasure", + shared: m.shared, + data: { + planned_destination: undefined, + recommended_trip: undefined, + interchange_station: undefined, + }, + }; + }); + }; + + const setRtUpdate = () => { + setMeasure((m) => { + return { + type: "RtUpdateMeasure", + shared: m.shared, + data: { trip: undefined, ribasis: undefined }, + }; + }); + }; + + return ( +
    +
    Maßnahmentyp wählen:
    +
    + + Ansage oder Anzeige der erwarteten Zugauslastung + + + Empfehlung an Reisende in einem Zug oder an einer Station, + Verbindungen mit einem empfohlenen Zug zu verwenden + + + Zugverlauf bearbeiten (Verspätungen, Umleitungen, Gleisänderungen) + + +
    +
    + ); +} + +export default MeasureEditor; diff --git a/ui/rsl/src/components/measures/MeasureInput.tsx b/ui/rsl/src/components/measures/MeasureInput.tsx deleted file mode 100644 index 1e6a83688..000000000 --- a/ui/rsl/src/components/measures/MeasureInput.tsx +++ /dev/null @@ -1,394 +0,0 @@ -import { useState } from "react"; - -import { queryKeys, usePaxMonStatusQuery } from "../../api/paxmon"; -import { Station, TripServiceInfo } from "../../api/protocol/motis"; -import { - LoadLevel, - MeasureType, - MeasureWrapper, -} from "../../api/protocol/motis/paxforecast"; - -import TripPicker from "../TripPicker"; -import StationPicker from "../StationPicker"; -import TripServiceInfoView from "../TripServiceInfoView"; -import TimeInput from "./TimeInput"; -import { useMutation, useQueryClient } from "react-query"; -import { useAtom } from "jotai"; -import { universeAtom } from "../../data/simulation"; -import { sendPaxForecastApplyMeasuresRequest } from "../../api/paxforecast"; -import { RISContentType } from "../../api/protocol/motis/ris"; - -const loadLevels: Array<{ level: LoadLevel; label: string }> = [ - { level: "Unknown", label: "unbekannt" }, - { level: "Low", label: "gering" }, - { level: "NoSeats", label: "keine Sitzplätze mehr" }, - { level: "Full", label: "voll" }, -]; - -const risContentTypes: Array<{ type: RISContentType; label: string }> = [ - { type: "RIBasis", label: "RI Basis" }, - { type: "RISML", label: "RISML" }, -]; - -const measureTypes: Array<{ type: MeasureType; label: string }> = [ - { type: "TripLoadInfoMeasure", label: "Auslastungsinformation" }, - { type: "TripRecommendationMeasure", label: "Alternativenempfehlung" }, - { type: "RtUpdateMeasure", label: "Echtzeitmeldung" }, -]; - -const labelClass = "font-semibold"; - -function MeasureInput(): JSX.Element { - const queryClient = useQueryClient(); - const [universe] = useAtom(universeAtom); - const [recipientTrips, setRecipientTrips] = useState([]); - const [recipientStations, setRecipientStations] = useState([]); - const { data: status } = usePaxMonStatusQuery(universe); - const [time, setTime] = useState(() => - status ? new Date(status.system_time * 1000) : new Date() - ); - - const [measureType, setMeasureType] = useState( - "TripLoadInfoMeasure" - ); - - const [loadInfoTrip, setLoadInfoTrip] = useState(); - const [loadInfoLevel, setLoadInfoLevel] = useState("Unknown"); - - const [tripRecDestination, setTripRecDestination] = useState(); - const [tripRecInterchange, setTripRecInterchange] = useState(); - const [tripRecTrip, setTripRecTrip] = useState(); - - const [rtContentType, setRtContentType] = useState("RIBasis"); - const [rtContent, setRtContent] = useState(""); - - const applyEnabled = universe != 0; - - const applyMeasuresMutation = useMutation( - (measures: MeasureWrapper[]) => - sendPaxForecastApplyMeasuresRequest({ - universe, - measures, - replace_existing: true, - preparation_time: 0, - }), - { - onSuccess: async () => { - console.log("measures applied"); - await queryClient.invalidateQueries(queryKeys.trip()); - }, - } - ); - - const addTrip = (trip: TripServiceInfo | undefined) => { - if (trip) { - const id = JSON.stringify(trip.trip); - if (!recipientTrips.some((t) => JSON.stringify(t.trip) === id)) { - setRecipientTrips([...recipientTrips, trip]); - } - } - }; - - const removeTrip = (idx: number) => { - const newTrips = [...recipientTrips]; - newTrips.splice(idx, 1); - setRecipientTrips(newTrips); - }; - - const addStation = (station: Station | undefined) => { - if (station && !recipientStations.some((s) => s.id == station.id)) { - setRecipientStations([...recipientStations, station]); - } - }; - - const removeStation = (idx: number) => { - const newStations = [...recipientStations]; - newStations.splice(idx, 1); - setRecipientStations(newStations); - }; - - const buildMeasure: () => MeasureWrapper = () => { - const recipients = { - trips: recipientTrips.map((tsi) => tsi.trip), - stations: recipientStations.map((s) => s.id), - }; - const unixTime = Math.round(time.getTime() / 1000); - - if (recipients.trips.length == 0 && recipients.stations.length == 0) { - throw new Error("Kein Ort für die Ansage ausgewählt"); - } - - switch (measureType) { - case "TripLoadInfoMeasure": - if (!loadInfoTrip) { - throw new Error("Kein Trip ausgewählt"); - } - return { - measure_type: "TripLoadInfoMeasure", - measure: { - recipients, - time: unixTime, - trip: loadInfoTrip.trip, - level: loadInfoLevel, - }, - }; - case "TripRecommendationMeasure": - if (!tripRecDestination || !tripRecInterchange || !tripRecTrip) { - throw new Error("Nicht alle benötigten Felder ausgefüllt"); - } - return { - measure_type: "TripRecommendationMeasure", - measure: { - recipients, - time: unixTime, - planned_trips: [], - planned_destinations: [tripRecDestination.id], - planned_long_distance_destinations: [], - recommended_trip: tripRecTrip.trip, - interchange_station: tripRecInterchange.id, - }, - }; - case "RtUpdateMeasure": - return { - measure_type: "RtUpdateMeasure", - measure: { - recipients, - time: unixTime, - type: rtContentType, - content: rtContent, - }, - }; - } - }; - - const measureDetails: () => JSX.Element = () => { - switch (measureType) { - case "TripLoadInfoMeasure": - return ( - <> - {/*
    Auslastungsinformation
    */} -
    -
    Trip
    -
    - -
    -
    -
    -
    Auslastungsstufe
    -
    - {loadLevels.map(({ level, label }) => ( - - ))} -
    -
    - - ); - case "TripRecommendationMeasure": - return ( - <> - {/*
    Alternativenempfehlung
    */} -
    -
    Reisende Richtung
    - -
    -
    -
    Umsteigen an Station
    - -
    -
    -
    in Trip
    - -
    - - ); - case "RtUpdateMeasure": - return ( - <> -
    -
    Meldungstyp
    -
    - {risContentTypes.map(({ type, label }) => ( - - ))} -
    -
    -
    -
    Echtzeitmeldung
    -
    -